Problem with Kernel Address Sanitizer and data on stack

Stephan Mühlstrasser via Gcc-help <[email protected]> Tue, 30 Dec 2025 16:19:26 +0100
Newsgroups gmane.comp.gcc.help
Message-ID <[email protected]>
Hi,

I'm trying to implement the Kernel Address Sanitizer (KASan) for an 
AArch64 bare-metal target. If there's a better place to ask questions 
about KASan, please let me know. Also if there is documentation on KASan 
available I would be grateful for a pointer. So far I'm basing my work 
on other examples. I mainly use 
https://github.com/androidoffsec/baremetal_kasan as a reference.

The problem that I see with KASan and stack data is that starting with a 
certain size of the data on the stack it looks to me like the shadow 
memory for the valid area on the stack is not unpoisoned.

These are my assumptions:

With -fsanitize=kernel-address --param asan-stack=1 there should be code 
on entry into a function that generates red zones in the shadow memory 
around the valid data on the stack. The shadow memory corresponding to 
the valid data on the stack should be "unpoisoned" by setting it to 0.

In my experiments I see the effect that starting with a certain data 
size the unpoisoning seems to be missing.

Consider the following code:

$ cat mini.c
typedef struct
{
   char x[31];
} s_t;

char f() {
     s_t s;
     return s.x[99];
}

I'm compiling this with the "Arm GNU Toolchain 14.3.Rel1 (Build 
arm-14.174)".

$ aarch64-none-elf-gcc -nostdinc -fsanitize=kernel-address --param 
asan-globals=1 --param asan-stack=1 -fno-builtin 
-fasan-shadow-offset=0x37000000 -mcpu=cortex-a53 	-O0 -g -ffreestanding 
--param asan-instrumentation-with-call-threshold=0 -mstrict-align -S 
-fverbose-asm -o mini-gcc.s mini.c

I think the following section in the generated code initializes the 
shadow memory (comments added by me):

lsr	x19, x0, 3	//
mov	x0, 922746880	// This is the asan-shadow-offset 0x37000000
add	x0, x19, x0	//
mov	w1, -235802127	// Poisoning red zone before with 0xf1f1f1f1
str	w1, [x0]	// Store poison
mov	w1, 117440512	// 0x7000000: poisoned/unpoisoned 32 byte block
str	w1, [x0, 4]	//
mov	w1, -202116109	// Poisoning red zone after with 0xf3f3f3f3
str	w1, [x0, 8]	// Store poison

Now I make the structure one byte larger:

typedef struct
{
   char x[32];
} s_t;

char f() {
     s_t s;
     return s.x[99];
}

Compiling this with the same command line as before results in this 
assembler code:

lsr	x19, x0, 3	//
mov	x0, 922746880	// This is the asan-shadow-offset 0x37000000
add	x0, x19, x0	//
mov	w1, -235802127	// Poisoning red zone before with 0xf1f1f1f1
str	w1, [x0]	// Store poison
mov	w1, -202116109	// Poisoning red zone after with 0xf3f3f3f3
str	w1, [x0, 8]	// Store poison

I don't see where the unpoisoning for the valid stack data area is 
happening now. And this is also the problem that I see when running a 
bare-metal program with Kernel Address Sanitizer enabled. I get 
sanitizer errors for valid access to stack data because the 
corresponding shadow memory has not been unpoisoned.

I'm not very proficient in Arm assembler, so I might be missing 
something, but this looks like a bug to me. Or do I need any further 
compiler options to make this work?

Thanks
Stephan