Commit f37a8cb8 authored by Daniel Borkmann's avatar Daniel Borkmann Committed by Alexei Starovoitov

bpf: reject stores into ctx via st and xadd

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: d691f9e8 ("bpf: allow programs to write to certain skb fields")
Reported-by: default avatarAlexei Starovoitov <ast@kernel.org>
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent a2284d91
...@@ -978,6 +978,13 @@ static bool is_pointer_value(struct bpf_verifier_env *env, int regno) ...@@ -978,6 +978,13 @@ static bool is_pointer_value(struct bpf_verifier_env *env, int regno)
return __is_pointer_value(env->allow_ptr_leaks, cur_regs(env) + regno); return __is_pointer_value(env->allow_ptr_leaks, cur_regs(env) + regno);
} }
static bool is_ctx_reg(struct bpf_verifier_env *env, int regno)
{
const struct bpf_reg_state *reg = cur_regs(env) + regno;
return reg->type == PTR_TO_CTX;
}
static int check_pkt_ptr_alignment(struct bpf_verifier_env *env, static int check_pkt_ptr_alignment(struct bpf_verifier_env *env,
const struct bpf_reg_state *reg, const struct bpf_reg_state *reg,
int off, int size, bool strict) 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 ...@@ -1258,6 +1265,12 @@ static int check_xadd(struct bpf_verifier_env *env, int insn_idx, struct bpf_ins
return -EACCES; return -EACCES;
} }
if (is_ctx_reg(env, insn->dst_reg)) {
verbose(env, "BPF_XADD stores into R%d context is not allowed\n",
insn->dst_reg);
return -EACCES;
}
/* check whether atomic_add can read the memory */ /* check whether atomic_add can read the memory */
err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off, err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
BPF_SIZE(insn->code), BPF_READ, -1); BPF_SIZE(insn->code), BPF_READ, -1);
...@@ -3993,6 +4006,12 @@ static int do_check(struct bpf_verifier_env *env) ...@@ -3993,6 +4006,12 @@ static int do_check(struct bpf_verifier_env *env)
if (err) if (err)
return err; return err;
if (is_ctx_reg(env, insn->dst_reg)) {
verbose(env, "BPF_ST stores into R%d context is not allowed\n",
insn->dst_reg);
return -EACCES;
}
/* check that memory (dst_reg + off) is writeable */ /* check that memory (dst_reg + off) is writeable */
err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off, err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
BPF_SIZE(insn->code), BPF_WRITE, BPF_SIZE(insn->code), BPF_WRITE,
......
...@@ -2592,6 +2592,29 @@ static struct bpf_test tests[] = { ...@@ -2592,6 +2592,29 @@ static struct bpf_test tests[] = {
.result = ACCEPT, .result = ACCEPT,
.prog_type = BPF_PROG_TYPE_SCHED_CLS, .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", "direct packet access: test1",
.insns = { .insns = {
...@@ -4312,7 +4335,8 @@ static struct bpf_test tests[] = { ...@@ -4312,7 +4335,8 @@ static struct bpf_test tests[] = {
.fixup_map1 = { 2 }, .fixup_map1 = { 2 },
.errstr_unpriv = "R2 leaks addr into mem", .errstr_unpriv = "R2 leaks addr into mem",
.result_unpriv = REJECT, .result_unpriv = REJECT,
.result = ACCEPT, .result = REJECT,
.errstr = "BPF_XADD stores into R1 context is not allowed",
}, },
{ {
"leak pointer into ctx 2", "leak pointer into ctx 2",
...@@ -4326,7 +4350,8 @@ static struct bpf_test tests[] = { ...@@ -4326,7 +4350,8 @@ static struct bpf_test tests[] = {
}, },
.errstr_unpriv = "R10 leaks addr into mem", .errstr_unpriv = "R10 leaks addr into mem",
.result_unpriv = REJECT, .result_unpriv = REJECT,
.result = ACCEPT, .result = REJECT,
.errstr = "BPF_XADD stores into R1 context is not allowed",
}, },
{ {
"leak pointer into ctx 3", "leak pointer into ctx 3",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment