Skip to content

Commit

Permalink
selftest/bpf: Verifier tests for var-off access
Browse files Browse the repository at this point in the history
commit 7a22930 upstream

Add tests for the new functionality - reading and writing to the stack
through a variable-offset pointer.

Signed-off-by: Andrei Matei <andreimatei1@gmail.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/20210207011027.676572-4-andreimatei1@gmail.com
Signed-off-by: Ovidiu Panait <ovidiu.panait@windriver.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
andreimatei authored and gregkh committed Aug 8, 2021
1 parent 30ea1c5 commit 7254e2d
Showing 1 changed file with 97 additions and 2 deletions.
99 changes: 97 additions & 2 deletions tools/testing/selftests/bpf/verifier/var_off.c
Expand Up @@ -31,14 +31,109 @@
* we don't know which
*/
BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
/* dereference it */
/* dereference it for a stack read */
BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_2, 0),
BPF_MOV64_IMM(BPF_REG_0, 0),
BPF_EXIT_INSN(),
},
.result = ACCEPT,
.result_unpriv = REJECT,
.errstr_unpriv = "R2 variable stack access prohibited for !root",
.prog_type = BPF_PROG_TYPE_CGROUP_SKB,
},
{
"variable-offset stack read, uninitialized",
.insns = {
/* Get an unknown value */
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
/* Make it small and 4-byte aligned */
BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4),
BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 8),
/* add it to fp. We now have either fp-4 or fp-8, but
* we don't know which
*/
BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
/* dereference it for a stack read */
BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_2, 0),
BPF_MOV64_IMM(BPF_REG_0, 0),
BPF_EXIT_INSN(),
},
.errstr = "variable stack access var_off=(0xfffffffffffffff8; 0x4)",
.result = REJECT,
.errstr = "invalid variable-offset read from stack R2",
.prog_type = BPF_PROG_TYPE_LWT_IN,
},
{
"variable-offset stack write, priv vs unpriv",
.insns = {
/* Get an unknown value */
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
/* Make it small and 8-byte aligned */
BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 8),
BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 16),
/* Add it to fp. We now have either fp-8 or fp-16, but
* we don't know which
*/
BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
/* Dereference it for a stack write */
BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
/* Now read from the address we just wrote. This shows
* that, after a variable-offset write, a priviledged
* program can read the slots that were in the range of
* that write (even if the verifier doesn't actually know
* if the slot being read was really written to or not.
*/
BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_2, 0),
BPF_MOV64_IMM(BPF_REG_0, 0),
BPF_EXIT_INSN(),
},
/* Variable stack access is rejected for unprivileged.
*/
.errstr_unpriv = "R2 variable stack access prohibited for !root",
.result_unpriv = REJECT,
.result = ACCEPT,
},
{
"variable-offset stack write clobbers spilled regs",
.insns = {
/* Dummy instruction; needed because we need to patch the next one
* and we can't patch the first instruction.
*/
BPF_MOV64_IMM(BPF_REG_6, 0),
/* Make R0 a map ptr */
BPF_LD_MAP_FD(BPF_REG_0, 0),
/* Get an unknown value */
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
/* Make it small and 8-byte aligned */
BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 8),
BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 16),
/* Add it to fp. We now have either fp-8 or fp-16, but
* we don't know which.
*/
BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
/* Spill R0(map ptr) into stack */
BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -8),
/* Dereference the unknown value for a stack write */
BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
/* Fill the register back into R2 */
BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_10, -8),
/* Try to dereference R2 for a memory load */
BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_2, 8),
BPF_EXIT_INSN(),
},
.fixup_map_hash_8b = { 1 },
/* The unpriviledged case is not too interesting; variable
* stack access is rejected.
*/
.errstr_unpriv = "R2 variable stack access prohibited for !root",
.result_unpriv = REJECT,
/* In the priviledged case, dereferencing a spilled-and-then-filled
* register is rejected because the previous variable offset stack
* write might have overwritten the spilled pointer (i.e. we lose track
* of the spilled register when we analyze the write).
*/
.errstr = "R2 invalid mem access 'inv'",
.result = REJECT,
},
{
"indirect variable-offset stack access, unbounded",
.insns = {
Expand Down

0 comments on commit 7254e2d

Please sign in to comment.