Add KernelMemorySanitizer infrastructure
Subsystems (46)
[email protected]
maintainerv2 cover Add KernelMemorySanitizer infrastructure
KernelMemorySanitizer (KMSAN) is a detector of errors related to uses of uninitialized memory. It relies on compile-time Clang instrumentation (similar to MSan: https://clang.llvm.org/docs/MemorySanitizer.html)
and tracks the state of every bit of kernel memory, being able to report an error if uninitialized value is used in a condition, dereferenced or copied to userspace, USB or network.
KMSAN has reported more than 200 bugs in the past two years, most of them with the help of syzkaller (http://syzkaller.appspot.com).
The proposed patchset contains KMSAN runtime implementation together with small changes to other subsystems needed to make KMSAN work. The latter changes fall into several categories:
- nice-to-have features that are independent from KMSAN but simplify its implementation (stackdepot changes, CONFIG_GENERIC_CSUM etc.);
- Kconfig changes that prohibit options incompatible with KMSAN;
- calls to KMSAN runtime functions that help KMSAN do the bookkeeping (e.g. tell it to allocate, copy or delete the metadata);
- calls to KMSAN runtime functions that tell KMSAN to check memory escaping the kernel for uninitialized values. These are required to increase the number of true positive error reports;
- calls to runtime functions that tell KMSAN to ignore certain memory ranges to avoid false negative reports. Most certainly there can be better ways to deal with every such report.
This patchset allows one to boot and run a defconfig+KMSAN kernel on a QEMU without known major false positives. It however doesn't guarantee there are no false positives in drivers of certain devices or less tested subsystems, although KMSAN is actively tested on syzbot with quite a rich config.
One may find it handy to review these patches in Gerrit:
https://linux-review.googlesource.com/c/linux/kernel/git/torvalds/linux/+/1081
I've ensured the Change-Id: tags stay away from commit descriptions.
The patchset was generated relative to Linux v5.4-rc5.
I also apologize for not sending every patch in the previous series to all recipients of patches from that series.
Note: checkpatch.pl complains a lot about the use of BUG_ON in KMSAN source. I don't have a strong opinion on this, but KMSAN is a debugging tool, so any runtime invariant violation in it renders the tool useless. Therefore it doesn't make much sense to not terminate after a bug in KMSAN.
Alexander Potapenko (25):
stackdepot: check depot_index before accessing the stack slab
stackdepot: prevent Clang from optimizing away stackdepot_memcmp()
kasan: stackdepot: move filter_irq_stacks() to stackdepot.c
stackdepot: reserve 5 extra bits in depot_stack_handle_t
kmsan: add ReST documentation
kmsan: gfp: introduce __GFP_NO_KMSAN_SHADOW
kmsan: introduce __no_sanitize_memory and __SANITIZE_MEMORY__
kmsan: reduce vmalloc space
kmsan: add KMSAN runtime
kmsan: define READ_ONCE_NOCHECK()
kmsan: x86: sync metadata pages on page fault
kmsan: add tests for KMSAN
kmsan: make READ_ONCE_TASK_STACK() return initialized values
kmsan: Kconfig changes to disable options incompatible with KMSAN
kmsan: Changing existing files to enable KMSAN builds
kmsan: disable KMSAN instrumentation for certain kernel parts
kmsan: mm: call KMSAN hooks from SLUB code
kmsan: call KMSAN hooks where needed
kmsan: disable instrumentation of certain functions
kmsan: unpoison |tlb| in arch_tlb_gather_mmu()
kmsan: use __msan_memcpy() where possible.
kmsan: unpoisoning buffers from devices etc.
kmsan: hooks for copy_to_user() and friends
kmsan: disable strscpy() optimization under KMSAN
net: kasan: kmsan: support CONFIG_GENERIC_CSUM on x86, enable it for
KASAN/KMSAN
To: Alexander Potapenko <[email protected]>
Cc: Alexander Viro <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Andrey Ryabinin <[email protected]>
Cc: Andy Lutomirski <[email protected]>
Cc: Ard Biesheuvel <[email protected]>
Cc: Arnd Bergmann <[email protected]>
Cc: Christoph Hellwig <[email protected]>
Cc: Dmitry Torokhov <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: Eric Dumazet <[email protected]>
Cc: Eric Van Hensbergen <[email protected]>
Cc: Greg Kroah-Hartman <[email protected]>
Cc: Harry Wentland <[email protected]>
Cc: Herbert Xu <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jens Axboe <[email protected]>
Cc: Martin K. Petersen <[email protected]>
Cc: Martin Schwidefsky <[email protected]>
Cc: "Michael S. Tsirkin" <[email protected]>
Cc: Michal Simek <[email protected]>
Cc: Petr Mladek <[email protected]>
Cc: Sergey Senozhatsky <[email protected]>
Cc: Steven Rostedt <[email protected]>
Cc: Takashi Iwai <[email protected]>
Cc: "Theodore Ts'o" <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Vegard Nossum <[email protected]>
Cc: Wolfram Sang <[email protected]>
Cc: Vasily Gorbik <[email protected]>
Cc: Ilya Leoshkevich <[email protected]>
Cc: Mark Rutland <[email protected]>
Cc: Matthew Wilcox <[email protected]>
Cc: Randy Dunlap <[email protected]>
Cc: Andrey Konovalov <[email protected]>
Cc: Marco Elver <[email protected]>
Cc: [email protected]
Documentation/dev-tools/index.rst | 1 + Documentation/dev-tools/kmsan.rst | 418 +++++++++++++++++ Makefile | 3 +- arch/Kconfig | 2 +- arch/x86/Kconfig | 6 + arch/x86/Kconfig.debug | 3 + arch/x86/boot/Makefile | 2 + arch/x86/boot/compressed/Makefile | 2 + arch/x86/boot/compressed/misc.h | 1 + arch/x86/entry/common.c | 1 + arch/x86/entry/entry_64.S | 18 + arch/x86/entry/vdso/Makefile | 3 + arch/x86/include/asm/checksum.h | 10 +- arch/x86/include/asm/irq_regs.h | 1 + arch/x86/include/asm/kmsan.h | 129 ++++++ arch/x86/include/asm/page_64.h | 13 + arch/x86/include/asm/page_64_types.h | 12 +- arch/x86/include/asm/pgtable_64_types.h | 15 + arch/x86/include/asm/string_64.h | 9 +- arch/x86/include/asm/syscall_wrapper.h | 1 + arch/x86/include/asm/uaccess.h | 12 + arch/x86/include/asm/unwind.h | 9 +- arch/x86/kernel/Makefile | 4 + arch/x86/kernel/apic/apic.c | 2 + arch/x86/kernel/cpu/Makefile | 1 + arch/x86/kernel/dumpstack_64.c | 1 + arch/x86/kernel/process_64.c | 5 + arch/x86/kernel/traps.c | 12 +- arch/x86/kernel/uprobes.c | 7 +- arch/x86/lib/Makefile | 2 + arch/x86/mm/Makefile | 2 + arch/x86/mm/fault.c | 20 + arch/x86/mm/ioremap.c | 3 + arch/x86/realmode/rm/Makefile | 2 + block/bio.c | 20 + block/blk.h | 7 + block/partition-generic.c | 9 +- crypto/Kconfig | 26 ++ drivers/char/random.c | 2 + drivers/firmware/efi/libstub/Makefile | 1 + drivers/gpu/drm/amd/display/Kconfig | 2 +- drivers/i2c/i2c-core-base.c | 2 + drivers/input/serio/libps2.c | 6 +- drivers/scsi/scsi_lib.c | 4 + drivers/usb/core/message.c | 6 +- drivers/usb/core/urb.c | 2 + drivers/virtio/virtio_ring.c | 14 + fs/buffer.c | 7 +- include/asm-generic/cacheflush.h | 7 +- include/asm-generic/uaccess.h | 12 +- include/linux/compiler-clang.h | 8 + include/linux/compiler-gcc.h | 5 + include/linux/compiler.h | 15 +- include/linux/dma-mapping.h | 2 + include/linux/gfp.h | 4 +- include/linux/highmem.h | 4 + include/linux/kmsan-checks.h | 121 +++++ include/linux/kmsan.h | 143 ++++++ include/linux/mm_types.h | 9 + include/linux/sched.h | 5 + include/linux/skbuff.h | 5 +- include/linux/stackdepot.h | 10 + include/linux/string.h | 2 + include/linux/uaccess.h | 32 +- init/main.c | 3 + kernel/Makefile | 1 + kernel/exit.c | 2 + kernel/fork.c | 2 + kernel/kthread.c | 2 + kernel/printk/printk.c | 8 +- kernel/profile.c | 1 + kernel/sched/core.c | 11 + kernel/softirq.c | 5 + lib/Kconfig.debug | 5 + lib/Kconfig.kmsan | 22 + lib/Makefile | 2 + lib/ioremap.c | 5 + lib/iov_iter.c | 6 + lib/stackdepot.c | 72 ++- lib/string.c | 5 +- lib/test_kmsan.c | 231 ++++++++++ lib/usercopy.c | 6 +- mm/Makefile | 1 + mm/compaction.c | 9 + mm/filemap.c | 1 + mm/gup.c | 3 + mm/kasan/common.c | 23 - mm/kmsan/Makefile | 4 + mm/kmsan/kmsan.c | 570 ++++++++++++++++++++++++ mm/kmsan/kmsan.h | 149 +++++++ mm/kmsan/kmsan_entry.c | 130 ++++++ mm/kmsan/kmsan_hooks.c | 393 ++++++++++++++++ mm/kmsan/kmsan_init.c | 88 ++++ mm/kmsan/kmsan_instr.c | 259 +++++++++++ mm/kmsan/kmsan_report.c | 133 ++++++ mm/kmsan/kmsan_shadow.c | 543 ++++++++++++++++++++++ mm/kmsan/kmsan_shadow.h | 30 ++ mm/memory.c | 2 + mm/mmu_gather.c | 10 + mm/page_alloc.c | 16 + mm/readahead.c | 6 + mm/slub.c | 37 +- mm/vmalloc.c | 23 +- net/9p/protocol.c | 2 + net/sched/sch_generic.c | 2 + scripts/Makefile.kmsan | 12 + scripts/Makefile.lib | 6 + sound/core/oss/pcm_oss.c | 7 + 108 files changed, 3999 insertions(+), 73 deletions(-) create mode 100644 Documentation/dev-tools/kmsan.rst create mode 100644 arch/x86/include/asm/kmsan.h create mode 100644 include/linux/kmsan-checks.h create mode 100644 include/linux/kmsan.h create mode 100644 lib/Kconfig.kmsan create mode 100644 lib/test_kmsan.c create mode 100644 mm/kmsan/Makefile create mode 100644 mm/kmsan/kmsan.c create mode 100644 mm/kmsan/kmsan.h create mode 100644 mm/kmsan/kmsan_entry.c create mode 100644 mm/kmsan/kmsan_hooks.c create mode 100644 mm/kmsan/kmsan_init.c create mode 100644 mm/kmsan/kmsan_instr.c create mode 100644 mm/kmsan/kmsan_report.c create mode 100644 mm/kmsan/kmsan_shadow.c create mode 100644 mm/kmsan/kmsan_shadow.h create mode 100644 scripts/Makefile.kmsan
Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
[email protected]
maintainerRFC PATCH v2 1/25 stackdepot: check depot_index before accessing the stack slab
Avoid crashes on corrupted stack ids.
To: Alexander Potapenko <[email protected]>
Cc: Vegard Nossum <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: [email protected]
---
Change-Id: I0a0b38ed5057090696a2c6ff0be7cfcc24ae6738
--- lib/stackdepot.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)
lib/stackdepot.c +15 -2
@@ -198,9 +198,22 @@ unsigned int stack_depot_fetch(depot_stack_handle_t handle, unsigned long **entries) {union handle_parts parts = { .handle = handle }; -void *slab = stack_slabs[parts.slabindex]; +void *slab;size_t offset = parts.offset <<STACK_ALLOC_ALIGN ; -struct stack_record *stack = slab + offset; +struct stack_record *stack; + +if (parts.slabindex > depot_index) { +WARN (1 ,"slab index %d out of bounds (%d) for stack id %08x\n" , + parts.slabindex, depot_index, handle); +__memset (trace,0 ,sizeof (*trace)); +return ; + } + slab = stack_slabs[parts.slabindex]; + stack = slab + offset; +if (!stack) { + entries =NULL ; +return 0 ; + } *entries = stack->entries;return stack->size;
Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
[email protected]
maintainerRFC PATCH v2 2/25 stackdepot: prevent Clang from optimizing away stackdepot_memcmp()
In reply to [email protected]Clang may replace stackdepot_memcmp() with a call to instrumented bcmp(), which is exactly what we wanted to avoid creating stackdepot_memcmp(). Add a compiler barrier() to prevent optimizations.
To: Alexander Potapenko <[email protected]>
Cc: Vegard Nossum <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: [email protected]
---
Change-Id: I4495b617b15c0ab003a61c1f0d54d0026fa8b144
--- lib/stackdepot.c | 5 +++++ 1 file changed, 5 insertions(+)
lib/stackdepot.c +5 -0
@@ -163,6 +163,11 @@ int stackdepot_memcmp(const unsigned long *u1, const unsigned long *u2, unsigned int n) {for ( ; n-- ; u1++, u2++) { +/* +* Prevent Clang from replacing this function with a bcmp() +* call. +*/ +barrier ();if (*u1 != *u2)return 1 ; }
Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
Re: [PATCH RFC v2 02/25] stackdepot: prevent Clang from optimizing away stackdepot_memcmp()
Quoted 3 lines · On (19/10/30 15:22), [email protected] wrote:
Clang may replace
stackdepot_memcmp()with a call to instrumentedbcmp(), which is exactly what we wanted to avoid creatingstackdepot_memcmp(). Add a compilerbarrier()to prevent optimizations.
[..]
lib/stackdepot.c int stackdepot_memcmp(const unsigned long *u1, const unsigned long *u2, · line 173
Quoted 12 lines
lib/stackdepot.c +5
-0@@ -163,6 +163,11 @@ int stackdepot_memcmp(const unsigned long *u1, const unsigned long *u2, unsigned int n) {for ( ; n-- ; u1++, u2++) { +/* +* Prevent Clang from replacing this function with a bcmp() +* call. +*/ +barrier ();if (*u1 != *u2)return 1 ; }
Would 'volatile' do the trick?
-ss
Alexander Potapenko
maintainerRe: [PATCH RFC v2 02/25] stackdepot: prevent Clang from optimizing away stackdepot_memcmp()
Quoted 8 lines · Sergey Senozhatsky
Quoted 3 lines · On (19/10/30 15:22), [email protected] wrote:
Clang may replace
stackdepot_memcmp()with a call to instrumentedbcmp(), which is exactly what we wanted to avoid creatingstackdepot_memcmp(). Add a compilerbarrier()to prevent optimizations.[..]
Quoted 14 lines
lib/stackdepot.c int stackdepot_memcmp(const unsigned long *u1, const unsigned long *u2, · line 173
Quoted 12 lines
lib/stackdepot.c +5
-0@@ -163,6 +163,11 @@ int stackdepot_memcmp(const unsigned long *u1, const unsigned long *u2, unsigned int n) {for ( ; n-- ; u1++, u2++) { +/* +* Prevent Clang from replacing this function with a bcmp() +* call. +*/ +barrier ();if (*u1 != *u2)return 1 ; }Would 'volatile' do the trick?
It does. I can replace the barrier with a volatile if you think that's better. However this'll add a checkpatch warning, as volatiles are discouraged for synchronization (although in this case there's no synchronization)
Quoted 2 lines
-ssSignature · 10 lines
Alexander Potapenko Software Engineer Google Germany GmbH Erika-Mann-Straße, 33 80636 München Geschäftsführer: Paul Manicle, Halimah DeLaine Prado Registergericht und -nummer: Hamburg, HRB 86891 Sitz der Gesellschaft: Hamburg
Re: [PATCH RFC v2 02/25] stackdepot: prevent Clang from optimizing away stackdepot_memcmp()
Quoted 15 lines · Alexander Potapenko
Quoted 7 lines · On (19/10/30 15:22), [email protected] wrote:
Quoted 6 lines
lib/stackdepot.c +2
-0@@ -163,6 +163,11 @@ int stackdepot_memcmp(const unsigned long *u1, const unsigned long *u2, unsigned int n) {for ( ; n-- ; u1++, u2++) { +/* +* Prevent Clang from replacing this function with a bcmp() Quoted 8 lines
lib/stackdepot.c int stackdepot_memcmp(const unsigned long *u1, const unsigned long *u2, · line 173
Quoted 6 lines
lib/stackdepot.c +3
-0+* call. +*/ +barrier ();if (*u1 != *u2)return 1 ; }Would 'volatile' do the trick?
Quoted 3 lines
It does. I can replace the barrier with a volatile if you think that's better. However this'll add a checkpatch warning, as volatiles are discouraged for synchronization (although in this case there's no synchronization)
Yeah, 'volatile' in this case will do what it sort of meant to do - prevent compiler optimizations. So, like you said, it's not a synchronization issue and we don't 'volatile' data structures.
Do you need to do barrier() on every iteration? Does clang behave if you do one barrier() instead of 'n' barrier()-s?
-ss
Arnd Bergmann
maintainerRe: [PATCH RFC v2 02/25] stackdepot: prevent Clang from optimizing away stackdepot_memcmp()
Quoted 17 lines · Sergey Senozhatsky
Quoted 15 lines · Alexander Potapenko
Quoted 15 lines · On (19/10/30 15:22), [email protected] wrote:
lib/stackdepot.c int stackdepot_memcmp(const unsigned long *u1, const unsigned long *u2, · line 173
Quoted 12 lines
lib/stackdepot.c +5
-0@@ -163,6 +163,11 @@ int stackdepot_memcmp(const unsigned long *u1, const unsigned long *u2, unsigned int n) {for ( ; n-- ; u1++, u2++) { +/* +* Prevent Clang from replacing this function with a bcmp() +* call. +*/ +barrier ();if (*u1 != *u2)return 1 ; }Would 'volatile' do the trick?
Quoted 7 lines
Quoted 3 lines
It does. I can replace the barrier with a volatile if you think that's better. However this'll add a checkpatch warning, as volatiles are discouraged for synchronization (although in this case there's no synchronization)
Yeah, 'volatile' in this case will do what it sort of meant to do - prevent compiler optimizations. So, like you said, it's not a synchronization issue and we don't 'volatile' data structures.
The normal way to do a volatile access would be READ_ONCE()/WRITE_ONCE(), but that seems stronger than the barrier() here. I'd just stick to adding a barrier.
Quoted 2 lines
Do you need to do
barrier()on every iteration? Does clang behave if you do onebarrier()instead of 'n' barrier()-s?
If it does things right, it would make that a single-byte copy plus a call to bcmp(). I certainly wouldn't want to have an implementation that relies on the compiler making sub-optimal decisions ;-)
Arnd
Alexander Potapenko
maintainerRe: [PATCH RFC v2 02/25] stackdepot: prevent Clang from optimizing away stackdepot_memcmp()
Quoted 24 lines · Arnd Bergmann
Quoted 21 lines · Sergey Senozhatsky
Quoted 18 lines · Alexander Potapenko
Quoted 7 lines · On (19/10/30 15:22), [email protected] wrote:
Quoted 6 lines
lib/stackdepot.c +2
-0@@ -163,6 +163,11 @@ int stackdepot_memcmp(const unsigned long *u1, const unsigned long *u2, unsigned int n) {for ( ; n-- ; u1++, u2++) { +/* +* Prevent Clang from replacing this function with a bcmp() Quoted 8 lines
lib/stackdepot.c int stackdepot_memcmp(const unsigned long *u1, const unsigned long *u2, · line 173
Quoted 6 lines
lib/stackdepot.c +3
-0+* call. +*/ +barrier ();if (*u1 != *u2)return 1 ; }Would 'volatile' do the trick?
It does. I can replace the barrier with a volatile if you think that's better. However this'll add a checkpatch warning, as volatiles are discouraged for synchronization (although in this case there's no synchronization)
Quoted 7 lines
Quoted 3 lines
Yeah, 'volatile' in this case will do what it sort of meant to do - prevent compiler optimizations. So, like you said, it's not a synchronization issue and we don't 'volatile' data structures.
The normal way to do a volatile access would be READ_ONCE()/WRITE_ONCE(), but that seems stronger than the
barrier()here. I'd just stick to adding a barrier.
I actually like the READ_ONCE idea more, as READ_ONCE is really a documented way to prevent the compiler from merging reads, which is what we want here.
I also thought that the original barrier() statement was just a compiler barrier, which didn't introduce any additional CPU instructions.
Turns out I was wrong, and barrier() also serves as a memory barrier. This doesn't really matter in this case, because this memcmp function isn't performance-critical (we are preventing Clang from optimizing it, after all).
Still, READ_ONCE and WRITE_ONCE might be even cheaper, as they are just relaxed memory accesses implemented using volatile.
Quoted 6 lines
Quoted 2 lines
Do you need to do
barrier()on every iteration? Does clang behave if you do onebarrier()instead of 'n' barrier()-s?If it does things right, it would make that a single-byte copy plus a call to
bcmp(). I certainly wouldn't want to have an implementation that relies on the compiler making sub-optimal decisions ;-)
That's a really good point :)
Quoted 1 line
Arnd
Signature · 10 lines
Alexander Potapenko Software Engineer Google Germany GmbH Erika-Mann-Straße, 33 80636 München Geschäftsführer: Paul Manicle, Halimah DeLaine Prado Registergericht und -nummer: Hamburg, HRB 86891 Sitz der Gesellschaft: Hamburg
Arnd Bergmann
maintainerRe: [PATCH RFC v2 02/25] stackdepot: prevent Clang from optimizing away stackdepot_memcmp()
Quoted 8 lines · Alexander Potapenko
Quoted 7 lines · Arnd Bergmann
Quoted 4 lines · Sergey Senozhatsky
Yeah, 'volatile' in this case will do what it sort of meant to do - prevent compiler optimizations. So, like you said, it's not a synchronization issue and we don't 'volatile' data structures.
Quoted 6 lines
Quoted 3 lines
The normal way to do a volatile access would be READ_ONCE()/WRITE_ONCE(), but that seems stronger than the
barrier()here. I'd just stick to adding a barrier.I actually like the
READ_ONCEidea more, asREAD_ONCEis really a documented way to prevent the compiler from merging reads, which is what we want here.
Fair enough.
Quoted 4 lines
I also thought that the original
barrier()statement was just a compiler barrier, which didn't introduce any additional CPU instructions.
Turns out I was wrong, andbarrier()also serves as a memory barrier.
The definition of barrier is
#define barrier() __asm__ __volatile__("": : :"memory")
which is no actual barrier instruction but is a full barrier to the compiler.
Only for the Intel ecc compiler it is defined as an intrinsic that I don't know.
Arnd
Alexander Potapenko
maintainerRe: [PATCH RFC v2 02/25] stackdepot: prevent Clang from optimizing away stackdepot_memcmp()
Quoted 24 lines · Arnd Bergmann
Quoted 8 lines · Alexander Potapenko
Quoted 7 lines · Arnd Bergmann
Quoted 4 lines · Sergey Senozhatsky
Yeah, 'volatile' in this case will do what it sort of meant to do - prevent compiler optimizations. So, like you said, it's not a synchronization issue and we don't 'volatile' data structures.
Quoted 6 lines
Quoted 3 lines
The normal way to do a volatile access would be READ_ONCE()/WRITE_ONCE(), but that seems stronger than the
barrier()here. I'd just stick to adding a barrier.I actually like the
READ_ONCEidea more, asREAD_ONCEis really a documented way to prevent the compiler from merging reads, which is what we want here.Fair enough.
Quoted 4 lines
I also thought that the original
barrier()statement was just a compiler barrier, which didn't introduce any additional CPU instructions.
Turns out I was wrong, andbarrier()also serves as a memory barrier.
Quoted 5 lines
The definition of barrier is
#define
barrier()__asm____volatile__("": : :"memory")which is no actual barrier instruction but is a full barrier to the compiler.
And you're right again, shame on me and my reading skills.
Quoted 4 lines
Only for the Intel ecc compiler it is defined as an intrinsic that I don't know.
Arnd
Signature · 10 lines
Alexander Potapenko Software Engineer Google Germany GmbH Erika-Mann-Straße, 33 80636 München Geschäftsführer: Paul Manicle, Halimah DeLaine Prado Registergericht und -nummer: Hamburg, HRB 86891 Sitz der Gesellschaft: Hamburg
A message that is not in the archive (sent off-list or not yet received): [email protected]
Arnd Bergmann
maintainerRe: [PATCH RFC v2 02/25] stackdepot: prevent Clang from optimizing away stackdepot_memcmp()
Quoted 7 lines · Andrey Ryabinin
Quoted 6 lines · Alexander Potapenko
Quoted 5 lines · Arnd Bergmann
On Thu, Nov 7, 2019 at 7:08 AM Sergey Senozhatsky <[email protected]> wrote:
The normal way to do a volatile access would be READ_ONCE()/WRITE_ONCE(), but that seems stronger than thebarrier()here. I'd just stick to adding a barrier.
Quoted 5 lines
Quoted 3 lines
I actually like the
READ_ONCEidea more, asREAD_ONCEis really a documented way to prevent the compiler from merging reads, which is what we want here.I would rather go with -fno-builtin-bcmp or maybe even -fno-builtin if that works.
The commit message for 5f074f3e192f ("lib/string.c: implement a basic bcmp") mentions that -fno-builtin-bcmp did not work for LTO when the global bcmp() help was added. I don't know whether the same applies here, but my guess is that it's the same issue.
Arnd
A message that is not in the archive (sent off-list or not yet received): [email protected]
Alexander Potapenko
maintainerRe: [PATCH RFC v2 02/25] stackdepot: prevent Clang from optimizing away stackdepot_memcmp()
Quoted 16 lines · Andrey Ryabinin
Quoted 12 lines · Arnd Bergmann
Quoted 11 lines · Andrey Ryabinin
Quoted 9 lines · Alexander Potapenko
Quoted 5 lines · Arnd Bergmann
On Thu, Nov 7, 2019 at 7:08 AM Sergey Senozhatsky <[email protected]> wrote:
The normal way to do a volatile access would be READ_ONCE()/WRITE_ONCE(), but that seems stronger than thebarrier()here. I'd just stick to adding a barrier.I actually like the
READ_ONCEidea more, asREAD_ONCEis really a documented way to prevent the compiler from merging reads, which is what we want here.
Quoted 8 lines
Quoted 6 lines
Quoted 1 line
I would rather go with -fno-builtin-bcmp or maybe even -fno-builtin if that works.
The commit message for
5f074f3e192f("lib/string.c: implement a basic bcmp") mentions that -fno-builtin-bcmp did not work for LTO when the globalbcmp()help was added. I don't know whether the same applies here, but my guess is that it's the same issue.But we don't do LTO.
I don't think not doing LTO now is a valid argument, as some distributions may start doing LTO in the future. (Android already does LTO, by the way)
Regarding this particular case, -fno-builtin-bcmp is insufficient, as Clang falls back to memcmp() in that case.
Building with -fno-builtin-bcmp -fno-builtin-memcmp does the trick, but we'd probably better use -fno-builtin just to avoid future surprises.
Quoted 4 lines
--
You received this message because you are subscribed to the Google Groups "Clang Built Linux" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/clang-built-linux/6875c6e6-2f1f-f8e6-e5d7-d451c48397ff%40virtuozzo.com.
Signature · 10 lines
Alexander Potapenko Software Engineer Google Germany GmbH Erika-Mann-Straße, 33 80636 München Geschäftsführer: Paul Manicle, Halimah DeLaine Prado Registergericht und -nummer: Hamburg, HRB 86891 Sitz der Gesellschaft: Hamburg
[email protected]
maintainerRFC PATCH v2 3/25 kasan: stackdepot: move filter_irq_stacks() to stackdepot.c
In reply to [email protected]filter_irq_stacks() can be used by other tools (e.g. KMSAN), so it needs to be moved to a common location.lib/stackdepot.c seems a good place, as filter_irq_stacks() is usually applied to the output of stack_trace_save().
To: Alexander Potapenko <[email protected]>
Cc: Vegard Nossum <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: Andrey Ryabinin <[email protected]>
Cc: [email protected]
---
Change-Id: I65acecf64930a3658e8c2aa7423801082ded8602
--- include/linux/stackdepot.h | 2 ++ lib/stackdepot.c | 23 +++++++++++++++++++++++ mm/kasan/common.c | 23 ----------------------- 3 files changed, 25 insertions(+), 23 deletions(-)
include/linux/stackdepot.h +2 -0
@@ -19,4 +19,6 @@ depot_stack_handle_t stack_depot_save(unsigned long *entries,unsigned int stack_depot_fetch (depot_stack_handle_t handle,unsigned long **entries); +unsigned int filter_irq_stacks (unsigned long *entries,unsigned int nr_entries); +#endif
lib/stackdepot.c +23 -0
@@ -20,6 +20,7 @@*/ #include <linux/gfp.h> +#include <linux/interrupt.h> #include <linux/jhash.h> #include <linux/kernel.h> #include <linux/mm.h>
@@ -319,3 +320,25 @@ depot_stack_handle_t stack_depot_save(unsigned long *entries,return retval; }EXPORT_SYMBOL_GPL (stack_depot_save); + +static inline int in_irqentry_text (unsigned long ptr) +{ +return (ptr >= (unsigned long )&__irqentry_text_start && + ptr < (unsigned long )&__irqentry_text_end) || + (ptr >= (unsigned long )&__softirqentry_text_start && + ptr < (unsigned long )&__softirqentry_text_end); +} + +unsigned int filter_irq_stacks (unsigned long *entries, +unsigned int nr_entries) +{ +unsigned int i; + +for (i =0 ; i < nr_entries; i++) { +if (in_irqentry_text (entries[i])) { +/* Include the irqentry function into the stack. */ +return i +1 ; + } + } +return nr_entries; +}
mm/kasan/common.c +0 -23
@@ -15,7 +15,6 @@*/ #include <linux/export.h> -#include <linux/interrupt.h> #include <linux/init.h> #include <linux/kasan.h> #include <linux/kernel.h>
@@ -39,28 +38,6 @@#include "kasan.h" #include "../slab.h" -static inline int in_irqentry_text (unsigned long ptr) -{ -return (ptr >= (unsigned long )&__irqentry_text_start && - ptr < (unsigned long )&__irqentry_text_end) || - (ptr >= (unsigned long )&__softirqentry_text_start && - ptr < (unsigned long )&__softirqentry_text_end); -} - -static inline unsigned int filter_irq_stacks (unsigned long *entries, -unsigned int nr_entries) -{ -unsigned int i; - -for (i =0 ; i < nr_entries; i++) { -if (in_irqentry_text (entries[i])) { -/* Include the irqentry function into the stack. */ -return i +1 ; - } - } -return nr_entries; -} -static inline depot_stack_handle_t save_stack (gfp_t flags) {unsigned long entries[KASAN_STACK_DEPTH ];
Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
[email protected]
maintainerRFC PATCH v2 4/25 stackdepot: reserve 5 extra bits in depot_stack_handle_t
In reply to [email protected]Some users (currently only KMSAN) may want to use spare bits in depot_stack_handle_t. Let them do so and provide get_dsh_extra_bits() and set_dsh_extra_bits() to access those bits.
To: Alexander Potapenko <[email protected]>
Cc: Vegard Nossum <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: [email protected]
---
Change-Id: I23580dbde85908eeda0bdd8f83a8c3882ab3e012
--- include/linux/stackdepot.h | 8 ++++++++ lib/stackdepot.c | 24 +++++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-)
include/linux/stackdepot.h +8 -0
@@ -12,6 +12,11 @@#define _LINUX_STACKDEPOT_Htypedef u32 depot_stack_handle_t ; +/* +* Number of bits in the handle that stack depot doesn't use. Users may store +* information in them. +*/ +#define STACK_DEPOT_EXTRA_BITS 5depot_stack_handle_t stack_depot_save (unsigned long *entries,unsigned int nr_entries,gfp_t gfp_flags);
@@ -20,5 +25,8 @@ unsigned int stack_depot_fetch(depot_stack_handle_t handle, unsigned long **entries);unsigned int filter_irq_stacks (unsigned long *entries,unsigned int nr_entries); +depot_stack_handle_t set_dsh_extra_bits (depot_stack_handle_t handle, +unsigned int bits); +unsigned int get_dsh_extra_bits (depot_stack_handle_t handle);#endif
lib/stackdepot.c +23 -1
@@ -40,8 +40,10 @@#define STACK_ALLOC_ALIGN 4#define STACK_ALLOC_OFFSET_BITS (STACK_ALLOC_ORDER + PAGE_SHIFT - \ STACK_ALLOC_ALIGN) +#define STACK_ALLOC_INDEX_BITS (DEPOT_STACK_BITS - \ - STACK_ALLOC_NULL_PROTECTION_BITS - STACK_ALLOC_OFFSET_BITS) + STACK_ALLOC_NULL_PROTECTION_BITS - \ + STACK_ALLOC_OFFSET_BITS - STACK_DEPOT_EXTRA_BITS)#define STACK_ALLOC_SLABS_CAP 8192#define STACK_ALLOC_MAX_SLABS \ (((1LL << (STACK_ALLOC_INDEX_BITS)) < STACK_ALLOC_SLABS_CAP) ? \
@@ -54,6 +56,7 @@ union handle_parts { u32 slabindex : STACK_ALLOC_INDEX_BITS; u32 offset : STACK_ALLOC_OFFSET_BITS; u32 valid : STACK_ALLOC_NULL_PROTECTION_BITS; + u32 extra : STACK_DEPOT_EXTRA_BITS; }; };
@@ -72,6 +75,24 @@ static int next_slab_inited;static size_t depot_offset;static DEFINE_SPINLOCK (depot_lock); +depot_stack_handle_t set_dsh_extra_bits (depot_stack_handle_t handle, +u32 bits) +{ +union handle_parts parts = { .handle = handle }; + + parts.extra = bits & ((1U <<STACK_DEPOT_EXTRA_BITS ) -1 ); +return parts.handle; +} +EXPORT_SYMBOL_GPL (set_dsh_extra_bits); + +u32 get_dsh_extra_bits (depot_stack_handle_t handle) +{ +union handle_parts parts = { .handle = handle }; + +return parts.extra; +} +EXPORT_SYMBOL_GPL (get_dsh_extra_bits); +static bool init_stack_slab (void **prealloc) {if (!*prealloc)
@@ -132,6 +153,7 @@ static struct stack_record *depot_alloc_stack(unsigned long *entries, int size, stack->handle.slabindex = depot_index; stack->handle.offset = depot_offset >>STACK_ALLOC_ALIGN ; stack->handle.valid =1 ; + stack->handle.extra =0 ;memcpy (stack->entries, entries, size *sizeof (unsigned long )); depot_offset += required_size;
Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
[email protected]
maintainerRFC PATCH v2 5/25 kmsan: add ReST documentation
In reply to [email protected]Add Documentation/dev-tools/kmsan.rst and reference it in the dev-tools index.
To: Alexander Potapenko <[email protected]>
Cc: Vegard Nossum <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: [email protected]
---
Change-Id: Iac6345065e6804ef811f1124fdf779c67ff1530e
--- Documentation/dev-tools/index.rst | 1 + Documentation/dev-tools/kmsan.rst | 418 ++++++++++++++++++++++++++++++ 2 files changed, 419 insertions(+) create mode 100644 Documentation/dev-tools/kmsan.rst
Documentation/dev-tools/index.rst +1 -0
@@ -19,6 +19,7 @@ whole; patches welcome! kcov gcov kasan + kmsan ubsan kmemleak gdb-kernel-debugging
Documentation/dev-tools/kmsan.rst new file +418 -0
418 lines not on this page · raw message
Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
[email protected]
maintainerRFC PATCH v2 6/25 kmsan: gfp: introduce __GFP_NO_KMSAN_SHADOW
In reply to [email protected]This flag is to be used by KMSAN runtime to mark that newly created memory pages don't need KMSAN metadata backing them.
To: Alexander Potapenko <[email protected]>
Cc: Vegard Nossum <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: [email protected]
---
We can't decide what to do here:
- do we need to conditionally define ___GFP_NO_KMSAN_SHADOW depending on CONFIG_KMSAN like LOCKDEP does?
- if KMSAN is defined, and LOCKDEP is not, do we want to "compactify" the GFP bits?
Change-Id: If5d0352fd5711ad103328e2c185eb885e826423a
--- include/linux/gfp.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
include/linux/gfp.h +3 -1
@@ -44,6 +44,7 @@ struct vm_area_struct;#else #define ___GFP_NOLOCKDEP 0#endif +#define ___GFP_NO_KMSAN_SHADOW 0x1000000u/* If the above are modified, __GFP_BITS_SHIFT may need updating */ /*
@@ -212,12 +213,13 @@ struct vm_area_struct;#define __GFP_NOWARN ((__force gfp_t)___GFP_NOWARN)#define __GFP_COMP ((__force gfp_t)___GFP_COMP)#define __GFP_ZERO ((__force gfp_t)___GFP_ZERO) +#define __GFP_NO_KMSAN_SHADOW ((__force gfp_t)___GFP_NO_KMSAN_SHADOW)/* Disable lockdep for GFP context tracking */ #define __GFP_NOLOCKDEP ((__force gfp_t)___GFP_NOLOCKDEP)/* Room for N __GFP_FOO bits */ -#define __GFP_BITS_SHIFT (23 + IS_ENABLED(CONFIG_LOCKDEP)) +#define __GFP_BITS_SHIFT (25)#define __GFP_BITS_MASK ((__force gfp_t)((1 << __GFP_BITS_SHIFT) - 1))/**
Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
[email protected]
maintainerRFC PATCH v2 7/25 kmsan: introduce __no_sanitize_memory and __SANITIZE_MEMORY__
In reply to [email protected]__no_sanitize_memory is a function attribute that makes KMSAN ignore the uninitialized values coming from the function's inputs, and initialize the function's outputs.
Functions marked with this attribute can't be inlined into functions not marked with it, and vice versa.
__SANITIZE_MEMORY__ is a macro that's defined iff the file is instrumented with KMSAN. This is not the same as CONFIG_KMSAN, which is defined for every file.
To: Alexander Potapenko <[email protected]>
Cc: Vegard Nossum <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: [email protected]
---
Change-Id: I1f1672652c8392f15f7ca8ac26cd4e71f9cc1e4b
--- include/linux/compiler-clang.h | 8 ++++++++ include/linux/compiler-gcc.h | 5 +++++ 2 files changed, 13 insertions(+)
include/linux/compiler-clang.h +8 -0
@@ -24,6 +24,14 @@#define __no_sanitize_address#endif +/* KMSAN is a Clang-only tool, thus putting the defines here */ +#if __has_feature (memory_sanitizer) +# define __SANITIZE_MEMORY__ +# define __no_sanitize_memory __attribute__((no_sanitize("kernel-memory"))) +#else +# define __no_sanitize_memory +#endif +/* * Not all versions of clang implement the the type-generic versions * of the builtin overflow checkers. Fortunately, clang implements
include/linux/compiler-gcc.h +5 -0
@@ -145,6 +145,11 @@#define __no_sanitize_address#endif +/* +* GCC doesn't support KMSAN. +*/ +#define __no_sanitize_memory +#if GCC_VERSION >=50100 #define COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW 1#endif
Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
Re: [PATCH RFC v2 07/25] kmsan: introduce __no_sanitize_memory and __SANITIZE_MEMORY__
Quoted 31 lines · On Wed, Oct 30, 2019 at 3:23 PM <[email protected]> wrote:
__no_sanitize_memoryis a function attribute that makes KMSAN ignore the uninitialized values coming from the function's inputs, and initialize the function's outputs.Functions marked with this attribute can't be inlined into functions not marked with it, and vice versa.
__SANITIZE_MEMORY__is a macro that's defined iff the file is instrumented with KMSAN. This is not the same asCONFIG_KMSAN, which is defined for every file.Signed-off-by Alexander Potapenko <[email protected]>To: Alexander Potapenko <[email protected]>
Cc: Vegard Nossum <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: [email protected]---
Change-Id: I1f1672652c8392f15f7ca8ac26cd4e71f9cc1e4b
--- include/linux/compiler-clang.h | 8 ++++++++ include/linux/compiler-gcc.h | 5 +++++ 2 files changed, 13 insertions(+)include/linux/compiler-clang.h +0
-0
include/linux/compiler-clang.h line 30
Quoted 7 lines
include/linux/compiler-clang.h +4
-0@@ -24,6 +24,14 @@#define __no_sanitize_address#endif +/* KMSAN is a Clang-only tool, thus putting the defines here */ +#if __has_feature (memory_sanitizer) +# define __SANITIZE_MEMORY__ +# define __no_sanitize_memory __attribute__((no_sanitize("kernel-memory")))
For KASAN with Clang we ended up choosing to use no_sanitize("address") instead of no_sanitize("kernel-address") to make it match what GCC uses. Do we want to use no_sanitize("memory") here?
Quoted 26 lines
include/linux/compiler-clang.h +4
-0+#else +# define __no_sanitize_memory +#endif +/* * Not all versions of clang implement the the type-generic versions * of the builtin overflow checkers. Fortunately, clang implements include/linux/compiler-gcc.h +5
-1@@ -145,6 +145,11 @@#define __no_sanitize_address#endif +/* +* GCC doesn't support KMSAN. +*/ +#define __no_sanitize_memory +#if GCC_VERSION >=50100 #define COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW 1#endif --2.24.0.rc0.303.g954a862665-goog
Alexander Potapenko
maintainerRe: [PATCH RFC v2 07/25] kmsan: introduce __no_sanitize_memory and __SANITIZE_MEMORY__
Quoted 36 lines · Andrey Konovalov
Quoted 34 lines · On Wed, Oct 30, 2019 at 3:23 PM <[email protected]> wrote:
__no_sanitize_memoryis a function attribute that makes KMSAN ignore the uninitialized values coming from the function's inputs, and initialize the function's outputs.Functions marked with this attribute can't be inlined into functions not marked with it, and vice versa.
__SANITIZE_MEMORY__is a macro that's defined iff the file is instrumented with KMSAN. This is not the same asCONFIG_KMSAN, which is defined for every file.Signed-off-by Alexander Potapenko <[email protected]>To: Alexander Potapenko <[email protected]>
Cc: Vegard Nossum <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: [email protected]---
Change-Id: I1f1672652c8392f15f7ca8ac26cd4e71f9cc1e4b
--- include/linux/compiler-clang.h | 8 ++++++++ include/linux/compiler-gcc.h | 5 +++++ 2 files changed, 13 insertions(+)include/linux/compiler-clang.h +0
-0@@ -24,6 +24,14 @@#define __no_sanitize_address#endif
Quoted 9 lines
include/linux/compiler-clang.h line 30
Quoted 4 lines
include/linux/compiler-clang.h +4
-0+/* KMSAN is a Clang-only tool, thus putting the defines here */ +#if __has_feature (memory_sanitizer) +# define __SANITIZE_MEMORY__ +# define __no_sanitize_memory __attribute__((no_sanitize("kernel-memory")))For KASAN with Clang we ended up choosing to use
no_sanitize("address")instead ofno_sanitize("kernel-address")to make it match what GCC uses. Do we want to useno_sanitize("memory")here?
Since GCC doesn't currently implement KMSAN instrumentation, I think we can stick to the current annotation and let GCC catch up :)
Quoted 26 lines
Quoted 26 lines
include/linux/compiler-clang.h +4
-0+#else +# define __no_sanitize_memory +#endif +/* * Not all versions of clang implement the the type-generic versions * of the builtin overflow checkers. Fortunately, clang implements include/linux/compiler-gcc.h +5
-1@@ -145,6 +145,11 @@#define __no_sanitize_address#endif +/* +* GCC doesn't support KMSAN. +*/ +#define __no_sanitize_memory +#if GCC_VERSION >=50100 #define COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW 1#endif --2.24.0.rc0.303.g954a862665-goog
Signature · 10 lines
Alexander Potapenko Software Engineer Google Germany GmbH Erika-Mann-Straße, 33 80636 München Geschäftsführer: Paul Manicle, Halimah DeLaine Prado Registergericht und -nummer: Hamburg, HRB 86891 Sitz der Gesellschaft: Hamburg
[email protected]
maintainerRFC PATCH v2 8/25 kmsan: reduce vmalloc space
In reply to [email protected]KMSAN is going to use 3/4 of existing vmalloc space to hold the metadata, therefore we lower VMALLOC_END to make sure vmalloc() doesn't allocate past the first 1/4.
To: Alexander Potapenko <[email protected]>
Cc: Vegard Nossum <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: [email protected]
---
Change-Id: Iaa5e8e0fc2aa66c956f937f5a1de6e5ef40d57cc
--- arch/x86/include/asm/pgtable_64_types.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
arch/x86/include/asm/pgtable_64_types.h +15 -0
@@ -139,7 +139,22 @@ extern unsigned int ptrs_per_p4d;# define VMEMMAP_START __VMEMMAP_BASE_L4#endif /* CONFIG_DYNAMIC_MEMORY_LAYOUT */ +#ifndef CONFIG_KMSAN #define VMALLOC_END (VMALLOC_START + (VMALLOC_SIZE_TB << 40) - 1) +#else +/* +* In KMSAN builds vmalloc area is four times smaller, and the remaining 3/4 +* are used to keep the metadata for virtual pages. +*/ +#define VMALLOC_QUARTER_SIZE ((VMALLOC_SIZE_TB << 40) >> 2) +#define VMALLOC_END (VMALLOC_START + VMALLOC_QUARTER_SIZE - 1) +#define VMALLOC_SHADOW_OFFSET VMALLOC_QUARTER_SIZE +#define VMALLOC_ORIGIN_OFFSET (VMALLOC_QUARTER_SIZE * 2) +#define VMALLOC_META_END (VMALLOC_END + VMALLOC_ORIGIN_OFFSET) +#define MODULES_SHADOW_START (VMALLOC_META_END + 1) +#define MODULES_ORIGIN_START (MODULES_SHADOW_START + MODULES_LEN) +#define MODULES_ORIGIN_END (MODULES_ORIGIN_START + MODULES_LEN) +#endif #define MODULES_VADDR (__START_KERNEL_map + KERNEL_IMAGE_SIZE)/* The module sections ends with the start of the fixmap */
Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
[email protected]
maintainerRFC PATCH v2 9/25 kmsan: add KMSAN runtime
In reply to [email protected]This patch adds the KernelMemorySanitizer runtime and associated files:
- arch/x86/include/asm/kmsan.h: assembly definitions for hooking
interrupt handlers;
- include/linux/kmsan-checks.h: user API to enable/disable KMSAN, poison/unpoison memory etc.
- include/linux/kmsan.h: declarations of KMSAN memory hooks to be referenced outside KMSAN runtime
- lib/Kconfig.kmsan: declarations for CONFIG_KMSAN and CONFIG_TEST_KMSAN
- mm/kmsan/Makefile: boilerplate Makefile
- mm/kmsan/kmsan.h: internal KMSAN declarations
- mm/kmsan/kmsan.c: core functions that operate with shadow and origin memory and perform checks, utility functions
- mm/kmsan/kmsan_entry.c: KMSAN hooks for entry_64.S
- mm/kmsan/kmsan_hooks.c: KMSAN hooks for kernel subsystems
- mm/kmsan/kmsan_init.c: KMSAN initialization routines
- mm/kmsan/kmsan_instr.c: functions called by KMSAN instrumentation
- scripts/Makefile.kmsan: CFLAGS_KMSAN
To: Alexander Potapenko <[email protected]>
Cc: Vegard Nossum <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: [email protected]
---
v2:
- dropped kmsan_handle_vprintk()
- use locking for single kmsan_pr_err() calls
- don't try to understand we're inside printk()
Change-Id: I4b3a7aba6d5804afac4f5f7274cadf8675b6e119
--- arch/x86/Kconfig | 1 + arch/x86/include/asm/kmsan.h | 129 ++++++++ include/linux/kmsan-checks.h | 121 ++++++++ include/linux/kmsan.h | 143 +++++++++ lib/Kconfig.debug | 2 + lib/Kconfig.kmsan | 22 ++ mm/kmsan/Makefile | 4 + mm/kmsan/kmsan.c | 570 +++++++++++++++++++++++++++++++++++ mm/kmsan/kmsan.h | 149 +++++++++ mm/kmsan/kmsan_entry.c | 130 ++++++++ mm/kmsan/kmsan_hooks.c | 393 ++++++++++++++++++++++++ mm/kmsan/kmsan_init.c | 88 ++++++ mm/kmsan/kmsan_instr.c | 259 ++++++++++++++++ mm/kmsan/kmsan_report.c | 133 ++++++++ mm/kmsan/kmsan_shadow.c | 543 +++++++++++++++++++++++++++++++++ mm/kmsan/kmsan_shadow.h | 30 ++ scripts/Makefile.kmsan | 12 + 17 files changed, 2729 insertions(+) create mode 100644 arch/x86/include/asm/kmsan.h create mode 100644 include/linux/kmsan-checks.h create mode 100644 include/linux/kmsan.h create mode 100644 lib/Kconfig.kmsan create mode 100644 mm/kmsan/Makefile create mode 100644 mm/kmsan/kmsan.c create mode 100644 mm/kmsan/kmsan.h create mode 100644 mm/kmsan/kmsan_entry.c create mode 100644 mm/kmsan/kmsan_hooks.c create mode 100644 mm/kmsan/kmsan_init.c create mode 100644 mm/kmsan/kmsan_instr.c create mode 100644 mm/kmsan/kmsan_report.c create mode 100644 mm/kmsan/kmsan_shadow.c create mode 100644 mm/kmsan/kmsan_shadow.h create mode 100644 scripts/Makefile.kmsan
arch/x86/Kconfig +1 -0
@@ -135,6 +135,7 @@ config X86 select HAVE_ARCH_JUMP_LABEL select HAVE_ARCH_JUMP_LABEL_RELATIVE select HAVE_ARCH_KASAN if X86_64 + select HAVE_ARCH_KMSAN if X86_64 select HAVE_ARCH_KGDB select HAVE_ARCH_MMAP_RND_BITS if MMU select HAVE_ARCH_MMAP_RND_COMPAT_BITS if MMU && COMPAT
arch/x86/include/asm/kmsan.h new file +129 -0
129 lines not on this page · raw message
include/linux/kmsan-checks.h new file +121 -0
121 lines not on this page · raw message
include/linux/kmsan.h new file +143 -0
143 lines not on this page · raw message
lib/Kconfig.debug +2 -0
@@ -756,6 +756,8 @@ config DEBUG_STACKOVERFLOW source "lib/Kconfig.kasan" +source "lib/Kconfig.kmsan" + endmenu # "Memory Debugging" config ARCH_HAS_KCOV
lib/Kconfig.kmsan new file +22 -0
@@ -0,0 +1,22 @@ +config HAVE_ARCH_KMSAN + bool + +if HAVE_ARCH_KMSAN + +config KMSAN + bool "KMSAN: detector of uninitialized memory use" + depends on SLUB && !KASAN + select STACKDEPOT + help + KMSAN is a dynamic detector of uses of uninitialized memory in the + kernel. It is based on compiler instrumentation provided by Clang + and thus requires Clang 10.0.0+ to build. + +config TEST_KMSAN + tristate "Module for testing KMSAN for bug detection" + depends on m && KMSAN + help + Test module that can trigger various uses of uninitialized memory + detectable by KMSAN. + +endif
mm/kmsan/Makefile new file +4 -0
@@ -0,0 +1,4 @@ +obj-y := kmsan.o kmsan_instr.o kmsan_init.o kmsan_entry.o kmsan_hooks.o kmsan_report.o kmsan_shadow.o + +KMSAN_SANITIZE := n +KCOV_INSTRUMENT := n
mm/kmsan/kmsan.c new file +570 -0
570 lines not on this page · raw message
mm/kmsan/kmsan.h new file +149 -0
149 lines not on this page · raw message
mm/kmsan/kmsan_entry.c new file +130 -0
130 lines not on this page · raw message
mm/kmsan/kmsan_hooks.c new file +393 -0
393 lines not on this page · raw message
mm/kmsan/kmsan_init.c new file +88 -0
88 lines not on this page · raw message
mm/kmsan/kmsan_instr.c new file +259 -0
259 lines not on this page · raw message
mm/kmsan/kmsan_report.c new file +133 -0
133 lines not on this page · raw message
mm/kmsan/kmsan_shadow.c new file +543 -0
543 lines not on this page · raw message
mm/kmsan/kmsan_shadow.h new file +30 -0
@@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* KMSAN shadow API. +* +* This should be agnostic to shadow implementation details. +* +* Copyright (C) 2017-2019 Google LLC +* Author: Alexander Potapenko <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +*/ + +#ifndef __MM_KMSAN_KMSAN_SHADOW_H +#define __MM_KMSAN_KMSAN_SHADOW_H + +#include <asm/cpu_entry_area.h> /* for CPU_ENTRY_AREA_MAP_SIZE */ + +struct shadow_origin_ptr { +void *s, *o; +}; + +struct shadow_origin_ptr kmsan_get_shadow_origin_ptr (void *addr,u64 size, +bool store); +void *kmsan_get_metadata (void *addr,size_t size,bool is_origin); +void __init kmsan_init_alloc_meta_for_range (void *start,void *end); + +#endif /* __MM_KMSAN_KMSAN_SHADOW_H */
scripts/Makefile.kmsan new file +12 -0
@@ -0,0 +1,12 @@ +ifdef CONFIG_KMSAN + +CFLAGS_KMSAN := -fsanitize=kernel-memory + +ifeq ($(call cc-option, $(CFLAGS_KMSAN) -Werror),) + ifneq ($(CONFIG_COMPILE_TEST),y) + $(warning Cannot use CONFIG_KMSAN: \ + -fsanitize=kernel-memory is not supported by compiler) + endif +endif + +endif
Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
Dmitry Vyukov
reviewerRe: [PATCH RFC v2 09/25] kmsan: add KMSAN runtime
Quoted 27 lines · On Wed, Oct 30, 2019 at 3:23 PM <[email protected]> wrote:
This patch adds the KernelMemorySanitizer runtime and associated files:
-
arch/x86/include/asm/kmsan.h: assembly definitions for hookinginterrupt handlers;-
include/linux/kmsan-checks.h: user API to enable/disable KMSAN, poison/unpoison memory etc.
-include/linux/kmsan.h: declarations of KMSAN memory hooks to be referenced outside KMSAN runtime
-lib/Kconfig.kmsan: declarations forCONFIG_KMSANandCONFIG_TEST_KMSAN
-mm/kmsan/Makefile: boilerplateMakefile
-mm/kmsan/kmsan.h: internal KMSAN declarations
-mm/kmsan/kmsan.c: core functions that operate with shadow and origin memory and perform checks, utility functions
-mm/kmsan/kmsan_entry.c: KMSAN hooks forentry_64.S
-mm/kmsan/kmsan_hooks.c: KMSAN hooks for kernel subsystems
-mm/kmsan/kmsan_init.c: KMSAN initialization routines
-mm/kmsan/kmsan_instr.c: functions called by KMSAN instrumentation
-scripts/Makefile.kmsan:CFLAGS_KMSANSigned-off-by Alexander Potapenko <[email protected]>To: Alexander Potapenko <[email protected]>
Cc: Vegard Nossum <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: [email protected]
mm/kmsan/kmsan_report.c line 43
Quoted 2 lines
mm/kmsan/kmsan_report.c new file +2
-0+kmsan_pr_err ("Local variable description: %s\n" , descr); +kmsan_pr_err ("Variable was created at:\n" );
It would be nice to tidy up the description, it contains lots of duplicate/unneeded/confusing info:
Local variable description: ----br.i@vp7045_read_mac_addr Variable was created at:
vp7045_read_eeprom drivers/media/usb/dvb-usb/vp7045.c:119 [inline] vp7045_read_mac_addr+0x7b/0xbe0 drivers/media/usb/dvb-usb/vp7045.c:132 vp7045_read_eeprom drivers/media/usb/dvb-usb/vp7045.c:119 [inline] vp7045_read_mac_addr+0x7b/0xbe0 drivers/media/usb/dvb-usb/vp7045.c:132
It could be just:
Local variable br was created at:
vp7045_read_eeprom drivers/media/usb/dvb-usb/vp7045.c:119 [inline] vp7045_read_mac_addr+0x7b/0xbe0 drivers/media/usb/dvb-usb/vp7045.c:132 vp7045_read_eeprom drivers/media/usb/dvb-usb/vp7045.c:119 [inline] vp7045_read_mac_addr+0x7b/0xbe0 drivers/media/usb/dvb-usb/vp7045.c:132
Dmitry Vyukov
reviewerRe: [PATCH RFC v2 09/25] kmsan: add KMSAN runtime
Quoted 51 lines · Dmitry Vyukov
Quoted 27 lines · On Wed, Oct 30, 2019 at 3:23 PM <[email protected]> wrote:
This patch adds the KernelMemorySanitizer runtime and associated files:
-
arch/x86/include/asm/kmsan.h: assembly definitions for hookinginterrupt handlers;-
include/linux/kmsan-checks.h: user API to enable/disable KMSAN, poison/unpoison memory etc.
-include/linux/kmsan.h: declarations of KMSAN memory hooks to be referenced outside KMSAN runtime
-lib/Kconfig.kmsan: declarations forCONFIG_KMSANandCONFIG_TEST_KMSAN
-mm/kmsan/Makefile: boilerplateMakefile
-mm/kmsan/kmsan.h: internal KMSAN declarations
-mm/kmsan/kmsan.c: core functions that operate with shadow and origin memory and perform checks, utility functions
-mm/kmsan/kmsan_entry.c: KMSAN hooks forentry_64.S
-mm/kmsan/kmsan_hooks.c: KMSAN hooks for kernel subsystems
-mm/kmsan/kmsan_init.c: KMSAN initialization routines
-mm/kmsan/kmsan_instr.c: functions called by KMSAN instrumentation
-scripts/Makefile.kmsan:CFLAGS_KMSANSigned-off-by Alexander Potapenko <[email protected]>To: Alexander Potapenko <[email protected]>
Cc: Vegard Nossum <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: [email protected]mm/kmsan/kmsan_report.c line 43
Quoted 2 lines
mm/kmsan/kmsan_report.c new file +2
-0+kmsan_pr_err ("Local variable description: %s\n" , descr); +kmsan_pr_err ("Variable was created at:\n" );It would be nice to tidy up the description, it contains lots of duplicate/unneeded/confusing info:
Local variable description: ----br.i@vp7045_read_mac_addr Variable was created at:
vp7045_read_eeprom drivers/media/usb/dvb-usb/vp7045.c:119 [inline] vp7045_read_mac_addr+0x7b/0xbe0 drivers/media/usb/dvb-usb/vp7045.c:132 vp7045_read_eeprom drivers/media/usb/dvb-usb/vp7045.c:119 [inline] vp7045_read_mac_addr+0x7b/0xbe0 drivers/media/usb/dvb-usb/vp7045.c:132It could be just:
Local variable br was created at:
vp7045_read_eeprom drivers/media/usb/dvb-usb/vp7045.c:119 [inline] vp7045_read_mac_addr+0x7b/0xbe0 drivers/media/usb/dvb-usb/vp7045.c:132 vp7045_read_eeprom drivers/media/usb/dvb-usb/vp7045.c:119 [inline] vp7045_read_mac_addr+0x7b/0xbe0 drivers/media/usb/dvb-usb/vp7045.c:132
mm/kmsan/kmsan_report.c line 56
Quoted 5 lines
mm/kmsan/kmsan_report.c new file +5
-0+kmsan_pr_err ("Uninit was stored to memory at:\n" ); + chained_nr_entries = +stack_depot_fetch (head, &chained_entries); +stack_trace_print (chained_entries, chained_nr_entries, +0 );
I like how KCSAN trims all stacks of internal runtime frames. It would be nice to do the same for KMSAN, currently we have 3-4 uninteresting frames in the beginning of each stack. Besides taking space, it also requires to manually visually search for the actual interesting frame somewhere in the middle of the stack. E.g. all these frames are pointing into kmsan runtime guts:
Call Trace: __dump_stack lib/dump_stack.c:77 [inline] dump_stack+0x1c9/0x220 lib/dump_stack.c:113 kmsan_report+0x12d/0x290 mm/kmsan/kmsan.c:682 __msan_warning+0x76/0xc0 mm/kmsan/kmsan_instr.c:316
Uninit was stored to memory at:
kmsan_save_stack_with_flags mm/kmsan/kmsan.c:247 [inline] kmsan_save_stack mm/kmsan/kmsan.c:262 [inline] kmsan_internal_chain_origin+0x162/0x260 mm/kmsan/kmsan.c:470 __msan_chain_origin+0x6d/0xb0 mm/kmsan/kmsan_instr.c:197
Uninit was stored to memory at:
kmsan_save_stack_with_flags mm/kmsan/kmsan.c:247 [inline] kmsan_save_stack mm/kmsan/kmsan.c:262 [inline] kmsan_internal_chain_origin+0x162/0x260 mm/kmsan/kmsan.c:470 __msan_chain_origin+0x6d/0xb0 mm/kmsan/kmsan_instr.c:197
Uninit was stored to memory at:
kmsan_save_stack_with_flags mm/kmsan/kmsan.c:247 [inline] kmsan_save_stack mm/kmsan/kmsan.c:262 [inline] kmsan_internal_chain_origin+0x162/0x260 mm/kmsan/kmsan.c:470 kmsan_memcpy_memmove_metadata+0x1a9/0xf30 mm/kmsan/kmsan.c:345 kmsan_memcpy_metadata+0xb/0x10 mm/kmsan/kmsan.c:363 __msan_memcpy+0x61/0x70 mm/kmsan/kmsan_instr.c:148
Uninit was created at:
kmsan_save_stack_with_flags mm/kmsan/kmsan.c:247 [inline] kmsan_internal_poison_shadow+0x92/0x150 mm/kmsan/kmsan.c:170 kmsan_kmalloc+0xa1/0x100 mm/kmsan/kmsan_hooks.c:179 kmsan_slab_alloc+0xe/0x10 mm/kmsan/kmsan_hooks.c:188 slab_post_alloc_hook mm/slab.h:446 [inline] slab_alloc_node mm/slub.c:2759 [inline] __kmalloc_node_track_caller+0xf06/0x1120 mm/slub.c:4383
Alexander Potapenko
maintainerRe: [PATCH RFC v2 09/25] kmsan: add KMSAN runtime
Quoted 92 lines · Dmitry Vyukov
Quoted 51 lines · Dmitry Vyukov
Quoted 27 lines · On Wed, Oct 30, 2019 at 3:23 PM <[email protected]> wrote:
This patch adds the KernelMemorySanitizer runtime and associated files:
-
arch/x86/include/asm/kmsan.h: assembly definitions for hookinginterrupt handlers;-
include/linux/kmsan-checks.h: user API to enable/disable KMSAN, poison/unpoison memory etc.
-include/linux/kmsan.h: declarations of KMSAN memory hooks to be referenced outside KMSAN runtime
-lib/Kconfig.kmsan: declarations forCONFIG_KMSANandCONFIG_TEST_KMSAN
-mm/kmsan/Makefile: boilerplateMakefile
-mm/kmsan/kmsan.h: internal KMSAN declarations
-mm/kmsan/kmsan.c: core functions that operate with shadow and origin memory and perform checks, utility functions
-mm/kmsan/kmsan_entry.c: KMSAN hooks forentry_64.S
-mm/kmsan/kmsan_hooks.c: KMSAN hooks for kernel subsystems
-mm/kmsan/kmsan_init.c: KMSAN initialization routines
-mm/kmsan/kmsan_instr.c: functions called by KMSAN instrumentation
-scripts/Makefile.kmsan:CFLAGS_KMSANSigned-off-by Alexander Potapenko <[email protected]>To: Alexander Potapenko <[email protected]>
Cc: Vegard Nossum <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: [email protected]mm/kmsan/kmsan_report.c line 43
Quoted 2 lines
mm/kmsan/kmsan_report.c new file +2
-0+kmsan_pr_err ("Local variable description: %s\n" , descr); +kmsan_pr_err ("Variable was created at:\n" );It would be nice to tidy up the description, it contains lots of duplicate/unneeded/confusing info:
Local variable description: ----br.i@vp7045_read_mac_addr Variable was created at:
vp7045_read_eeprom drivers/media/usb/dvb-usb/vp7045.c:119 [inline] vp7045_read_mac_addr+0x7b/0xbe0 drivers/media/usb/dvb-usb/vp7045.c:132 vp7045_read_eeprom drivers/media/usb/dvb-usb/vp7045.c:119 [inline] vp7045_read_mac_addr+0x7b/0xbe0 drivers/media/usb/dvb-usb/vp7045.c:132It could be just:
Local variable br was created at:
vp7045_read_eeprom drivers/media/usb/dvb-usb/vp7045.c:119 [inline] vp7045_read_mac_addr+0x7b/0xbe0 drivers/media/usb/dvb-usb/vp7045.c:132 vp7045_read_eeprom drivers/media/usb/dvb-usb/vp7045.c:119 [inline] vp7045_read_mac_addr+0x7b/0xbe0 drivers/media/usb/dvb-usb/vp7045.c:132mm/kmsan/kmsan_report.c line 56
Quoted 5 lines
mm/kmsan/kmsan_report.c new file +5
-0+kmsan_pr_err ("Uninit was stored to memory at:\n" ); + chained_nr_entries = +stack_depot_fetch (head, &chained_entries); +stack_trace_print (chained_entries, chained_nr_entries, +0 );I like how KCSAN trims all stacks of internal runtime frames. It would be nice to do the same for KMSAN, currently we have 3-4 uninteresting frames in the beginning of each stack. Besides taking space, it also requires to manually visually search for the actual interesting frame somewhere in the middle of the stack. E.g. all these frames are pointing into kmsan runtime guts:
Call Trace: __dump_stack lib/dump_stack.c:77 [inline] dump_stack+0x1c9/0x220 lib/dump_stack.c:113 kmsan_report+0x12d/0x290 mm/kmsan/kmsan.c:682 __msan_warning+0x76/0xc0 mm/kmsan/kmsan_instr.c:316Uninit was stored to memory at:
kmsan_save_stack_with_flags mm/kmsan/kmsan.c:247 [inline] kmsan_save_stack mm/kmsan/kmsan.c:262 [inline] kmsan_internal_chain_origin+0x162/0x260 mm/kmsan/kmsan.c:470 __msan_chain_origin+0x6d/0xb0 mm/kmsan/kmsan_instr.c:197Uninit was stored to memory at:
kmsan_save_stack_with_flags mm/kmsan/kmsan.c:247 [inline] kmsan_save_stack mm/kmsan/kmsan.c:262 [inline] kmsan_internal_chain_origin+0x162/0x260 mm/kmsan/kmsan.c:470 __msan_chain_origin+0x6d/0xb0 mm/kmsan/kmsan_instr.c:197Uninit was stored to memory at:
kmsan_save_stack_with_flags mm/kmsan/kmsan.c:247 [inline] kmsan_save_stack mm/kmsan/kmsan.c:262 [inline] kmsan_internal_chain_origin+0x162/0x260 mm/kmsan/kmsan.c:470 kmsan_memcpy_memmove_metadata+0x1a9/0xf30 mm/kmsan/kmsan.c:345 kmsan_memcpy_metadata+0xb/0x10 mm/kmsan/kmsan.c:363 __msan_memcpy+0x61/0x70 mm/kmsan/kmsan_instr.c:148
Quoted 8 lines
Uninit was created at:
kmsan_save_stack_with_flags mm/kmsan/kmsan.c:247 [inline] kmsan_internal_poison_shadow+0x92/0x150 mm/kmsan/kmsan.c:170 kmsan_kmalloc+0xa1/0x100 mm/kmsan/kmsan_hooks.c:179 kmsan_slab_alloc+0xe/0x10 mm/kmsan/kmsan_hooks.c:188 slab_post_alloc_hook mm/slab.h:446 [inline] slab_alloc_node mm/slub.c:2759 [inline] __kmalloc_node_track_caller+0xf06/0x1120 mm/slub.c:4383
Not sure this is strictly required for the initial version, but I've added the feature to the issue tracker:
https://github.com/google/kmsan/issues/66
Signature · 10 lines
Alexander Potapenko Software Engineer Google Germany GmbH Erika-Mann-Straße, 33 80636 München Geschäftsführer: Paul Manicle, Halimah DeLaine Prado Registergericht und -nummer: Hamburg, HRB 86891 Sitz der Gesellschaft: Hamburg
Re: [PATCH RFC v2 09/25] kmsan: add KMSAN runtime
In reply to [email protected]Hi,
Quoted 1 line
+/* Helper function to check I2C-transferred data. */
I assume I2C is just one of the first users and other users like SPI will be implemented as time passes? Otherwise I would wonder why I2C needs to be handled with this special function.
mm/kmsan/kmsan_hooks.c line 382
Quoted 6 lines
mm/kmsan/kmsan_hooks.c new file +6
-0+void kmsan_handle_i2c_transfer (struct i2c_msg *msgs,int num) +{ +int i; + +if (!msgs) +return ;
Can go. You call this function from __i2c_transfer and this checks for valid 'msgs'.
Kind regards,
Wolfram
Alexander Potapenko
maintainerRe: [PATCH RFC v2 09/25] kmsan: add KMSAN runtime
Quoted 8 lines · Wolfram Sang
Hi,
Quoted 1 line
+/* Helper function to check I2C-transferred data. */
I assume I2C is just one of the first users and other users like SPI will be implemented as time passes? Otherwise I would wonder why I2C needs to be handled with this special function.
Initially this was just because I2C errors kept firing in the default build. v3 adds DMA support to KMSAN, so I think we don't need to specially handle i2c.
Quoted 14 lines
mm/kmsan/kmsan_hooks.c line 382
Quoted 6 lines
mm/kmsan/kmsan_hooks.c new file +6
-0+void kmsan_handle_i2c_transfer (struct i2c_msg *msgs,int num) +{ +int i; + +if (!msgs) +return ;Can go. You call this function from
__i2c_transferand this checks for valid 'msgs'.Kind regards,
Wolfram
Signature · 10 lines
Alexander Potapenko Software Engineer Google Germany GmbH Erika-Mann-Straße, 33 80636 München Geschäftsführer: Paul Manicle, Halimah DeLaine Prado Registergericht und -nummer: Hamburg, HRB 86891 Sitz der Gesellschaft: Hamburg
[email protected]
maintainerRFC PATCH v2 10/25 kmsan: define READ_ONCE_NOCHECK()
In reply to [email protected]READ_ONCE_NOCHECK() is already used by KASAN to ignore memory accesses from e.g. stack unwinders.
Define READ_ONCE_NOCHECK() for KMSAN so that it returns initialized values. This helps defeat false positives from leftover stack contents.
To: Alexander Potapenko <[email protected]>
Cc: Vegard Nossum <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: [email protected]
---
Change-Id: Ib38369ba038ab3b581d8e45b81036c3304fb79cb
--- include/linux/compiler.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
include/linux/compiler.h +5 -1
@@ -270,9 +270,13 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s/* * Use READ_ONCE_NOCHECK() instead of READ_ONCE() if you need -* to hide memory access from KASAN. +* to hide memory access from KASAN or KMSAN. */ +#ifndef CONFIG_KMSAN #define READ_ONCE_NOCHECK (x) __READ_ONCE(x, 0) +#else +#define READ_ONCE_NOCHECK (x) KMSAN_INIT_VALUE(__READ_ONCE(x, 0)) +#endif static __no_kasan_or_inline unsigned long read_word_at_a_time (const void *addr)
Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
Re: [PATCH RFC v2 10/25] kmsan: define READ_ONCE_NOCHECK()
Quoted 23 lines · On Wed, Oct 30, 2019 at 03:22:22PM +0100, [email protected] wrote:
READ_ONCE_NOCHECK()is already used by KASAN to ignore memory accesses from e.g. stack unwinders.
DefineREAD_ONCE_NOCHECK()for KMSAN so that it returns initialized values. This helps defeat false positives from leftover stack contents.Signed-off-by Alexander Potapenko <[email protected]>To: Alexander Potapenko <[email protected]>
Cc: Vegard Nossum <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: [email protected]
---Change-Id: Ib38369ba038ab3b581d8e45b81036c3304fb79cb
--- include/linux/compiler.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)include/linux/compiler.h +0
-0@@ -270,9 +270,13 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s
include/linux/compiler.h static __always_inline void __write_once_size(volatile void *p, void *res, int s · line 279
Quoted 10 lines
include/linux/compiler.h +5
-1/* * Use READ_ONCE_NOCHECK() instead of READ_ONCE() if you need -* to hide memory access from KASAN. +* to hide memory access from KASAN or KMSAN. */ +#ifndef CONFIG_KMSAN #define READ_ONCE_NOCHECK (x) __READ_ONCE(x, 0) +#else +#define READ_ONCE_NOCHECK (x) KMSAN_INIT_VALUE(__READ_ONCE(x, 0)) +#endif
When !CONFIG_KMSAN, we have:
| #define KMSAN_INIT_VALUE(value) (value)
... so we don't need ifdeffery here, and can simply have:
/*
* Use READ_ONCE_NOCHECK() instead of READ_ONCE() if you need
* to hide memory access from KASAN or KMSAN.
*/
#define READ_ONCE_NOCHECK(x) KMSAN_INIT_VALUE(__READ_ONCE(x, 0))
Thanks,
Mark.
Quoted 6 lines
include/linux/compiler.h +0
-0static __no_kasan_or_inline unsigned long read_word_at_a_time (const void *addr)Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
Alexander Potapenko
maintainerRe: [PATCH RFC v2 10/25] kmsan: define READ_ONCE_NOCHECK()
Quoted 40 lines · Mark Rutland
Quoted 23 lines · On Wed, Oct 30, 2019 at 03:22:22PM +0100, [email protected] wrote:
READ_ONCE_NOCHECK()is already used by KASAN to ignore memory accesses from e.g. stack unwinders.
DefineREAD_ONCE_NOCHECK()for KMSAN so that it returns initialized values. This helps defeat false positives from leftover stack contents.Signed-off-by Alexander Potapenko <[email protected]>To: Alexander Potapenko <[email protected]>
Cc: Vegard Nossum <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: [email protected]
---Change-Id: Ib38369ba038ab3b581d8e45b81036c3304fb79cb
--- include/linux/compiler.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)include/linux/compiler.h +0
-0@@ -270,9 +270,13 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int sinclude/linux/compiler.h static __always_inline void __write_once_size(volatile void *p, void *res, int s · line 279
Quoted 10 lines
include/linux/compiler.h +5
-1/* * Use READ_ONCE_NOCHECK() instead of READ_ONCE() if you need -* to hide memory access from KASAN. +* to hide memory access from KASAN or KMSAN. */ +#ifndef CONFIG_KMSAN #define READ_ONCE_NOCHECK (x) __READ_ONCE(x, 0) +#else +#define READ_ONCE_NOCHECK (x) KMSAN_INIT_VALUE(__READ_ONCE(x, 0)) +#endif When !CONFIG_KMSAN, we have:
| #define
KMSAN_INIT_VALUE(value)(value)
Quoted 7 lines
... so we don't need ifdeffery here, and can simply have:
/*
* UseREAD_ONCE_NOCHECK()instead ofREAD_ONCE()if you need
* to hide memory access from KASAN or KMSAN.
*/
#defineREAD_ONCE_NOCHECK(x)KMSAN_INIT_VALUE(__READ_ONCE(x, 0))
Agreed, thanks!
Quoted 9 lines
Thanks,
Mark.Quoted 6 lines
include/linux/compiler.h +0
-1static __no_kasan_or_inline unsigned long read_word_at_a_time (const void *addr) --2.24.0.rc0.303.g954a862665-goog
Signature · 10 lines
Alexander Potapenko Software Engineer Google Germany GmbH Erika-Mann-Straße, 33 80636 München Geschäftsführer: Paul Manicle, Halimah DeLaine Prado Registergericht und -nummer: Hamburg, HRB 86891 Sitz der Gesellschaft: Hamburg
[email protected]
maintainerRFC PATCH v2 11/25 kmsan: x86: sync metadata pages on page fault
In reply to [email protected]KMSAN assumes shadow and origin pages for every allocated page are accessible. For pages in vmalloc region those metadata pages reside in [VMALLOC_END, VMALLOC_META_END), therefore we must sync a bigger memory region.
To: Alexander Potapenko <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Vegard Nossum <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: [email protected]
---
Change-Id: I0d54855489870ef1180b37fe2120b601da464bf7
--- arch/x86/mm/fault.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
arch/x86/mm/fault.c +20 -0
@@ -320,7 +320,17 @@ static void dump_pagetable(unsigned long address)void vmalloc_sync_all (void ) { +#ifdef CONFIG_KMSAN +/* +* For KMSAN, make sure metadata pages for vmalloc area and modules are +* also synced. +*/ +sync_global_pgds (VMALLOC_START &PGDIR_MASK ,VMALLOC_META_END ); +sync_global_pgds (MODULES_SHADOW_START &PGDIR_MASK , +MODULES_ORIGIN_END ); +#else sync_global_pgds (VMALLOC_START &PGDIR_MASK ,VMALLOC_END ); +#endif }/*
@@ -337,7 +347,17 @@ static noinline int vmalloc_fault(unsigned long address)pte_t *pte;/* Make sure we are in vmalloc area: */ +#ifdef CONFIG_KMSAN +/* +* For KMSAN, make sure metadata pages for vmalloc area and modules are +* also synced. +*/ +if (!(address >=VMALLOC_START && address <VMALLOC_META_END ) && + !(address >=MODULES_SHADOW_START && + address <MODULES_ORIGIN_END )) +#else if (!(address >= VMALLOC_START && address < VMALLOC_END)) +#endif return -1 ;/*
Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
[email protected]
maintainerRFC PATCH v2 12/25 kmsan: add tests for KMSAN
In reply to [email protected]The initial commit adds several tests that trigger KMSAN warnings in simple cases.
To use, build the kernel with CONFIG_TEST_KMSAN and do insmod test_kmsan.ko
To: Alexander Potapenko <[email protected]>
Cc: Vegard Nossum <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: [email protected]
---
v2:
- added printk_test()
Change-Id: I287e86ae83a82b770f2baa46e5bbdce1dfa65195
--- lib/Makefile | 1 + lib/test_kmsan.c | 231 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 232 insertions(+) create mode 100644 lib/test_kmsan.c
lib/Makefile +1 -0
@@ -65,6 +65,7 @@ CFLAGS_test_kasan.o += $(call cc-disable-warning, vla) obj-$(CONFIG_TEST_UBSAN) += test_ubsan.o CFLAGS_test_ubsan.o += $(call cc-disable-warning, vla) UBSAN_SANITIZE_test_ubsan.o := y +obj-$(CONFIG_TEST_KMSAN) += test_kmsan.o obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o obj-$(CONFIG_TEST_LIST_SORT) += test_list_sort.o obj-$(CONFIG_TEST_LKM) += test_module.o
lib/test_kmsan.c new file +231 -0
231 lines not on this page · raw message
Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
[email protected]
maintainerRFC PATCH v2 13/25 kmsan: make READ_ONCE_TASK_STACK() return initialized values
In reply to [email protected]To avoid false positives, assume that reading from the task stack always produces initialized values.
To: Alexander Potapenko <[email protected]>
Cc: Vegard Nossum <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: [email protected]
---
Change-Id: Ie73e5a41fdc8195699928e65f5cbe0d3d3c9e2fa
--- arch/x86/include/asm/unwind.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
arch/x86/include/asm/unwind.h +5 -4
@@ -100,9 +100,10 @@ void unwind_module_init(struct module *mod, void *orc_ip, size_t orc_ip_size,#endif /* -* This disables KASAN checking when reading a value from another task's stack, -* since the other task could be running on another CPU and could have poisoned -* the stack in the meantime. +* This disables KASAN/KMSAN checking when reading a value from another task's +* stack, since the other task could be running on another CPU and could have +* poisoned the stack in the meantime. Frame pointers are uninitialized by +* default, so for KMSAN we mark the return value initialized unconditionally. */ #define READ_ONCE_TASK_STACK (task, x) \ ({ \
@@ -111,7 +112,7 @@ void unwind_module_init(struct module *mod, void *orc_ip, size_t orc_ip_size, val =READ_ONCE (x); \ else \ val =READ_ONCE_NOCHECK (x); \ - val; \ +KMSAN_INIT_VALUE (val); \ })static inline bool task_on_another_cpu (struct task_struct *task)
Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
[email protected]
maintainerRFC PATCH v2 14/25 kmsan: Kconfig changes to disable options incompatible with KMSAN
In reply to [email protected]Certain config options are currently incompatible with KMSAN, disable them.
To: Alexander Potapenko <[email protected]>
Cc: Herbert Xu <[email protected]>
Cc: Harry Wentland <[email protected]>
Cc: Vegard Nossum <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: [email protected]
---
Change-Id: I4521f5c764cfaeba2fae79c954925c302c5e3bc0
--- arch/Kconfig | 2 +- arch/x86/Kconfig | 1 + arch/x86/Kconfig.debug | 3 +++ crypto/Kconfig | 26 ++++++++++++++++++++++++++ drivers/gpu/drm/amd/display/Kconfig | 2 +- lib/Kconfig.debug | 3 +++ 6 files changed, 35 insertions(+), 2 deletions(-)
arch/Kconfig +1 -1
@@ -843,7 +843,7 @@ config HAVE_ARCH_VMAP_STACK config VMAP_STACK default y bool "Use a virtually-mapped stack" - depends on HAVE_ARCH_VMAP_STACK && !KASAN + depends on HAVE_ARCH_VMAP_STACK && !KASAN && !KMSAN ---help--- Enable this if you want the use virtually-mapped kernel stacks with guard pages. This causes kernel stack overflows to be
arch/x86/Kconfig +1 -0
@@ -2143,6 +2143,7 @@ config RELOCATABLE config RANDOMIZE_BASE bool "Randomize the address of the kernel image (KASLR)" depends on RELOCATABLE + depends on !KMSAN default y ---help--- In support of Kernel Address Space Layout Randomization (KASLR),
arch/x86/Kconfig.debug +3 -0
@@ -292,6 +292,9 @@ choice config UNWINDER_ORC bool "ORC unwinder" depends on X86_64 + # KMSAN doesn't support UNWINDER_ORC yet, + # see https://github.com/google/kmsan/issues/48. + depends on !KMSAN select STACK_VALIDATION ---help--- This option enables the ORC (Oops Rewind Capability) unwinder for
crypto/Kconfig +26 -0
@@ -309,11 +309,13 @@ config CRYPTO_AEGIS128 config CRYPTO_AEGIS128_SIMD bool "Support SIMD acceleration for AEGIS-128" depends on CRYPTO_AEGIS128 && ((ARM || ARM64) && KERNEL_MODE_NEON) + depends on !KMSAN default y config CRYPTO_AEGIS128_AESNI_SSE2 tristate "AEGIS-128 AEAD algorithm (x86_64 AESNI+SSE2 implementation)" depends on X86 && 64BIT + depends on !KMSAN select CRYPTO_AEAD select CRYPTO_SIMD help
@@ -571,6 +573,7 @@ config CRYPTO_CRC32C config CRYPTO_CRC32C_INTEL tristate "CRC32c INTEL hardware acceleration" depends on X86 + depends on !KMSAN select CRYPTO_HASH help In Intel processor with SSE4.2 supported, the processor will
@@ -611,6 +614,7 @@ config CRYPTO_CRC32 config CRYPTO_CRC32_PCLMUL tristate "CRC32 PCLMULQDQ hardware acceleration" depends on X86 + depends on !KMSAN select CRYPTO_HASH select CRC32 help
@@ -649,6 +653,7 @@ config CRYPTO_CRCT10DIF config CRYPTO_CRCT10DIF_PCLMUL tristate "CRCT10DIF PCLMULQDQ hardware acceleration" depends on X86 && 64BIT && CRC_T10DIF + depends on !KMSAN select CRYPTO_HASH help For x86_64 processors with SSE4.2 and PCLMULQDQ supported,
@@ -695,6 +700,7 @@ config CRYPTO_POLY1305 config CRYPTO_POLY1305_X86_64 tristate "Poly1305 authenticator algorithm (x86_64/SSE2/AVX2)" depends on X86 && 64BIT + depends on !KMSAN select CRYPTO_POLY1305 help Poly1305 authenticator algorithm, RFC7539.
@@ -814,6 +820,7 @@ config CRYPTO_SHA1 config CRYPTO_SHA1_SSSE3 tristate "SHA1 digest algorithm (SSSE3/AVX/AVX2/SHA-NI)" depends on X86 && 64BIT + depends on !KMSAN select CRYPTO_SHA1 select CRYPTO_HASH help
@@ -825,6 +832,7 @@ config CRYPTO_SHA1_SSSE3 config CRYPTO_SHA256_SSSE3 tristate "SHA256 digest algorithm (SSSE3/AVX/AVX2/SHA-NI)" depends on X86 && 64BIT + depends on !KMSAN select CRYPTO_SHA256 select CRYPTO_HASH help
@@ -837,6 +845,7 @@ config CRYPTO_SHA256_SSSE3 config CRYPTO_SHA512_SSSE3 tristate "SHA512 digest algorithm (SSSE3/AVX/AVX2)" depends on X86 && 64BIT + depends on !KMSAN select CRYPTO_SHA512 select CRYPTO_HASH help
@@ -1011,6 +1020,7 @@ config CRYPTO_WP512 config CRYPTO_GHASH_CLMUL_NI_INTEL tristate "GHASH hash function (CLMUL-NI accelerated)" depends on X86 && 64BIT + depends on !KMSAN select CRYPTO_CRYPTD help This is the x86_64 CLMUL-NI accelerated implementation of
@@ -1064,6 +1074,7 @@ config CRYPTO_AES_TI config CRYPTO_AES_NI_INTEL tristate "AES cipher algorithms (AES-NI)" depends on X86 + depends on !KMSAN select CRYPTO_AEAD select CRYPTO_LIB_AES select CRYPTO_ALGAPI
@@ -1190,6 +1201,7 @@ config CRYPTO_BLOWFISH_COMMON config CRYPTO_BLOWFISH_X86_64 tristate "Blowfish cipher algorithm (x86_64)" depends on X86 && 64BIT + depends on !KMSAN select CRYPTO_BLKCIPHER select CRYPTO_BLOWFISH_COMMON help
@@ -1221,6 +1233,7 @@ config CRYPTO_CAMELLIA_X86_64 tristate "Camellia cipher algorithm (x86_64)" depends on X86 && 64BIT depends on CRYPTO + depends on !KMSAN select CRYPTO_BLKCIPHER select CRYPTO_GLUE_HELPER_X86 help
@@ -1238,6 +1251,7 @@ config CRYPTO_CAMELLIA_AESNI_AVX_X86_64 tristate "Camellia cipher algorithm (x86_64/AES-NI/AVX)" depends on X86 && 64BIT depends on CRYPTO + depends on !KMSAN select CRYPTO_BLKCIPHER select CRYPTO_CAMELLIA_X86_64 select CRYPTO_GLUE_HELPER_X86
@@ -1258,6 +1272,7 @@ config CRYPTO_CAMELLIA_AESNI_AVX2_X86_64 tristate "Camellia cipher algorithm (x86_64/AES-NI/AVX2)" depends on X86 && 64BIT depends on CRYPTO + depends on !KMSAN select CRYPTO_CAMELLIA_AESNI_AVX_X86_64 help Camellia cipher algorithm module (x86_64/AES-NI/AVX2).
@@ -1303,6 +1318,7 @@ config CRYPTO_CAST5 config CRYPTO_CAST5_AVX_X86_64 tristate "CAST5 (CAST-128) cipher algorithm (x86_64/AVX)" depends on X86 && 64BIT + depends on !KMSAN select CRYPTO_BLKCIPHER select CRYPTO_CAST5 select CRYPTO_CAST_COMMON
@@ -1325,6 +1341,7 @@ config CRYPTO_CAST6 config CRYPTO_CAST6_AVX_X86_64 tristate "CAST6 (CAST-256) cipher algorithm (x86_64/AVX)" depends on X86 && 64BIT + depends on !KMSAN select CRYPTO_BLKCIPHER select CRYPTO_CAST6 select CRYPTO_CAST_COMMON
@@ -1360,6 +1377,7 @@ config CRYPTO_DES_SPARC64 config CRYPTO_DES3_EDE_X86_64 tristate "Triple DES EDE cipher algorithm (x86-64)" depends on X86 && 64BIT + depends on !KMSAN select CRYPTO_BLKCIPHER select CRYPTO_LIB_DES help
@@ -1426,6 +1444,7 @@ config CRYPTO_CHACHA20 config CRYPTO_CHACHA20_X86_64 tristate "ChaCha stream cipher algorithms (x86_64/SSSE3/AVX2/AVX-512VL)" depends on X86 && 64BIT + depends on !KMSAN select CRYPTO_BLKCIPHER select CRYPTO_CHACHA20 help
@@ -1462,6 +1481,7 @@ config CRYPTO_SERPENT config CRYPTO_SERPENT_SSE2_X86_64 tristate "Serpent cipher algorithm (x86_64/SSE2)" depends on X86 && 64BIT + depends on !KMSAN select CRYPTO_BLKCIPHER select CRYPTO_GLUE_HELPER_X86 select CRYPTO_SERPENT
@@ -1481,6 +1501,7 @@ config CRYPTO_SERPENT_SSE2_X86_64 config CRYPTO_SERPENT_SSE2_586 tristate "Serpent cipher algorithm (i586/SSE2)" depends on X86 && !64BIT + depends on !KMSAN select CRYPTO_BLKCIPHER select CRYPTO_GLUE_HELPER_X86 select CRYPTO_SERPENT
@@ -1500,6 +1521,7 @@ config CRYPTO_SERPENT_SSE2_586 config CRYPTO_SERPENT_AVX_X86_64 tristate "Serpent cipher algorithm (x86_64/AVX)" depends on X86 && 64BIT + depends on !KMSAN select CRYPTO_BLKCIPHER select CRYPTO_GLUE_HELPER_X86 select CRYPTO_SERPENT
@@ -1520,6 +1542,7 @@ config CRYPTO_SERPENT_AVX_X86_64 config CRYPTO_SERPENT_AVX2_X86_64 tristate "Serpent cipher algorithm (x86_64/AVX2)" depends on X86 && 64BIT + depends on !KMSAN select CRYPTO_SERPENT_AVX_X86_64 help Serpent cipher algorithm, by Anderson, Biham & Knudsen.
@@ -1615,6 +1638,7 @@ config CRYPTO_TWOFISH_586 config CRYPTO_TWOFISH_X86_64 tristate "Twofish cipher algorithm (x86_64)" depends on (X86 || UML_X86) && 64BIT + depends on !KMSAN select CRYPTO_ALGAPI select CRYPTO_TWOFISH_COMMON help
@@ -1631,6 +1655,7 @@ config CRYPTO_TWOFISH_X86_64 config CRYPTO_TWOFISH_X86_64_3WAY tristate "Twofish cipher algorithm (x86_64, 3-way parallel)" depends on X86 && 64BIT + depends on !KMSAN select CRYPTO_BLKCIPHER select CRYPTO_TWOFISH_COMMON select CRYPTO_TWOFISH_X86_64
@@ -1652,6 +1677,7 @@ config CRYPTO_TWOFISH_X86_64_3WAY config CRYPTO_TWOFISH_AVX_X86_64 tristate "Twofish cipher algorithm (x86_64/AVX)" depends on X86 && 64BIT + depends on !KMSAN select CRYPTO_BLKCIPHER select CRYPTO_GLUE_HELPER_X86 select CRYPTO_SIMD
drivers/gpu/drm/amd/display/Kconfig +1 -1
@@ -6,7 +6,7 @@ config DRM_AMD_DC bool "AMD DC - Enable new display engine" default y select SND_HDA_COMPONENT if SND_HDA_CORE - select DRM_AMD_DC_DCN1_0 if X86 && !(KCOV_INSTRUMENT_ALL && KCOV_ENABLE_COMPARISONS) + select DRM_AMD_DC_DCN1_0 if X86 && !(KCOV_INSTRUMENT_ALL && KCOV_ENABLE_COMPARISONS) && !KMSAN help Choose this option if you want to use the new display engine support for AMDGPU. This adds required support for Vega and
lib/Kconfig.debug +3 -0
@@ -1068,6 +1068,9 @@ menu "Lock Debugging (spinlocks, mutexes, etc...)" config LOCK_DEBUGGING_SUPPORT bool depends on TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT + # KMSAN is incompatible with lockdep, + # see https://github.com/google/kmsan/issues/57. + depends on !KMSAN default y config PROVE_LOCKING
Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
Re: [PATCH RFC v2 14/25] kmsan: Kconfig changes to disable options incompatible with KMSAN
Quoted 2 lines · On Wed, 2019-10-30 at 15:22 +0100, [email protected] wrote:
Certain config options are currently incompatible with KMSAN, disable them.
It would be useful to describe the reasons why each option is incompatible with KMSAN at the moment to make life easier for someone who might want to fix some of them in the future.
Quoted 298 lines
Signed-off-by Alexander Potapenko <[email protected]>Acked-by Harry Wentland <[email protected]>To: Alexander Potapenko <[email protected]>
Cc: Herbert Xu <[email protected]>
Cc: Harry Wentland <[email protected]>
Cc: Vegard Nossum <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: [email protected]---
Change-Id: I4521f5c764cfaeba2fae79c954925c302c5e3bc0
--- arch/Kconfig | 2 +- arch/x86/Kconfig | 1 + arch/x86/Kconfig.debug | 3 +++ crypto/Kconfig | 26 ++++++++++++++++++++++++++ drivers/gpu/drm/amd/display/Kconfig | 2 +- lib/Kconfig.debug | 3 +++ 6 files changed, 35 insertions(+), 2 deletions(-)arch/Kconfig +1
-1@@ -843,7 +843,7 @@ config HAVE_ARCH_VMAP_STACK config VMAP_STACK default y bool "Use a virtually-mapped stack" - depends on HAVE_ARCH_VMAP_STACK && !KASAN + depends on HAVE_ARCH_VMAP_STACK && !KASAN && !KMSAN ---help--- Enable this if you want the use virtually-mapped kernel stacks with guard pages. This causes kernel stack overflows to bearch/x86/Kconfig +1
-0@@ -2143,6 +2143,7 @@ config RELOCATABLE config RANDOMIZE_BASE bool "Randomize the address of the kernel image (KASLR)" depends on RELOCATABLE + depends on !KMSAN default y ---help--- In support of Kernel Address Space Layout Randomization (KASLR),arch/x86/Kconfig.debug +3
-0@@ -292,6 +292,9 @@ choice config UNWINDER_ORC bool "ORC unwinder" depends on X86_64 + # KMSAN doesn't support UNWINDER_ORC yet, + # see https://github.com/google/kmsan/issues/48. + depends on !KMSAN select STACK_VALIDATION ---help--- This option enables the ORC (Oops Rewind Capability) unwinder forcrypto/Kconfig +26
-0@@ -309,11 +309,13 @@ config CRYPTO_AEGIS128 config CRYPTO_AEGIS128_SIMD bool "Support SIMD acceleration for AEGIS-128" depends on CRYPTO_AEGIS128 && ((ARM || ARM64) && KERNEL_MODE_NEON) + depends on !KMSAN default y config CRYPTO_AEGIS128_AESNI_SSE2 tristate "AEGIS-128 AEAD algorithm (x86_64 AESNI+SSE2 implementation)" depends on X86 && 64BIT + depends on !KMSAN select CRYPTO_AEAD select CRYPTO_SIMD help@@ -571,6 +573,7 @@ config CRYPTO_CRC32C config CRYPTO_CRC32C_INTEL tristate "CRC32c INTEL hardware acceleration" depends on X86 + depends on !KMSAN select CRYPTO_HASH help In Intel processor with SSE4.2 supported, the processor will@@ -611,6 +614,7 @@ config CRYPTO_CRC32 config CRYPTO_CRC32_PCLMUL tristate "CRC32 PCLMULQDQ hardware acceleration" depends on X86 + depends on !KMSAN select CRYPTO_HASH select CRC32 help@@ -649,6 +653,7 @@ config CRYPTO_CRCT10DIF config CRYPTO_CRCT10DIF_PCLMUL tristate "CRCT10DIF PCLMULQDQ hardware acceleration" depends on X86 && 64BIT && CRC_T10DIF + depends on !KMSAN select CRYPTO_HASH help For x86_64 processors with SSE4.2 and PCLMULQDQ supported,@@ -695,6 +700,7 @@ config CRYPTO_POLY1305 config CRYPTO_POLY1305_X86_64 tristate "Poly1305 authenticator algorithm (x86_64/SSE2/AVX2)" depends on X86 && 64BIT + depends on !KMSAN select CRYPTO_POLY1305 help Poly1305 authenticator algorithm, RFC7539.@@ -814,6 +820,7 @@ config CRYPTO_SHA1 config CRYPTO_SHA1_SSSE3 tristate "SHA1 digest algorithm (SSSE3/AVX/AVX2/SHA-NI)" depends on X86 && 64BIT + depends on !KMSAN select CRYPTO_SHA1 select CRYPTO_HASH help@@ -825,6 +832,7 @@ config CRYPTO_SHA1_SSSE3 config CRYPTO_SHA256_SSSE3 tristate "SHA256 digest algorithm (SSSE3/AVX/AVX2/SHA-NI)" depends on X86 && 64BIT + depends on !KMSAN select CRYPTO_SHA256 select CRYPTO_HASH help@@ -837,6 +845,7 @@ config CRYPTO_SHA256_SSSE3 config CRYPTO_SHA512_SSSE3 tristate "SHA512 digest algorithm (SSSE3/AVX/AVX2)" depends on X86 && 64BIT + depends on !KMSAN select CRYPTO_SHA512 select CRYPTO_HASH help@@ -1011,6 +1020,7 @@ config CRYPTO_WP512 config CRYPTO_GHASH_CLMUL_NI_INTEL tristate "GHASH hash function (CLMUL-NI accelerated)" depends on X86 && 64BIT + depends on !KMSAN select CRYPTO_CRYPTD help This is the x86_64 CLMUL-NI accelerated implementation of@@ -1064,6 +1074,7 @@ config CRYPTO_AES_TI config CRYPTO_AES_NI_INTEL tristate "AES cipher algorithms (AES-NI)" depends on X86 + depends on !KMSAN select CRYPTO_AEAD select CRYPTO_LIB_AES select CRYPTO_ALGAPI@@ -1190,6 +1201,7 @@ config CRYPTO_BLOWFISH_COMMON config CRYPTO_BLOWFISH_X86_64 tristate "Blowfish cipher algorithm (x86_64)" depends on X86 && 64BIT + depends on !KMSAN select CRYPTO_BLKCIPHER select CRYPTO_BLOWFISH_COMMON help@@ -1221,6 +1233,7 @@ config CRYPTO_CAMELLIA_X86_64 tristate "Camellia cipher algorithm (x86_64)" depends on X86 && 64BIT depends on CRYPTO + depends on !KMSAN select CRYPTO_BLKCIPHER select CRYPTO_GLUE_HELPER_X86 help@@ -1238,6 +1251,7 @@ config CRYPTO_CAMELLIA_AESNI_AVX_X86_64 tristate "Camellia cipher algorithm (x86_64/AES-NI/AVX)" depends on X86 && 64BIT depends on CRYPTO + depends on !KMSAN select CRYPTO_BLKCIPHER select CRYPTO_CAMELLIA_X86_64 select CRYPTO_GLUE_HELPER_X86@@ -1258,6 +1272,7 @@ config CRYPTO_CAMELLIA_AESNI_AVX2_X86_64 tristate "Camellia cipher algorithm (x86_64/AES-NI/AVX2)" depends on X86 && 64BIT depends on CRYPTO + depends on !KMSAN select CRYPTO_CAMELLIA_AESNI_AVX_X86_64 help Camellia cipher algorithm module (x86_64/AES-NI/AVX2).@@ -1303,6 +1318,7 @@ config CRYPTO_CAST5 config CRYPTO_CAST5_AVX_X86_64 tristate "CAST5 (CAST-128) cipher algorithm (x86_64/AVX)" depends on X86 && 64BIT + depends on !KMSAN select CRYPTO_BLKCIPHER select CRYPTO_CAST5 select CRYPTO_CAST_COMMON@@ -1325,6 +1341,7 @@ config CRYPTO_CAST6 config CRYPTO_CAST6_AVX_X86_64 tristate "CAST6 (CAST-256) cipher algorithm (x86_64/AVX)" depends on X86 && 64BIT + depends on !KMSAN select CRYPTO_BLKCIPHER select CRYPTO_CAST6 select CRYPTO_CAST_COMMON@@ -1360,6 +1377,7 @@ config CRYPTO_DES_SPARC64 config CRYPTO_DES3_EDE_X86_64 tristate "Triple DES EDE cipher algorithm (x86-64)" depends on X86 && 64BIT + depends on !KMSAN select CRYPTO_BLKCIPHER select CRYPTO_LIB_DES help@@ -1426,6 +1444,7 @@ config CRYPTO_CHACHA20 config CRYPTO_CHACHA20_X86_64 tristate "ChaCha stream cipher algorithms (x86_64/SSSE3/AVX2/AVX-512VL)" depends on X86 && 64BIT + depends on !KMSAN select CRYPTO_BLKCIPHER select CRYPTO_CHACHA20 help@@ -1462,6 +1481,7 @@ config CRYPTO_SERPENT config CRYPTO_SERPENT_SSE2_X86_64 tristate "Serpent cipher algorithm (x86_64/SSE2)" depends on X86 && 64BIT + depends on !KMSAN select CRYPTO_BLKCIPHER select CRYPTO_GLUE_HELPER_X86 select CRYPTO_SERPENT@@ -1481,6 +1501,7 @@ config CRYPTO_SERPENT_SSE2_X86_64 config CRYPTO_SERPENT_SSE2_586 tristate "Serpent cipher algorithm (i586/SSE2)" depends on X86 && !64BIT + depends on !KMSAN select CRYPTO_BLKCIPHER select CRYPTO_GLUE_HELPER_X86 select CRYPTO_SERPENT@@ -1500,6 +1521,7 @@ config CRYPTO_SERPENT_SSE2_586 config CRYPTO_SERPENT_AVX_X86_64 tristate "Serpent cipher algorithm (x86_64/AVX)" depends on X86 && 64BIT + depends on !KMSAN select CRYPTO_BLKCIPHER select CRYPTO_GLUE_HELPER_X86 select CRYPTO_SERPENT@@ -1520,6 +1542,7 @@ config CRYPTO_SERPENT_AVX_X86_64 config CRYPTO_SERPENT_AVX2_X86_64 tristate "Serpent cipher algorithm (x86_64/AVX2)" depends on X86 && 64BIT + depends on !KMSAN select CRYPTO_SERPENT_AVX_X86_64 help Serpent cipher algorithm, by Anderson, Biham & Knudsen.@@ -1615,6 +1638,7 @@ config CRYPTO_TWOFISH_586 config CRYPTO_TWOFISH_X86_64 tristate "Twofish cipher algorithm (x86_64)" depends on (X86 || UML_X86) && 64BIT + depends on !KMSAN select CRYPTO_ALGAPI select CRYPTO_TWOFISH_COMMON help@@ -1631,6 +1655,7 @@ config CRYPTO_TWOFISH_X86_64 config CRYPTO_TWOFISH_X86_64_3WAY tristate "Twofish cipher algorithm (x86_64, 3-way parallel)" depends on X86 && 64BIT + depends on !KMSAN select CRYPTO_BLKCIPHER select CRYPTO_TWOFISH_COMMON select CRYPTO_TWOFISH_X86_64@@ -1652,6 +1677,7 @@ config CRYPTO_TWOFISH_X86_64_3WAY config CRYPTO_TWOFISH_AVX_X86_64 tristate "Twofish cipher algorithm (x86_64/AVX)" depends on X86 && 64BIT + depends on !KMSAN select CRYPTO_BLKCIPHER select CRYPTO_GLUE_HELPER_X86 select CRYPTO_SIMDdrivers/gpu/drm/amd/display/Kconfig +1
-1@@ -6,7 +6,7 @@ config DRM_AMD_DC bool "AMD DC - Enable new display engine" default y select SND_HDA_COMPONENT if SND_HDA_CORE - select DRM_AMD_DC_DCN1_0 if X86 && !(KCOV_INSTRUMENT_ALL && KCOV_ENABLE_COMPARISONS) + select DRM_AMD_DC_DCN1_0 if X86 && !(KCOV_INSTRUMENT_ALL && KCOV_ENABLE_COMPARISONS) && !KMSAN help Choose this option if you want to use the new display engine support for AMDGPU. This adds required support for Vega andlib/Kconfig.debug +3
-0@@ -1068,6 +1068,9 @@ menu "Lock Debugging (spinlocks, mutexes, etc...)" config LOCK_DEBUGGING_SUPPORT bool depends on TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT + # KMSAN is incompatible with lockdep, + # see https://github.com/google/kmsan/issues/57. + depends on !KMSAN default y config PROVE_LOCKING
Re: [PATCH RFC v2 14/25] kmsan: Kconfig changes to disable options incompatible with KMSAN
In reply to [email protected]Quoted 2 lines · On Wed, Oct 30, 2019 at 03:22:26PM +0100, [email protected] wrote:
Certain config options are currently incompatible with KMSAN, disable them.
This looks like a very random collection. Please annotate each of them with a reason why they are incompatible. Either by adding a comment to the Kconfig, or by having one commit per incompatible option with a commit log explaining it.
[email protected]
maintainerRFC PATCH v2 15/25 kmsan: Changing existing files to enable KMSAN builds
In reply to [email protected]Do the following to make KMSAN usable:
- add KMSAN declarations to struct page and struct task_struct;
- add Makefile.kmsan to top-level Makefile;
- call KMSAN initialization from init/main.c
- add asm hooks to arch/x86/entry/entry_64.S;
- increase task stack size under KMSAN;
- disable page merging in block/blk.h;
- disable CONFIG_KMSAN in arch/x86/boot/compressed/misc.h to use default string functions instead of KMSAN ones.
To: Alexander Potapenko <[email protected]>
Cc: Jens Axboe <[email protected]>
Cc: Andy Lutomirski <[email protected]>
Cc: Vegard Nossum <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: [email protected]
---
Change-Id: I37e0b7f2d2f2b0aeac5753ff9d6b411485fc374e
--- Makefile | 3 ++- arch/x86/boot/compressed/misc.h | 1 + arch/x86/entry/entry_64.S | 18 ++++++++++++++++++ arch/x86/include/asm/page_64_types.h | 12 +++++++----- block/blk.h | 7 +++++++ include/linux/mm_types.h | 9 +++++++++ include/linux/sched.h | 5 +++++ init/main.c | 3 +++ lib/stackdepot.c | 7 ++++--- mm/Makefile | 1 + scripts/Makefile.lib | 6 ++++++ 11 files changed, 63 insertions(+), 9 deletions(-)
Makefile +2 -1
@@ -478,7 +478,7 @@ export KBUILD_HOSTCXXFLAGS KBUILD_HOSTLDFLAGS KBUILD_HOSTLDLIBS LDFLAGS_MODULE export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS KBUILD_LDFLAGS export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE -export CFLAGS_KASAN CFLAGS_KASAN_NOSANITIZE CFLAGS_UBSAN +export CFLAGS_KASAN CFLAGS_KASAN_NOSANITIZE CFLAGS_UBSAN CFLAGS_KMSAN export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL
@@ -898,6 +898,7 @@ KBUILD_CFLAGS += $(call cc-option,-fcf-protection=none) endif include scripts/Makefile.kasan +include scripts/Makefile.kmsan include scripts/Makefile.extrawarn include scripts/Makefile.ubsan
arch/x86/boot/compressed/misc.h +1 -0
@@ -12,6 +12,7 @@#undef CONFIG_PARAVIRT_XXL#undef CONFIG_PARAVIRT_SPINLOCKS#undef CONFIG_KASAN +#undef CONFIG_KMSAN/* cpu_feature_enabled() cannot be used this early */ #define USE_EARLY_PGTABLE_L5
arch/x86/entry/entry_64.S +18 -0
@@ -35,6 +35,7 @@ #include <asm/asm.h> #include <asm/smap.h> #include <asm/pgtable_types.h> +#include <asm/kmsan.h> #include <asm/export.h> #include <asm/frame.h> #include <asm/nospec-branch.h>
@@ -168,12 +169,14 @@ GLOBAL(entry_SYSCALL_64_after_hwframe) PUSH_AND_CLEAR_REGS rax=$-ENOSYS TRACE_IRQS_OFF + KMSAN_SYSCALL_ENTER /* IRQs are off. */ movq %rax, %rdi movq %rsp, %rsi call do_syscall_64 /* returns with IRQs disabled */ + KMSAN_SYSCALL_EXIT TRACE_IRQS_IRETQ /* we're about to change IF */ /*
@@ -575,6 +578,7 @@ ENTRY(interrupt_entry) 1: ENTER_IRQ_STACK old_rsp=%rdi save_ret=1 + KMSAN_INTERRUPT_ENTER /* We entered an interrupt context - irqs are off: */ TRACE_IRQS_OFF
@@ -604,12 +608,14 @@ common_interrupt: addq $-0x80, (%rsp) /* Adjust vector to [-256, -1] range */ call interrupt_entry UNWIND_HINT_REGS indirect=1 + KMSAN_UNPOISON_PT_REGS call do_IRQ /* rdi points to pt_regs */ /* 0(%rsp): old RSP */ ret_from_intr: DISABLE_INTERRUPTS(CLBR_ANY) TRACE_IRQS_OFF + KMSAN_INTERRUPT_EXIT LEAVE_IRQ_STACK testb $3, CS(%rsp)
@@ -802,6 +808,7 @@ ENTRY(\sym) .Lcommon_\sym: call interrupt_entry UNWIND_HINT_REGS indirect=1 + KMSAN_UNPOISON_PT_REGS call \do_sym /* rdi points to pt_regs */ jmp ret_from_intr END(\sym)
@@ -909,15 +916,18 @@ apicinterrupt IRQ_WORK_VECTOR irq_work_interrupt smp_irq_work_interrupt .if \shift_ist != -1 subq $\ist_offset, CPU_TSS_IST(\shift_ist) + KMSAN_IST_ENTER(\shift_ist) .endif .if \read_cr2 movq %r12, %rdx /* Move CR2 into 3rd argument */ .endif + KMSAN_UNPOISON_PT_REGS call \do_sym .if \shift_ist != -1 + KMSAN_IST_EXIT(\shift_ist) addq $\ist_offset, CPU_TSS_IST(\shift_ist) .endif
@@ -1079,7 +1089,9 @@ ENTRY(do_softirq_own_stack) pushq %rbp mov %rsp, %rbp ENTER_IRQ_STACK regs=0 old_rsp=%r11 + KMSAN_SOFTIRQ_ENTER call __do_softirq + KMSAN_SOFTIRQ_EXIT LEAVE_IRQ_STACK regs=0 leaveq ret
@@ -1466,9 +1478,12 @@ ENTRY(nmi) * done with the NMI stack. */ + KMSAN_NMI_ENTER movq %rsp, %rdi movq $-1, %rsi + KMSAN_UNPOISON_PT_REGS call do_nmi + KMSAN_NMI_EXIT /* * Return back to user mode. We must *not* do the normal exit
@@ -1678,10 +1693,13 @@ end_repeat_nmi: call paranoid_entry UNWIND_HINT_REGS + KMSAN_NMI_ENTER /* paranoidentry do_nmi, 0; without TRACE_IRQS_OFF */ movq %rsp, %rdi movq $-1, %rsi + KMSAN_UNPOISON_PT_REGS call do_nmi + KMSAN_NMI_EXIT /* Always restore stashed CR3 value (see paranoid_entry) */ RESTORE_CR3 scratch_reg=%r15 save_reg=%r14
arch/x86/include/asm/page_64_types.h +7 -5
@@ -7,18 +7,20 @@#endif #ifdef CONFIG_KASAN -#define KASAN_STACK_ORDER 1 +#define EXTRA_STACK_ORDER 1 +#elif defined(CONFIG_KMSAN ) +#define EXTRA_STACK_ORDER 2#else -#define KASAN_STACK_ORDER 0 +#define EXTRA_STACK_ORDER 0#endif -#define THREAD_SIZE_ORDER (2 + KASAN_STACK_ORDER) +#define THREAD_SIZE_ORDER (2 + EXTRA_STACK_ORDER)#define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER) -#define EXCEPTION_STACK_ORDER (0 + KASAN_STACK_ORDER) +#define EXCEPTION_STACK_ORDER (0 + EXTRA_STACK_ORDER)#define EXCEPTION_STKSZ (PAGE_SIZE << EXCEPTION_STACK_ORDER) -#define IRQ_STACK_ORDER (2 + KASAN_STACK_ORDER) +#define IRQ_STACK_ORDER (2 + EXTRA_STACK_ORDER)#define IRQ_STACK_SIZE (PAGE_SIZE << IRQ_STACK_ORDER)/*
block/blk.h +7 -0
@@ -78,6 +78,13 @@ static inline bool biovec_phys_mergeable(struct request_queue *q,phys_addr_t addr1 =page_to_phys (vec1->bv_page) + vec1->bv_offset;phys_addr_t addr2 =page_to_phys (vec2->bv_page) + vec2->bv_offset; +#ifdef CONFIG_KMSAN +/* +* Merging consequent physical pages may not work correctly under KMSAN +* if their metadata pages aren't consequent. Just disable merging. +*/ +return false; +#endif if (addr1 + vec1->bv_len != addr2)return false;if (xen_domain () && !xen_biovec_phys_mergeable (vec1, vec2->bv_page))
include/linux/mm_types.h +9 -0
@@ -216,6 +216,15 @@ struct page {not kmapped, ie. highmem) */ #endif /* WANT_PAGE_VIRTUAL */ +#ifdef CONFIG_KMSAN +/* +* Bits in struct page are scarce, so the LSB in *shadow is used to +* indicate whether the page should be ignored by KMSAN or not. +*/ +struct page *shadow; +struct page *origin; +#endif +#ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS int _last_cpupid;#endif
include/linux/sched.h +5 -0
@@ -15,6 +15,7 @@#include <linux/sem.h> #include <linux/shm.h> #include <linux/kcov.h> +#include <linux/kmsan.h> #include <linux/mutex.h> #include <linux/plist.h> #include <linux/hrtimer.h>
@@ -1173,6 +1174,10 @@ struct task_struct {unsigned int kasan_depth;#endif +#ifdef CONFIG_KMSAN +struct kmsan_task_state kmsan; +#endif +#ifdef CONFIG_FUNCTION_GRAPH_TRACER /* Index of current stored address in ret_stack: */ int curr_ret_stack;
init/main.c +3 -0
@@ -32,6 +32,7 @@#include <linux/nmi.h> #include <linux/percpu.h> #include <linux/kmod.h> +#include <linux/kmsan.h> #include <linux/vmalloc.h> #include <linux/kernel_stat.h> #include <linux/start_kernel.h>
@@ -554,6 +555,7 @@ static void __init mm_init(void)*/ page_ext_init_flatmem ();report_meminit (); +kmsan_initialize_shadow ();mem_init ();kmem_cache_init ();kmemleak_init ();
@@ -625,6 +627,7 @@ asmlinkage __visible void __init start_kernel(void)sort_main_extable ();trap_init ();mm_init (); +kmsan_initialize ();ftrace_init ();
lib/stackdepot.c +4 -3
@@ -233,8 +233,8 @@ unsigned int stack_depot_fetch(depot_stack_handle_t handle,if (parts.slabindex > depot_index) {WARN (1 ,"slab index %d out of bounds (%d) for stack id %08x\n" , parts.slabindex, depot_index, handle); -__memset (trace,0 ,sizeof (*trace)); -return ; + *entries =NULL ; +return 0 ; } slab = stack_slabs[parts.slabindex]; stack = slab + offset;
@@ -299,7 +299,8 @@ depot_stack_handle_t stack_depot_save(unsigned long *entries,* contexts and I/O. */ alloc_flags &= ~GFP_ZONEMASK ; - alloc_flags &= (GFP_ATOMIC |GFP_KERNEL ); + alloc_flags &= (GFP_ATOMIC |GFP_KERNEL | + __GFP_NO_KMSAN_SHADOW); alloc_flags |= __GFP_NOWARN; page =alloc_pages (alloc_flags,STACK_ALLOC_ORDER );if (page)
mm/Makefile +1 -0
@@ -71,6 +71,7 @@ obj-$(CONFIG_PAGE_POISONING) += page_poison.o obj-$(CONFIG_SLAB) += slab.o obj-$(CONFIG_SLUB) += slub.o obj-$(CONFIG_KASAN) += kasan/ +obj-$(CONFIG_KMSAN) += kmsan/ obj-$(CONFIG_FAILSLAB) += failslab.o obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o obj-$(CONFIG_MEMTEST) += memtest.o
scripts/Makefile.lib +6 -0
@@ -140,6 +140,12 @@ _c_flags += $(if $(patsubst n%,, \ $(CFLAGS_KASAN), $(CFLAGS_KASAN_NOSANITIZE)) endif +ifeq ($(CONFIG_KMSAN),y) +_c_flags += $(if $(patsubst n%,, \ + $(KMSAN_SANITIZE_$(basetarget).o)$(KMSAN_SANITIZE)y), \ + $(CFLAGS_KMSAN)) +endif + ifeq ($(CONFIG_UBSAN),y) _c_flags += $(if $(patsubst n%,, \ $(UBSAN_SANITIZE_$(basetarget).o)$(UBSAN_SANITIZE)$(CONFIG_UBSAN_SANITIZE_ALL)), \
Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
Re: [PATCH RFC v2 15/25] kmsan: Changing existing files to enable KMSAN builds
Changing existing files is not a very good changelog, and hints that this is doing multiple things at a time.
Quoted 8 lines
block/blk.h +0
-0@@ -78,6 +78,13 @@ static inline bool biovec_phys_mergeable(struct request_queue *q,phys_addr_t addr1 =page_to_phys (vec1->bv_page) + vec1->bv_offset;phys_addr_t addr2 =page_to_phys (vec2->bv_page) + vec2->bv_offset;
block/blk.h static inline bool biovec_phys_mergeable(struct request_queue *q, · line 90
Quoted 10 lines
block/blk.h +7
-0+#ifdef CONFIG_KMSAN +/* +* Merging consequent physical pages may not work correctly under KMSAN +* if their metadata pages aren't consequent. Just disable merging. +*/ +return false; +#endif if (addr1 + vec1->bv_len != addr2)return false;if (xen_domain () && !xen_biovec_phys_mergeable (vec1, vec2->bv_page))
e.g. this looks pretty standaline. And could be simplified to:
if (IS_ENABLED(CONFIG_KMSAN)) return false;
[email protected]
maintainerRFC PATCH v2 16/25 kmsan: disable KMSAN instrumentation for certain kernel parts
In reply to [email protected]Instrumenting some files with KMSAN will result in kernel being unable to link, boot or crashing at runtime for various reasons (e.g. infinite recursion caused by instrumentation hooks calling instrumented code again).
Disable KMSAN in the following places:
- arch/x86/boot and arch/x86/realmode/rm, as KMSAN doesn't work for i386;
- arch/x86/entry/vdso, which isn't linked with KMSAN runtime;
- three files in arch/x86/kernel - boot problems;
- arch/x86/mm/cpu_entry_area.c - recursion;
- EFI stub - build failures;
- kcov, stackdepot - recursion.
To: Alexander Potapenko <[email protected]>
Cc: Ard Biesheuvel <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Vegard Nossum <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: [email protected]
---
Change-Id: I90961eabf2dcb9ae992aed259088953bad5e4d6d
--- arch/x86/boot/Makefile | 2 ++ arch/x86/boot/compressed/Makefile | 2 ++ arch/x86/entry/vdso/Makefile | 3 +++ arch/x86/kernel/Makefile | 4 ++++ arch/x86/kernel/cpu/Makefile | 1 + arch/x86/mm/Makefile | 2 ++ arch/x86/realmode/rm/Makefile | 2 ++ drivers/firmware/efi/libstub/Makefile | 1 + kernel/Makefile | 1 + lib/Makefile | 1 + 10 files changed, 19 insertions(+)
arch/x86/boot/Makefile +2 -0
@@ -10,6 +10,8 @@ # KASAN_SANITIZE := n +# KMSAN doesn't work for i386 +KMSAN_SANITIZE := n OBJECT_FILES_NON_STANDARD := y # Kernel does not boot with kcov instrumentation here.
arch/x86/boot/compressed/Makefile +2 -0
@@ -18,6 +18,8 @@ # compressed vmlinux.bin.all + u32 size of vmlinux.bin.all KASAN_SANITIZE := n +# KMSAN doesn't work for i386 +KMSAN_SANITIZE := n OBJECT_FILES_NON_STANDARD := y # Prevents link failures: __sanitizer_cov_trace_pc() is not linked in.
arch/x86/entry/vdso/Makefile +3 -0
@@ -11,6 +11,9 @@ include $(srctree)/lib/vdso/Makefile KBUILD_CFLAGS += $(DISABLE_LTO) KASAN_SANITIZE := n +# Undefined references to KMSAN hooks. +KMSAN_SANITIZE_vclock_gettime.o := n +KMSAN_SANITIZE_vgetcpu.o := n UBSAN_SANITIZE := n OBJECT_FILES_NON_STANDARD := y
arch/x86/kernel/Makefile +4 -0
@@ -28,6 +28,10 @@ KASAN_SANITIZE_dumpstack_$(BITS).o := n KASAN_SANITIZE_stacktrace.o := n KASAN_SANITIZE_paravirt.o := n +# Work around reboot loop. +KMSAN_SANITIZE_head$(BITS).o := n +KMSAN_SANITIZE_nmi.o := n + OBJECT_FILES_NON_STANDARD_relocate_kernel_$(BITS).o := y OBJECT_FILES_NON_STANDARD_test_nx.o := y OBJECT_FILES_NON_STANDARD_paravirt_patch.o := y
arch/x86/kernel/cpu/Makefile +1 -0
@@ -12,6 +12,7 @@ endif # If these files are instrumented, boot hangs during the first second. KCOV_INSTRUMENT_common.o := n KCOV_INSTRUMENT_perf_event.o := n +KMSAN_SANITIZE_common.o := n # Make sure load_percpu_segment has no stackprotector nostackp := $(call cc-option, -fno-stack-protector)
arch/x86/mm/Makefile +2 -0
@@ -7,6 +7,8 @@ KCOV_INSTRUMENT_mem_encrypt_identity.o := n KASAN_SANITIZE_mem_encrypt.o := n KASAN_SANITIZE_mem_encrypt_identity.o := n +KMSAN_SANITIZE_cpu_entry_area.o := n + ifdef CONFIG_FUNCTION_TRACER CFLAGS_REMOVE_mem_encrypt.o = -pg CFLAGS_REMOVE_mem_encrypt_identity.o = -pg
arch/x86/realmode/rm/Makefile +2 -0
@@ -7,6 +7,8 @@ # # KASAN_SANITIZE := n +# KMSAN doesn't work for i386 +KMSAN_SANITIZE := n OBJECT_FILES_NON_STANDARD := y # Prevents link failures: __sanitizer_cov_trace_pc() is not linked in.
drivers/firmware/efi/libstub/Makefile +1 -0
@@ -32,6 +32,7 @@ KBUILD_CFLAGS := $(cflags-y) -DDISABLE_BRANCH_PROFILING \ GCOV_PROFILE := n KASAN_SANITIZE := n +KMSAN_SANITIZE := n UBSAN_SANITIZE := n OBJECT_FILES_NON_STANDARD := y
kernel/Makefile +1 -0
@@ -30,6 +30,7 @@ KCOV_INSTRUMENT_extable.o := n # Don't self-instrument. KCOV_INSTRUMENT_kcov.o := n KASAN_SANITIZE_kcov.o := n +KMSAN_SANITIZE_kcov.o := n CFLAGS_kcov.o := $(call cc-option, -fno-conserve-stack -fno-stack-protector) # cond_syscall is currently not LTO compatible
lib/Makefile +1 -0
@@ -218,6 +218,7 @@ obj-$(CONFIG_IRQ_POLL) += irq_poll.o obj-$(CONFIG_STACKDEPOT) += stackdepot.o KASAN_SANITIZE_stackdepot.o := n +KMSAN_SANITIZE_stackdepot.o := n KCOV_INSTRUMENT_stackdepot.o := n libfdt_files = fdt.o fdt_ro.o fdt_wip.o fdt_rw.o fdt_sw.o fdt_strerror.o \
Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
[email protected]
maintainerRFC PATCH v2 17/25 kmsan: mm: call KMSAN hooks from SLUB code
In reply to [email protected]In order to report uninitialized memory coming from heap allocations KMSAN has to poison them unless they're created with __GFP_ZERO.
It's handy that we need KMSAN hooks in the places where init_on_alloc/init_on_free initialization is performed.
To: Alexander Potapenko <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Vegard Nossum <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: [email protected]
---
Change-Id: I51103b7981d3aabed747d0c85cbdc85568665871
--- mm/slub.c | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-)
mm/slub.c +31 -6
@@ -21,6 +21,8 @@#include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/kasan.h> +#include <linux/kmsan.h> +#include <linux/kmsan-checks.h> /* KMSAN_INIT_VALUE */ #include <linux/cpu.h> #include <linux/cpuset.h> #include <linux/mempolicy.h>
@@ -285,17 +287,27 @@ static void prefetch_freepointer(const struct kmem_cache *s, void *object)prefetch (object + s->offset); } +/* +* When running under KMSAN, get_freepointer_safe() may return an uninitialized +* pointer value in the case the current thread loses the race for the next +* memory chunk in the freelist. In that case this_cpu_cmpxchg_double() in +* slab_alloc_node() will fail, so the uninitialized value won't be used, but +* KMSAN will still check all arguments of cmpxchg because of imperfect +* handling of inline assembly. +* To work around this problem, use KMSAN_INIT_VALUE() to force initialize the +* return value of get_freepointer_safe(). +*/ static inline void *get_freepointer_safe (struct kmem_cache *s,void *object) {unsigned long freepointer_addr;void *p;if (!debug_pagealloc_enabled ()) -return get_freepointer (s, object); +return KMSAN_INIT_VALUE (get_freepointer (s, object)); freepointer_addr = (unsigned long )object + s->offset;probe_kernel_read (&p, (void **)freepointer_addr,sizeof (p)); -return freelist_ptr (s, p, freepointer_addr); +return KMSAN_INIT_VALUE (freelist_ptr (s, p, freepointer_addr)); }static inline void set_freepointer (struct kmem_cache *s,void *object,void *fp)
@@ -1390,6 +1402,7 @@ static inline void *kmalloc_large_node_hook(void *ptr, size_t size, gfp_t flags) ptr =kasan_kmalloc_large (ptr, size, flags);/* As ptr might get tagged, call kmemleak hook after KASAN. */ kmemleak_alloc (ptr, size,1 , flags); +kmsan_kmalloc_large (ptr, size, flags);return ptr; }
@@ -1397,6 +1410,7 @@ static __always_inline void kfree_hook(void *x) {kmemleak_free (x);kasan_kfree_large (x, _RET_IP_); +kmsan_kfree_large (x); } static __always_inline bool slab_free_hook(struct kmem_cache *s, void *x)
@@ -1453,6 +1467,12 @@ static inline bool slab_free_freelist_hook(struct kmem_cache *s, }while (object != old_tail); } +do { + object = next; + next =get_freepointer (s, object); +kmsan_slab_free (s, object); + }while (object != old_tail); +/* * Compiler cannot detect this function can be removed if slab_free_hook() * evaluates to nothing. Thus, catch all relevant config debug options here.
@@ -2776,6 +2796,7 @@ static __always_inline void *slab_alloc_node(struct kmem_cache *s,if (unlikely (slab_want_init_on_alloc (gfpflags, s)) && object)memset (object,0 , s->object_size); +kmsan_slab_alloc (s, object, gfpflags);slab_post_alloc_hook (s, gfpflags,1 , &object);return object;
@@ -2804,6 +2825,7 @@ void *kmem_cache_alloc_trace(struct kmem_cache *s, gfp_t gfpflags, size_t size)void *ret =slab_alloc (s, gfpflags, _RET_IP_);trace_kmalloc (_RET_IP_, ret, size, s->size, gfpflags); ret =kasan_kmalloc (s, ret, size, gfpflags); +return ret; }EXPORT_SYMBOL (kmem_cache_alloc_trace);
@@ -2816,7 +2838,6 @@ void *kmem_cache_alloc_node(struct kmem_cache *s, gfp_t gfpflags, int node)trace_kmem_cache_alloc_node (_RET_IP_, ret, s->object_size, s->size, gfpflags, node); -return ret; }EXPORT_SYMBOL (kmem_cache_alloc_node);
@@ -2832,6 +2853,7 @@ void *kmem_cache_alloc_node_trace(struct kmem_cache *s, size, s->size, gfpflags, node); ret =kasan_kmalloc (s, ret, size, gfpflags); +return ret; }EXPORT_SYMBOL (kmem_cache_alloc_node_trace);
@@ -3157,7 +3179,7 @@ int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size, void **p) {struct kmem_cache_cpu *c; -int i; +int i, j;/* memcg and kmem_cache debug support */ s =slab_pre_alloc_hook (s, flags);
@@ -3198,11 +3220,11 @@ int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,/* Clear memory outside IRQ disabled fastpath loop */ if (unlikely (slab_want_init_on_alloc (flags, s))) { -int j; -for (j =0 ; j < i; j++)memset (p[j],0 , s->object_size); } +for (j =0 ; j < i; j++) +kmsan_slab_alloc (s, p[j], flags);/* memcg and kmem_cache debug support */ slab_post_alloc_hook (s, flags, size, p);
@@ -3803,6 +3825,7 @@ static int __init setup_slub_min_objects(char *str)__setup ("slub_min_objects=" , setup_slub_min_objects); +__no_sanitize_memory void *__kmalloc(size_t size, gfp_t flags) {struct kmem_cache *s;
@@ -5717,6 +5740,7 @@ static char *create_unique_id(struct kmem_cache *s) p +=sprintf (p,"%07u" , s->size);BUG_ON (p > name +ID_STR_LENGTH -1 ); +kmsan_unpoison_shadow (name, p - name);return name; }
@@ -5866,6 +5890,7 @@ static int sysfs_slab_alias(struct kmem_cache *s, const char *name) al->name = name; al->next = alias_list; alias_list = al; +kmsan_unpoison_shadow (al,sizeof (struct saved_alias ));return 0 ; }
Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
Re: [PATCH RFC v2 17/25] kmsan: mm: call KMSAN hooks from SLUB code
Quoted 101 lines · On Wed, Oct 30, 2019 at 3:23 PM <[email protected]> wrote:
In order to report uninitialized memory coming from heap allocations KMSAN has to poison them unless they're created with
__GFP_ZERO.It's handy that we need KMSAN hooks in the places where init_on_alloc/init_on_free initialization is performed.
Signed-off-by Alexander Potapenko <[email protected]>To: Alexander Potapenko <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Vegard Nossum <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: [email protected]
---Change-Id: I51103b7981d3aabed747d0c85cbdc85568665871
--- mm/slub.c | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-)mm/slub.c +23
-2@@ -21,6 +21,8 @@#include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/kasan.h> +#include <linux/kmsan.h> +#include <linux/kmsan-checks.h> /* KMSAN_INIT_VALUE */ #include <linux/cpu.h> #include <linux/cpuset.h> #include <linux/mempolicy.h> @@ -285,17 +287,27 @@ static void prefetch_freepointer(const struct kmem_cache *s, void *object)prefetch (object + s->offset); } +/* +* When running under KMSAN, get_freepointer_safe() may return an uninitialized +* pointer value in the case the current thread loses the race for the next +* memory chunk in the freelist. In that case this_cpu_cmpxchg_double() in +* slab_alloc_node() will fail, so the uninitialized value won't be used, but +* KMSAN will still check all arguments of cmpxchg because of imperfect +* handling of inline assembly. +* To work around this problem, use KMSAN_INIT_VALUE() to force initialize the +* return value of get_freepointer_safe(). +*/ static inline void *get_freepointer_safe (struct kmem_cache *s,void *object) {unsigned long freepointer_addr;void *p;if (!debug_pagealloc_enabled ()) -return get_freepointer (s, object); +return KMSAN_INIT_VALUE (get_freepointer (s, object)); freepointer_addr = (unsigned long )object + s->offset;probe_kernel_read (&p, (void **)freepointer_addr,sizeof (p)); -return freelist_ptr (s, p, freepointer_addr); +return KMSAN_INIT_VALUE (freelist_ptr (s, p, freepointer_addr)); }static inline void set_freepointer (struct kmem_cache *s,void *object,void *fp)@@ -1390,6 +1402,7 @@ static inline void *kmalloc_large_node_hook(void *ptr, size_t size, gfp_t flags) ptr =kasan_kmalloc_large (ptr, size, flags);/* As ptr might get tagged, call kmemleak hook after KASAN. */ kmemleak_alloc (ptr, size,1 , flags); +kmsan_kmalloc_large (ptr, size, flags);return ptr; }@@ -1397,6 +1410,7 @@ static __always_inline void kfree_hook(void *x) {kmemleak_free (x);kasan_kfree_large (x, _RET_IP_); +kmsan_kfree_large (x); } static __always_inline bool slab_free_hook(struct kmem_cache *s, void *x)@@ -1453,6 +1467,12 @@ static inline bool slab_free_freelist_hook(struct kmem_cache *s, }while (object != old_tail); } +do { + object = next; + next =get_freepointer (s, object); +kmsan_slab_free (s, object); + }while (object != old_tail); +/* * Compiler cannot detect this function can be removed if slab_free_hook() * evaluates to nothing. Thus, catch all relevant config debug options here. @@ -2776,6 +2796,7 @@ static __always_inline void *slab_alloc_node(struct kmem_cache *s,if (unlikely (slab_want_init_on_alloc (gfpflags, s)) && object)memset (object,0 , s->object_size); +kmsan_slab_alloc (s, object, gfpflags);slab_post_alloc_hook (s, gfpflags,1 , &object);return object;
mm/slub.c void *kmem_cache_alloc_trace(struct kmem_cache *s, gfp_t gfpflags, size_t size) · line 2828
Quoted 4 lines
mm/slub.c +1
-0@@ -2804,6 +2825,7 @@ void *kmem_cache_alloc_trace(struct kmem_cache *s, gfp_t gfpflags, size_t size)void *ret =slab_alloc (s, gfpflags, _RET_IP_);trace_kmalloc (_RET_IP_, ret, size, s->size, gfpflags); ret =kasan_kmalloc (s, ret, size, gfpflags); +
Looks like unrelated change.
mm/slub.c void *kmem_cache_alloc_node(struct kmem_cache *s, gfp_t gfpflags, int node) · line 2819
Quoted 8 lines
mm/slub.c +0
-1return ret; }EXPORT_SYMBOL (kmem_cache_alloc_trace);@@ -2816,7 +2838,6 @@ void *kmem_cache_alloc_node(struct kmem_cache *s, gfp_t gfpflags, int node)trace_kmem_cache_alloc_node (_RET_IP_, ret, s->object_size, s->size, gfpflags, node); -
Same here.
mm/slub.c void *kmem_cache_alloc_node_trace(struct kmem_cache *s, · line 2856
Quoted 8 lines
mm/slub.c +1
-0return ret; }EXPORT_SYMBOL (kmem_cache_alloc_node);@@ -2832,6 +2853,7 @@ void *kmem_cache_alloc_node_trace(struct kmem_cache *s, size, s->size, gfpflags, node); ret =kasan_kmalloc (s, ret, size, gfpflags); +
And here.
Quoted 53 lines
mm/slub.c +6
-4return ret; }EXPORT_SYMBOL (kmem_cache_alloc_node_trace);@@ -3157,7 +3179,7 @@ int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size, void **p) {struct kmem_cache_cpu *c; -int i; +int i, j;/* memcg and kmem_cache debug support */ s =slab_pre_alloc_hook (s, flags);@@ -3198,11 +3220,11 @@ int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,/* Clear memory outside IRQ disabled fastpath loop */ if (unlikely (slab_want_init_on_alloc (flags, s))) { -int j; -for (j =0 ; j < i; j++)memset (p[j],0 , s->object_size); } +for (j =0 ; j < i; j++) +kmsan_slab_alloc (s, p[j], flags);/* memcg and kmem_cache debug support */ slab_post_alloc_hook (s, flags, size, p);@@ -3803,6 +3825,7 @@ static int __init setup_slub_min_objects(char *str)__setup ("slub_min_objects=" , setup_slub_min_objects); +__no_sanitize_memory void *__kmalloc(size_t size, gfp_t flags) {struct kmem_cache *s;@@ -5717,6 +5740,7 @@ static char *create_unique_id(struct kmem_cache *s) p +=sprintf (p,"%07u" , s->size);BUG_ON (p > name +ID_STR_LENGTH -1 ); +kmsan_unpoison_shadow (name, p - name);return name; }@@ -5866,6 +5890,7 @@ static int sysfs_slab_alias(struct kmem_cache *s, const char *name) al->name = name; al->next = alias_list; alias_list = al; +kmsan_unpoison_shadow (al,sizeof (struct saved_alias ));return 0 ; } --2.24.0.rc0.303.g954a862665-goog
[email protected]
maintainerRFC PATCH v2 18/25 kmsan: call KMSAN hooks where needed
In reply to [email protected]Insert KMSAN hooks that check for potential memory errors and/or make necessary bookkeeping changes:
- allocate/split/deallocate metadata pages in alloc_pages()/split_page()/free_page();
- clear page shadow and origins in clear_page(), copy_user_highpage();
- copy page metadata in copy_highpage(), wp_page_copy();
- handle vmap()/vunmap()/iounmap();
- handle task creation and deletion;
- initialize result of vscnprintf() in vprintk_store();
- call softirq entry/exit hooks in kernel/softirq.c;
- check/initialize memory sent to/read from USB, I2C, and network
To: Alexander Potapenko <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Greg Kroah-Hartman <[email protected]>
Cc: Eric Dumazet <[email protected]>
Cc: Wolfram Sang <[email protected]>
Cc: Petr Mladek <[email protected]>
Cc: Vegard Nossum <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: [email protected]
---
v2:
- dropped call to kmsan_handle_vprintk, updated comment in printk.c
Change-Id: I1250a928d9263bf71fdaa067a070bdee686ef47b
--- arch/x86/include/asm/page_64.h | 13 +++++++++++++ arch/x86/mm/ioremap.c | 3 +++ drivers/i2c/i2c-core-base.c | 2 ++ drivers/usb/core/urb.c | 2 ++ include/linux/highmem.h | 4 ++++ kernel/exit.c | 2 ++ kernel/fork.c | 2 ++ kernel/kthread.c | 2 ++ kernel/printk/printk.c | 8 +++++++- kernel/softirq.c | 5 +++++ lib/ioremap.c | 5 +++++ mm/compaction.c | 9 +++++++++ mm/gup.c | 3 +++ mm/memory.c | 2 ++ mm/page_alloc.c | 16 ++++++++++++++++ mm/vmalloc.c | 23 +++++++++++++++++++++-- net/sched/sch_generic.c | 2 ++ 17 files changed, 100 insertions(+), 3 deletions(-)
arch/x86/include/asm/page_64.h +13 -0
@@ -44,14 +44,27 @@ void clear_page_orig(void *page);void clear_page_rep (void *page);void clear_page_erms (void *page); +/* This is an assembly header, avoid including too much of kmsan.h */ +#ifdef CONFIG_KMSAN +void kmsan_clear_page (void *page_addr); +#endif +__no_sanitize_memory static inline void clear_page(void *page) { +#ifdef CONFIG_KMSAN +/* alternative_call_2() changes |page|. */ +void *page_copy = page; +#endif alternative_call_2 (clear_page_orig, clear_page_rep,X86_FEATURE_REP_GOOD , clear_page_erms,X86_FEATURE_ERMS ,"=D" (page), "0" (page) : "cc", "memory", "rax", "rcx"); +#ifdef CONFIG_KMSAN +/* Clear KMSAN shadow for the pages that have it. */ +kmsan_clear_page (page_copy); +#endif }void copy_page (void *to,void *from);
arch/x86/mm/ioremap.c +3 -0
@@ -7,6 +7,7 @@* (C) Copyright 1995 1996 Linus Torvalds */ +#include <linux/kmsan.h> #include <linux/memblock.h> #include <linux/init.h> #include <linux/io.h>
@@ -451,6 +452,8 @@ void iounmap(volatile void __iomem *addr)return ; } +kmsan_iounmap_page_range ((unsigned long )addr, + (unsigned long )addr +get_vm_area_size (p));free_memtype (p->phys_addr, p->phys_addr +get_vm_area_size (p));/* Finally remove it */
drivers/i2c/i2c-core-base.c +2 -0
@@ -27,6 +27,7 @@#include <linux/irqflags.h> #include <linux/jump_label.h> #include <linux/kernel.h> +#include <linux/kmsan.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/of_device.h>
@@ -1975,6 +1976,7 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)trace_i2c_write (adap, &msgs[i], i); } +kmsan_handle_i2c_transfer (msgs, num);/* Retry automatically on arbitration loss */ orig_jiffies = jiffies;for (ret =0 , try =0 ; try <= adap->retries; try++) {
drivers/usb/core/urb.c +2 -0
@@ -8,6 +8,7 @@#include <linux/bitops.h> #include <linux/slab.h> #include <linux/log2.h> +#include <linux/kmsan-checks.h> #include <linux/usb.h> #include <linux/wait.h> #include <linux/usb/hcd.h>
@@ -401,6 +402,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)URB_SETUP_MAP_SINGLE |URB_SETUP_MAP_LOCAL | URB_DMA_SG_COMBINED); urb->transfer_flags |= (is_out ?URB_DIR_OUT :URB_DIR_IN ); +kmsan_handle_urb (urb, is_out);if (xfertype !=USB_ENDPOINT_XFER_CONTROL && dev->state <USB_STATE_CONFIGURED )
include/linux/highmem.h +4 -0
@@ -5,6 +5,7 @@#include <linux/fs.h> #include <linux/kernel.h> #include <linux/bug.h> +#include <linux/kmsan.h> #include <linux/mm.h> #include <linux/uaccess.h> #include <linux/hardirq.h>
@@ -255,6 +256,8 @@ static inline void copy_user_highpage(struct page *to, struct page *from, vfrom =kmap_atomic (from); vto =kmap_atomic (to);copy_user_page (vto, vfrom, vaddr, to); +/* User pages don't have shadow, just clear the destination. */ +kmsan_clear_page (page_address (to));kunmap_atomic (vto);kunmap_atomic (vfrom); }
@@ -270,6 +273,7 @@ static inline void copy_highpage(struct page *to, struct page *from) vfrom =kmap_atomic (from); vto =kmap_atomic (to);copy_page (vto, vfrom); +kmsan_copy_page_meta (to, from);kunmap_atomic (vto);kunmap_atomic (vfrom); }
kernel/exit.c +2 -0
@@ -60,6 +60,7 @@#include <linux/writeback.h> #include <linux/shm.h> #include <linux/kcov.h> +#include <linux/kmsan.h> #include <linux/random.h> #include <linux/rcuwait.h> #include <linux/compat.h>
@@ -719,6 +720,7 @@ void __noreturn do_exit(long code)profile_task_exit (tsk);kcov_task_exit (tsk); +kmsan_task_exit (tsk);WARN_ON (blk_needs_flush_plug (tsk));
kernel/fork.c +2 -0
@@ -37,6 +37,7 @@#include <linux/fdtable.h> #include <linux/iocontext.h> #include <linux/key.h> +#include <linux/kmsan.h> #include <linux/binfmts.h> #include <linux/mman.h> #include <linux/mmu_notifier.h>
@@ -931,6 +932,7 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node)account_kernel_stack (tsk,1 );kcov_task_init (tsk); +kmsan_task_create (tsk);#ifdef CONFIG_FAULT_INJECTION tsk->fail_nth =0 ;
kernel/kthread.c +2 -0
@@ -17,6 +17,7 @@#include <linux/unistd.h> #include <linux/file.h> #include <linux/export.h> +#include <linux/kmsan.h> #include <linux/mutex.h> #include <linux/slab.h> #include <linux/freezer.h>
@@ -350,6 +351,7 @@ struct task_struct *__kthread_create_on_node(int (*threadfn)(void *data),set_cpus_allowed_ptr (task, cpu_all_mask); }kfree (create); +kmsan_task_create (task);return task; }
kernel/printk/printk.c +7 -1
@@ -1914,7 +1914,13 @@ int vprintk_store(int facility, int level,* The printf needs to come first; we need the syslog * prefix which might be passed-in as a parameter. */ - text_len =vscnprintf (text,sizeof (textbuf), fmt, args); +/* +* If any of vscnprintf() arguments is uninitialized, KMSAN will report +* one or more errors and also probably mark text_len as uninitialized. +* Initialize |text_len| to prevent the errors from spreading further. +*/ + text_len =KMSAN_INIT_VALUE (vscnprintf (text,sizeof (textbuf), fmt, + args));/* mark and strip a trailing newline */ if (text_len && text[text_len-1 ] =='\n' ) {
kernel/softirq.c +5 -0
@@ -11,6 +11,7 @@#include <linux/export.h> #include <linux/kernel_stat.h> +#include <linux/kmsan.h> #include <linux/interrupt.h> #include <linux/init.h> #include <linux/mm.h>
@@ -370,7 +371,9 @@ static inline void invoke_softirq(void)* it is the irq stack, because it should be near empty * at this stage. */ +kmsan_softirq_enter ();__do_softirq (); +kmsan_softirq_exit ();#else /* * Otherwise, irq_exit() is called on the task stack that can
@@ -600,7 +603,9 @@ static void run_ksoftirqd(unsigned int cpu)* We can safely run softirq on inline stack, as we are not deep * in the task stack here. */ +kmsan_softirq_enter ();__do_softirq (); +kmsan_softirq_exit ();local_irq_enable ();cond_resched ();return ;
lib/ioremap.c +5 -0
@@ -6,6 +6,7 @@* * (C) Copyright 1995 1996 Linus Torvalds */ +#include <linux/kmsan.h> #include <linux/vmalloc.h> #include <linux/mm.h> #include <linux/sched.h>
@@ -214,6 +215,8 @@ int ioremap_page_range(unsigned long addr,unsigned long start;unsigned long next;int err; +unsigned long old_addr = addr; +phys_addr_t old_phys_addr = phys_addr;might_sleep ();BUG_ON (addr >= end);
@@ -228,6 +231,8 @@ int ioremap_page_range(unsigned long addr, }while (pgd++, phys_addr += (next - addr), addr = next, addr != end);flush_cache_vmap (start, end); +if (!err) +kmsan_ioremap_page_range (old_addr, end, old_phys_addr, prot);return err; }
mm/compaction.c +9 -0
@@ -84,6 +84,15 @@ static void split_map_pages(struct list_head *list)for (i =0 ; i < nr_pages; i++) {list_add (&page->lru, &tmp_list); +#ifdef CONFIG_KMSAN +/* +* TODO(glider): we may lose the metadata when copying +* something to these pages. Need to allocate shadow +* and origin pages here instead. +*/ + page->shadow =NULL ; + page->origin =NULL ; +#endif page++; } }
mm/gup.c +3 -0
@@ -4,6 +4,7 @@#include <linux/err.h> #include <linux/spinlock.h> +#include <linux/kmsan.h> #include <linux/mm.h> #include <linux/memremap.h> #include <linux/pagemap.h>
@@ -2349,6 +2350,7 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write, gup_fast_permitted(start, end)) {local_irq_save (flags);gup_pgd_range (start, end, write ?FOLL_WRITE :0 , pages, &nr); +kmsan_gup_pgd_range (pages, nr);local_irq_restore (flags); }
@@ -2418,6 +2420,7 @@ int get_user_pages_fast(unsigned long start, int nr_pages, gup_fast_permitted(start, end)) {local_irq_disable ();gup_pgd_range (addr, end, gup_flags, pages, &nr); +kmsan_gup_pgd_range (pages, nr);local_irq_enable (); ret = nr; }
mm/memory.c +2 -0
@@ -51,6 +51,7 @@#include <linux/highmem.h> #include <linux/pagemap.h> #include <linux/memremap.h> +#include <linux/kmsan.h> #include <linux/ksm.h> #include <linux/rmap.h> #include <linux/export.h>
@@ -2328,6 +2329,7 @@ static vm_fault_t wp_page_copy(struct vm_fault *vmf)if (!new_page) goto oom;cow_user_page (new_page, old_page, vmf->address, vma); +kmsan_copy_page_meta (new_page, old_page); }if (mem_cgroup_try_charge_delay (new_page, mm,GFP_KERNEL , &memcg, false))
mm/page_alloc.c +16 -0
@@ -26,6 +26,8 @@#include <linux/compiler.h> #include <linux/kernel.h> #include <linux/kasan.h> +#include <linux/kmsan.h> +#include <linux/kmsan-checks.h> #include <linux/module.h> #include <linux/suspend.h> #include <linux/pagevec.h>
@@ -1133,6 +1135,7 @@ static __always_inline bool free_pages_prepare(struct page *page,VM_BUG_ON_PAGE (PageTail (page), page);trace_mm_page_free (page, order); +kmsan_free_page (page, order);/* * Check tail pages before head page information is cleared to
@@ -3121,6 +3124,7 @@ void split_page(struct page *page, unsigned int order)VM_BUG_ON_PAGE (PageCompound (page), page);VM_BUG_ON_PAGE (!page_count (page), page); +kmsan_split_page (page, order);for (i =1 ; i < (1 << order); i++)set_page_refcounted (page + i);split_page_owner (page, order);
@@ -3253,6 +3257,13 @@ static struct page *rmqueue_pcplist(struct zone *preferred_zone,/* * Allocate a page from the given zone. Use pcplists for order-0 allocations. */ +/* +* TODO(glider): rmqueue() may call __msan_poison_alloca() through a call to +* set_pfnblock_flags_mask(). If __msan_poison_alloca() attempts to allocate +* pages for the stack depot, it may call rmqueue() again, which will result +* in a deadlock. +*/ +__no_sanitize_memory static inline struct page *rmqueue(struct zone *preferred_zone, struct zone *zone, unsigned int order,
@@ -4781,6 +4792,11 @@ __alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order, int preferred_nid,trace_mm_page_alloc (page, order, alloc_mask, ac.migratetype); +if (page) +if (kmsan_alloc_page (page, order, gfp_mask)) { +__free_pages (page, order); + page =NULL ; + }return page; }EXPORT_SYMBOL (__alloc_pages_nodemask);
mm/vmalloc.c +21 -2
@@ -29,6 +29,7 @@#include <linux/rcupdate.h> #include <linux/pfn.h> #include <linux/kmemleak.h> +#include <linux/kmsan.h> #include <linux/atomic.h> #include <linux/compiler.h> #include <linux/llist.h>
@@ -119,7 +120,8 @@ static void vunmap_p4d_range(pgd_t *pgd, unsigned long addr, unsigned long end) }while (p4d++, addr = next, addr != end); } -static void vunmap_page_range (unsigned long addr,unsigned long end) +/* Exported for KMSAN, visible in mm/kmsan/kmsan.h only. */ +void __vunmap_page_range (unsigned long addr,unsigned long end) {pgd_t *pgd;unsigned long next;
@@ -133,6 +135,12 @@ static void vunmap_page_range(unsigned long addr, unsigned long end)vunmap_p4d_range (pgd, addr, next); }while (pgd++, addr = next, addr != end); } +EXPORT_SYMBOL (__vunmap_page_range); +static void vunmap_page_range (unsigned long addr,unsigned long end) +{ +kmsan_vunmap_page_range (addr, end); +__vunmap_page_range (addr, end); +}static int vmap_pte_range (pmd_t *pmd,unsigned long addr,unsigned long end,pgprot_t prot,struct page **pages,int *nr)
@@ -216,8 +224,11 @@ static int vmap_p4d_range(pgd_t *pgd, unsigned long addr,* will have pfns corresponding to the "pages" array. * * Ie. pte at addr+N*PAGE_SIZE shall point to pfn corresponding to pages[N] +* +* This function is exported for use in KMSAN, but is only declared in KMSAN +* headers. */ -static int vmap_page_range_noflush (unsigned long start,unsigned long end, +int __vmap_page_range_noflush (unsigned long start,unsigned long end,pgprot_t prot,struct page **pages) {pgd_t *pgd;
@@ -237,6 +248,14 @@ static int vmap_page_range_noflush(unsigned long start, unsigned long end,return nr; } +EXPORT_SYMBOL (__vmap_page_range_noflush); + +static int vmap_page_range_noflush (unsigned long start,unsigned long end, +pgprot_t prot,struct page **pages) +{ +kmsan_vmap_page_range_noflush (start, end, prot, pages); +return __vmap_page_range_noflush (start, end, prot, pages); +}static int vmap_page_range (unsigned long start,unsigned long end,pgprot_t prot,struct page **pages)
net/sched/sch_generic.c +2 -0
@@ -11,6 +11,7 @@#include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> +#include <linux/kmsan-checks.h> #include <linux/sched.h> #include <linux/string.h> #include <linux/errno.h>
@@ -659,6 +660,7 @@ static struct sk_buff *pfifo_fast_dequeue(struct Qdisc *qdisc) }else { qdisc->empty = true; } +kmsan_check_skb (skb);return skb; }
Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
Re: [PATCH RFC v2 18/25] kmsan: call KMSAN hooks where needed
Quoted 32 lines · On Wed 2019-10-30 15:22:30, [email protected] wrote:
Insert KMSAN hooks that check for potential memory errors and/or make necessary bookkeeping changes:
- allocate/split/deallocate metadata pages in alloc_pages()/split_page()/free_page();
- clear page shadow and origins inclear_page(),copy_user_highpage();
- copy page metadata incopy_highpage(),wp_page_copy();
- handle vmap()/vunmap()/iounmap();
- handle task creation and deletion;
- initialize result ofvscnprintf()invprintk_store();
- call softirq entry/exit hooks inkernel/softirq.c;
- check/initialize memory sent to/read from USB, I2C, and networkSigned-off-by Alexander Potapenko <[email protected]>To: Alexander Potapenko <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Greg Kroah-Hartman <[email protected]>
Cc: Eric Dumazet <[email protected]>
Cc: Wolfram Sang <[email protected]>
Cc: Petr Mladek <[email protected]>
Cc: Vegard Nossum <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: [email protected]
---v2:
- dropped call tokmsan_handle_vprintk, updated comment inprintk.ckernel/printk/printk.c +0
-0
kernel/printk/printk.c int vprintk_store(int facility, int level, · line 1917
Quoted 5 lines
kernel/printk/printk.c +1
-1@@ -1914,7 +1914,13 @@ int vprintk_store(int facility, int level,* The printf needs to come first; we need the syslog * prefix which might be passed-in as a parameter. */ - text_len =vscnprintf (text,sizeof (textbuf), fmt, args); +/*
Please, separate the two comments with an empty line instead of using */ and /*.
kernel/printk/printk.c int vprintk_store(int facility, int level, · line 1923
Quoted 6 lines
kernel/printk/printk.c +6
-0+* If any of vscnprintf() arguments is uninitialized, KMSAN will report +* one or more errors and also probably mark text_len as uninitialized. +* Initialize |text_len| to prevent the errors from spreading further. +*/ + text_len =KMSAN_INIT_VALUE (vscnprintf (text,sizeof (textbuf), fmt, + args));
Please, keep it on a single line. This seems to be the case where the 80-characters limit rule just breaks readability.
I still think that KMSAN should report only the first use of an uninitialized value. It should _not_ report locations where the value is spread. The root of the problem must be fixed. Everything else looks like an unnecessary noise.
Well, this fake initialization is added only 4 times in this patchset. So, it is not a disaster. I could live with the change. And if people like/want this behavior...
With the two cosmetic changes, feel free to use:
Best Regards,
Petr
Re: [PATCH RFC v2 18/25] kmsan: call KMSAN hooks where needed
Quoted 10 lines · Petr Mladek
Please, separate the two comments with an empty line instead of using */ and /*.
kernel/printk/printk.c int vprintk_store(int facility, int level, · line 1923
Quoted 6 lines
kernel/printk/printk.c +6
-0+* If any of vscnprintf() arguments is uninitialized, KMSAN will report +* one or more errors and also probably mark text_len as uninitialized. +* Initialize |text_len| to prevent the errors from spreading further. +*/ + text_len =KMSAN_INIT_VALUE (vscnprintf (text,sizeof (textbuf), fmt, + args));
Or maybe this can be
text_len = vscnprintf(text, sizeof(textbuf), fmt, args);
+ KMSAN_INIT_VALUE(text_len);
-ss
Alexander Potapenko
maintainerRe: [PATCH RFC v2 18/25] kmsan: call KMSAN hooks where needed
Quoted 13 lines · Sergey Senozhatsky
Quoted 10 lines · Petr Mladek
Please, separate the two comments with an empty line instead of using */ and /*.
Quoted 6 lines
kernel/printk/printk.c +6
-0+* If any of vscnprintf() arguments is uninitialized, KMSAN will report +* one or more errors and also probably mark text_len as uninitialized. +* Initialize |text_len| to prevent the errors from spreading further. +*/ + text_len =KMSAN_INIT_VALUE (vscnprintf (text,sizeof (textbuf), fmt, + args));
Quoted 4 lines
Or maybe this can be
text_len = vscnprintf(text, sizeof(textbuf), fmt, args);+
KMSAN_INIT_VALUE(text_len);
This isn't how KMSAN_INIT_VALUE works. It takes a value that may be uninitialized and returns the same value marked as initialized. Shall I do:
text_len = KMSAN_INIT_VALUE(text_len);
instead?
Quoted 2 lines
-ssSignature · 10 lines
Alexander Potapenko Software Engineer Google Germany GmbH Erika-Mann-Straße, 33 80636 München Geschäftsführer: Paul Manicle, Halimah DeLaine Prado Registergericht und -nummer: Hamburg, HRB 86891 Sitz der Gesellschaft: Hamburg
Petr Mladek
maintainerRe: [PATCH RFC v2 18/25] kmsan: call KMSAN hooks where needed
Quoted 17 lines · Alexander Potapenko
Quoted 15 lines · Sergey Senozhatsky
Quoted 10 lines · Petr Mladek
Please, separate the two comments with an empty line instead of using */ and /*.
Quoted 6 lines
kernel/printk/printk.c +6
-0+* If any of vscnprintf() arguments is uninitialized, KMSAN will report +* one or more errors and also probably mark text_len as uninitialized. +* Initialize |text_len| to prevent the errors from spreading further. +*/ + text_len =KMSAN_INIT_VALUE (vscnprintf (text,sizeof (textbuf), fmt, + args));Or maybe this can be
Quoted 7 lines
Quoted 2 lines
text_len = vscnprintf(text, sizeof(textbuf), fmt, args);+
KMSAN_INIT_VALUE(text_len);This isn't how
KMSAN_INIT_VALUEworks. It takes a value that may be uninitialized and returns the same value marked as initialized. Shall I do:
text_len=KMSAN_INIT_VALUE(text_len);
instead?
I like this. It nicely separates the KMSAN specific things. Also the comment might be separate.
Best Regards,
Petr
Re: [PATCH RFC v2 18/25] kmsan: call KMSAN hooks where needed
In reply to Alexander PotapenkoOn (19/11/05 15:12), Alexander Potapenko wrote:
[..]
Quoted 7 lines
Quoted 7 lines
Quoted 6 lines
Quoted 6 lines
kernel/printk/printk.c +6
-0+* If any of vscnprintf() arguments is uninitialized, KMSAN will report +* one or more errors and also probably mark text_len as uninitialized. +* Initialize |text_len| to prevent the errors from spreading further. +*/ + text_len =KMSAN_INIT_VALUE (vscnprintf (text,sizeof (textbuf), fmt, + args));
Quoted 6 lines
Quoted 4 lines
Or maybe this can be
text_len = vscnprintf(text, sizeof(textbuf), fmt, args);+
KMSAN_INIT_VALUE(text_len);This isn't how
KMSAN_INIT_VALUEworks. It takes a value that may be uninitialized and returns the same value marked as initialized.
Ah, I see.
Quoted 3 lines
Shall I do:
text_len=KMSAN_INIT_VALUE(text_len);
instead?
Yes, +1 from me.
-ss
[email protected]
maintainerRFC PATCH v2 19/25 kmsan: disable instrumentation of certain functions
In reply to [email protected]Some functions are called from handwritten assembly, and therefore don't have their arguments' metadata fully set up by the instrumentation code. Mark them with __no_sanitize_memory to avoid false positives from spreading further.
Certain functions perform task switching, so that the value of |current| is different as they proceed. Because KMSAN state pointer is only read once at the beginning of the function, touching it after |current| has changed may be dangerous.
To: Alexander Potapenko <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Vegard Nossum <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: [email protected]
---
Change-Id: I684d23dac5a22eb0a4cea71993cb934302b17cea
--- arch/x86/entry/common.c | 1 + arch/x86/include/asm/irq_regs.h | 1 + arch/x86/include/asm/syscall_wrapper.h | 1 + arch/x86/kernel/apic/apic.c | 2 ++ arch/x86/kernel/dumpstack_64.c | 1 + arch/x86/kernel/process_64.c | 5 +++++ arch/x86/kernel/traps.c | 12 ++++++++++-- arch/x86/kernel/uprobes.c | 7 ++++++- kernel/profile.c | 1 + kernel/sched/core.c | 11 +++++++++++ 10 files changed, 39 insertions(+), 3 deletions(-)
arch/x86/entry/common.c +1 -0
@@ -275,6 +275,7 @@ __visible inline void syscall_return_slowpath(struct pt_regs *regs) }#ifdef CONFIG_X86_64 +__no_sanitize_memory __visible void do_syscall_64(unsigned long nr, struct pt_regs *regs) {struct thread_info *ti;
arch/x86/include/asm/irq_regs.h +1 -0
@@ -14,6 +14,7 @@ DECLARE_PER_CPU(struct pt_regs *, irq_regs); +__no_sanitize_memory static inline struct pt_regs *get_irq_regs(void) {return __this_cpu_read (irq_regs);
arch/x86/include/asm/syscall_wrapper.h +1 -0
@@ -159,6 +159,7 @@ ALLOW_ERROR_INJECTION(__x64_sys##name, ERRNO); \ static long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \ static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));\ + __no_sanitize_memory \ asmlinkage long __x64_sys##name(const struct pt_regs *regs) \ { \ return __se_sys##name(SC_X86_64_REGS_TO_ARGS(x,__VA_ARGS__));\
arch/x86/kernel/apic/apic.c +2 -0
@@ -1118,6 +1118,8 @@ static void local_apic_timer_interrupt(void)* [ if a single-CPU system runs an SMP kernel then we call the local * interrupt as well. Thus we cannot inline the local irq ... ] */ +/* TODO(glider): |regs| is uninitialized, so is |*regs|. */ +__no_sanitize_memory __visible void __irq_entry smp_apic_timer_interrupt(struct pt_regs *regs) {struct pt_regs *old_regs =set_irq_regs (regs);
arch/x86/kernel/dumpstack_64.c +1 -0
@@ -143,6 +143,7 @@ static bool in_irq_stack(unsigned long *stack, struct stack_info *info)return true; } +__no_sanitize_memory int get_stack_info(unsigned long *stack, struct task_struct *task,struct stack_info *info,unsigned long *visit_mask) {
arch/x86/kernel/process_64.c +5 -0
@@ -500,6 +500,11 @@ void compat_start_thread(struct pt_regs *regs, u32 new_ip, u32 new_sp)* Kprobes not supported here. Set the probe on schedule instead. * Function graph tracer not supported too. */ +/* +* TODO(glider): __switch_to() does weird things with tasks, don't report +* anything here (also avoid touching the KMSAN state). +*/ +__no_sanitize_memory __visible __notrace_funcgraph struct task_struct *__switch_to (struct task_struct *prev_p,struct task_struct *next_p) {
arch/x86/kernel/traps.c +10 -2
@@ -618,7 +618,10 @@ NOKPROBE_SYMBOL(do_int3);* Help handler running on a per-cpu (IST or entry trampoline) stack * to switch to the normal thread stack if the interrupted code was in * user mode. The actual stack switch is done in entry_64.S +* +* This function switches the registers - don't instrument it with KMSAN! */ +__no_sanitize_memory asmlinkage __visible notrace struct pt_regs *sync_regs(struct pt_regs *eregs) {struct pt_regs *regs = (struct pt_regs *)this_cpu_read (cpu_current_top_of_stack) -1 ;
@@ -634,6 +637,11 @@ struct bad_iret_stack { }; asmlinkage __visible notrace +/* +* Dark magic happening here, let's not instrument this function. +* Also avoid copying any metadata by using raw __memmove(). +*/ +__no_sanitize_memorystruct bad_iret_stack *fixup_bad_iret (struct bad_iret_stack *s) {/*
@@ -648,10 +656,10 @@ struct bad_iret_stack *fixup_bad_iret(struct bad_iret_stack *s) (struct bad_iret_stack *)this_cpu_read (cpu_tss_rw.x86_tss.sp0) -1 ;/* Copy the IRET target to the new stack. */ -memmove (&new_stack->regs.ip, (void *)s->regs.sp,5 *8 ); +__memmove (&new_stack->regs.ip, (void *)s->regs.sp,5 *8 );/* Copy the remainder of the stack from the current stack. */ - memmove(new_stack, s, offsetof(struct bad_iret_stack, regs.ip)); + __memmove(new_stack, s, offsetof(struct bad_iret_stack, regs.ip));BUG_ON (!user_mode (&new_stack->regs));return new_stack;
arch/x86/kernel/uprobes.c +6 -1
@@ -8,6 +8,7 @@* Jim Keniston */ #include <linux/kernel.h> +#include <linux/kmsan-checks.h> #include <linux/sched.h> #include <linux/ptrace.h> #include <linux/uprobes.h>
@@ -997,9 +998,13 @@ int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)int arch_uprobe_exception_notify (struct notifier_block *self,unsigned long val,void *data) {struct die_args *args = data; -struct pt_regs *regs = args->regs; +struct pt_regs *regs;int ret =NOTIFY_DONE ; +kmsan_unpoison_shadow (args,sizeof (*args)); + regs = args->regs; +if (regs) +kmsan_unpoison_shadow (regs,sizeof (*regs));/* We are only interested in userspace traps */ if (regs && !user_mode (regs))return NOTIFY_DONE ;
kernel/profile.c +1 -0
@@ -399,6 +399,7 @@ void profile_hits(int type, void *__pc, unsigned int nr_hits) }EXPORT_SYMBOL_GPL (profile_hits); +__no_sanitize_memory void profile_tick(int type) {struct pt_regs *regs =get_irq_regs ();
kernel/sched/core.c +11 -0
@@ -475,6 +475,8 @@ void wake_q_add_safe(struct wake_q_head *head, struct task_struct *task)put_task_struct (task); } +/* TODO(glider): context switching here. */ +__no_sanitize_memory void wake_up_q(struct wake_q_head *head) {struct wake_q_node *node = head->first;
@@ -3180,6 +3182,8 @@ prepare_task_switch(struct rq *rq, struct task_struct *prev,* past. prev == current is still correct but we need to recalculate this_rq * because prev may have moved to another CPU. */ +/* TODO(glider): |current| changes here. */ +__no_sanitize_memory static struct rq *finish_task_switch(struct task_struct *prev) __releases(rq->lock) {
@@ -3986,6 +3990,8 @@ pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)* * WARNING: must be called with preemption disabled! */ +/* TODO(glider): |current| changes here. */ +__no_sanitize_memory static void __sched notrace __schedule(bool preempt) {struct task_struct *prev, *next;
@@ -4605,6 +4611,8 @@ int task_prio(const struct task_struct *p)* * Return: 1 if the CPU is currently idle. 0 otherwise. */ +/* TODO(glider): nothing to report here. */ +__no_sanitize_memory int idle_cpu(int cpu) {struct rq *rq =cpu_rq (cpu);
@@ -6544,6 +6552,7 @@ static struct kmem_cache *task_group_cache __read_mostly;DECLARE_PER_CPU (cpumask_var_t, load_balance_mask);DECLARE_PER_CPU (cpumask_var_t, select_idle_mask); +__no_sanitize_memory void __init sched_init(void) {unsigned long ptr =0 ;
@@ -6716,6 +6725,8 @@ static inline int preempt_count_equals(int preempt_offset)return (nested == preempt_offset); } +/* TODO(glider): the args are most certainly initialized. */ +__no_sanitize_memory void __might_sleep(const char *file, int line, int preempt_offset) {/*
Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
[email protected]
maintainerRFC PATCH v2 20/25 kmsan: unpoison |tlb| in arch_tlb_gather_mmu()
In reply to [email protected]This is a hack to reduce stackdepot pressure.
To: Alexander Potapenko <[email protected]>
Cc: Vegard Nossum <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: [email protected]
---
Change-Id: I22a201e7e4f67ed74f8129072f12e5351b26103a
--- mm/mmu_gather.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
mm/mmu_gather.c +10 -0
@@ -1,6 +1,7 @@#include <linux/gfp.h> #include <linux/highmem.h> #include <linux/kernel.h> +#include <linux/kmsan-checks.h> #include <linux/mmdebug.h> #include <linux/mm_types.h> #include <linux/pagemap.h>
@@ -206,6 +207,15 @@ void tlb_flush_mmu(struct mmu_gather *tlb)void tlb_gather_mmu (struct mmu_gather *tlb,struct mm_struct *mm,unsigned long start,unsigned long end) { +/* +* TODO(glider): struct mmu_gather contains 7 1-bit fields packed into a +* 32-bit unsigned int value. The remaining 25 bits remain uninitialized +* and are never used, but KMSAN updates the origin for them in +* zap_pXX_range() in mm/memory.c, thus creating very long origin +* chains. This is technically correct, but consumes too much memory. +* Unpoisoning the whole structure will prevent creating such chains. +*/ +kmsan_unpoison_shadow (tlb,sizeof (*tlb)); tlb->mm = mm;/* Is it from 0 to ~0? */
Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
[email protected]
maintainerRFC PATCH v2 21/25 kmsan: use __msan_memcpy() where possible.
In reply to [email protected]Unless stated otherwise (by explicitly calling __memcpy()) we want all memcpy() calls to call __msan_memcpy() so that shadow and origin values are updated accordingly.
To: Alexander Potapenko <[email protected]>
Cc: Vegard Nossum <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: [email protected]
---
Change-Id: Ib2512ce5aa8d457453dd38caa12f58f002166813
--- arch/x86/include/asm/string_64.h | 9 ++++++++- include/linux/compiler.h | 9 ++++++++- include/linux/string.h | 2 ++ 3 files changed, 18 insertions(+), 2 deletions(-)
arch/x86/include/asm/string_64.h +8 -1
@@ -11,7 +11,13 @@function. */ #define __HAVE_ARCH_MEMCPY 1 +#if defined(CONFIG_KMSAN ) +#undef memcpy +/* __msan_memcpy() is defined in compiler.h */ +#define memcpy (dst, src, len) __msan_memcpy(dst, src, len) +#else extern void *memcpy (void *to,const void *from,size_t len); +#endif extern void *__memcpy (void *to,const void *from,size_t len);#define __HAVE_ARCH_MEMSET
@@ -64,7 +70,8 @@ char *strcpy(char *dest, const char *src);char *strcat (char *dest,const char *src);int strcmp (const char *cs,const char *ct); -#if defined(CONFIG_KASAN ) && !defined(__SANITIZE_ADDRESS__) +#if (defined(CONFIG_KASAN ) && !defined(__SANITIZE_ADDRESS__)) || \ + (defined(CONFIG_KMSAN ) && !defined(__SANITIZE_MEMORY__))/* * For files that not instrumented (e.g. mm/slub.c) we
include/linux/compiler.h +8 -1
@@ -179,6 +179,13 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,#include <uapi/linux/types.h> +#ifdef CONFIG_KMSAN +void *__msan_memcpy (void *dst,const void *src,u64 size); +#define __DO_MEMCPY (res, p, size) __msan_memcpy(res, p, size) +#else +#define __DO_MEMCPY (res, p, size) __builtin_memcpy(res, p, size) +#endif +#define __READ_ONCE_SIZE \ ({ \ switch (size) { \
@@ -188,7 +195,7 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,case 8 : *(__u64 *)res = *(volatile __u64 *)p;break ; \default : \barrier (); \ -__builtin_memcpy ((void *)res, (const void *)p, size); \ +__DO_MEMCPY ((void *)res, (const void *)p, size); \barrier (); \ } \ })
include/linux/string.h +2 -0
@@ -363,6 +363,7 @@ __FORTIFY_INLINE void *memset(void *p, int c, __kernel_size_t size)return __builtin_memset (p, c, size); } +#ifndef CONFIG_KMSAN __FORTIFY_INLINE void *memcpy(void *p, const void *q, __kernel_size_t size) {size_t p_size =__builtin_object_size (p,0 );
@@ -377,6 +378,7 @@ __FORTIFY_INLINE void *memcpy(void *p, const void *q, __kernel_size_t size)fortify_panic (__func__);return __builtin_memcpy (p, q, size); } +#endif __FORTIFY_INLINE void *memmove(void *p, const void *q, __kernel_size_t size) {
Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
[email protected]
maintainerRFC PATCH v2 22/25 kmsan: unpoisoning buffers from devices etc.
In reply to [email protected]When data is copied to memory from a device KMSAN should treat it as initialized. In most cases it's enough to just unpoison the buffer that is known to come from a device.
In the case with __do_page_cache_readahead() and bio_copy_user_iov() we have to mark the whole pages as ignored by KMSAN, as it's not obvious where these pages are read again.
To: Alexander Potapenko <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Jens Axboe <[email protected]>
Cc: "Theodore Ts'o" <[email protected]>
Cc: Dmitry Torokhov <[email protected]>
Cc: Martin K. Petersen <[email protected]>
Cc: "Michael S. Tsirkin" <[email protected]>
Cc: Christoph Hellwig <[email protected]>
Cc: Eric Dumazet <[email protected]>
Cc: Eric Van Hensbergen <[email protected]>
Cc: Takashi Iwai <[email protected]>
Cc: Vegard Nossum <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: Matthew Wilcox <[email protected]>
Cc: [email protected]
---
Suggestions on how to avoid scattering too many annotations over the code are welcome. Perhaps annotating DMA reads/writes is enough to get rid of most of these annotations.
v2:
- dropped a call to kmsan_unpoison_shadow() in do_read_cache_page()
Change-Id: Id460e7a86ce564f1357469f53d0c7410ca08f0e9
--- block/bio.c | 20 ++++++++++++++++++++ block/partition-generic.c | 9 ++++++++- drivers/char/random.c | 2 ++ drivers/input/serio/libps2.c | 6 +++++- drivers/scsi/scsi_lib.c | 4 ++++ drivers/usb/core/message.c | 6 +++++- drivers/virtio/virtio_ring.c | 14 ++++++++++++++ fs/buffer.c | 7 ++++++- include/linux/dma-mapping.h | 2 ++ include/linux/skbuff.h | 5 ++++- mm/filemap.c | 1 + mm/readahead.c | 6 ++++++ net/9p/protocol.c | 2 ++ sound/core/oss/pcm_oss.c | 7 +++++++ 14 files changed, 86 insertions(+), 5 deletions(-)
block/bio.c +20 -0
@@ -11,6 +11,7 @@#include <linux/slab.h> #include <linux/init.h> #include <linux/kernel.h> +#include <linux/kmsan-checks.h> #include <linux/export.h> #include <linux/mempool.h> #include <linux/workqueue.h>
@@ -900,6 +901,13 @@ static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)__bio_add_page (bio, page, len, offset); } offset =0 ; +/* +* TODO(glider): these pages will be soon passed to block +* device for reading, so consider them initialized. +*/ +if (iov_iter_rw (iter) ==READ ) +kmsan_unpoison_shadow (page_address (page), +PAGE_SIZE ); }iov_iter_advance (iter, size);
@@ -1274,11 +1282,16 @@ struct bio *bio_copy_user_iov(struct request_queue *q, i++; }else { +/* +* TODO(glider): KMSAN doesn't track the pages +* allocated for bio here. +*/ page =alloc_page (q->bounce_gfp | gfp_mask);if (!page) { ret = -ENOMEM ;break ; } +kmsan_ignore_page (page,/*order*/ 0 ); }if (bio_add_pc_page (q, bio, page, bytes, offset) < bytes) {
@@ -1574,6 +1587,13 @@ struct bio *bio_copy_kern(struct request_queue *q, void *data, unsigned int len,if (!page) goto cleanup; +/* +* TODO(glider): if we're about to read data from a SCSI device, +* assume the page allocated for that is already initialized. +*/ +if (reading) +kmsan_unpoison_shadow (page_address (page),PAGE_SIZE ); +if (!reading)memcpy (page_address (page), p, bytes);
block/partition-generic.c +8 -1
@@ -663,13 +663,20 @@ unsigned char *read_dev_sector(struct block_device *bdev, sector_t n, Sector *p) {struct address_space *mapping = bdev->bd_inode->i_mapping;struct page *page; +unsigned char *retval; page =read_mapping_page (mapping, (pgoff_t)(n >> (PAGE_SHIFT -9 )),NULL );if (!IS_ERR (page)) {if (PageError (page)) goto fail; p->v = page; -return (unsigned char *)page_address (page) + ((n & ((1 << (PAGE_SHIFT -9 )) -1 )) <<9 ); + retval = (unsigned char *)page_address (page) + + ((n & ((1 << (PAGE_SHIFT -9 )) -1 )) <<9 ); +/* +* Unpoison sector-sized chunk of memory coming from the device. +*/ +kmsan_unpoison_shadow (retval,SECTOR_SIZE ); +return retval; fail:put_page (page); }
drivers/char/random.c +2 -0
@@ -320,6 +320,7 @@#include <linux/fs.h> #include <linux/genhd.h> #include <linux/interrupt.h> +#include <linux/kmsan-checks.h> #include <linux/mm.h> #include <linux/nodemask.h> #include <linux/spinlock.h>
@@ -1061,6 +1062,7 @@ static void _extract_crng(struct crng_state *crng,spin_lock_irqsave (&crng->lock, flags);if (arch_get_random_long (&v)) crng->state[14 ] ^= v; +kmsan_unpoison_shadow (crng->state,sizeof (crng->state));chacha20_block (&crng->state[0 ], out);if (crng->state[12 ] ==0 ) crng->state[13 ]++;
drivers/input/serio/libps2.c +5 -1
@@ -8,6 +8,7 @@#include <linux/delay.h> +#include <linux/kmsan-checks.h> #include <linux/module.h> #include <linux/sched.h> #include <linux/interrupt.h>
@@ -30,6 +31,7 @@ static int ps2_do_sendbyte(struct ps2dev *ps2dev, u8 byte,int error;lockdep_assert_held (&ps2dev->serio->lock); +kmsan_check_memory (&byte,1 ); do { ps2dev->nak = 1;
@@ -294,9 +296,11 @@ int __ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command)serio_pause_rx (ps2dev->serio); -if (param) +if (param) {for (i =0 ; i < receive; i++) param[i] = ps2dev->cmdbuf[(receive -1 ) - i]; +kmsan_unpoison_shadow (param, receive); + }if (ps2dev->cmdcnt && (command !=PS2_CMD_RESET_BAT || ps2dev->cmdcnt !=1 )) {
drivers/scsi/scsi_lib.c +4 -0
@@ -14,6 +14,7 @@#include <linux/blkdev.h> #include <linux/completion.h> #include <linux/kernel.h> +#include <linux/kmsan-checks.h> #include <linux/export.h> #include <linux/init.h> #include <linux/pci.h>
@@ -296,6 +297,9 @@ int __scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, ret = rq->result; out:blk_put_request (req); +/* TODO(glider): this is a bit rough. */ +if (data_direction ==DMA_FROM_DEVICE ) +kmsan_unpoison_shadow (buffer, bufflen);return ret; }
drivers/usb/core/message.c +5 -1
@@ -9,6 +9,7 @@#include <linux/usb.h> #include <linux/module.h> #include <linux/slab.h> +#include <linux/kmsan-checks.h> #include <linux/mm.h> #include <linux/timer.h> #include <linux/ctype.h>
@@ -101,8 +102,11 @@ static int usb_internal_control_msg(struct usb_device *usb_dev, retv =usb_start_wait_urb (urb, timeout, &length);if (retv <0 )return retv; -else +else { +/* TODO(glider): USB initializes |length| bytes? */ +kmsan_unpoison_shadow (data, length);return length; + } }/**
drivers/virtio/virtio_ring.c +14 -0
@@ -11,6 +11,7 @@#include <linux/module.h> #include <linux/hrtimer.h> #include <linux/dma-mapping.h> +#include <linux/kmsan-checks.h> #include <xen/xen.h> #ifdef DEBUG
@@ -387,6 +388,12 @@ static void vring_unmap_one_split(const struct vring_virtqueue *vq, (flags &VRING_DESC_F_WRITE ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } +/* +* Unmapping DMA memory after a transfer from device requires this +* memory to be unpoisoned. +*/ +if (flags &VRING_DESC_F_WRITE ) +kmsan_unpoison_shadow ((const void *)desc->addr, desc->len); } static struct vring_desc *alloc_indirect_split(struct virtqueue *_vq,
@@ -500,6 +507,13 @@ static inline int virtqueue_add_split(struct virtqueue *_vq, desc[i].flags =cpu_to_virtio16 (_vq->vdev,VRING_DESC_F_NEXT |VRING_DESC_F_WRITE ); desc[i].addr =cpu_to_virtio64 (_vq->vdev, addr); desc[i].len =cpu_to_virtio32 (_vq->vdev, sg->length); +/* +* It's hard to figure out the buffer's address upon +* receive. Instead we unpoison it once, when exposing +* it to the device, and hope nobody else will write to +* it. +*/ +kmsan_unpoison_shadow (sg_virt (sg), sg->length); prev = i; i =virtio16_to_cpu (_vq->vdev, desc[i].next); }
fs/buffer.c +6 -1
@@ -1170,14 +1170,17 @@ static struct buffer_head *__bread_slow(struct buffer_head *bh)lock_buffer (bh);if (buffer_uptodate (bh)) {unlock_buffer (bh); +kmsan_unpoison_shadow (bh->b_data, bh->b_size);return bh; }else {get_bh (bh); bh->b_end_io = end_buffer_read_sync;submit_bh (REQ_OP_READ ,0 , bh);wait_on_buffer (bh); -if (buffer_uptodate (bh)) +if (buffer_uptodate (bh)) { +kmsan_unpoison_shadow (bh->b_data, bh->b_size);return bh; + } }brelse (bh);return NULL ;
@@ -1320,6 +1323,8 @@ __getblk_gfp(struct block_device *bdev, sector_t block,might_sleep ();if (bh ==NULL ) bh =__getblk_slow (bdev, block, size, gfp); +if (bh) +kmsan_unpoison_shadow (bh->b_data, bh->b_size);return bh; }EXPORT_SYMBOL (__getblk_gfp);
include/linux/dma-mapping.h +2 -0
@@ -8,6 +8,7 @@#include <linux/err.h> #include <linux/dma-debug.h> #include <linux/dma-direction.h> +#include <linux/kmsan-checks.h> #include <linux/scatterlist.h> #include <linux/bug.h> #include <linux/mem_encrypt.h>
@@ -281,6 +282,7 @@ static inline dma_addr_t dma_map_page_attrs(struct device *dev,const struct dma_map_ops *ops =get_dma_ops (dev);dma_addr_t addr; +kmsan_unpoison_shadow (page_address (page), size);BUG_ON (!valid_dma_direction (dir));if (dma_is_direct (ops)) addr =dma_direct_map_page (dev, page, offset, size, dir, attrs);
include/linux/skbuff.h +4 -1
@@ -11,6 +11,7 @@#define _LINUX_SKBUFF_H#include <linux/kernel.h> +#include <linux/kmsan-checks.h> #include <linux/compiler.h> #include <linux/time.h> #include <linux/bug.h>
@@ -2214,6 +2215,8 @@ static inline void *skb_put_data(struct sk_buff *skb, const void *data, {void *tmp =skb_put (skb, len); +/* Unpoison the data received from the network device. */ +kmsan_unpoison_shadow (data, len);memcpy (tmp, data, len);return tmp;
@@ -2221,7 +2224,7 @@ static inline void *skb_put_data(struct sk_buff *skb, const void *data,static inline void skb_put_u8 (struct sk_buff *skb,u8 val) { - *(u8 *)skb_put (skb,1 ) = val; + *(u8 *)skb_put (skb,1 ) =KMSAN_INIT_VALUE (val); }void *skb_push (struct sk_buff *skb,unsigned int len);
mm/filemap.c +1 -0
@@ -18,6 +18,7 @@#include <linux/uaccess.h> #include <linux/capability.h> #include <linux/kernel_stat.h> +#include <linux/kmsan-checks.h> #include <linux/gfp.h> #include <linux/mm.h> #include <linux/swap.h>
mm/readahead.c +6 -0
@@ -193,7 +193,13 @@ unsigned int __do_page_cache_readahead(struct address_space *mapping,continue ; } +/* +* The easiest way to handle these pages is to mark them +* untracked by KMSAN, assuming they're never used by anything +* else. +*/ page =__page_cache_alloc (gfp_mask); +kmsan_ignore_page (page,/*order*/ 0 );if (!page)break ; page->index = page_offset;
net/9p/protocol.c +2 -0
@@ -13,6 +13,7 @@#include <linux/module.h> #include <linux/errno.h> #include <linux/kernel.h> +#include <linux/kmsan-checks.h> #include <linux/uaccess.h> #include <linux/slab.h> #include <linux/sched.h>
@@ -46,6 +47,7 @@ EXPORT_SYMBOL(p9stat_free);size_t pdu_read (struct p9_fcall *pdu,void *data,size_t size) {size_t len =min (pdu->size - pdu->offset, size); +kmsan_unpoison_shadow (&pdu->sdata[pdu->offset], len);memcpy (data, &pdu->sdata[pdu->offset], len); pdu->offset += len;return size - len;
sound/core/oss/pcm_oss.c +7 -0
@@ -12,6 +12,7 @@#endif #include <linux/init.h> +#include <linux/kmsan-checks.h> /* for kmsan_unpoison_shadow() */ #include <linux/slab.h> #include <linux/sched/signal.h> #include <linux/time.h>
@@ -1054,6 +1055,12 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream) err = -ENOMEM ; goto failure; } +/* +* Unpoison the freshly created buffer to prevent KMSAN from reporting +* uninit errors. +* TODO(glider): unpoison it only when it's actually initialized. +*/ +kmsan_unpoison_shadow (runtime->oss.buffer, runtime->oss.period_bytes); runtime->oss.params =0 ; runtime->oss.prepare =1 ;
Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
Re: [PATCH RFC v2 22/25] kmsan: unpoisoning buffers from devices etc.
Quoted 6 lines · On Wed, Oct 30, 2019 at 03:22:34PM +0100, [email protected] wrote:
When data is copied to memory from a device KMSAN should treat it as initialized. In most cases it's enough to just unpoison the buffer that is known to come from a device.
In the case with__do_page_cache_readahead()andbio_copy_user_iov()we have to mark the whole pages as ignored by KMSAN, as it's not obvious where these pages are read again.
A lot of this looks pretty strange. Why don't you instrument the dma_map / dma_sync infrastucture? That should avoid most of the driver hooks.
Alexander Potapenko
maintainerRe: [PATCH RFC v2 22/25] kmsan: unpoisoning buffers from devices etc.
Quoted 9 lines · Christoph Hellwig
Quoted 6 lines · On Wed, Oct 30, 2019 at 03:22:34PM +0100, [email protected] wrote:
When data is copied to memory from a device KMSAN should treat it as initialized. In most cases it's enough to just unpoison the buffer that is known to come from a device.
In the case with__do_page_cache_readahead()andbio_copy_user_iov()we have to mark the whole pages as ignored by KMSAN, as it's not obvious where these pages are read again.
Quoted 3 lines
A lot of this looks pretty strange. Why don't you instrument the
dma_map/dma_syncinfrastucture? That should avoid most of the driver hooks.
That's the exact reason I'm sending these patches: I simply don't know the kernel code good enough.
May I ask you for some pointers?
My goal is to mark data copied from the device as initialized (by calling kmsan_unpoison_shadow(ptr, size)), and, if possible, check data that's about to be copied to device (by calling kmsan_check_memory(ptr, size)).
My understanding is that:
1. calls to dma_map_* and dma_sync_* with direction=DMA_FROM_DEVICE
denote that the corresponding kernel buffer can be marked as initialized
2. calls to dma_unmap_* and dma_sync_* with direction=DMA_TO_DEVICE
denote that the buffer will be copied to device (and must be checked for being initialized)
3. I need some translation table to find out the virtual address for
a given dma_addr_t
Does this sound reasonable?
I still don't understand how to handle DMA_BIDIRECTIONAL. Will it be sane to assume that at each dma_{map,sync,unmap}_* call must always check the memory range and then unpoison it?
Thanks in advance
Signature · 10 lines
Alexander Potapenko Software Engineer Google Germany GmbH Erika-Mann-Straße, 33 80636 München Geschäftsführer: Paul Manicle, Halimah DeLaine Prado Registergericht und -nummer: Hamburg, HRB 86891 Sitz der Gesellschaft: Hamburg
Alexander Potapenko
maintainerRe: [PATCH RFC v2 22/25] kmsan: unpoisoning buffers from devices etc.
Quoted 24 lines · Alexander Potapenko
Quoted 9 lines · Christoph Hellwig
Quoted 6 lines · On Wed, Oct 30, 2019 at 03:22:34PM +0100, [email protected] wrote:
When data is copied to memory from a device KMSAN should treat it as initialized. In most cases it's enough to just unpoison the buffer that is known to come from a device.
In the case with__do_page_cache_readahead()andbio_copy_user_iov()we have to mark the whole pages as ignored by KMSAN, as it's not obvious where these pages are read again.Quoted 3 lines
A lot of this looks pretty strange. Why don't you instrument the
dma_map/dma_syncinfrastucture? That should avoid most of the driver hooks.That's the exact reason I'm sending these patches: I simply don't know the kernel code good enough.
May I ask you for some pointers?
My goal is to mark data copied from the device as initialized (by callingkmsan_unpoison_shadow(ptr, size)), and, if possible, check data that's about to be copied to device (by callingkmsan_check_memory(ptr, size)).
My understanding is that:
1. calls to dma_map_* and dma_sync_* with direction=DMA_FROM_DEVICE
Quoted 8 lines
denote that the corresponding kernel buffer can be marked as initialized
2. calls to dma_unmap_* and dma_sync_* with direction=DMA_TO_DEVICE
denote that the buffer will be copied to device (and must be checked for being initialized)
3. I need some translation table to find out the virtual address for
a givendma_addr_t
Does this sound reasonable?
Initializing memory in dma_map_ still leaves out the reports as the one below. There seems to be a DMA access somewhere in blk_execute_rq(), but I fail to see why it's not covered.
=============================================
BUG: KMSAN: uninit-value in[< none >] sr_check_events+0x1091/0x1190 drivers/scsi/sr.c:246 CPU: 0 PID: 5 Comm: kworker/0:0 Not tainted 5.4.0-rc5+ #3266 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-1 04/01/2014 Workqueue: events_freezable_power_ disk_events_workfn Call Trace: [< inline >] __dump_stack lib/dump_stack.c:77 [< none >] dump_stack+0x196/0x1f0 lib/dump_stack.c:113 [< none >] kmsan_report+0x127/0x220 mm/kmsan/kmsan_report.c:108 [< none >] __msan_warning+0x73/0xe0 mm/kmsan/kmsan_instr.c:245 [< inline >] sr_get_events drivers/scsi/sr.c:213 [< none >] sr_check_events+0x1091/0x1190 drivers/scsi/sr.c:246 [< inline >] cdrom_update_events drivers/cdrom/cdrom.c:1476 [< none >] cdrom_check_events+0xc3/0x260 drivers/cdrom/cdrom.c:1486 [< none >] sr_block_check_events+0x3c4/0x670 drivers/scsi/sr.c:614 [< none >] disk_check_events+0x154/0x8b0 block/genhd.c:1855 [< none >] disk_events_workfn+0x47/0x50 block/genhd.c:1841 [< none >] process_one_work+0x1556/0x1ef0 kernel/workqueue.c:2269 ... Uninit was stored to memory at: [< inline >] kmsan_save_stack_with_flags mm/kmsan/kmsan.c:151 [< none >] kmsan_internal_chain_origin+0xa3/0x160 mm/kmsan/kmsan.c:319 [< none >] kmsan_memcpy_memmove_metadata+0x271/0x2e0 mm/kmsan/kmsan.c:254 [< none >] kmsan_memcpy_metadata+0xb/0x10 mm/kmsan/kmsan.c:274 [< none >] __msan_memcpy+0x55/0x70 mm/kmsan/kmsan_instr.c:129 [< none >] bio_copy_kern_endio_read+0x467/0x990 block/bio.c:1543 [< none >] bio_endio+0xa36/0xbb0 block/bio.c:1850 [< inline >] req_bio_endio block/blk-core.c:242 [< none >] blk_update_request+0xd3c/0x20a0 block/blk-core.c:1462 [< none >] scsi_end_request+0x10b/0xeb0 drivers/scsi/scsi_lib.c:579 [< none >] scsi_io_completion+0x279/0x2660 drivers/scsi/scsi_lib.c:963 [< none >] scsi_finish_command+0x6f9/0x720 drivers/scsi/scsi.c:228 [< none >] scsi_softirq_done+0x772/0x980 drivers/scsi/scsi_lib.c:1477 [< none >] blk_done_softirq+0x300/0x4f0 block/blk-softirq.c:37 [< none >] __do_softirq+0x311/0x83d kernel/softirq.c:293 ... Uninit was created at: [< none >] kmsan_save_stack_with_flags+0x3f/0x90 mm/kmsan/kmsan.c:151 [< inline >] kmsan_internal_alloc_meta_for_pages mm/kmsan/kmsan_shadow.c:362 [< none >] kmsan_alloc_page+0x14e/0x360 mm/kmsan/kmsan_shadow.c:391 [< none >] __alloc_pages_nodemask+0x594e/0x6050 mm/page_alloc.c:4796 [< none >] alloc_pages_current+0x682/0x990 mm/mempolicy.c:2188 [< inline >] alloc_pages ./include/linux/gfp.h:511 [< none >] bio_copy_kern+0x4c5/0xed0 block/bio.c:1590 [< none >] blk_rq_map_kern+0x458/0x7e0 block/blk-map.c:237 [< none >] __scsi_execute+0x2cf/0xaf0 drivers/scsi/scsi_lib.c:265 [< inline >] scsi_execute_req ./include/scsi/scsi_device.h:451 [< inline >] sr_get_events drivers/scsi/sr.c:207 [< none >] sr_check_events+0x2ff/0x1190 drivers/scsi/sr.c:246 [< inline >] cdrom_update_events drivers/cdrom/cdrom.c:1476 [< none >] cdrom_check_events+0xc3/0x260 drivers/cdrom/cdrom.c:1486 [< none >] sr_block_check_events+0x3c4/0x670 drivers/scsi/sr.c:614 [< none >] disk_check_events+0x154/0x8b0 block/genhd.c:1855 [< none >] disk_events_workfn+0x47/0x50 block/genhd.c:1841 =============================================
Quoted 17 lines
I still don't understand how to handle
DMA_BIDIRECTIONAL. Will it be sane to assume that at each dma_{map,sync,unmap}_* call must always check the memory range and then unpoison it?Thanks in advance
--
Alexander Potapenko
Software EngineerGoogle Germany GmbH
Erika-Mann-Straße, 33
80636 MünchenGeschäftsführer: Paul Manicle, Halimah DeLaine Prado Registergericht und -nummer: Hamburg, HRB 86891 Sitz der Gesellschaft: Hamburg
Signature · 10 lines
Alexander Potapenko Software Engineer Google Germany GmbH Erika-Mann-Straße, 33 80636 München Geschäftsführer: Paul Manicle, Halimah DeLaine Prado Registergericht und -nummer: Hamburg, HRB 86891 Sitz der Gesellschaft: Hamburg
Alexander Potapenko
maintainerRe: [PATCH RFC v2 22/25] kmsan: unpoisoning buffers from devices etc.
Quoted 90 lines · Alexander Potapenko
Quoted 24 lines · Alexander Potapenko
Quoted 9 lines · Christoph Hellwig
Quoted 6 lines · On Wed, Oct 30, 2019 at 03:22:34PM +0100, [email protected] wrote:
When data is copied to memory from a device KMSAN should treat it as initialized. In most cases it's enough to just unpoison the buffer that is known to come from a device.
In the case with__do_page_cache_readahead()andbio_copy_user_iov()we have to mark the whole pages as ignored by KMSAN, as it's not obvious where these pages are read again.Quoted 3 lines
A lot of this looks pretty strange. Why don't you instrument the
dma_map/dma_syncinfrastucture? That should avoid most of the driver hooks.That's the exact reason I'm sending these patches: I simply don't know the kernel code good enough.
May I ask you for some pointers?
My goal is to mark data copied from the device as initialized (by callingkmsan_unpoison_shadow(ptr, size)), and, if possible, check data that's about to be copied to device (by callingkmsan_check_memory(ptr, size)).
My understanding is that:
1. calls to dma_map_* and dma_sync_* with direction=DMA_FROM_DEVICEQuoted 8 lines
denote that the corresponding kernel buffer can be marked as initialized
2. calls to dma_unmap_* and dma_sync_* with direction=DMA_TO_DEVICE
denote that the buffer will be copied to device (and must be checked for being initialized)
3. I need some translation table to find out the virtual address for
a givendma_addr_t
Does this sound reasonable?Initializing memory in
dma_map_still leaves out the reports as the one below. There seems to be a DMA access somewhere inblk_execute_rq(), but I fail to see why it's not covered.=============================================
BUG: KMSAN: uninit-value in[< none >] sr_check_events+0x1091/0x1190 drivers/scsi/sr.c:246 CPU: 0 PID: 5 Comm: kworker/0:0 Not tainted 5.4.0-rc5+ #3266 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-1 04/01/2014 Workqueue: events_freezable_power_ disk_events_workfn Call Trace: [< inline >] __dump_stack lib/dump_stack.c:77 [< none >] dump_stack+0x196/0x1f0 lib/dump_stack.c:113 [< none >] kmsan_report+0x127/0x220 mm/kmsan/kmsan_report.c:108 [< none >] __msan_warning+0x73/0xe0 mm/kmsan/kmsan_instr.c:245 [< inline >] sr_get_events drivers/scsi/sr.c:213 [< none >] sr_check_events+0x1091/0x1190 drivers/scsi/sr.c:246 [< inline >] cdrom_update_events drivers/cdrom/cdrom.c:1476 [< none >] cdrom_check_events+0xc3/0x260 drivers/cdrom/cdrom.c:1486 [< none >] sr_block_check_events+0x3c4/0x670 drivers/scsi/sr.c:614 [< none >] disk_check_events+0x154/0x8b0 block/genhd.c:1855 [< none >] disk_events_workfn+0x47/0x50 block/genhd.c:1841 [< none >] process_one_work+0x1556/0x1ef0 kernel/workqueue.c:2269 ... Uninit was stored to memory at: [< inline >] kmsan_save_stack_with_flags mm/kmsan/kmsan.c:151 [< none >] kmsan_internal_chain_origin+0xa3/0x160 mm/kmsan/kmsan.c:319 [< none >] kmsan_memcpy_memmove_metadata+0x271/0x2e0 mm/kmsan/kmsan.c:254 [< none >] kmsan_memcpy_metadata+0xb/0x10 mm/kmsan/kmsan.c:274 [< none >] __msan_memcpy+0x55/0x70 mm/kmsan/kmsan_instr.c:129 [< none >] bio_copy_kern_endio_read+0x467/0x990 block/bio.c:1543 [< none >] bio_endio+0xa36/0xbb0 block/bio.c:1850 [< inline >] req_bio_endio block/blk-core.c:242 [< none >] blk_update_request+0xd3c/0x20a0 block/blk-core.c:1462 [< none >] scsi_end_request+0x10b/0xeb0 drivers/scsi/scsi_lib.c:579 [< none >] scsi_io_completion+0x279/0x2660 drivers/scsi/scsi_lib.c:963 [< none >] scsi_finish_command+0x6f9/0x720 drivers/scsi/scsi.c:228 [< none >] scsi_softirq_done+0x772/0x980 drivers/scsi/scsi_lib.c:1477 [< none >] blk_done_softirq+0x300/0x4f0 block/blk-softirq.c:37 [< none >] __do_softirq+0x311/0x83d kernel/softirq.c:293 ... Uninit was created at: [< none >] kmsan_save_stack_with_flags+0x3f/0x90 mm/kmsan/kmsan.c:151 [< inline >] kmsan_internal_alloc_meta_for_pages mm/kmsan/kmsan_shadow.c:362 [< none >] kmsan_alloc_page+0x14e/0x360 mm/kmsan/kmsan_shadow.c:391 [< none >] __alloc_pages_nodemask+0x594e/0x6050 mm/page_alloc.c:4796 [< none >] alloc_pages_current+0x682/0x990 mm/mempolicy.c:2188 [< inline >] alloc_pages ./include/linux/gfp.h:511 [< none >] bio_copy_kern+0x4c5/0xed0 block/bio.c:1590 [< none >] blk_rq_map_kern+0x458/0x7e0 block/blk-map.c:237 [< none >] __scsi_execute+0x2cf/0xaf0 drivers/scsi/scsi_lib.c:265 [< inline >] scsi_execute_req ./include/scsi/scsi_device.h:451
Quoted 8 lines
[< inline >] sr_get_events drivers/scsi/sr.c:207 [< none >] sr_check_events+0x2ff/0x1190 drivers/scsi/sr.c:246 [< inline >] cdrom_update_events drivers/cdrom/cdrom.c:1476 [< none >] cdrom_check_events+0xc3/0x260 drivers/cdrom/cdrom.c:1486 [< none >] sr_block_check_events+0x3c4/0x670 drivers/scsi/sr.c:614 [< none >] disk_check_events+0x154/0x8b0 block/genhd.c:1855 [< none >] disk_events_workfn+0x47/0x50 block/genhd.c:1841 =============================================
Turned out these reports were coming from reads from iomapped memory. Unpoisoning those (in lib/iomap.c) in addition to DMA reads will probably eliminate the need of ad-hoc annotations in device drivers.
Quoted 31 lines
Quoted 10 lines
I still don't understand how to handle
DMA_BIDIRECTIONAL. Will it be sane to assume that at each dma_{map,sync,unmap}_* call must always check the memory range and then unpoison it?Thanks in advance
--
Alexander Potapenko
Software EngineerQuoted 7 lines
Google Germany GmbH
Erika-Mann-Straße, 33
80636 MünchenGeschäftsführer: Paul Manicle, Halimah DeLaine Prado Registergericht und -nummer: Hamburg, HRB 86891 Sitz der Gesellschaft: Hamburg
--
Alexander Potapenko
Software EngineerGoogle Germany GmbH
Erika-Mann-Straße, 33
80636 MünchenGeschäftsführer: Paul Manicle, Halimah DeLaine Prado Registergericht und -nummer: Hamburg, HRB 86891 Sitz der Gesellschaft: Hamburg
Signature · 10 lines
Alexander Potapenko Software Engineer Google Germany GmbH Erika-Mann-Straße, 33 80636 München Geschäftsführer: Paul Manicle, Halimah DeLaine Prado Registergericht und -nummer: Hamburg, HRB 86891 Sitz der Gesellschaft: Hamburg
kbuild test robot
build botRe: [PATCH RFC v2 22/25] kmsan: unpoisoning buffers from devices etc.
In reply to [email protected][if your patch is applied to the wrong git tree, please drop us a note to help improve the system. BTW, we also suggest to use '--base' option to specify the base tree in git format-patch, please…
Hi,
[FYI, it's a private test report for your RFC patch.]
[auto build test ERROR on linus/master]
[also build test ERROR on v5.4-rc5]
[cannot apply to next-20191031]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system. BTW, we also suggest to use '--base' option to specify the base tree in git format-patch, please see https://stackoverflow.com/a/37406982]
url: https://github.com/0day-ci/linux/commits/glider-google-com/Add-KernelMemorySanitizer-infrastructure/20191102-050032 base: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 0dbe6cb8f7e05bc9611602ef45980a6c57b245a3 config: i386-tinyconfig (attached as .config) compiler: gcc-7 (Debian 7.4.0-14) 7.4.0 reproduce: # save the attached .config to linux build tree make ARCH=i386
If you fix the issue, kindly add following tag
Note: the linux-review/glider-google-com/Add-KernelMemorySanitizer-infrastructure/20191102-050032 HEAD 31fca64f1cb0e53b524f81abfbc906fc55ab8488 builds fine.
It only hurts bisectibility.
All errors (new ones prefixed by >>):
mm/readahead.c: In function '__do_page_cache_readahead':
>> mm/readahead.c:202:3: error: implicit declaration of function 'kmsan_ignore_page'; did you mean 'kmsan_clear_page'? [-Werror=implicit-function-declaration]
kmsan_ignore_page(page, /*order*/0);
^~~~~~~~~~~~~~~~~
kmsan_clear_pagecc1: some warnings being treated as errors
vim +202 mm/readahead.c
146
147 /*
148 * __do_page_cache_readahead() actually reads a chunk of disk. It allocates
149 * the pages first, then submits them for I/O. This avoids the very bad
150 * behaviour which would occur if page allocations are causing VM writeback.
151 * We really don't want to intermingle reads and writes like that.
152 *
153 * Returns the number of pages requested, or the maximum amount of I/O allowed.
154 */
155 unsigned int __do_page_cache_readahead(struct address_space *mapping,
156 struct file *filp, pgoff_t offset, unsigned long nr_to_read,
157 unsigned long lookahead_size)
158 {
159 struct inode *inode = mapping->host;
160 struct page *page;
161 unsigned long end_index; /* The last page we want to read */
162 LIST_HEAD(page_pool);
163 int page_idx;
164 unsigned int nr_pages = 0;
165 loff_t isize = i_size_read(inode);
166 gfp_t gfp_mask = readahead_gfp_mask(mapping);
167
168 if (isize == 0)
169 goto out;
170
171 end_index = ((isize - 1) >> PAGE_SHIFT);
172
173 /*
174 * Preallocate as many pages as we will need.
175 */
176 for (page_idx = 0; page_idx < nr_to_read; page_idx++) {
177 pgoff_t page_offset = offset + page_idx;
178
179 if (page_offset > end_index)
180 break;
181
182 page = xa_load(&mapping->i_pages, page_offset);
183 if (page && !xa_is_value(page)) {
184 /*
185 * Page already present? Kick off the current batch of
186 * contiguous pages before continuing with the next
187 * batch.
188 */
189 if (nr_pages)
190 read_pages(mapping, filp, &page_pool, nr_pages,
191 gfp_mask);
192 nr_pages = 0;
193 continue;
194 }
195
196 /*
197 * The easiest way to handle these pages is to mark them
198 * untracked by KMSAN, assuming they're never used by anything
199 * else.
200 */
201 page = __page_cache_alloc(gfp_mask);
> 202 kmsan_ignore_page(page, /*order*/0);
203 if (!page)
204 break;
205 page->index = page_offset;
206 list_add(&page->lru, &page_pool);
207 if (page_idx == nr_to_read - lookahead_size)
208 SetPageReadahead(page);
209 nr_pages++;
210 }
211
212 /*
213 * Now start the IO. We ignore I/O errors - if the page is not
214 * uptodate then the caller will launch readpage again, and
215 * will then handle the error.
216 */
217 if (nr_pages)
218 read_pages(mapping, filp, &page_pool, nr_pages, gfp_mask);
219 BUG_ON(!list_empty(&page_pool));
220 out:
221 return nr_pages;
222 }
223
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
kbuild test robot
build botRe: [PATCH RFC v2 22/25] kmsan: unpoisoning buffers from devices etc.
In reply to [email protected][if your patch is applied to the wrong git tree, please drop us a note to help improve the system. BTW, we also suggest to use '--base' option to specify the base tree in git format-patch, please…
Hi,
[FYI, it's a private test report for your RFC patch.]
[auto build test WARNING on linus/master]
[also build test WARNING on v5.4-rc5]
[cannot apply to next-20191031]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system. BTW, we also suggest to use '--base' option to specify the base tree in git format-patch, please see https://stackoverflow.com/a/37406982]
url: https://github.com/0day-ci/linux/commits/glider-google-com/Add-KernelMemorySanitizer-infrastructure/20191102-050032 base: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 0dbe6cb8f7e05bc9611602ef45980a6c57b245a3 reproduce: # apt-get install sparse # sparse version: v0.6.1-6-g57f8611-dirty make ARCH=x86_64 allmodconfig make C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__'
If you fix the issue, kindly add following tag
sparse warnings: (new ones prefixed by >>)
>> drivers/virtio/virtio_ring.c:396:40: sparse: sparse: cast from restricted __virtio64 >> drivers/virtio/virtio_ring.c:396:69: sparse: sparse: incorrect type in argument 2 (different base types) @@ expected unsigned long [usertype] size @@ got restrictunsigned long [usertype] size @@ >> drivers/virtio/virtio_ring.c:396:69: sparse: expected unsigned long [usertype] size >> drivers/virtio/virtio_ring.c:396:69: sparse: got restricted __virtio32 [usertype] len
drivers/virtio/virtio_ring.c:1414:50: sparse: sparse: incorrect type in argument 2 (different base types) @@ expected restricted __virtio16 [usertype] *p @@ got rtio16 [usertype] *p @@
drivers/virtio/virtio_ring.c:1414:50: sparse: expected restricted __virtio16 [usertype] *p
drivers/virtio/virtio_ring.c:1414:50: sparse: got restricted __le16 *
drivers/virtio/virtio_ring.c:1415:33: sparse: sparse: incorrect type in argument 3 (different base types) @@ expected restricted __virtio16 [usertype] v @@ got ricted __virtio16 [usertype] v @@
drivers/virtio/virtio_ring.c:1415:33: sparse: expected restricted __virtio16 [usertype] v
drivers/virtio/virtio_ring.c:1415:33: sparse: got restricted __le16 [usertype]
vim +396 drivers/virtio/virtio_ring.c
362
363
364 /*
365 * Split ring specific functions - *_split().
366 */
367
368 static void vring_unmap_one_split(const struct vring_virtqueue *vq,
369 struct vring_desc *desc)
370 {
371 u16 flags;
372
373 if (!vq->use_dma_api)
374 return;
375
376 flags = virtio16_to_cpu(vq->vq.vdev, desc->flags);
377
378 if (flags & VRING_DESC_F_INDIRECT) {
379 dma_unmap_single(vring_dma_dev(vq),
380 virtio64_to_cpu(vq->vq.vdev, desc->addr),
381 virtio32_to_cpu(vq->vq.vdev, desc->len),
382 (flags & VRING_DESC_F_WRITE) ?
383 DMA_FROM_DEVICE : DMA_TO_DEVICE);
384 } else {
385 dma_unmap_page(vring_dma_dev(vq),
386 virtio64_to_cpu(vq->vq.vdev, desc->addr), 387 virtio32_to_cpu(vq->vq.vdev, desc->len), 388 (flags & VRING_DESC_F_WRITE) ? 389 DMA_FROM_DEVICE : DMA_TO_DEVICE); 390 } 391 /* 392 * Unmapping DMA memory after a transfer from device requires this 393 * memory to be unpoisoned. 394 */ 395 if (flags & VRING_DESC_F_WRITE) > 396 kmsan_unpoison_shadow((const void *)desc->addr, desc->len);
397 }
398
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[email protected]
maintainerRFC PATCH v2 23/25 kmsan: hooks for copy_to_user() and friends
In reply to [email protected]Memory that is copied from userspace must be unpoisoned. Before copying memory to userspace, check it and report an error if it contains uninitialized bits.
To: Alexander Potapenko <[email protected]>
Cc: Alexander Viro <[email protected]>
Cc: Vegard Nossum <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: [email protected]
---
Change-Id: I38428b9c7d1909b8441dcec1749b080494a7af99
--- arch/x86/include/asm/uaccess.h | 12 ++++++++++++ include/asm-generic/cacheflush.h | 7 ++++++- include/asm-generic/uaccess.h | 12 ++++++++++-- include/linux/uaccess.h | 32 +++++++++++++++++++++++++++----- lib/iov_iter.c | 6 ++++++ lib/usercopy.c | 6 +++++- 6 files changed, 66 insertions(+), 9 deletions(-)
arch/x86/include/asm/uaccess.h +12 -0
@@ -6,6 +6,7 @@*/ #include <linux/compiler.h> #include <linux/kasan-checks.h> +#include <linux/kmsan-checks.h> #include <linux/string.h> #include <asm/asm.h> #include <asm/page.h>
@@ -174,6 +175,7 @@ __typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL)) ASM_CALL_CONSTRAINT \ : "0" (ptr), "i" (sizeof(*(ptr)))); \ (x) = (__force __typeof__(*(ptr))) __val_gu; \ +kmsan_unpoison_shadow (&(x),sizeof (*(ptr))); \__builtin_expect (__ret_gu,0 ); \ })
@@ -248,6 +250,7 @@ extern void __put_user_8(void);__chk_user_ptr (ptr); \might_fault (); \ __pu_val = x; \ +kmsan_check_memory (&(__pu_val),sizeof (*(ptr))); \switch (sizeof (*(ptr))) { \case 1 : \__put_user_x (1 , __pu_val, ptr, __ret_pu); \
@@ -270,7 +273,9 @@ extern void __put_user_8(void);#define __put_user_size (x, ptr, size, label) \ do { \ + __typeof__(*(ptr)) __pus_val = x; \ __chk_user_ptr(ptr); \ + kmsan_check_memory(&(__pus_val), size); \ switch (size) { \ case 1: \ __put_user_goto(x, ptr, "b", "b", "iq", label); \
@@ -295,7 +300,10 @@ do { \*/ #define __put_user_size_ex (x, ptr, size) \ do { \ + __typeof__(*(ptr)) __puse_val; \ __chk_user_ptr(ptr); \ + __puse_val = x; \ + kmsan_check_memory(&(__puse_val), size); \ switch (size) { \ case 1: \ __put_user_asm_ex(x, ptr, "b", "b", "iq"); \
@@ -363,6 +371,7 @@ do { \default : \ (x) =__get_user_bad (); \ } \ +kmsan_unpoison_shadow (&(x), size); \ }while (0 ) #define __get_user_asm(x, addr, err, itype, rtype, ltype, errret) \
@@ -413,6 +422,7 @@ do { \default : \ (x) =__get_user_bad (); \ } \ +kmsan_unpoison_shadow (&(x), size); \ }while (0 ) #define __get_user_asm_ex(x, addr, itype, rtype, ltype) \
@@ -428,11 +438,13 @@ do { \#define __put_user_nocheck (x, ptr, size) \ ({ \ __label__ __pu_label; \ + __typeof__(*(ptr)) __pun_val = x; \ int __pu_err = -EFAULT; \ __typeof__(*(ptr)) __pu_val = (x); \ __typeof__(ptr) __pu_ptr = (ptr); \ __typeof__(size) __pu_size = (size); \ __uaccess_begin(); \ + kmsan_check_memory(&(__pun_val), size); \ __put_user_size(__pu_val, __pu_ptr, __pu_size, __pu_label); \ __pu_err = 0; \ __pu_label: \
include/asm-generic/cacheflush.h +6 -1
@@ -4,6 +4,7 @@/* Keep includes the same across arches. */ #include <linux/mm.h> +#include <linux/kmsan-checks.h> #define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
@@ -72,10 +73,14 @@ static inline void flush_cache_vunmap(unsigned long start, unsigned long end)#define copy_to_user_page (vma, page, vaddr, dst, src, len) \ do { \ + kmsan_check_memory(src, len); \ memcpy(dst, src, len); \ flush_icache_user_range(vma, page, vaddr, len); \ } while (0)#define copy_from_user_page (vma, page, vaddr, dst, src, len) \ - memcpy(dst, src, len) + do { \ + memcpy(dst, src, len); \ + kmsan_unpoison_shadow(dst, len); \ + } while (0)#endif /* __ASM_CACHEFLUSH_H */
include/asm-generic/uaccess.h +10 -2
@@ -142,7 +142,11 @@ static inline int __access_ok(unsigned long addr, unsigned long size)static inline int __put_user_fn (size_t size,void __user *ptr,void *x) { -return unlikely (raw_copy_to_user (ptr, x, size)) ? -EFAULT :0 ; +int n; + + n =raw_copy_to_user (ptr, x, size); +kmsan_copy_to_user (ptr, x, size, n); +return unlikely (n) ? -EFAULT :0 ; }#define __put_user_fn (sz, u, k) __put_user_fn(sz, u, k)
@@ -203,7 +207,11 @@ extern int __put_user_bad(void) __attribute__((noreturn));#ifndef __get_user_fnstatic inline int __get_user_fn (size_t size,const void __user *ptr,void *x) { -return unlikely (raw_copy_from_user (x, ptr, size)) ? -EFAULT :0 ; +int copied, to_copy = size; + + copied =raw_copy_from_user (x, ptr, size); +kmsan_unpoison_shadow (to, to_copy - res); +return unlikely (copied) ? -EFAULT :0 ; }#define __get_user_fn (sz, u, k) __get_user_fn(sz, u, k)
include/linux/uaccess.h +27 -5
@@ -5,6 +5,7 @@#include <linux/sched.h> #include <linux/thread_info.h> #include <linux/kasan-checks.h> +#include <linux/kmsan-checks.h> #define uaccess_kernel () segment_eq(get_fs(), KERNEL_DS)
@@ -58,18 +59,26 @@static __always_inline __must_check unsigned long __copy_from_user_inatomic (void *to,const void __user *from,unsigned long n) { +unsigned long to_copy = n; +kasan_check_write (to, n);check_object_size (to, n, false); -return raw_copy_from_user (to, from, n); + n =raw_copy_from_user (to, from, n); +kmsan_unpoison_shadow (to, to_copy - n); +return n; }static __always_inline __must_check unsigned long __copy_from_user (void *to,const void __user *from,unsigned long n) { +unsigned long to_copy = n; +might_fault ();kasan_check_write (to, n);check_object_size (to, n, false); -return raw_copy_from_user (to, from, n); + n =raw_copy_from_user (to, from, n); +kmsan_unpoison_shadow (to, to_copy - n); +return n; }/**
@@ -88,29 +97,39 @@ __copy_from_user(void *to, const void __user *from, unsigned long n)static __always_inline __must_check unsigned long __copy_to_user_inatomic (void __user *to,const void *from,unsigned long n) { +unsigned long to_copy = n; +kasan_check_read (from, n);check_object_size (from, n, true); -return raw_copy_to_user (to, from, n); + n =raw_copy_to_user (to, from, n); +kmsan_copy_to_user (to, from, to_copy, n); +return n; }static __always_inline __must_check unsigned long __copy_to_user (void __user *to,const void *from,unsigned long n) { +unsigned long to_copy = n; +might_fault ();kasan_check_read (from, n);check_object_size (from, n, true); -return raw_copy_to_user (to, from, n); + n =raw_copy_to_user (to, from, n); +kmsan_copy_to_user (to, from, to_copy, n); +return n; }#ifdef INLINE_COPY_FROM_USER static inline __must_check unsigned long _copy_from_user (void *to,const void __user *from,unsigned long n) { -unsigned long res = n; +unsigned long res = n, to_copy = n; +might_fault ();if (likely (access_ok (from, n))) {kasan_check_write (to, n); res =raw_copy_from_user (to, from, n); +kmsan_unpoison_shadow (to, to_copy - res); }if (unlikely (res))memset (to + (n - res),0 , res);
@@ -125,10 +144,13 @@ _copy_from_user(void *, const void __user *, unsigned long);static inline __must_check unsigned long _copy_to_user (void __user *to,const void *from,unsigned long n) { +unsigned long to_copy = n; +might_fault ();if (access_ok (to, n)) {kasan_check_read (from, n); n =raw_copy_to_user (to, from, n); +kmsan_copy_to_user (to, from, to_copy, n); }return n; }
lib/iov_iter.c +6 -0
@@ -137,18 +137,24 @@static int copyout (void __user *to,const void *from,size_t n) { +size_t to_copy = n; +if (access_ok (to, n)) {kasan_check_read (from, n); n =raw_copy_to_user (to, from, n); +kmsan_copy_to_user (to, from, to_copy, n); }return n; }static int copyin (void *to,const void __user *from,size_t n) { +size_t to_copy = n; +if (access_ok (from, n)) {kasan_check_write (to, n); n =raw_copy_from_user (to, from, n); +kmsan_unpoison_shadow (to, to_copy - n); }return n; }
lib/usercopy.c +5 -1
@@ -1,4 +1,5 @@// SPDX-License-Identifier: GPL-2.0 +#include <linux/kmsan-checks.h> #include <linux/uaccess.h> #include <linux/bitops.h>
@@ -7,11 +8,12 @@#ifndef INLINE_COPY_FROM_USER unsigned long _copy_from_user (void *to,const void __user *from,unsigned long n) { -unsigned long res = n; +unsigned long res = n, to_copy = n;might_fault ();if (likely (access_ok (from, n))) {kasan_check_write (to, n); res =raw_copy_from_user (to, from, n); +kmsan_unpoison_shadow (to, to_copy - res); }if (unlikely (res))memset (to + (n - res),0 , res);
@@ -23,10 +25,12 @@ EXPORT_SYMBOL(_copy_from_user);#ifndef INLINE_COPY_TO_USER unsigned long _copy_to_user (void __user *to,const void *from,unsigned long n) { +unsigned long to_copy = n;might_fault ();if (likely (access_ok (to, n))) {kasan_check_read (from, n); n =raw_copy_to_user (to, from, n); +kmsan_copy_to_user (to, from, to_copy, n); }return n; }
Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
kbuild test robot
build botRe: [PATCH RFC v2 23/25] kmsan: hooks for copy_to_user() and friends
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system. BTW, we also suggest to use '--base' option to specify the base tree in git format-patch, please…
Hi,
[FYI, it's a private test report for your RFC patch.]
[auto build test ERROR on linus/master]
[also build test ERROR on v5.4-rc5]
[cannot apply to next-20191031]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system. BTW, we also suggest to use '--base' option to specify the base tree in git format-patch, please see https://stackoverflow.com/a/37406982]
url: https://github.com/0day-ci/linux/commits/glider-google-com/Add-KernelMemorySanitizer-infrastructure/20191102-050032 base: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 0dbe6cb8f7e05bc9611602ef45980a6c57b245a3 config: h8300-h8300h-sim_defconfig (attached as .config) compiler: h8300-linux-gcc (GCC) 7.4.0
reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
GCC_VERSION=7.4.0 make.cross ARCH=h8300
If you fix the issue, kindly add following tag
All errors (new ones prefixed by >>):
In file included from ./arch/h8300/include/generated/asm/uaccess.h:1:0,
from include/linux/uaccess.h:12,
from include/linux/sched/task.h:11,
from include/linux/sched/signal.h:9,
from include/linux/ptrace.h:7,
from arch/h8300/kernel/asm-offsets.c:15:
include/asm-generic/uaccess.h: In function '__get_user_fn':
include/asm-generic/uaccess.h:213:24: error: 'to' undeclared (first use in this function); did you mean 'tm'?
kmsan_unpoison_shadow(to, to_copy - res);
^~
tm
include/asm-generic/uaccess.h:213:24: note: each undeclared identifier is reported only once for each function it appears in
>> include/asm-generic/uaccess.h:213:38: error: 'res' undeclared (first use in this function); did you mean 'kref'?
kmsan_unpoison_shadow(to, to_copy - res);
^~~
kref make[2]: *** [arch/h8300/kernel/asm-offsets.s] Error 1 make[2]: Target '__build' not remade because of errors. make[1]: *** [prepare0] Error 2
make[1]: Target 'prepare' not remade because of errors.
make: *** [sub-make] Error 2
38 real 11 user 11 sys 60.51% cpu make prepare
vim +213 include/asm-generic/uaccess.h
206
207 #ifndef __get_user_fn
208 static inline int __get_user_fn(size_t size, const void __user *ptr, void *x)
209 {
210 int copied, to_copy = size;
211
212 copied = raw_copy_from_user(x, ptr, size);
> 213 kmsan_unpoison_shadow(to, to_copy - res);
214 return unlikely(copied) ? -EFAULT : 0;
215 }
216
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
kbuild test robot
build botRe: [PATCH RFC v2 23/25] kmsan: hooks for copy_to_user() and friends
In reply to [email protected][if your patch is applied to the wrong git tree, please drop us a note to help improve the system. BTW, we also suggest to use '--base' option to specify the base tree in git format-patch, please…
Hi,
[FYI, it's a private test report for your RFC patch.]
[auto build test WARNING on linus/master]
[also build test WARNING on v5.4-rc5]
[cannot apply to next-20191031]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system. BTW, we also suggest to use '--base' option to specify the base tree in git format-patch, please see https://stackoverflow.com/a/37406982]
url: https://github.com/0day-ci/linux/commits/glider-google-com/Add-KernelMemorySanitizer-infrastructure/20191102-050032 base: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 0dbe6cb8f7e05bc9611602ef45980a6c57b245a3 reproduce: # apt-get install sparse # sparse version: v0.6.1-6-g57f8611-dirty make ARCH=x86_64 allmodconfig make C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__'
If you fix the issue, kindly add following tag
sparse warnings: (new ones prefixed by >>)
>> include/linux/uaccess.h:118:28: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *to @@ got void [noderevoid const *to @@ >> include/linux/uaccess.h:118:28: sparse: expected void const *to >> include/linux/uaccess.h:118:28: sparse: got void [noderef] <asn:1> *to
--
drivers/firmware/efi/test/efi_test.c:44:13: sparse: got unsigned short [usertype] *
drivers/firmware/efi/test/efi_test.c:50:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] <asn:1> * @@ got olatile [noderef] <asn:1> * @@
drivers/firmware/efi/test/efi_test.c:50:21: sparse: expected void const volatile [noderef] <asn:1> *
drivers/firmware/efi/test/efi_test.c:50:21: sparse: got unsigned short [usertype] *
drivers/firmware/efi/test/efi_test.c:265:39: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const [noderef] <asn:1> * @@ got [noderef] <asn:1> * @@
drivers/firmware/efi/test/efi_test.c:265:39: sparse: expected void const [noderef] <asn:1> *
drivers/firmware/efi/test/efi_test.c:265:39: sparse: got void *[addressable] data
drivers/firmware/efi/test/efi_test.c:275:13: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] <asn:1> * @@ got uvoid const volatile [noderef] <asn:1> * @@
drivers/firmware/efi/test/efi_test.c:275:13: sparse: expected void const volatile [noderef] <asn:1> *
drivers/firmware/efi/test/efi_test.c:275:13: sparse: got unsigned long [usertype] *[addressable] status
drivers/firmware/efi/test/efi_test.c:304:13: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] <asn:1> * @@ got uvoid const volatile [noderef] <asn:1> * @@
drivers/firmware/efi/test/efi_test.c:304:13: sparse: expected void const volatile [noderef] <asn:1> *
drivers/firmware/efi/test/efi_test.c:304:13: sparse: got unsigned long [usertype] *[addressable] status
drivers/firmware/efi/test/efi_test.c:313:27: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct efi_time_cap_t [noderef] [usertype] <asn:1> *cap_local @@ got p_t [noderef] [usertype] <asn:1> *cap_local @@
drivers/firmware/efi/test/efi_test.c:313:27: sparse: expected struct efi_time_cap_t [noderef] [usertype] <asn:1> *cap_local
drivers/firmware/efi/test/efi_test.c:313:27: sparse: got struct efi_time_cap_t [usertype] *
drivers/firmware/efi/test/efi_test.c:320:41: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void [noderef] <asn:1> *to @@ got struct efi_time_t [uvoid [noderef] <asn:1> *to @@
drivers/firmware/efi/test/efi_test.c:320:41: sparse: expected void [noderef] <asn:1> *to
drivers/firmware/efi/test/efi_test.c:320:41: sparse: got struct efi_time_t [usertype] *[addressable] time
drivers/firmware/efi/test/efi_test.c:337:46: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void const [noderef] <asn:1> *from @@ got struct efi_timvoid const [noderef] <asn:1> *from @@
drivers/firmware/efi/test/efi_test.c:337:46: sparse: expected void const [noderef] <asn:1> *from
drivers/firmware/efi/test/efi_test.c:337:46: sparse: got struct efi_time_t [usertype] *[addressable] time
drivers/firmware/efi/test/efi_test.c:342:13: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] <asn:1> * @@ got uvoid const volatile [noderef] <asn:1> * @@
drivers/firmware/efi/test/efi_test.c:342:13: sparse: expected void const volatile [noderef] <asn:1> *
drivers/firmware/efi/test/efi_test.c:342:13: sparse: got unsigned long [usertype] *[addressable] status
drivers/firmware/efi/test/efi_test.c:366:13: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] <asn:1> * @@ got uvoid const volatile [noderef] <asn:1> * @@
drivers/firmware/efi/test/efi_test.c:366:13: sparse: expected void const volatile [noderef] <asn:1> *
drivers/firmware/efi/test/efi_test.c:366:13: sparse: got unsigned long [usertype] *[addressable] status
drivers/firmware/efi/test/efi_test.c:372:38: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] <asn:1> * @@ got uvoid const volatile [noderef] <asn:1> * @@
drivers/firmware/efi/test/efi_test.c:372:38: sparse: expected void const volatile [noderef] <asn:1> *
drivers/firmware/efi/test/efi_test.c:372:38: sparse: got unsigned char [usertype] *[addressable] enabled
drivers/firmware/efi/test/efi_test.c:377:47: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void [noderef] <asn:1> *to @@ got struct efi_time_t [uvoid [noderef] <asn:1> *to @@
drivers/firmware/efi/test/efi_test.c:377:47: sparse: expected void [noderef] <asn:1> *to
drivers/firmware/efi/test/efi_test.c:377:47: sparse: got struct efi_time_t [usertype] *[addressable] time
drivers/firmware/efi/test/efi_test.c:401:60: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void const [noderef] <asn:1> *from @@ got struct efi_timvoid const [noderef] <asn:1> *from @@
drivers/firmware/efi/test/efi_test.c:401:60: sparse: expected void const [noderef] <asn:1> *from
drivers/firmware/efi/test/efi_test.c:401:60: sparse: got struct efi_time_t [usertype] *[addressable] time
drivers/firmware/efi/test/efi_test.c:409:13: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] <asn:1> * @@ got uvoid const volatile [noderef] <asn:1> * @@
drivers/firmware/efi/test/efi_test.c:409:13: sparse: expected void const volatile [noderef] <asn:1> *
drivers/firmware/efi/test/efi_test.c:409:13: sparse: got unsigned long [usertype] *[addressable] status
drivers/firmware/efi/test/efi_test.c:433:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] <asn:1> * @@ got volatile [noderef] <asn:1> * @@
drivers/firmware/efi/test/efi_test.c:433:21: sparse: expected void const volatile [noderef] <asn:1> *
drivers/firmware/efi/test/efi_test.c:433:21: sparse: got unsigned long *[addressable] variable_name_size
drivers/firmware/efi/test/efi_test.c:441:52: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void const [noderef] <asn:1> *from @@ got struct guivoid const [noderef] <asn:1> *from @@
drivers/firmware/efi/test/efi_test.c:441:52: sparse: expected void const [noderef] <asn:1> *from
drivers/firmware/efi/test/efi_test.c:441:52: sparse: got struct guid_t [usertype] *[addressable] vendor_guid
drivers/firmware/efi/test/efi_test.c:451:52: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected unsigned short [noderef] [usertype] <asn:1> *src @@ got gned short [noderef] [usertype] <asn:1> *src @@
drivers/firmware/efi/test/efi_test.c:451:52: sparse: expected unsigned short [noderef] [usertype] <asn:1> *src
drivers/firmware/efi/test/efi_test.c:451:52: sparse: got unsigned short [usertype] *[addressable] variable_name
drivers/firmware/efi/test/efi_test.c:35:27: sparse: sparse: incorrect type in initializer (different address spaces) @@ expected unsigned short [usertype] *[assigned] s @@ got unsigneunsigned short [usertype] *[assigned] s @@
drivers/firmware/efi/test/efi_test.c:35:27: sparse: expected unsigned short [usertype] *[assigned] s
drivers/firmware/efi/test/efi_test.c:35:27: sparse: got unsigned short [noderef] [usertype] <asn:1> *str
drivers/firmware/efi/test/efi_test.c:44:13: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] <asn:1> * @@ got olatile [noderef] <asn:1> * @@
drivers/firmware/efi/test/efi_test.c:44:13: sparse: expected void const volatile [noderef] <asn:1> *
drivers/firmware/efi/test/efi_test.c:44:13: sparse: got unsigned short [usertype] *
drivers/firmware/efi/test/efi_test.c:50:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] <asn:1> * @@ got olatile [noderef] <asn:1> * @@
drivers/firmware/efi/test/efi_test.c:50:21: sparse: expected void const volatile [noderef] <asn:1> *
drivers/firmware/efi/test/efi_test.c:50:21: sparse: got unsigned short [usertype] *
drivers/firmware/efi/test/efi_test.c:464:52: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected unsigned short [noderef] [usertype] <asn:1> *src @@ got gned short [noderef] [usertype] <asn:1> *src @@
drivers/firmware/efi/test/efi_test.c:464:52: sparse: expected unsigned short [noderef] [usertype] <asn:1> *src
drivers/firmware/efi/test/efi_test.c:464:52: sparse: got unsigned short [usertype] *[addressable] variable_name
drivers/firmware/efi/test/efi_test.c:473:13: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] <asn:1> * @@ got uvoid const volatile [noderef] <asn:1> * @@
drivers/firmware/efi/test/efi_test.c:473:13: sparse: expected void const volatile [noderef] <asn:1> *
drivers/firmware/efi/test/efi_test.c:473:13: sparse: got unsigned long [usertype] *[addressable] status
drivers/firmware/efi/test/efi_test.c:480:35: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] <asn:1> * @@ got volatile [noderef] <asn:1> * @@
drivers/firmware/efi/test/efi_test.c:480:35: sparse: expected void const volatile [noderef] <asn:1> *
drivers/firmware/efi/test/efi_test.c:480:35: sparse: got unsigned long *[addressable] variable_name_size
drivers/firmware/efi/test/efi_test.c:491:62: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected unsigned short [noderef] [usertype] <asn:1> *dst @@ got gned short [noderef] [usertype] <asn:1> *dst @@
drivers/firmware/efi/test/efi_test.c:491:62: sparse: expected unsigned short [noderef] [usertype] <asn:1> *dst
drivers/firmware/efi/test/efi_test.c:491:62: sparse: got unsigned short [usertype] *[addressable] variable_name
drivers/firmware/efi/test/efi_test.c:499:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] <asn:1> * @@ got volatile [noderef] <asn:1> * @@
drivers/firmware/efi/test/efi_test.c:499:21: sparse: expected void const volatile [noderef] <asn:1> *
drivers/firmware/efi/test/efi_test.c:499:21: sparse: got unsigned long *[addressable] variable_name_size
drivers/firmware/efi/test/efi_test.c:506:53: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void [noderef] <asn:1> *to @@ got struct guid_t [uvoid [noderef] <asn:1> *to @@
drivers/firmware/efi/test/efi_test.c:506:53: sparse: expected void [noderef] <asn:1> *to
drivers/firmware/efi/test/efi_test.c:506:53: sparse: got struct guid_t [usertype] *[addressable] vendor_guid
drivers/firmware/efi/test/efi_test.c:534:13: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] <asn:1> * @@ got uvoid const volatile [noderef] <asn:1> * @@
drivers/firmware/efi/test/efi_test.c:534:13: sparse: expected void const volatile [noderef] <asn:1> *
drivers/firmware/efi/test/efi_test.c:534:13: sparse: got unsigned long [usertype] *[addressable] status
drivers/firmware/efi/test/efi_test.c:541:13: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] <asn:1> * @@ got void const volatile [noderef] <asn:1> * @@
drivers/firmware/efi/test/efi_test.c:541:13: sparse: expected void const volatile [noderef] <asn:1> *
drivers/firmware/efi/test/efi_test.c:541:13: sparse: got unsigned int [usertype] *[addressable] high_count
drivers/firmware/efi/test/efi_test.c:558:37: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const [noderef] <asn:1> * @@ got n:1> * @@
drivers/firmware/efi/test/efi_test.c:558:37: sparse: expected void const [noderef] <asn:1> *
drivers/firmware/efi/test/efi_test.c:558:37: sparse: got void *
drivers/firmware/efi/test/efi_test.c:587:13: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] <asn:1> * @@ got uvoid const volatile [noderef] <asn:1> * @@
drivers/firmware/efi/test/efi_test.c:587:13: sparse: expected void const volatile [noderef] <asn:1> *
drivers/firmware/efi/test/efi_test.c:587:13: sparse: got unsigned long [usertype] *[addressable] status
drivers/firmware/efi/test/efi_test.c:593:13: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] <asn:1> * @@ got unsignvoid const volatile [noderef] <asn:1> * @@
drivers/firmware/efi/test/efi_test.c:593:13: sparse: expected void const volatile [noderef] <asn:1> *
drivers/firmware/efi/test/efi_test.c:593:13: sparse: got unsigned long long [usertype] *[addressable] maximum_variable_storage_size
drivers/firmware/efi/test/efi_test.c:597:13: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] <asn:1> * @@ got unsignvoid const volatile [noderef] <asn:1> * @@
drivers/firmware/efi/test/efi_test.c:597:13: sparse: expected void const volatile [noderef] <asn:1> *
drivers/firmware/efi/test/efi_test.c:597:13: sparse: got unsigned long long [usertype] *[addressable] remaining_variable_storage_size
drivers/firmware/efi/test/efi_test.c:601:13: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] <asn:1> * @@ got unsignvoid const volatile [noderef] <asn:1> * @@
drivers/firmware/efi/test/efi_test.c:601:13: sparse: expected void const volatile [noderef] <asn:1> *
drivers/firmware/efi/test/efi_test.c:601:13: sparse: got unsigned long long [usertype] *[addressable] maximum_variable_size
drivers/firmware/efi/test/efi_test.c:637:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] <asn:1> * @@ got stvoid const volatile [noderef] <asn:1> * @@
drivers/firmware/efi/test/efi_test.c:637:21: sparse: expected void const volatile [noderef] <asn:1> *
drivers/firmware/efi/test/efi_test.c:637:21: sparse: got struct efi_capsule_header_t [usertype] **
>> drivers/firmware/efi/test/efi_test.c:641:50: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void const [noderef] <asn:1> *from @@ got struct efi_capsule_header_t [usertyvoid const [noderef] <asn:1> *from @@ drivers/firmware/efi/test/efi_test.c:641:50: sparse: expected void const [noderef] <asn:1> *from >> drivers/firmware/efi/test/efi_test.c:641:50: sparse: got struct efi_capsule_header_t [usertype] *[addressable] [assigned] c
drivers/firmware/efi/test/efi_test.c:655:13: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] <asn:1> * @@ got unsigned lonvoid const volatile [noderef] <asn:1> * @@
drivers/firmware/efi/test/efi_test.c:655:13: sparse: expected void const volatile [noderef] <asn:1> *
drivers/firmware/efi/test/efi_test.c:655:13: sparse: got unsigned long [usertype] *[addressable] [assigned] status
drivers/firmware/efi/test/efi_test.c:665:13: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] <asn:1> * @@ got unsigned long lonvoid const volatile [noderef] <asn:1> * @@
drivers/firmware/efi/test/efi_test.c:665:13: sparse: expected void const volatile [noderef] <asn:1> *
drivers/firmware/efi/test/efi_test.c:665:13: sparse: got unsigned long long [usertype] *[addressable] [assigned] maximum_capsule_size
drivers/firmware/efi/test/efi_test.c:670:13: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] <asn:1> * @@ got t volatile [noderef] <asn:1> * @@
drivers/firmware/efi/test/efi_test.c:670:13: sparse: expected void const volatile [noderef] <asn:1> *
drivers/firmware/efi/test/efi_test.c:670:13: sparse: got int *[addressable] [assigned] reset_type
--
>> include/linux/uaccess.h:118:28: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *to @@ got void [noderevoid const *to @@ >> include/linux/uaccess.h:118:28: sparse: expected void const *to >> include/linux/uaccess.h:118:28: sparse: got void [noderef] <asn:1> *to >> include/linux/uaccess.h:118:28: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *to @@ got void [noderevoid const *to @@ >> include/linux/uaccess.h:118:28: sparse: expected void const *to >> include/linux/uaccess.h:118:28: sparse: got void [noderef] <asn:1> *to >> include/linux/uaccess.h:118:28: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *to @@ got void [noderevoid const *to @@ >> include/linux/uaccess.h:118:28: sparse: expected void const *to >> include/linux/uaccess.h:118:28: sparse: got void [noderef] <asn:1> *to >> include/linux/uaccess.h:118:28: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *to @@ got void [noderevoid const *to @@ >> include/linux/uaccess.h:118:28: sparse: expected void const *to >> include/linux/uaccess.h:118:28: sparse: got void [noderef] <asn:1> *to
--
drivers/scsi/esas2r/esas2r.h:1305:13: sparse: sparse: cast to restricted __le32 drivers/scsi/esas2r/esas2r_ioctl.c:321:23: sparse: sparse: cast to restricted __le32 drivers/scsi/esas2r/esas2r_ioctl.c:322:23: sparse: sparse: cast to restricted __le32 drivers/scsi/esas2r/esas2r_ioctl.c:333:25: sparse: sparse: cast to restricted __le16 drivers/scsi/esas2r/esas2r_ioctl.c:334:29: sparse: sparse: invalid assignment: |=
drivers/scsi/esas2r/esas2r_ioctl.c:334:29: sparse: left side has type unsigned int
drivers/scsi/esas2r/esas2r_ioctl.c:334:29: sparse: right side has type restricted __le32
drivers/scsi/esas2r/esas2r_ioctl.c:355:31: sparse: sparse: incorrect type in assignment (different base types) @@ expected unsigned int [usertype] ctrl_code @@ got restrunsigned int [usertype] ctrl_code @@
drivers/scsi/esas2r/esas2r_ioctl.c:355:31: sparse: expected unsigned int [usertype] ctrl_code
drivers/scsi/esas2r/esas2r_ioctl.c:355:31: sparse: got restricted __le32 [usertype]
drivers/scsi/esas2r/esas2r_ioctl.c:356:31: sparse: sparse: incorrect type in assignment (different base types) @@ expected unsigned short [usertype] target_id @@ got resunsigned short [usertype] target_id @@
drivers/scsi/esas2r/esas2r_ioctl.c:356:31: sparse: expected unsigned short [usertype] target_id
drivers/scsi/esas2r/esas2r_ioctl.c:356:31: sparse: got restricted __le16 [usertype]
drivers/scsi/esas2r/esas2r_ioctl.c:357:31: sparse: sparse: cast to restricted __le32 drivers/scsi/esas2r/esas2r.h:1305:13: sparse: sparse: cast to restricted __le32
drivers/scsi/esas2r/esas2r_ioctl.c:419:57: sparse: sparse: incorrect type in assignment (different base types) @@ expected unsigned int [usertype] csmi_status @@ got restrunsigned int [usertype] csmi_status @@
drivers/scsi/esas2r/esas2r_ioctl.c:419:57: sparse: expected unsigned int [usertype] csmi_status
drivers/scsi/esas2r/esas2r_ioctl.c:419:57: sparse: got restricted __le32 [usertype]
drivers/scsi/esas2r/esas2r_ioctl.c:425:29: sparse: sparse: invalid assignment: |=
drivers/scsi/esas2r/esas2r_ioctl.c:425:29: sparse: left side has type unsigned int
drivers/scsi/esas2r/esas2r_ioctl.c:425:29: sparse: right side has type restricted __le32
drivers/scsi/esas2r/esas2r_ioctl.c:569:39: sparse: sparse: cast to restricted __le32
drivers/scsi/esas2r/esas2r_ioctl.c:600:49: sparse: sparse: incorrect type in assignment (different base types) @@ expected unsigned int [usertype] csmi_status @@ got restrunsigned int [usertype] csmi_status @@
drivers/scsi/esas2r/esas2r_ioctl.c:600:49: sparse: expected unsigned int [usertype] csmi_status
drivers/scsi/esas2r/esas2r_ioctl.c:600:49: sparse: got restricted __le32 [usertype]
drivers/scsi/esas2r/esas2r_ioctl.c:632:21: sparse: sparse: cast to restricted __le32 drivers/scsi/esas2r/esas2r_ioctl.c:642:22: sparse: sparse: cast to restricted __le32 drivers/scsi/esas2r/esas2r.h:1305:13: sparse: sparse: cast to restricted __le32 drivers/scsi/esas2r/esas2r_ioctl.c:697:17: sparse: sparse: cast to restricted __le32 drivers/scsi/esas2r/esas2r_ioctl.c:1013:37: sparse: sparse: invalid assignment: |=
drivers/scsi/esas2r/esas2r_ioctl.c:1013:37: sparse: left side has type unsigned int
drivers/scsi/esas2r/esas2r_ioctl.c:1013:37: sparse: right side has type restricted __le32
drivers/scsi/esas2r/esas2r_ioctl.c:1015:38: sparse: sparse: incorrect type in assignment (different base types) @@ expected unsigned int [usertype] length @@ got restrunsigned int [usertype] length @@
drivers/scsi/esas2r/esas2r_ioctl.c:1015:38: sparse: expected unsigned int [usertype] length
drivers/scsi/esas2r/esas2r_ioctl.c:1015:38: sparse: got restricted __le32 [usertype]
drivers/scsi/esas2r/esas2r_ioctl.c:1030:45: sparse: sparse: invalid assignment: |=
drivers/scsi/esas2r/esas2r_ioctl.c:1030:45: sparse: left side has type unsigned int
drivers/scsi/esas2r/esas2r_ioctl.c:1030:45: sparse: right side has type restricted __le32
drivers/scsi/esas2r/esas2r_ioctl.c:1032:45: sparse: sparse: invalid assignment: |=
drivers/scsi/esas2r/esas2r_ioctl.c:1032:45: sparse: left side has type unsigned int
drivers/scsi/esas2r/esas2r_ioctl.c:1032:45: sparse: right side has type restricted __le32
drivers/scsi/esas2r/esas2r_ioctl.c:1041:45: sparse: sparse: invalid assignment: |=
drivers/scsi/esas2r/esas2r_ioctl.c:1041:45: sparse: left side has type unsigned int
drivers/scsi/esas2r/esas2r_ioctl.c:1041:45: sparse: right side has type restricted __le32
drivers/scsi/esas2r/esas2r_ioctl.c:1044:45: sparse: sparse: invalid assignment: |=
drivers/scsi/esas2r/esas2r_ioctl.c:1044:45: sparse: left side has type unsigned int
drivers/scsi/esas2r/esas2r_ioctl.c:1044:45: sparse: right side has type restricted __le32
drivers/scsi/esas2r/esas2r.h:1305:13: sparse: sparse: cast to restricted __le32
>> include/linux/uaccess.h:118:28: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *to @@ got void [noderevoid const *to @@ >> include/linux/uaccess.h:118:28: sparse: expected void const *to >> include/linux/uaccess.h:118:28: sparse: got void [noderef] <asn:1> *to -- >> include/linux/uaccess.h:118:28: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *to @@ got void [noderevoid const *to @@ >> include/linux/uaccess.h:118:28: sparse: expected void const *to >> include/linux/uaccess.h:118:28: sparse: got void [noderef] <asn:1> *to >> include/linux/uaccess.h:118:28: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *to @@ got void [noderevoid const *to @@ >> include/linux/uaccess.h:118:28: sparse: expected void const *to >> include/linux/uaccess.h:118:28: sparse: got void [noderef] <asn:1> *to -- >> include/linux/uaccess.h:118:28: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *to @@ got void [noderevoid const *to @@ >> include/linux/uaccess.h:118:28: sparse: expected void const *to >> include/linux/uaccess.h:118:28: sparse: got void [noderef] <asn:1> *to >> include/linux/uaccess.h:118:28: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *to @@ got void [noderevoid const *to @@ >> include/linux/uaccess.h:118:28: sparse: expected void const *to >> include/linux/uaccess.h:118:28: sparse: got void [noderef] <asn:1> *to
--
arch/x86/kvm/../../../virt/kvm/kvm_main.c:2960:57: sparse: sparse: cast removes address space '<asn:1>' of expression
arch/x86/kvm/../../../virt/kvm/kvm_main.c:2960:57: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct compat_sigset_t const [noderef] [usertype] <asn:1> *compat @@ got n:1> *compat @@
arch/x86/kvm/../../../virt/kvm/kvm_main.c:2960:57: sparse: expected struct compat_sigset_t const [noderef] [usertype] <asn:1> *compat
arch/x86/kvm/../../../virt/kvm/kvm_main.c:2960:57: sparse: got void *
>> include/linux/uaccess.h:118:28: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *to @@ got void [noderevoid const *to @@ >> include/linux/uaccess.h:118:28: sparse: expected void const *to >> include/linux/uaccess.h:118:28: sparse: got void [noderef] <asn:1> *to >> include/linux/uaccess.h:118:28: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *to @@ got void [noderevoid const *to @@ >> include/linux/uaccess.h:118:28: sparse: expected void const *to >> include/linux/uaccess.h:118:28: sparse: got void [noderef] <asn:1> *to -- >> include/linux/uaccess.h:118:28: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *to @@ got void [noderevoid const *to @@ >> include/linux/uaccess.h:118:28: sparse: expected void const *to >> include/linux/uaccess.h:118:28: sparse: got void [noderef] <asn:1> *to >> include/linux/uaccess.h:118:28: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *to @@ got void [noderevoid const *to @@ >> include/linux/uaccess.h:118:28: sparse: expected void const *to >> include/linux/uaccess.h:118:28: sparse: got void [noderef] <asn:1> *to >> include/linux/uaccess.h:118:28: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *to @@ got void [noderevoid const *to @@ >> include/linux/uaccess.h:118:28: sparse: expected void const *to >> include/linux/uaccess.h:118:28: sparse: got void [noderef] <asn:1> *to -- >> lib/iov_iter.c:145:36: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *to @@ got void [noderevoid const *to @@ >> lib/iov_iter.c:145:36: sparse: expected void const *to >> lib/iov_iter.c:145:36: sparse: got void [noderef] <asn:1> *to -- >> lib/usercopy.c:33:36: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *to @@ got void [noderevoid const *to @@ >> lib/usercopy.c:33:36: sparse: expected void const *to >> lib/usercopy.c:33:36: sparse: got void [noderef] <asn:1> *to -- >> include/linux/uaccess.h:118:28: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *to @@ got void [noderevoid const *to @@ >> include/linux/uaccess.h:118:28: sparse: expected void const *to >> include/linux/uaccess.h:118:28: sparse: got void [noderef] <asn:1> *to
include/linux/uaccess.h:105:28: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *to @@ got void [noderevoid const *to @@
include/linux/uaccess.h:105:28: sparse: expected void const *to
include/linux/uaccess.h:105:28: sparse: got void [noderef] <asn:1> *to
arch/x86/include/asm/bitops.h:104:36: sparse: sparse: shift too big (72) for type int
--
>> include/linux/uaccess.h:118:28: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *to @@ got void [noderevoid const *to @@ >> include/linux/uaccess.h:118:28: sparse: expected void const *to >> include/linux/uaccess.h:118:28: sparse: got void [noderef] <asn:1> *to >> include/linux/uaccess.h:118:28: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *to @@ got void [noderevoid const *to @@ >> include/linux/uaccess.h:118:28: sparse: expected void const *to >> include/linux/uaccess.h:118:28: sparse: got void [noderef] <asn:1> *to drivers/vhost/scsi.c:1218:30: sparse: sparse: restricted __virtio32 degrades to integer drivers/vhost/scsi.c:1218:30: sparse: sparse: restricted __virtio32 degrades to integer -- >> include/linux/uaccess.h:118:28: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *to @@ got void [noderevoid const *to @@ >> include/linux/uaccess.h:118:28: sparse: expected void const *to >> include/linux/uaccess.h:118:28: sparse: got void [noderef] <asn:1> *to drivers/vhost/vhost.c:747:17: sparse: sparse: incorrect type in return expression (different address spaces) @@ expected void [noderef] <asn:1> * @@ got n:1> * @@ drivers/vhost/vhost.c:747:17: sparse: expected void [noderef] <asn:1> * drivers/vhost/vhost.c:747:17: sparse: got void * >> include/linux/uaccess.h:118:28: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *to @@ got void [noderevoid const *to @@ >> include/linux/uaccess.h:118:28: sparse: expected void const *to >> include/linux/uaccess.h:118:28: sparse: got void [noderef] <asn:1> *to
drivers/vhost/vhost.c:747:17: sparse: sparse: incorrect type in return expression (different address spaces) @@ expected void [noderef] <asn:1> * @@ got n:1> * @@
drivers/vhost/vhost.c:747:17: sparse: expected void [noderef] <asn:1> *
drivers/vhost/vhost.c:747:17: sparse: got void *
drivers/vhost/vhost.c:747:17: sparse: sparse: incorrect type in return expression (different address spaces) @@ expected void [noderef] <asn:1> * @@ got n:1> * @@
drivers/vhost/vhost.c:747:17: sparse: expected void [noderef] <asn:1> *
drivers/vhost/vhost.c:747:17: sparse: got void *
drivers/vhost/vhost.c:931:16: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void *addr @@ got restricted __virtio16 [noderef] <asvoid *addr @@
drivers/vhost/vhost.c:931:16: sparse: expected void *addr
drivers/vhost/vhost.c:931:16: sparse: got restricted __virtio16 [noderef] <asn:1> *
drivers/vhost/vhost.c:747:17: sparse: sparse: incorrect type in return expression (different address spaces) @@ expected void [noderef] <asn:1> * @@ got n:1> * @@
drivers/vhost/vhost.c:747:17: sparse: expected void [noderef] <asn:1> *
drivers/vhost/vhost.c:747:17: sparse: got void *
drivers/vhost/vhost.c:894:42: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void [noderef] <asn:1> *addr @@ got n:1> *addr @@
drivers/vhost/vhost.c:894:42: sparse: expected void [noderef] <asn:1> *addr
drivers/vhost/vhost.c:894:42: sparse: got void *addr
drivers/vhost/vhost.c:916:16: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void *addr @@ got restricted __virtio16 [noderef] [usertype] <asvoid *addr @@
drivers/vhost/vhost.c:916:16: sparse: expected void *addr
drivers/vhost/vhost.c:916:16: sparse: got restricted __virtio16 [noderef] [usertype] <asn:1> *
drivers/vhost/vhost.c:747:17: sparse: sparse: incorrect type in return expression (different address spaces) @@ expected void [noderef] <asn:1> * @@ got n:1> * @@
drivers/vhost/vhost.c:747:17: sparse: expected void [noderef] <asn:1> *
drivers/vhost/vhost.c:747:17: sparse: got void *
drivers/vhost/vhost.c:894:42: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void [noderef] <asn:1> *addr @@ got n:1> *addr @@
drivers/vhost/vhost.c:894:42: sparse: expected void [noderef] <asn:1> *addr
drivers/vhost/vhost.c:894:42: sparse: got void *addr
drivers/vhost/vhost.c:1008:16: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void *addr @@ got restricted __virtio16 [noderef] <asvoid *addr @@
drivers/vhost/vhost.c:1008:16: sparse: expected void *addr
drivers/vhost/vhost.c:1008:16: sparse: got restricted __virtio16 [noderef] <asn:1> *
drivers/vhost/vhost.c:747:17: sparse: sparse: incorrect type in return expression (different address spaces) @@ expected void [noderef] <asn:1> * @@ got n:1> * @@
drivers/vhost/vhost.c:747:17: sparse: expected void [noderef] <asn:1> *
drivers/vhost/vhost.c:747:17: sparse: got void *
drivers/vhost/vhost.c:894:42: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void [noderef] <asn:1> *addr @@ got n:1> *addr @@
drivers/vhost/vhost.c:894:42: sparse: expected void [noderef] <asn:1> *addr
drivers/vhost/vhost.c:894:42: sparse: got void *addr
drivers/vhost/vhost.c:983:16: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void *addr @@ got restricted __virtio16 [noderef] <asvoid *addr @@
drivers/vhost/vhost.c:983:16: sparse: expected void *addr
drivers/vhost/vhost.c:983:16: sparse: got restricted __virtio16 [noderef] <asn:1> *
drivers/vhost/vhost.c:747:17: sparse: sparse: incorrect type in return expression (different address spaces) @@ expected void [noderef] <asn:1> * @@ got n:1> * @@
drivers/vhost/vhost.c:747:17: sparse: expected void [noderef] <asn:1> *
drivers/vhost/vhost.c:747:17: sparse: got void *
drivers/vhost/vhost.c:894:42: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void [noderef] <asn:1> *addr @@ got n:1> *addr @@
drivers/vhost/vhost.c:894:42: sparse: expected void [noderef] <asn:1> *addr
drivers/vhost/vhost.c:894:42: sparse: got void *addr
drivers/vhost/vhost.c:989:16: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void *addr @@ got restricted __virtio16 [noderef] <asvoid *addr @@
drivers/vhost/vhost.c:989:16: sparse: expected void *addr
drivers/vhost/vhost.c:989:16: sparse: got restricted __virtio16 [noderef] <asn:1> *
drivers/vhost/vhost.c:747:17: sparse: sparse: incorrect type in return expression (different address spaces) @@ expected void [noderef] <asn:1> * @@ got n:1> * @@
drivers/vhost/vhost.c:747:17: sparse: expected void [noderef] <asn:1> *
drivers/vhost/vhost.c:747:17: sparse: got void *
drivers/vhost/vhost.c:894:42: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void [noderef] <asn:1> *addr @@ got n:1> *addr @@
drivers/vhost/vhost.c:894:42: sparse: expected void [noderef] <asn:1> *addr
drivers/vhost/vhost.c:894:42: sparse: got void *addr
drivers/vhost/vhost.c:938:16: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void *addr @@ got restricted __virtio16 [noderef] <asvoid *addr @@
drivers/vhost/vhost.c:938:16: sparse: expected void *addr
drivers/vhost/vhost.c:938:16: sparse: got restricted __virtio16 [noderef] <asn:1> *
drivers/vhost/vhost.c:747:17: sparse: sparse: incorrect type in return expression (different address spaces) @@ expected void [noderef] <asn:1> * @@ got n:1> * @@
drivers/vhost/vhost.c:747:17: sparse: expected void [noderef] <asn:1> *
drivers/vhost/vhost.c:747:17: sparse: got void *
drivers/vhost/vhost.c:894:42: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void [noderef] <asn:1> *addr @@ got n:1> *addr @@
drivers/vhost/vhost.c:894:42: sparse: expected void [noderef] <asn:1> *addr
drivers/vhost/vhost.c:894:42: sparse: got void *addr
drivers/vhost/vhost.c:996:16: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void *addr @@ got restricted __virtio16 [noderef] <asvoid *addr @@
drivers/vhost/vhost.c:996:16: sparse: expected void *addr
drivers/vhost/vhost.c:996:16: sparse: got restricted __virtio16 [noderef] <asn:1> *
drivers/vhost/vhost.c:747:17: sparse: sparse: incorrect type in return expression (different address spaces) @@ expected void [noderef] <asn:1> * @@ got n:1> * @@
drivers/vhost/vhost.c:747:17: sparse: expected void [noderef] <asn:1> *
drivers/vhost/vhost.c:747:17: sparse: got void *
drivers/vhost/vhost.c:894:42: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void [noderef] <asn:1> *addr @@ got n:1> *addr @@
drivers/vhost/vhost.c:894:42: sparse: expected void [noderef] <asn:1> *addr
drivers/vhost/vhost.c:894:42: sparse: got void *addr
drivers/vhost/vhost.c:1002:16: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void *addr @@ got restricted __virtio16 [noderef] [usertype] <asvoid *addr @@
drivers/vhost/vhost.c:1002:16: sparse: expected void *addr
drivers/vhost/vhost.c:1002:16: sparse: got restricted __virtio16 [noderef] [usertype] <asn:1> *
drivers/vhost/vhost.c:747:17: sparse: sparse: incorrect type in return expression (different address spaces) @@ expected void [noderef] <asn:1> * @@ got n:1> * @@
drivers/vhost/vhost.c:747:17: sparse: expected void [noderef] <asn:1> *
drivers/vhost/vhost.c:747:17: sparse: got void *
drivers/vhost/vhost.c:894:42: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void [noderef] <asn:1> *addr @@ got n:1> *addr @@
drivers/vhost/vhost.c:894:42: sparse: expected void [noderef] <asn:1> *addr
drivers/vhost/vhost.c:894:42: sparse: got void *addr
drivers/vhost/vhost.c:983:16: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void *addr @@ got restricted __virtio16 [noderef] <asvoid *addr @@
drivers/vhost/vhost.c:983:16: sparse: expected void *addr
drivers/vhost/vhost.c:983:16: sparse: got restricted __virtio16 [noderef] <asn:1> *
drivers/vhost/vhost.c:747:17: sparse: sparse: incorrect type in return expression (different address spaces) @@ expected void [noderef] <asn:1> * @@ got n:1> * @@
drivers/vhost/vhost.c:747:17: sparse: expected void [noderef] <asn:1> *
drivers/vhost/vhost.c:747:17: sparse: got void *
drivers/vhost/vhost.c:894:42: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void [noderef] <asn:1> *addr @@ got n:1> *addr @@
drivers/vhost/vhost.c:894:42: sparse: expected void [noderef] <asn:1> *addr
drivers/vhost/vhost.c:894:42: sparse: got void *addr
drivers/vhost/vhost.c:983:16: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void *addr @@ got restricted __virtio16 [noderef] <asvoid *addr @@
drivers/vhost/vhost.c:983:16: sparse: expected void *addr
drivers/vhost/vhost.c:983:16: sparse: got restricted __virtio16 [noderef] <asn:1> *
drivers/vhost/vhost.c:747:17: sparse: sparse: incorrect type in return expression (different address spaces) @@ expected void [noderef] <asn:1> * @@ got n:1> * @@
drivers/vhost/vhost.c:747:17: sparse: expected void [noderef] <asn:1> *
drivers/vhost/vhost.c:747:17: sparse: got void *
drivers/vhost/vhost.c:894:42: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void [noderef] <asn:1> *addr @@ got n:1> *addr @@
drivers/vhost/vhost.c:894:42: sparse: expected void [noderef] <asn:1> *addr
drivers/vhost/vhost.c:894:42: sparse: got void *addr
--
>> net/dccp/proto.c:527:52: sparse: sparse: incorrect type in argument 2 (different base types) @@ expected restricted __be32 const [usertype] service @@ got cted __be32 const [usertype] service @@ net/dccp/proto.c:527:52: sparse: expected restricted __be32 const [usertype] service >> net/dccp/proto.c:527:52: sparse: got int [addressable] [assigned] val
net/dccp/proto.c:736:57: sparse: sparse: incorrect type in argument 2 (different base types) @@ expected restricted __be32 [usertype] param @@ got pe] param @@
net/dccp/proto.c:736:57: sparse: expected restricted __be32 [usertype] param
net/dccp/proto.c:736:57: sparse: got int cmsg_type
--
>> include/linux/uaccess.h:118:28: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *to @@ got void [noderevoid const *to @@ >> include/linux/uaccess.h:118:28: sparse: expected void const *to >> include/linux/uaccess.h:118:28: sparse: got void [noderef] <asn:1> *to
include/linux/uaccess.h:105:28: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *to @@ got void [noderevoid const *to @@
include/linux/uaccess.h:105:28: sparse: expected void const *to
include/linux/uaccess.h:105:28: sparse: got void [noderef] <asn:1> *to
--
>> include/linux/uaccess.h:118:28: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *to @@ got void [noderevoid const *to @@ >> include/linux/uaccess.h:118:28: sparse: expected void const *to >> include/linux/uaccess.h:118:28: sparse: got void [noderef] <asn:1> *to >> include/linux/uaccess.h:118:28: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *to @@ got void [noderevoid const *to @@ >> include/linux/uaccess.h:118:28: sparse: expected void const *to >> include/linux/uaccess.h:118:28: sparse: got void [noderef] <asn:1> *to >> include/linux/uaccess.h:118:28: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *to @@ got void [noderevoid const *to @@ >> include/linux/uaccess.h:118:28: sparse: expected void const *to >> include/linux/uaccess.h:118:28: sparse: got void [noderef] <asn:1> *to >> include/linux/uaccess.h:118:28: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *to @@ got void [noderevoid const *to @@ >> include/linux/uaccess.h:118:28: sparse: expected void const *to >> include/linux/uaccess.h:118:28: sparse: got void [noderef] <asn:1> *to >> include/linux/uaccess.h:118:28: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *to @@ got void [noderevoid const *to @@ >> include/linux/uaccess.h:118:28: sparse: expected void const *to >> include/linux/uaccess.h:118:28: sparse: got void [noderef] <asn:1> *to >> include/linux/uaccess.h:118:28: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *to @@ got void [noderevoid const *to @@ >> include/linux/uaccess.h:118:28: sparse: expected void const *to >> include/linux/uaccess.h:118:28: sparse: got void [noderef] <asn:1> *to
vim +118 include/linux/uaccess.h
108
109 static __always_inline __must_check unsigned long
110 __copy_to_user(void __user *to, const void *from, unsigned long n)
111 {
112 unsigned long to_copy = n;
113
114 might_fault();
115 kasan_check_read(from, n);
116 check_object_size(from, n, true);
117 n = raw_copy_to_user(to, from, n);
> 118 kmsan_copy_to_user(to, from, to_copy, n);
119 return n;
120 }
121
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[email protected]
maintainerRFC PATCH v2 24/25 kmsan: disable strscpy() optimization under KMSAN
In reply to [email protected]Disable the efficient 8-byte reading under KMSAN to avoid false positives.
To: Alexander Potapenko <[email protected]>
Cc: Vegard Nossum <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: [email protected]
---
Change-Id: I25d1acf5c3df6eff85894cd94f5ddbe93308271c
--- lib/string.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
lib/string.c +4 -1
@@ -186,7 +186,10 @@ ssize_t strscpy(char *dest, const char *src, size_t count)if (count ==0 ||WARN_ON_ONCE (count >INT_MAX ))return -E2BIG ; -#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS +/** +* Disable the efficient 8-byte reading under KMSAN to avoid false positives. +*/ +#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS ) && !defined(CONFIG_KMSAN )/* * If src is unaligned, don't cross a page boundary, * since we don't know if the next page is mapped.
Signature · 1 line
2.24.0.rc0.303.g954a862665-goog
[email protected]
maintainerRFC PATCH v2 25/25 net: kasan: kmsan: support CONFIG_GENERIC_CSUM on x86, enable it for KASAN/KMSAN
In reply to [email protected]This is needed to allow memory tools like KASAN and KMSAN see the memory accesses from the checksum code. Without CONFIG_GENERIC_CSUM the tools can't see memory accesses originating from handwritten assembly code.
For KASAN it's a question of detecting more bugs, for KMSAN using the C implementation also helps avoid false positives originating from seemingly uninitialized checksum values.
To: Alexander Potapenko <[email protected]>
Cc: Arnd Bergmann <[email protected]>
Cc: Michal Simek <[email protected]>
Cc: Andrey Ryabinin <[email protected]>
Cc: Vegard Nossum <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: Randy Dunlap <[email protected]>
Cc: [email protected]
---
v2:
- dropped the "default n" (as requested by Randy Dunlap)
Change-Id: I645e2c097253a8d5717ad87e2e2df6f6f67251f3
--- arch/x86/Kconfig | 4 ++++ arch/x86/include/asm/checksum.h | 10 +++++++--- arch/x86/lib/Makefile | 2 ++ 3 files changed, 13 insertions(+), 3 deletions(-)
arch/x86/Kconfig +4 -0
@@ -272,6 +272,10 @@ config GENERIC_ISA_DMA def_bool y depends on ISA_DMA_API +config GENERIC_CSUM + bool + default y if KMSAN || KASAN + config GENERIC_BUG def_bool y depends on BUG
arch/x86/include/asm/checksum.h +7 -3
@@ -1,6 +1,10 @@/* SPDX-License-Identifier: GPL-2.0 */ -#ifdef CONFIG_X86_32 -# include <asm/checksum_32.h> +#ifdef CONFIG_GENERIC_CSUM +# include <asm-generic/checksum.h> #else -# include <asm/checksum_64.h> +# ifdef CONFIG_X86_32 +# include <asm/checksum_32.h> +# else +# include <asm/checksum_64.h> +# endif #endif
arch/x86/lib/Makefile +2 -0
@@ -55,7 +55,9 @@ endif lib-$(CONFIG_X86_USE_3DNOW) += mmx_32.o else obj-y += iomap_copy_64.o +ifneq ($(CONFIG_GENERIC_CSUM),y) lib-y += csum-partial_64.o csum-copy_64.o csum-wrappers_64.o +endif lib-y += clear_page_64.o copy_page_64.o lib-y += memmove_64.o memset_64.o lib-y += copy_user_64.o
Signature · 1 line
2.24.0.rc0.303.g954a862665-goog