Bug 216180 - KASAN: some memset's are not intercepted
Summary: KASAN: some memset's are not intercepted
Status: RESOLVED INVALID
Alias: None
Product: Memory Management
Classification: Unclassified
Component: Sanitizers (show other bugs)
Hardware: All Linux
: P1 enhancement
Assignee: MM/Sanitizers virtual assignee
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2022-06-27 07:34 UTC by Dmitry Vyukov
Modified: 2022-06-27 10:29 UTC (History)
3 users (show)

See Also:
Kernel Version: ALL
Subsystem:
Regression: No
Bisected commit-id:


Attachments
.config (235.40 KB, text/plain)
2022-06-27 07:34 UTC, Dmitry Vyukov
Details

Description Dmitry Vyukov 2022-06-27 07:34:47 UTC
Created attachment 301283 [details]
.config

syzkaller produced the following report on commit 92f20ff72066:

BUG: unable to handle page fault for address: ffff8880789a6005
#PF: supervisor write access in kernel mode
#PF: error_code(0x0002) - not-present page
RIP: 0010:memset_erms+0x9/0x10 arch/x86/lib/memset_64.S:64
Call Trace:
 <TASK>
 zero_user_segments include/linux/highmem.h:272 [inline]
 folio_zero_range include/linux/highmem.h:428 [inline]
 truncate_inode_partial_folio+0x76a/0xdf0 mm/truncate.c:237

KASAN should have been intercepted memset, checked the range and produced a KASAN report with more info.

Is there something special about this memset call?
Does it affect KCSAN/KMSAN?
Comment 1 Alexander Potapenko 2022-06-27 08:38:47 UTC
When I build the kernel with this config, I can see a call to memset() in almost the same place in truncate_inode_partial_folio(), and that memset() is actually the one in mm/kasan/shadow.c

Could it be that KASAN addressability check (https://elixir.bootlin.com/linux/latest/source/mm/kasan/generic.c#L162) returned true for the non-existing page?

For posterity, here are the registers from the report:

================================================
RIP: 0010:memset_erms+0x9/0x10 arch/x86/lib/memset_64.S:64
Code: c1 e9 03 40 0f b6 f6 48 b8 01 01 01 01 01 01 01 01 48 0f af c6 f3 48 ab 89 d1 f3 aa 4c 89 c8 c3 90 49 89 f9 40 88 f0 48 89 d1 <f3> aa 4c 89 c8 c3 90 49 89 fa 40 0f b6 ce 48 b8 01 01 01 01 01 01
RSP: 0018:ffffc9000547fa90 EFLAGS: 00010202
RAX: 0000000000000000 RBX: 0000000000001000 RCX: 0000000000000ffb
RDX: 0000000000000ffb RSI: 0000000000000000 RDI: ffff8880789a6005
RBP: ffffea0001e26980 R08: 0000000000000001 R09: ffff8880789a6005
R10: ffffed100f134dff R11: 0000000000000000 R12: 0000000000000005
R13: 0000000000000000 R14: 0000000000001000 R15: 0000000000000ffb
FS:  00007fd5095b3700(0000) GS:ffff8880b9b00000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: ffff8880789a6005 CR3: 000000005a582000 CR4: 00000000003506e0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
Call Trace:
================================================

, so it was a call to memset(0xffff8880789a6005, 0x0, 4091)
Comment 2 Dmitry Vyukov 2022-06-27 08:45:14 UTC
This address belongs to physical memory:

   ffff888000000000 | -119.5  TB | ffffc87fffffffff |   64 TB | direct mapping of all physical memory (page_offset_base)

I think addressability check can go wrong for pages that were somehow unmapped/protected but allocated from page_alloc perspective.


Does KASAN interceptor tail-call memset_erms in this build?
If the interceptor would be in the stack trace, it would be clear that it was called and no point in filing such reports.
Comment 3 Alexander Potapenko 2022-06-27 10:25:09 UTC
> Does KASAN interceptor tail-call memset_erms in this build?

It calls __memset:

ffffffff81c68d30 <memset>:
ffffffff81c68d30:       41 55                   push   %r13
ffffffff81c68d32:       41 89 f5                mov    %esi,%r13d
ffffffff81c68d35:       41 54                   push   %r12
ffffffff81c68d37:       49 89 d4                mov    %rdx,%r12
ffffffff81c68d3a:       ba 01 00 00 00          mov    $0x1,%edx
ffffffff81c68d3f:       55                      push   %rbp
ffffffff81c68d40:       48 8b 4c 24 18          mov    0x18(%rsp),%rcx
ffffffff81c68d45:       4c 89 e6                mov    %r12,%rsi
ffffffff81c68d48:       48 89 fd                mov    %rdi,%rbp
ffffffff81c68d4b:       e8 30 f8 ff ff          call   ffffffff81c68580 <kasan_check_range>
ffffffff81c68d50:       84 c0                   test   %al,%al
ffffffff81c68d52:       74 13                   je     ffffffff81c68d67 <memset+0x37>
ffffffff81c68d54:       4c 89 e2                mov    %r12,%rdx
ffffffff81c68d57:       44 89 ee                mov    %r13d,%esi
ffffffff81c68d5a:       48 89 ef                mov    %rbp,%rdi
ffffffff81c68d5d:       5d                      pop    %rbp
ffffffff81c68d5e:       41 5c                   pop    %r12
ffffffff81c68d60:       41 5d                   pop    %r13
ffffffff81c68d62:       e9 79 81 5b 02          jmp    ffffffff84220ee0 <__memset>
ffffffff81c68d67:       5d                      pop    %rbp
ffffffff81c68d68:       31 c0                   xor    %eax,%eax
ffffffff81c68d6a:       41 5c                   pop    %r12
ffffffff81c68d6c:       41 5d                   pop    %r13
ffffffff81c68d6e:       c3                      ret    
ffffffff81c68d6f:       90                      nop


, which uses an ALTERNATIVE_2 to switch between memset_orig() and memset_erms(): https://elixir.bootlin.com/linux/latest/source/arch/x86/lib/memset_64.S#L27
Comment 4 Dmitry Vyukov 2022-06-27 10:29:09 UTC
It indeed tail-calls. I guess this can be closed then. Sorry for the noise.

Note You need to log in before you can comment on or make changes to this bug.