Hi all,
I’m having trouble wrapping my head around hwasan instrumentation for specific alloca instructions. For the given (minimized reproducer) C code:
void func(const char *);
void trace(const char *str, ...) {
func(str);
}
I can generate the following IR:
; Compiled (from a near ToT clang) with:
; clang /tmp/test.c -fsanitize=hwaddress --target=aarch64-unknown-fuchsia -S -o - -mllvm --hwasan-instrument-with-calls=1 -mllvm --hwasan-generate-tags-with-calls=1 -emit-llvm
; Function Attrs: noinline nounwind optnone sanitize_hwaddress shadowcallstack sspstrong uwtable
define dso_local void @trace(i8* %0, ...) #0 {
%2 = call i8* asm "", "=r,0"(i8* null)
%3 = alloca i8*, align 8
%4 = ptrtoint i8** %3 to i64
call void @__hwasan_store8(i64 %4)
store i8* %0, i8** %3, align 8
%5 = ptrtoint i8** %3 to i64
call void @__hwasan_load8(i64 %5)
%6 = load i8*, i8** %3, align 8
call void @func(i8* %6) #2
ret void
}
This IR contains one load and store check on the %3 = alloca i8*, align 8
. The thing that confuses me is the alloca in this instance isn’t tagged, nor is shadow memory setup for it, but we still check a load/store on it. My understanding is that if shadow isn’t set up with a tag, then hwasan will likely throw an error on the first __hwasan_store8 from comparing an untagged pointer against a value at an arbitrary shadow address which could be non-zero from some previous allocation. The above C code is a minimal reproducer for the case I ran into which I think might be a false-negative.
In the pass, it looks like hwasan will only instrument an alloca based on isInterestingAlloca()
, which is dependent on isAllocaPromotable()
returning false. All other requirements for isInterestingAlloca()
seem to be fulfilled except for this. Based on comments, it looks like we only want to instrument an alloca that is not promotable to a register. This looks to be the case since the alloca
seems to be lowered to space on the stack:
trace:
sub sp, sp, #256
str x30, [x18], #8
stp x29, x30, [sp, #240]
**add x29, sp, #240**
**str x0, [sp, #8]**
...
**sub x0, x29, #16**
bl __hwasan_store8 // x29 is offset into stack
**ldr x8, [sp, #8]**
**stur x8, [x29, #-16] // Load original arg onto stack**
...
At a glance, it looks like the store into the alloca isn’t an actual bug, so we shouldn’t need to instrument it. I’m thinking perhaps this is an issue regarding where to add load/store checks. HWASan has a similar function getInterestingMemoryOperands()
for determining interesting places to add checks before loads/stores, but it doesn’t seem to specifically if a load/store operand accepts one of these ignored allocas. Should there be extra checks to ensure that these allocas aren’t checked?
Thanks,
Leonard