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.
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
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.