Browse Source
* PCC: add checking of struct field types on loads and stores. Co-authored-by: Nick Fitzgerald <fitzgen@gmail.com> * PCC: check that blockparams uphold facts appropriately. Co-authored-by: Nick Fitzgerald <fitzgen@gmail.com> * PCC: infer facts based on types' value ranges; add a mock vmctx example. Co-authored-by: Nick Fitzgerald <fitzgen@gmail.com> * Fix formatting. * Add two fixes required by new default facts: - Allow any fact at all to subsume a trivially-true range fact that states a bitslice is within the maximum range for its width. - Clamp the maximum value of a bitslice at the maximum value for the slice's width. --------- Co-authored-by: Nick Fitzgerald <fitzgen@gmail.com>pch/bound_tcp_userland_buffer
Chris Fallin
1 year ago
committed by
GitHub
13 changed files with 497 additions and 91 deletions
@ -0,0 +1,19 @@ |
|||
test compile expect-fail |
|||
set enable_pcc=true |
|||
target aarch64 |
|||
|
|||
function %f0(i64, i32) -> i64 { |
|||
block0(v0 ! max(64, 0x100): i64, v1: i32): |
|||
v2 ! max(64, 0x100) = iconst.i64 0x100 |
|||
v3 ! max(64, 0x200) = iadd v0, v2 |
|||
brif v1, block1(v0), block2(v3) |
|||
|
|||
block1(v4 ! max(64, 0xff): i64): ;; shrink the range -- should be caught |
|||
jump block3(v4) |
|||
|
|||
block2(v5 ! max(64, 0x1ff): i64): |
|||
jump block3(v5) |
|||
|
|||
block3(v6 ! max(64, 1): i64): |
|||
return v6 |
|||
} |
@ -0,0 +1,19 @@ |
|||
test compile expect-fail |
|||
set enable_pcc=true |
|||
target aarch64 |
|||
|
|||
function %f0(i64) -> i64 { |
|||
mt0 = struct 8 { 0: i64 ! mem(mt1, 0) } |
|||
mt1 = memory 0x1_0000_0000 |
|||
block0(v0 ! mem(mt0, 0): i64): |
|||
v1 ! mem(mt1, 8) = load.i64 checked v0 |
|||
return v1 |
|||
} |
|||
|
|||
function %f1(i64, i64) { |
|||
mt0 = struct 8 { 0: i64 ! mem(mt1, 0) } |
|||
mt1 = memory 0x1_0000_0000 |
|||
block0(v0 ! mem(mt0, 0): i64, v1 ! mem(mt1, 8): i64): |
|||
store.i64 checked v1, v0 |
|||
return |
|||
} |
@ -0,0 +1,37 @@ |
|||
test compile expect-fail |
|||
set enable_pcc=true |
|||
target aarch64 |
|||
|
|||
;; Equivalent to a Wasm `i64.load` from a static memory. |
|||
function %f0(i64, i32) -> i64 { |
|||
;; mock vmctx struct: |
|||
mt0 = struct 8 { 0: i64 readonly ! mem(mt1, 0) } |
|||
;; mock static memory: 4GiB range, *but insufficient guard* |
|||
mt1 = memory 0x1_0000_0000 |
|||
|
|||
block0(v0 ! mem(mt0, 0): i64, v1: i32): |
|||
;; Compute the address: base + offset. Guard region (2GiB) is |
|||
;; sufficient for an 8-byte I64 load. |
|||
v2 ! mem(mt1, 0) = load.i64 checked v0+0 ;; base pointer |
|||
v3 ! max(64, 0xffff_ffff) = uextend.i64 v1 ;; offset |
|||
v4 ! mem(mt1, 0xffff_ffff) = iadd.i64 v2, v3 |
|||
v5 = load.i64 checked v4 |
|||
return v5 |
|||
} |
|||
|
|||
;; Equivalent to a Wasm `i64.load` from a static memory. |
|||
function %f1(i64, i32) -> i64 { |
|||
;; mock vmctx struct: |
|||
mt0 = struct 16 { 0: i64 readonly ! mem(mt1, 0), 8: i64 readonly } |
|||
;; mock static memory: 4GiB range, *but insufficient guard* |
|||
mt1 = memory 0x1_8000_0000 |
|||
|
|||
block0(v0 ! mem(mt0, 0): i64, v1: i32): |
|||
;; Compute the address: base + offset. Guard region (2GiB) is |
|||
;; sufficient for an 8-byte I64 load. |
|||
v2 ! mem(mt1, 0) = load.i64 checked v0+8 ;; base pointer, but the wrong one |
|||
v3 ! max(64, 0xffff_ffff) = uextend.i64 v1 ;; offset |
|||
v4 ! mem(mt1, 0xffff_ffff) = iadd.i64 v2, v3 |
|||
v5 = load.i64 checked v4 |
|||
return v5 |
|||
} |
@ -0,0 +1,19 @@ |
|||
test compile |
|||
set enable_pcc=true |
|||
target aarch64 |
|||
|
|||
function %f0(i64, i32) -> i64 { |
|||
block0(v0 ! max(64, 0x100): i64, v1: i32): |
|||
v2 ! max(64, 0x100) = iconst.i64 0x100 |
|||
v3 ! max(64, 0x200) = iadd v0, v2 |
|||
brif v1, block1(v0), block2(v3) |
|||
|
|||
block1(v4 ! max(64, 0x1000): i64): ;; broaden the range -- always allowed |
|||
jump block3(v4) |
|||
|
|||
block2(v5 ! max(64, 0x2000): i64): |
|||
jump block3(v5) |
|||
|
|||
block3(v6 ! max(64, 0x2001): i64): |
|||
return v6 |
|||
} |
@ -0,0 +1,19 @@ |
|||
test compile |
|||
set enable_pcc=true |
|||
target aarch64 |
|||
|
|||
function %f0(i64) -> i64 { |
|||
mt0 = struct 8 { 0: i64 ! mem(mt1, 0) } |
|||
mt1 = memory 0x1_0000_0000 |
|||
block0(v0 ! mem(mt0, 0): i64): |
|||
v1 ! mem(mt1, 0) = load.i64 checked v0 |
|||
return v1 |
|||
} |
|||
|
|||
function %f1(i64, i64) { |
|||
mt0 = struct 8 { 0: i64 ! mem(mt1, 0) } |
|||
mt1 = memory 0x1_0000_0000 |
|||
block0(v0 ! mem(mt0, 0): i64, v1 ! mem(mt1, 0): i64): |
|||
store.i64 checked v1, v0 |
|||
return |
|||
} |
@ -0,0 +1,20 @@ |
|||
test compile |
|||
set enable_pcc=true |
|||
target aarch64 |
|||
|
|||
;; Equivalent to a Wasm `i64.load` from a static memory. |
|||
function %f0(i64, i32) -> i64 { |
|||
;; mock vmctx struct: |
|||
mt0 = struct 8 { 0: i64 readonly ! mem(mt1, 0) } |
|||
;; mock static memory: 4GiB range, plus 2GiB guard |
|||
mt1 = memory 0x1_8000_0000 |
|||
|
|||
block0(v0 ! mem(mt0, 0): i64, v1: i32): |
|||
;; Compute the address: base + offset. Guard region (2GiB) is |
|||
;; sufficient for an 8-byte I64 load. |
|||
v2 ! mem(mt1, 0) = load.i64 checked v0+0 ;; base pointer |
|||
v3 ! max(64, 0xffff_ffff) = uextend.i64 v1 ;; offset |
|||
v4 ! mem(mt1, 0xffff_ffff) = iadd.i64 v2, v3 |
|||
v5 = load.i64 checked v4 |
|||
return v5 |
|||
} |
Loading…
Reference in new issue