Message ID | 20200325161249.55095-34-glider@google.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Add KernelMemorySanitizer infrastructure | expand |
On Wed, Mar 25, 2020 at 5:14 PM <glider@google.com> wrote: > > Functions from lib/iomap.c interact with hardware, so KMSAN must ensure > that: > - every read function returns an initialized value > - every write function checks values before sending them to hardware. > > Signed-off-by: Alexander Potapenko <glider@google.com> > Cc: Christoph Hellwig <hch@infradead.org> > Cc: Darrick J. Wong <darrick.wong@oracle.com> > Cc: Vegard Nossum <vegard.nossum@oracle.com> > Cc: Dmitry Vyukov <dvyukov@google.com> > Cc: Marco Elver <elver@google.com> > Cc: Andrey Konovalov <andreyknvl@google.com> > Cc: linux-mm@kvack.org Reviewed-by: Andrey Konovalov <andreyknvl@google.com> > --- > v4: > - adjust sizes of checked memory buffers as requested by Marco Elver > > Change-Id: Iacd96265e56398d8c111637ddad3cad727e48c8d > --- > lib/iomap.c | 40 ++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 40 insertions(+) > > diff --git a/lib/iomap.c b/lib/iomap.c > index e909ab71e995d..3582e8d1ca34e 100644 > --- a/lib/iomap.c > +++ b/lib/iomap.c > @@ -6,6 +6,7 @@ > */ > #include <linux/pci.h> > #include <linux/io.h> > +#include <linux/kmsan-checks.h> > > #include <linux/export.h> > > @@ -70,26 +71,31 @@ static void bad_io_access(unsigned long port, const char *access) > #define mmio_read64be(addr) swab64(readq(addr)) > #endif > > +__no_sanitize_memory > unsigned int ioread8(void __iomem *addr) > { > IO_COND(addr, return inb(port), return readb(addr)); > return 0xff; > } > +__no_sanitize_memory > unsigned int ioread16(void __iomem *addr) > { > IO_COND(addr, return inw(port), return readw(addr)); > return 0xffff; > } > +__no_sanitize_memory > unsigned int ioread16be(void __iomem *addr) > { > IO_COND(addr, return pio_read16be(port), return mmio_read16be(addr)); > return 0xffff; > } > +__no_sanitize_memory > unsigned int ioread32(void __iomem *addr) > { > IO_COND(addr, return inl(port), return readl(addr)); > return 0xffffffff; > } > +__no_sanitize_memory > unsigned int ioread32be(void __iomem *addr) > { > IO_COND(addr, return pio_read32be(port), return mmio_read32be(addr)); > @@ -142,18 +148,21 @@ static u64 pio_read64be_hi_lo(unsigned long port) > return lo | (hi << 32); > } > > +__no_sanitize_memory > u64 ioread64_lo_hi(void __iomem *addr) > { > IO_COND(addr, return pio_read64_lo_hi(port), return readq(addr)); > return 0xffffffffffffffffULL; > } > > +__no_sanitize_memory > u64 ioread64_hi_lo(void __iomem *addr) > { > IO_COND(addr, return pio_read64_hi_lo(port), return readq(addr)); > return 0xffffffffffffffffULL; > } > > +__no_sanitize_memory > u64 ioread64be_lo_hi(void __iomem *addr) > { > IO_COND(addr, return pio_read64be_lo_hi(port), > @@ -161,6 +170,7 @@ u64 ioread64be_lo_hi(void __iomem *addr) > return 0xffffffffffffffffULL; > } > > +__no_sanitize_memory > u64 ioread64be_hi_lo(void __iomem *addr) > { > IO_COND(addr, return pio_read64be_hi_lo(port), > @@ -188,22 +198,32 @@ EXPORT_SYMBOL(ioread64be_hi_lo); > > void iowrite8(u8 val, void __iomem *addr) > { > + /* Make sure uninitialized memory isn't copied to devices. */ > + kmsan_check_memory(&val, sizeof(val)); > IO_COND(addr, outb(val,port), writeb(val, addr)); > } > void iowrite16(u16 val, void __iomem *addr) > { > + /* Make sure uninitialized memory isn't copied to devices. */ > + kmsan_check_memory(&val, sizeof(val)); > IO_COND(addr, outw(val,port), writew(val, addr)); > } > void iowrite16be(u16 val, void __iomem *addr) > { > + /* Make sure uninitialized memory isn't copied to devices. */ > + kmsan_check_memory(&val, sizeof(val)); > IO_COND(addr, pio_write16be(val,port), mmio_write16be(val, addr)); > } > void iowrite32(u32 val, void __iomem *addr) > { > + /* Make sure uninitialized memory isn't copied to devices. */ > + kmsan_check_memory(&val, sizeof(val)); > IO_COND(addr, outl(val,port), writel(val, addr)); > } > void iowrite32be(u32 val, void __iomem *addr) > { > + /* Make sure uninitialized memory isn't copied to devices. */ > + kmsan_check_memory(&val, sizeof(val)); > IO_COND(addr, pio_write32be(val,port), mmio_write32be(val, addr)); > } > EXPORT_SYMBOL(iowrite8); > @@ -239,24 +259,32 @@ static void pio_write64be_hi_lo(u64 val, unsigned long port) > > void iowrite64_lo_hi(u64 val, void __iomem *addr) > { > + /* Make sure uninitialized memory isn't copied to devices. */ > + kmsan_check_memory(&val, sizeof(val)); > IO_COND(addr, pio_write64_lo_hi(val, port), > writeq(val, addr)); > } > > void iowrite64_hi_lo(u64 val, void __iomem *addr) > { > + /* Make sure uninitialized memory isn't copied to devices. */ > + kmsan_check_memory(&val, sizeof(val)); > IO_COND(addr, pio_write64_hi_lo(val, port), > writeq(val, addr)); > } > > void iowrite64be_lo_hi(u64 val, void __iomem *addr) > { > + /* Make sure uninitialized memory isn't copied to devices. */ > + kmsan_check_memory(&val, sizeof(val)); > IO_COND(addr, pio_write64be_lo_hi(val, port), > mmio_write64be(val, addr)); > } > > void iowrite64be_hi_lo(u64 val, void __iomem *addr) > { > + /* Make sure uninitialized memory isn't copied to devices. */ > + kmsan_check_memory(&val, sizeof(val)); > IO_COND(addr, pio_write64be_hi_lo(val, port), > mmio_write64be(val, addr)); > } > @@ -328,14 +356,20 @@ static inline void mmio_outsl(void __iomem *addr, const u32 *src, int count) > void ioread8_rep(void __iomem *addr, void *dst, unsigned long count) > { > IO_COND(addr, insb(port,dst,count), mmio_insb(addr, dst, count)); > + /* KMSAN must treat values read from devices as initialized. */ > + kmsan_unpoison_shadow(dst, count); > } > void ioread16_rep(void __iomem *addr, void *dst, unsigned long count) > { > IO_COND(addr, insw(port,dst,count), mmio_insw(addr, dst, count)); > + /* KMSAN must treat values read from devices as initialized. */ > + kmsan_unpoison_shadow(dst, count * 2); > } > void ioread32_rep(void __iomem *addr, void *dst, unsigned long count) > { > IO_COND(addr, insl(port,dst,count), mmio_insl(addr, dst, count)); > + /* KMSAN must treat values read from devices as initialized. */ > + kmsan_unpoison_shadow(dst, count * 4); > } > EXPORT_SYMBOL(ioread8_rep); > EXPORT_SYMBOL(ioread16_rep); > @@ -343,14 +377,20 @@ EXPORT_SYMBOL(ioread32_rep); > > void iowrite8_rep(void __iomem *addr, const void *src, unsigned long count) > { > + /* Make sure uninitialized memory isn't copied to devices. */ > + kmsan_check_memory(src, count); > IO_COND(addr, outsb(port, src, count), mmio_outsb(addr, src, count)); > } > void iowrite16_rep(void __iomem *addr, const void *src, unsigned long count) > { > + /* Make sure uninitialized memory isn't copied to devices. */ > + kmsan_check_memory(src, count * 2); > IO_COND(addr, outsw(port, src, count), mmio_outsw(addr, src, count)); > } > void iowrite32_rep(void __iomem *addr, const void *src, unsigned long count) > { > + /* Make sure uninitialized memory isn't copied to devices. */ > + kmsan_check_memory(src, count * 4); > IO_COND(addr, outsl(port, src,count), mmio_outsl(addr, src, count)); > } > EXPORT_SYMBOL(iowrite8_rep); > -- > 2.25.1.696.g5e7596f4ac-goog >
diff --git a/lib/iomap.c b/lib/iomap.c index e909ab71e995d..3582e8d1ca34e 100644 --- a/lib/iomap.c +++ b/lib/iomap.c @@ -6,6 +6,7 @@ */ #include <linux/pci.h> #include <linux/io.h> +#include <linux/kmsan-checks.h> #include <linux/export.h> @@ -70,26 +71,31 @@ static void bad_io_access(unsigned long port, const char *access) #define mmio_read64be(addr) swab64(readq(addr)) #endif +__no_sanitize_memory unsigned int ioread8(void __iomem *addr) { IO_COND(addr, return inb(port), return readb(addr)); return 0xff; } +__no_sanitize_memory unsigned int ioread16(void __iomem *addr) { IO_COND(addr, return inw(port), return readw(addr)); return 0xffff; } +__no_sanitize_memory unsigned int ioread16be(void __iomem *addr) { IO_COND(addr, return pio_read16be(port), return mmio_read16be(addr)); return 0xffff; } +__no_sanitize_memory unsigned int ioread32(void __iomem *addr) { IO_COND(addr, return inl(port), return readl(addr)); return 0xffffffff; } +__no_sanitize_memory unsigned int ioread32be(void __iomem *addr) { IO_COND(addr, return pio_read32be(port), return mmio_read32be(addr)); @@ -142,18 +148,21 @@ static u64 pio_read64be_hi_lo(unsigned long port) return lo | (hi << 32); } +__no_sanitize_memory u64 ioread64_lo_hi(void __iomem *addr) { IO_COND(addr, return pio_read64_lo_hi(port), return readq(addr)); return 0xffffffffffffffffULL; } +__no_sanitize_memory u64 ioread64_hi_lo(void __iomem *addr) { IO_COND(addr, return pio_read64_hi_lo(port), return readq(addr)); return 0xffffffffffffffffULL; } +__no_sanitize_memory u64 ioread64be_lo_hi(void __iomem *addr) { IO_COND(addr, return pio_read64be_lo_hi(port), @@ -161,6 +170,7 @@ u64 ioread64be_lo_hi(void __iomem *addr) return 0xffffffffffffffffULL; } +__no_sanitize_memory u64 ioread64be_hi_lo(void __iomem *addr) { IO_COND(addr, return pio_read64be_hi_lo(port), @@ -188,22 +198,32 @@ EXPORT_SYMBOL(ioread64be_hi_lo); void iowrite8(u8 val, void __iomem *addr) { + /* Make sure uninitialized memory isn't copied to devices. */ + kmsan_check_memory(&val, sizeof(val)); IO_COND(addr, outb(val,port), writeb(val, addr)); } void iowrite16(u16 val, void __iomem *addr) { + /* Make sure uninitialized memory isn't copied to devices. */ + kmsan_check_memory(&val, sizeof(val)); IO_COND(addr, outw(val,port), writew(val, addr)); } void iowrite16be(u16 val, void __iomem *addr) { + /* Make sure uninitialized memory isn't copied to devices. */ + kmsan_check_memory(&val, sizeof(val)); IO_COND(addr, pio_write16be(val,port), mmio_write16be(val, addr)); } void iowrite32(u32 val, void __iomem *addr) { + /* Make sure uninitialized memory isn't copied to devices. */ + kmsan_check_memory(&val, sizeof(val)); IO_COND(addr, outl(val,port), writel(val, addr)); } void iowrite32be(u32 val, void __iomem *addr) { + /* Make sure uninitialized memory isn't copied to devices. */ + kmsan_check_memory(&val, sizeof(val)); IO_COND(addr, pio_write32be(val,port), mmio_write32be(val, addr)); } EXPORT_SYMBOL(iowrite8); @@ -239,24 +259,32 @@ static void pio_write64be_hi_lo(u64 val, unsigned long port) void iowrite64_lo_hi(u64 val, void __iomem *addr) { + /* Make sure uninitialized memory isn't copied to devices. */ + kmsan_check_memory(&val, sizeof(val)); IO_COND(addr, pio_write64_lo_hi(val, port), writeq(val, addr)); } void iowrite64_hi_lo(u64 val, void __iomem *addr) { + /* Make sure uninitialized memory isn't copied to devices. */ + kmsan_check_memory(&val, sizeof(val)); IO_COND(addr, pio_write64_hi_lo(val, port), writeq(val, addr)); } void iowrite64be_lo_hi(u64 val, void __iomem *addr) { + /* Make sure uninitialized memory isn't copied to devices. */ + kmsan_check_memory(&val, sizeof(val)); IO_COND(addr, pio_write64be_lo_hi(val, port), mmio_write64be(val, addr)); } void iowrite64be_hi_lo(u64 val, void __iomem *addr) { + /* Make sure uninitialized memory isn't copied to devices. */ + kmsan_check_memory(&val, sizeof(val)); IO_COND(addr, pio_write64be_hi_lo(val, port), mmio_write64be(val, addr)); } @@ -328,14 +356,20 @@ static inline void mmio_outsl(void __iomem *addr, const u32 *src, int count) void ioread8_rep(void __iomem *addr, void *dst, unsigned long count) { IO_COND(addr, insb(port,dst,count), mmio_insb(addr, dst, count)); + /* KMSAN must treat values read from devices as initialized. */ + kmsan_unpoison_shadow(dst, count); } void ioread16_rep(void __iomem *addr, void *dst, unsigned long count) { IO_COND(addr, insw(port,dst,count), mmio_insw(addr, dst, count)); + /* KMSAN must treat values read from devices as initialized. */ + kmsan_unpoison_shadow(dst, count * 2); } void ioread32_rep(void __iomem *addr, void *dst, unsigned long count) { IO_COND(addr, insl(port,dst,count), mmio_insl(addr, dst, count)); + /* KMSAN must treat values read from devices as initialized. */ + kmsan_unpoison_shadow(dst, count * 4); } EXPORT_SYMBOL(ioread8_rep); EXPORT_SYMBOL(ioread16_rep); @@ -343,14 +377,20 @@ EXPORT_SYMBOL(ioread32_rep); void iowrite8_rep(void __iomem *addr, const void *src, unsigned long count) { + /* Make sure uninitialized memory isn't copied to devices. */ + kmsan_check_memory(src, count); IO_COND(addr, outsb(port, src, count), mmio_outsb(addr, src, count)); } void iowrite16_rep(void __iomem *addr, const void *src, unsigned long count) { + /* Make sure uninitialized memory isn't copied to devices. */ + kmsan_check_memory(src, count * 2); IO_COND(addr, outsw(port, src, count), mmio_outsw(addr, src, count)); } void iowrite32_rep(void __iomem *addr, const void *src, unsigned long count) { + /* Make sure uninitialized memory isn't copied to devices. */ + kmsan_check_memory(src, count * 4); IO_COND(addr, outsl(port, src,count), mmio_outsl(addr, src, count)); } EXPORT_SYMBOL(iowrite8_rep);
Functions from lib/iomap.c interact with hardware, so KMSAN must ensure that: - every read function returns an initialized value - every write function checks values before sending them to hardware. Signed-off-by: Alexander Potapenko <glider@google.com> Cc: Christoph Hellwig <hch@infradead.org> Cc: Darrick J. Wong <darrick.wong@oracle.com> Cc: Vegard Nossum <vegard.nossum@oracle.com> Cc: Dmitry Vyukov <dvyukov@google.com> Cc: Marco Elver <elver@google.com> Cc: Andrey Konovalov <andreyknvl@google.com> Cc: linux-mm@kvack.org --- v4: - adjust sizes of checked memory buffers as requested by Marco Elver Change-Id: Iacd96265e56398d8c111637ddad3cad727e48c8d --- lib/iomap.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+)