Bug 218043

Summary: KASAN (sw-tags): Clang incorrectly calculates shadow memory address
Product: Memory Management Reporter: Andrey Konovalov (andreyknvl)
Component: SanitizersAssignee: MM/Sanitizers virtual assignee (mm_sanitizers)
Status: NEW ---    
Severity: normal CC: kasan-dev, melver
Priority: P3    
Hardware: All   
OS: Linux   
Kernel Version: Subsystem:
Regression: No Bisected commit-id:

Description Andrey Konovalov 2023-10-24 22:21:41 UTC
Software Tag-Based KASAN calculates the shadow memory address based on the following formula:

shadow_addr = (addr >> KASAN_SHADOW_SCALE_SHIFT) + KASAN_SHADOW_OFFSET,

where the bit shift operates on an unsigned value.

With CONFIG_KASAN_SW_TAGS + CONFIG_KASAN_INLINE, Clang generates the following code to load a value from the shadow memory:

ffff8000800143f0 <__hwasan_check_x0_67043376>:
ffff8000800143f0:       9344dc10        sbfx    x16, x0, #4, #52
ffff8000800143f4:       38706930        ldrb    w16, [x9, x16]

Here, x0 is addr, x16 is supposed to be (addr >> KASAN_SHADOW_SCALE_SHIFT), and x9 is KASAN_SHADOW_OFFSET.

However, sbfx (Signed Bit Field Extract) sign extends the value. As a result, the shadow address is calculated incorrectly:

x0:  42fffb80aaaaaaaa
x9:  efff800000000000
x16: ffffffb80aaaaaaa

x9 + x16 = 0xefff800000000000 + 0xffffffb80aaaaaaa = 0xefff7fb80aaaaaaa (0x1efff7fb80aaaaaaa fit to 64 bits)

Instead, Clang should not sign extend the value when calculating x16:

x0:  42fffb80aaaaaaaa
x9:  efff800000000000
x16: 0fffffb80aaaaaaa

x9 + x16 = 0xefff800000000000 + 0x0fffffb80aaaaaaa = 0xffff7fb80aaaaaaa

So far this has gone unnoticed, as only the top byte of the shadow address is miscalculated and Software Tag-Based KASAN requires TBI (Top Byte Ignore) to be enabled.

This issue doesn't affect other mode/compiler combinations.
Comment 1 Marco Elver 2023-10-25 06:51:32 UTC
This looks like a Clang bug. It should probably be reported here:
https://github.com/ClangBuiltLinux/linux/issues
or here:
https://github.com/llvm/llvm-project/issues
Comment 2 Andrey Konovalov 2023-11-03 17:52:05 UTC
Reported: https://github.com/ClangBuiltLinux/linux/issues/1956

FTR, I noticed this bug when investigating why kasan_non_canonical_hook does not print a report in certain cases. Turned out it bailed out on the addr < KASAN_SHADOW_OFFSET check, which should not happen if the shadow address is calculated correctly.

I don't think it's worth it to try applying a workaround for kasan_non_canonical_hook to handle this buggy Clang behavior though.