bpf: reject stores into ctx via st and xadd
[ upstream commit f37a8cb84cce18762e8f86a70bd6a49a66ab964c ] Alexei found that verifier does not reject stores into context via BPF_ST instead of BPF_STX. And while looking at it, we also should not allow XADD variant of BPF_STX. The context rewriter is only assuming either BPF_LDX_MEM- or BPF_STX_MEM-type operations, thus reject anything other than that so that assumptions in the rewriter properly hold. Add test cases as well for BPF selftests. Fixes: d691f9e8d440 ("bpf: allow programs to write to certain skb fields") Reported-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
ca0a096720
commit
a17536742b
@ -986,6 +986,13 @@ static bool is_pointer_value(struct bpf_verifier_env *env, int regno)
|
||||
return __is_pointer_value(env->allow_ptr_leaks, &env->cur_state.regs[regno]);
|
||||
}
|
||||
|
||||
static bool is_ctx_reg(struct bpf_verifier_env *env, int regno)
|
||||
{
|
||||
const struct bpf_reg_state *reg = &env->cur_state.regs[regno];
|
||||
|
||||
return reg->type == PTR_TO_CTX;
|
||||
}
|
||||
|
||||
static int check_pkt_ptr_alignment(const struct bpf_reg_state *reg,
|
||||
int off, int size, bool strict)
|
||||
{
|
||||
@ -1258,6 +1265,12 @@ static int check_xadd(struct bpf_verifier_env *env, int insn_idx, struct bpf_ins
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
if (is_ctx_reg(env, insn->dst_reg)) {
|
||||
verbose("BPF_XADD stores into R%d context is not allowed\n",
|
||||
insn->dst_reg);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
/* check whether atomic_add can read the memory */
|
||||
err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
|
||||
BPF_SIZE(insn->code), BPF_READ, -1);
|
||||
@ -3859,6 +3872,12 @@ static int do_check(struct bpf_verifier_env *env)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (is_ctx_reg(env, insn->dst_reg)) {
|
||||
verbose("BPF_ST stores into R%d context is not allowed\n",
|
||||
insn->dst_reg);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
/* check that memory (dst_reg + off) is writeable */
|
||||
err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
|
||||
BPF_SIZE(insn->code), BPF_WRITE,
|
||||
|
@ -2595,6 +2595,29 @@ static struct bpf_test tests[] = {
|
||||
.result = ACCEPT,
|
||||
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
|
||||
},
|
||||
{
|
||||
"context stores via ST",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_1, offsetof(struct __sk_buff, mark), 0),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.errstr = "BPF_ST stores into R1 context is not allowed",
|
||||
.result = REJECT,
|
||||
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
|
||||
},
|
||||
{
|
||||
"context stores via XADD",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_RAW_INSN(BPF_STX | BPF_XADD | BPF_W, BPF_REG_1,
|
||||
BPF_REG_0, offsetof(struct __sk_buff, mark), 0),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.errstr = "BPF_XADD stores into R1 context is not allowed",
|
||||
.result = REJECT,
|
||||
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
|
||||
},
|
||||
{
|
||||
"direct packet access: test1",
|
||||
.insns = {
|
||||
@ -4317,7 +4340,8 @@ static struct bpf_test tests[] = {
|
||||
.fixup_map1 = { 2 },
|
||||
.errstr_unpriv = "R2 leaks addr into mem",
|
||||
.result_unpriv = REJECT,
|
||||
.result = ACCEPT,
|
||||
.result = REJECT,
|
||||
.errstr = "BPF_XADD stores into R1 context is not allowed",
|
||||
},
|
||||
{
|
||||
"leak pointer into ctx 2",
|
||||
@ -4331,7 +4355,8 @@ static struct bpf_test tests[] = {
|
||||
},
|
||||
.errstr_unpriv = "R10 leaks addr into mem",
|
||||
.result_unpriv = REJECT,
|
||||
.result = ACCEPT,
|
||||
.result = REJECT,
|
||||
.errstr = "BPF_XADD stores into R1 context is not allowed",
|
||||
},
|
||||
{
|
||||
"leak pointer into ctx 3",
|
||||
|
Loading…
x
Reference in New Issue
Block a user