Skip to content

Commit

Permalink
Havoc register if truncating non-number
Browse files Browse the repository at this point in the history
Signed-off-by: Alan Jowett <[email protected]>
  • Loading branch information
Alan Jowett committed Oct 25, 2024
1 parent 3308618 commit ae600cc
Show file tree
Hide file tree
Showing 3 changed files with 364 additions and 0 deletions.
6 changes: 6 additions & 0 deletions src/crab/ebpf_domain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2497,6 +2497,12 @@ void ebpf_domain_t::operator()(const Bin& bin) {
// Use only the low 32 bits of the value.
imm = gsl::narrow_cast<int32_t>(pimm->v);
bitwise_and(dst.svalue, dst.uvalue, std::numeric_limits<uint32_t>::max());
// If this is a 32-bit operation and the destination is not a number, forget everything about the register.
if (!type_inv.has_type(m_inv, bin.dst, T_NUM)) {
havoc_register(m_inv, bin.dst);
havoc_offsets(bin.dst);
havoc(dst.type);
}
}
switch (bin.op) {
case Bin::Op::MOV:
Expand Down
1 change: 1 addition & 0 deletions src/test/test_yaml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ YAML_CASE("test-data/movsx.yaml")
YAML_CASE("test-data/muldiv.yaml")
YAML_CASE("test-data/packet.yaml")
YAML_CASE("test-data/parse.yaml")
YAML_CASE("test-data/pointer.yaml")
YAML_CASE("test-data/sext.yaml")
YAML_CASE("test-data/shift.yaml")
YAML_CASE("test-data/stack.yaml")
Expand Down
357 changes: 357 additions & 0 deletions test-data/pointer.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,357 @@
# Copyright (c) Prevail Verifier contributors.
# SPDX-License-Identifier: MIT
---
test-case: 32-bit pointer truncation - addition

pre:
- "r1.ctx_offset=0"
- "r1.svalue=[0, 4294967295]"
- "r1.svalue=r1.uvalue"
- "r1.type=ctx"
- "r1.uvalue=[0, 4294967295]"

# Trigger 32-bit ALU operation without changing the value
code:
<start>: |
w1 += 0
r2 = *(u32 *)(r1 + 0)
post: []

messages:
- "1: Invalid type (r1.type in {ctx, stack, packet, shared})"
- "1: Invalid type (valid_access(r1.offset, width=4) for read)"

---
test-case: 32-bit pointer truncation - subtraction

pre:
- "r1.ctx_offset=0"
- "r1.svalue=[0, 4294967295]"
- "r1.svalue=r1.uvalue"
- "r1.type=ctx"
- "r1.uvalue=[0, 4294967295]"

# Trigger 32-bit ALU operation without changing the value
code:
<start>: |
w1 -= 0
r2 = *(u32 *)(r1 + 0)
post: []

messages:
- "1: Invalid type (r1.type in {ctx, stack, packet, shared})"
- "1: Invalid type (valid_access(r1.offset, width=4) for read)"

---
test-case: 32-bit pointer truncation - multiplication

pre:
- "r1.ctx_offset=0"
- "r1.svalue=[0, 4294967295]"
- "r1.svalue=r1.uvalue"
- "r1.type=ctx"
- "r1.uvalue=[0, 4294967295]"

# Trigger 32-bit ALU operation without changing the value
code:
<start>: |
w1 *= 1
r2 = *(u32 *)(r1 + 0)
post:
- "r1.svalue=[0, 4294967295]"
- "r1.svalue=r1.uvalue"
- "r1.uvalue=[0, 4294967295]"

messages:
- "0: Invalid type (r1.type == number)"
- "1: Invalid type (r1.type in {ctx, stack, packet, shared})"
- "1: Invalid type (valid_access(r1.offset, width=4) for read)"

---
test-case: 32-bit pointer truncation - division

pre:
- "r1.ctx_offset=0"
- "r1.svalue=[0, 4294967295]"
- "r1.svalue=r1.uvalue"
- "r1.type=ctx"
- "r1.uvalue=[0, 4294967295]"

# Trigger 32-bit ALU operation without changing the value
code:
<start>: |
w1 /= 1
r2 = *(u32 *)(r1 + 0)
post:
- "r1.svalue=[0, 4294967295]"
- "r1.svalue=r1.uvalue"
- "r1.uvalue=[0, 4294967295]"

messages:
- "0: Invalid type (r1.type == number)"
- "1: Invalid type (r1.type in {ctx, stack, packet, shared})"
- "1: Invalid type (valid_access(r1.offset, width=4) for read)"

---
test-case: 32-bit pointer truncation - modulo

pre:
- "r1.ctx_offset=0"
- "r1.svalue=[0, 4294967295]"
- "r1.svalue=r1.uvalue"
- "r1.type=ctx"
- "r1.uvalue=[0, 4294967295]"

# Trigger 32-bit ALU operation without changing the value
code:
<start>: |
w1 %= 0
r2 = *(u32 *)(r1 + 0)
post:
- "r1.svalue=[0, 4294967295]"
- "r1.svalue=r1.uvalue"
- "r1.uvalue=[0, 4294967295]"

messages:
- "0: Invalid type (r1.type == number)"
- "1: Invalid type (r1.type in {ctx, stack, packet, shared})"
- "1: Invalid type (valid_access(r1.offset, width=4) for read)"

---
test-case: 32-bit pointer truncation - signed division

pre:
- "r1.ctx_offset=0"
- "r1.svalue=[0, 4294967295]"
- "r1.svalue=r1.uvalue"
- "r1.type=ctx"
- "r1.uvalue=[0, 4294967295]"

# Trigger 32-bit ALU operation without changing the value
code:
<start>: |
w1 s/= 1
r2 = *(u32 *)(r1 + 0)
post:
- "r1.svalue=[0, 4294967295]"
- "r1.svalue=r1.uvalue"
- "r1.uvalue=[0, 4294967295]"

messages:
- "0: Invalid type (r1.type == number)"
- "1: Invalid type (r1.type in {ctx, stack, packet, shared})"
- "1: Invalid type (valid_access(r1.offset, width=4) for read)"

---
test-case: 32-bit pointer truncation - signed modulo

pre:
- "r1.ctx_offset=0"
- "r1.svalue=[0, 4294967295]"
- "r1.svalue=r1.uvalue"
- "r1.type=ctx"
- "r1.uvalue=[0, 4294967295]"

# Trigger 32-bit ALU operation without changing the value
code:
<start>: |
w1 s%= 0
r2 = *(u32 *)(r1 + 0)
post:
- "r1.svalue=[0, 4294967295]"
- "r1.svalue=r1.uvalue"
- "r1.uvalue=[0, 4294967295]"

messages:
- "0: Invalid type (r1.type == number)"
- "1: Invalid type (r1.type in {ctx, stack, packet, shared})"
- "1: Invalid type (valid_access(r1.offset, width=4) for read)"

---
test-case: 32-bit pointer truncation - AND

pre:
- "r1.ctx_offset=0"
- "r1.svalue=[0, 4294967295]"
- "r1.svalue=r1.uvalue"
- "r1.type=ctx"
- "r1.uvalue=[0, 4294967295]"

# Trigger 32-bit ALU operation without changing the value
code:
<start>: |
w1 &= -1
r2 = *(u32 *)(r1 + 0)
post:
- "r1.svalue=[0, 4294967295]"
- "r1.svalue=r1.uvalue"
- "r1.uvalue=[0, 4294967295]"

messages:
- "0: Invalid type (r1.type == number)"
- "1: Invalid type (r1.type in {ctx, stack, packet, shared})"
- "1: Invalid type (valid_access(r1.offset, width=4) for read)"

---
test-case: 32-bit pointer truncation - OR

pre:
- "r1.ctx_offset=0"
- "r1.svalue=[0, 4294967295]"
- "r1.svalue=r1.uvalue"
- "r1.type=ctx"
- "r1.uvalue=[0, 4294967295]"

# Trigger 32-bit ALU operation without changing the value
code:
<start>: |
w1 |= 0
r2 = *(u32 *)(r1 + 0)
post:
- "r1.svalue=[0, 4294967295]"
- "r1.svalue=r1.uvalue"
- "r1.uvalue=[0, 4294967295]"

messages:
- "0: Invalid type (r1.type == number)"
- "1: Invalid type (r1.type in {ctx, stack, packet, shared})"
- "1: Invalid type (valid_access(r1.offset, width=4) for read)"

---
test-case: 32-bit pointer truncation - XOR

pre:
- "r1.ctx_offset=0"
- "r1.svalue=[0, 4294967295]"
- "r1.svalue=r1.uvalue"
- "r1.type=ctx"
- "r1.uvalue=[0, 4294967295]"

# Trigger 32-bit ALU operation without changing the value
code:
<start>: |
w1 ^= 0
r2 = *(u32 *)(r1 + 0)
post:
- "r1.svalue=[0, 4294967295]"
- "r1.svalue=r1.uvalue"
- "r1.uvalue=[0, 4294967295]"

messages:
- "0: Invalid type (r1.type == number)"
- "1: Invalid type (r1.type in {ctx, stack, packet, shared})"
- "1: Invalid type (valid_access(r1.offset, width=4) for read)"

---
test-case: 32-bit pointer truncation - LSH

pre:
- "r1.ctx_offset=0"
- "r1.svalue=[0, 4294967295]"
- "r1.svalue=r1.uvalue"
- "r1.type=ctx"
- "r1.uvalue=[0, 4294967295]"

# Trigger 32-bit ALU operation without changing the value
code:
<start>: |
w1 <<= 0
r2 = *(u32 *)(r1 + 0)
post:
- "r1.svalue=[0, 4294967295]"
- "r1.svalue=r1.uvalue"
- "r1.uvalue=[0, 4294967295]"

messages:
- "0: Invalid type (r1.type == number)"
- "1: Invalid type (r1.type in {ctx, stack, packet, shared})"
- "1: Invalid type (valid_access(r1.offset, width=4) for read)"

---
test-case: 32-bit pointer truncation - RSH

pre:
- "r1.ctx_offset=0"
- "r1.svalue=[0, 4294967295]"
- "r1.svalue=r1.uvalue"
- "r1.type=ctx"
- "r1.uvalue=[0, 4294967295]"

# Trigger 32-bit ALU operation without changing the value
code:
<start>: |
w1 >>= 0
r2 = *(u32 *)(r1 + 0)
post:
- "r1.svalue=[0, 4294967295]"
- "r1.svalue=r1.uvalue"
- "r1.uvalue=[0, 4294967295]"

messages:
- "0: Invalid type (r1.type == number)"
- "1: Invalid type (r1.type in {ctx, stack, packet, shared})"
- "1: Invalid type (valid_access(r1.offset, width=4) for read)"

---
test-case: 32-bit pointer truncation - ARSH

pre:
- "r1.ctx_offset=0"
- "r1.svalue=[0, 4294967295]"
- "r1.svalue=r1.uvalue"
- "r1.type=ctx"
- "r1.uvalue=[0, 4294967295]"

# Trigger 32-bit ALU operation without changing the value
code:
<start>: |
w1 s>>= 0
r2 = *(u32 *)(r1 + 0)
post:
- "r1.svalue=[0, 4294967295]"
- "r1.svalue=r1.uvalue"
- "r1.uvalue=[0, 4294967295]"

messages:
- "0: Invalid type (r1.type == number)"
- "1: Invalid type (r1.type in {ctx, stack, packet, shared})"
- "1: Invalid type (valid_access(r1.offset, width=4) for read)"

---
test-case: 32-bit pointer truncation - NOT

pre:
- "r1.ctx_offset=0"
- "r1.svalue=[0, 4294967295]"
- "r1.svalue=r1.uvalue"
- "r1.type=ctx"
- "r1.uvalue=[0, 4294967295]"

# Trigger 32-bit ALU operation without changing the value
code:
<start>: |
w1 = - w1
w1 = - w1
r2 = *(u32 *)(r1 + 0)
post:
- "r1.type=ctx"

messages:
- "0: Invalid type (r1.type == number)"
- "1: Invalid type (r1.type == number)"
- "2: Lower bound must be at least 0 (valid_access(r1.offset, width=4) for read)"
- "2: Upper bound must be at most 64 (valid_access(r1.offset, width=4) for read)"

0 comments on commit ae600cc

Please sign in to comment.