mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-19 02:34:01 +08:00
bpf: Preserve const register type on const OR alu ops
Occasionally, clang (e.g. version 3.8.1) translates a sum between two constant operands using a BPF_OR instead of a BPF_ADD. The verifier is currently not handling this scenario, and the destination register type becomes UNKNOWN_VALUE even if it's still storing a constant. As a result, the destination register cannot be used as argument to a helper function expecting a ARG_CONST_STACK_*, limiting some use cases. Modify the verifier to handle this case, and add a few tests to make sure all combinations are supported, and stack boundaries are still verified even with BPF_OR. Signed-off-by: Gianluca Borello <g.borello@gmail.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Acked-by: Daniel Borkmann <daniel@iogearbox.net> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
f0903ea371
commit
3c839744b3
@ -1481,14 +1481,19 @@ static int evaluate_reg_imm_alu(struct bpf_verifier_env *env,
|
||||
struct bpf_reg_state *src_reg = ®s[insn->src_reg];
|
||||
u8 opcode = BPF_OP(insn->code);
|
||||
|
||||
/* dst_reg->type == CONST_IMM here, simulate execution of 'add' insn.
|
||||
* Don't care about overflow or negative values, just add them
|
||||
/* dst_reg->type == CONST_IMM here, simulate execution of 'add'/'or'
|
||||
* insn. Don't care about overflow or negative values, just add them
|
||||
*/
|
||||
if (opcode == BPF_ADD && BPF_SRC(insn->code) == BPF_K)
|
||||
dst_reg->imm += insn->imm;
|
||||
else if (opcode == BPF_ADD && BPF_SRC(insn->code) == BPF_X &&
|
||||
src_reg->type == CONST_IMM)
|
||||
dst_reg->imm += src_reg->imm;
|
||||
else if (opcode == BPF_OR && BPF_SRC(insn->code) == BPF_K)
|
||||
dst_reg->imm |= insn->imm;
|
||||
else if (opcode == BPF_OR && BPF_SRC(insn->code) == BPF_X &&
|
||||
src_reg->type == CONST_IMM)
|
||||
dst_reg->imm |= src_reg->imm;
|
||||
else
|
||||
mark_reg_unknown_value(regs, insn->dst_reg);
|
||||
return 0;
|
||||
|
1
tools/testing/selftests/bpf/.gitignore
vendored
1
tools/testing/selftests/bpf/.gitignore
vendored
@ -1,2 +1,3 @@
|
||||
test_verifier
|
||||
test_maps
|
||||
test_lru_map
|
||||
|
@ -2683,6 +2683,66 @@ static struct bpf_test tests[] = {
|
||||
.errstr_unpriv = "R0 pointer arithmetic prohibited",
|
||||
.result_unpriv = REJECT,
|
||||
},
|
||||
{
|
||||
"constant register |= constant should keep constant type",
|
||||
.insns = {
|
||||
BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -48),
|
||||
BPF_MOV64_IMM(BPF_REG_2, 34),
|
||||
BPF_ALU64_IMM(BPF_OR, BPF_REG_2, 13),
|
||||
BPF_MOV64_IMM(BPF_REG_3, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_probe_read),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.result = ACCEPT,
|
||||
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
|
||||
},
|
||||
{
|
||||
"constant register |= constant should not bypass stack boundary checks",
|
||||
.insns = {
|
||||
BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -48),
|
||||
BPF_MOV64_IMM(BPF_REG_2, 34),
|
||||
BPF_ALU64_IMM(BPF_OR, BPF_REG_2, 24),
|
||||
BPF_MOV64_IMM(BPF_REG_3, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_probe_read),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.errstr = "invalid stack type R1 off=-48 access_size=58",
|
||||
.result = REJECT,
|
||||
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
|
||||
},
|
||||
{
|
||||
"constant register |= constant register should keep constant type",
|
||||
.insns = {
|
||||
BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -48),
|
||||
BPF_MOV64_IMM(BPF_REG_2, 34),
|
||||
BPF_MOV64_IMM(BPF_REG_4, 13),
|
||||
BPF_ALU64_REG(BPF_OR, BPF_REG_2, BPF_REG_4),
|
||||
BPF_MOV64_IMM(BPF_REG_3, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_probe_read),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.result = ACCEPT,
|
||||
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
|
||||
},
|
||||
{
|
||||
"constant register |= constant register should not bypass stack boundary checks",
|
||||
.insns = {
|
||||
BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -48),
|
||||
BPF_MOV64_IMM(BPF_REG_2, 34),
|
||||
BPF_MOV64_IMM(BPF_REG_4, 24),
|
||||
BPF_ALU64_REG(BPF_OR, BPF_REG_2, BPF_REG_4),
|
||||
BPF_MOV64_IMM(BPF_REG_3, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_probe_read),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.errstr = "invalid stack type R1 off=-48 access_size=58",
|
||||
.result = REJECT,
|
||||
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
|
||||
},
|
||||
};
|
||||
|
||||
static int probe_filter_length(const struct bpf_insn *fp)
|
||||
|
Loading…
Reference in New Issue
Block a user