santoshn / softboundcets-34

SoftBoundCETS for LLVM+Clang version 34
BSD 3-Clause "New" or "Revised" License
56 stars 17 forks source link

SoftBoundCETS shadow stack metadata propagation is wrong when llvm optimizations remove arguments #8

Open jayPLim opened 8 years ago

jayPLim commented 8 years ago

I found a bug with softboundcets when llvm optimization removes function arguments. Softboundcets is retrieving function argument base and bound by using the position of the function argument as a reference, but when llvm optimization removes function arguments, softboundcets base and bound retrieving function does not change the index of the function argument.

Here is an example: In unoptimized code:

define internal void @foo(i32* %pwidth, i32* %ptype) #1 {
entry:
  %0 = call i8* @__softboundcets_load_base_shadow_stack(i32 2)
  %1 = call i8* @__softboundcets_load_bound_shadow_stack(i32 2)
  %2 = call i64 @__softboundcets_load_key_shadow_stack(i32 2)
  %3 = call i8* @__softboundcets_load_lock_shadow_stack(i32 2)
  %4 = call i8* @__softboundcets_load_base_shadow_stack(i32 1)
  %5 = call i8* @__softboundcets_load_bound_shadow_stack(i32 1)
  %6 = call i64 @__softboundcets_load_key_shadow_stack(i32 1)
  %7 = call i8* @__softboundcets_load_lock_shadow_stack(i32 1)
  %8 = call i8* @__softboundcets_get_global_lock()

...

  %bitcast8 = bitcast i32* %ptype to i8*
  %cmp.i = icmp ult i8* %bitcast8, %0, !tv.orig !1
  %add.ptr.i1 = getelementptr inbounds i8, i8* %bitcast8, i64 ptrtoint (i32* getelementptr (i32, i32* null, i32 1) to i64), !tv.orig !1
  %cmp1.i2 = icmp ugt i8* %add.ptr.i1, %1, !tv.orig !1
  %or.cond.i = or i1 %cmp.i, %cmp1.i2
  br i1 %or.cond.i, label %if.then.i3, label %__softboundcets_spatial_store_dereference_check.exit, !tv.orig !1

And in optimized code (ran with O1)

define internal fastcc void @foo(i32* %ptype) unnamed_addr #1 {
entry:
  %0 = tail call fastcc i8* @__softboundcets_load_base_shadow_stack(i32 2)
  %1 = tail call fastcc i8* @__softboundcets_load_bound_shadow_stack(i32 2)
  %2 = tail call fastcc i64 @__softboundcets_load_key_shadow_stack(i32 2)
  %3 = tail call fastcc i8* @__softboundcets_load_lock_shadow_stack(i32 2)
  %4 = tail call fastcc i8* @__softboundcets_load_base_shadow_stack(i32 1)
  %5 = tail call fastcc i8* @__softboundcets_load_bound_shadow_stack(i32 1)
  %6 = tail call fastcc i64 @__softboundcets_load_key_shadow_stack(i32 1)
  %7 = tail call fastcc i8* @__softboundcets_load_lock_shadow_stack(i32 1)

...

  %bitcast8 = bitcast i32* %ptype to i8*
  %cmp.i = icmp ult i8* %bitcast8, %0, !tv.orig !1
  %add.ptr.i11 = getelementptr inbounds i32, i32* %ptype, i64 1
  %add.ptr.i1 = bitcast i32* %add.ptr.i11 to i8*
  %cmp1.i2 = icmp ugt i8* %add.ptr.i1, %1, !tv.orig !1
  %or.cond.i = or i1 %cmp.i, %cmp1.i2
  br i1 %or.cond.i, label %if.then.i3, label %__softboundcets_spatial_store_dereference_check.exit, !tv.orig !1

In both cases softboundcets checks the base and bound of ptype by using the 2nd function argument's base and bound. However, in optimized code, there is no second argument. ptype is the first argument.

santoshn commented 8 years ago

This is a valid bug. Probably this is the bug that is causing a significant number of false violations with the use of compiler optimizations.