[PATCH][ARM] Prevent stack guard address from being spilled

Akira Hatanaka ahatanak at gmail.com
Fri Jul 11 15:34:57 PDT 2014


The attached patch fixes a bug where the address of the stack guard was
being spilled to the stack, which is a potential security vulnerability
attackers can take advantage of.

Currently, instruction selection emits multiple load instructions in the
prologue to load the stack guard value, and then loads the value again in
the epilogue using a volatile load (the instruction defining %vreg7):

%vreg0<def> = LDRLIT_ga_pcrel <ga:@__stack_chk_guard>[TF=128]; GPR:%vreg0

%vreg1<def> = LDRi12 %vreg0<kill>, 0, pred:14, pred:%noreg; mem:LD4[GOT]
GPR:%vreg1,%vreg0

%vreg2<def> = LDRi12 %vreg1, 0, pred:14, pred:%noreg;
mem:LD4[@__stack_chk_guard] GPR:%vreg2,%vreg1

STRi12 %vreg2<kill>, <fi#0>, 0, pred:14, pred:%noreg; mem:Volatile
ST4[FixedStack0] GPR:%vreg2


...


%vreg7<def> = LDRi12 %vreg1<kill>, 0, pred:14, pred:%noreg; mem:Volatile
LD4[@__stack_chk_guard] GPR:%vreg7,%vreg1

%vreg8<def> = LDRi12 <fi#0>, 0, pred:14, pred:%noreg; mem:Volatile
LD4[FixedStack0] GPR:%vreg8

 %vreg9<def,dead> = SUBrr %vreg7<kill>, %vreg8<kill>, pred:14, pred:%noreg,
opt:%CPSR<def>; GPR:%vreg9,%vreg7,%vreg8

 Bcc <BB#1>, pred:1, pred:%CPSR<kill>



Register allocator then spills the interval holding the address (%vreg1).
The instruction that loads the address (the second instruction) cannot be
rematted because %vreg1 is not available at the location where it is used:

%R0<def> = LDRLIT_ga_pcrel <ga:@__stack_chk_guard>[TF=128]

%R0<def> = LDRi12 %R0<kill>, 0, pred:14, pred:%noreg; mem:LD4[GOT]

 STRi12 %R0, <fi#2>, 0, pred:14, pred:%noreg; mem:ST4[FixedStack2] // SPILL

%R0<def> = LDRi12 %R0<kill>, 0, pred:14, pred:%noreg;
mem:LD4[@__stack_chk_guard]

STRi12 %R0<kill>, <fi#0>, 0, pred:14, pred:%noreg; mem:Volatile
ST4[FixedStack0]


...


%R0<def> = LDRi12 <fi#2>, 0, pred:14, pred:%noreg; mem:LD4[FixedStack2] //
RELOAD

%R0<def> = LDRi12 %R0<kill>, 0, pred:14, pred:%noreg; mem:Volatile
LD4[@__stack_chk_guard]

 %R1<def> = LDRi12 <fi#0>, 0, pred:14, pred:%noreg; mem:Volatile
LD4[FixedStack0]

%R0<def,dead> = SUBrr %R0<kill>, %R1<kill>, pred:14, pred:%noreg,
opt:%CPSR<def>

Bcc <BB#1>, pred:1, pred:%CPSR<kill>


The fix in the attached patch defines a target-independent node
LOAD_STACK_GUARD and emits a single LOAD_STACK_GUARD node in the prologue
instead of emitting multiple loads:

 %vreg0<def> = LOAD_STACK_GUARD; mem:LD4[@__stack_chk_guard](align=0)
GPR:%vreg0

STRi12 %vreg0, <fi#0>, 0, pred:14, pred:%noreg; mem:Volatile
ST4[FixedStack0] GPR:%vreg0

...

%vreg3<def> = LDRi12 <fi#0>, 0, pred:14, pred:%noreg; mem:Volatile
LD4[FixedStack0] GPR:%vreg3

%vreg4<def,dead> = SUBrr %vreg0<kill>, %vreg3<kill>, pred:14, pred:%noreg,
opt:%CPSR<def>; GPR:%vreg4,%vreg0,%vreg3

Bcc <BB#1>, pred:1, pred:%CPSR<kill>

Since LOAD_STACK_GUARD is rematerializable, register allocator remats it
instead of spilling to the stack:


%R0<def> = LOAD_STACK_GUARD; mem:LD4[@__stack_chk_guard](align=0)

 STRi12 %R0<kill>, <fi#0>, 0, pred:14, pred:%noreg; mem:Volatile
ST4[FixedStack0]


...


%R0<def> = LDRi12 <fi#0>, 0, pred:14, pred:%noreg; mem:Volatile
LD4[FixedStack0]

%R1<def> = LOAD_STACK_GUARD; mem:LD4[@__stack_chk_guard](align=0) //
REMATTED

 %R0<def,dead> = SUBrr %R1<kill>, %R0<kill>, pred:14, pred:%noreg,
opt:%CPSR<def>

 Bcc <BB#1>, pred:1, pred:%CPSR<kill>

The LOAD_STACK_GUARD instruction is then expanded after register allocation:


%R0<def> = LDRLIT_ga_pcrel <ga:@__stack_chk_guard>[TF=128]

 %R0<def> = LDRi12 %R0<kill>, 0, pred:14, pred:%noreg; mem:LD4[GOT]

%R0<def> = LDRi12 %R0<kill>, 0, pred:14, pred:%noreg;
mem:LD4[@__stack_chk_guard](align=0)

 STRi12 %R0<kill>, %R7, -20, pred:14, pred:%noreg; mem:Volatile
ST4[FixedStack0]

...

%R0<def> = LDRi12 %R7, -20, pred:14, pred:%noreg; mem:Volatile
LD4[FixedStack0]

%R1<def> = LDRLIT_ga_pcrel <ga:@__stack_chk_guard>[TF=128]

%R1<def> = LDRi12 %R1<kill>, 0, pred:14, pred:%noreg; mem:LD4[GOT]

%R1<def> = LDRi12 %R1<kill>, 0, pred:14, pred:%noreg;
mem:LD4[@__stack_chk_guard](align=0)

%R0<def,dead> = SUBrr %R1<kill>, %R0<kill>, pred:14, pred:%noreg,
opt:%CPSR<def>

Bcc <BB#2>, pred:1, pred:%CPSR



The patch also changes code generation of AArch64 and X86-64 to emit
LOAD_STACK_GUARD. Although it's not necessary to do so (ARM and X86-64 both
emit pseudo instructions that are rematerializable for loading the stack
guard address), it removes the need to emit a (volatile) load in the
epilogue if the interval holding the stack guard value doesn't have to be
spilled.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20140711/c170b160/attachment.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: stackguard1.patch
Type: application/octet-stream
Size: 27451 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20140711/c170b160/attachment.obj>


More information about the llvm-commits mailing list