|
@@ -1356,6 +1356,13 @@ static bool is_ctx_reg(struct bpf_verifier_env *env, int regno)
|
|
|
return reg->type == PTR_TO_CTX;
|
|
|
}
|
|
|
|
|
|
+static bool is_pkt_reg(struct bpf_verifier_env *env, int regno)
|
|
|
+{
|
|
|
+ const struct bpf_reg_state *reg = cur_regs(env) + regno;
|
|
|
+
|
|
|
+ return type_is_pkt_pointer(reg->type);
|
|
|
+}
|
|
|
+
|
|
|
static int check_pkt_ptr_alignment(struct bpf_verifier_env *env,
|
|
|
const struct bpf_reg_state *reg,
|
|
|
int off, int size, bool strict)
|
|
@@ -1416,10 +1423,10 @@ static int check_generic_ptr_alignment(struct bpf_verifier_env *env,
|
|
|
}
|
|
|
|
|
|
static int check_ptr_alignment(struct bpf_verifier_env *env,
|
|
|
- const struct bpf_reg_state *reg,
|
|
|
- int off, int size)
|
|
|
+ const struct bpf_reg_state *reg, int off,
|
|
|
+ int size, bool strict_alignment_once)
|
|
|
{
|
|
|
- bool strict = env->strict_alignment;
|
|
|
+ bool strict = env->strict_alignment || strict_alignment_once;
|
|
|
const char *pointer_desc = "";
|
|
|
|
|
|
switch (reg->type) {
|
|
@@ -1576,9 +1583,9 @@ static void coerce_reg_to_size(struct bpf_reg_state *reg, int size)
|
|
|
* if t==write && value_regno==-1, some unknown value is stored into memory
|
|
|
* if t==read && value_regno==-1, don't care what we read from memory
|
|
|
*/
|
|
|
-static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regno, int off,
|
|
|
- int bpf_size, enum bpf_access_type t,
|
|
|
- int value_regno)
|
|
|
+static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regno,
|
|
|
+ int off, int bpf_size, enum bpf_access_type t,
|
|
|
+ int value_regno, bool strict_alignment_once)
|
|
|
{
|
|
|
struct bpf_reg_state *regs = cur_regs(env);
|
|
|
struct bpf_reg_state *reg = regs + regno;
|
|
@@ -1590,7 +1597,7 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
|
|
|
return size;
|
|
|
|
|
|
/* alignment checks will add in reg->off themselves */
|
|
|
- err = check_ptr_alignment(env, reg, off, size);
|
|
|
+ err = check_ptr_alignment(env, reg, off, size, strict_alignment_once);
|
|
|
if (err)
|
|
|
return err;
|
|
|
|
|
@@ -1735,21 +1742,23 @@ 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(env, "BPF_XADD stores into R%d context is not allowed\n",
|
|
|
- insn->dst_reg);
|
|
|
+ if (is_ctx_reg(env, insn->dst_reg) ||
|
|
|
+ is_pkt_reg(env, insn->dst_reg)) {
|
|
|
+ verbose(env, "BPF_XADD stores into R%d %s is not allowed\n",
|
|
|
+ insn->dst_reg, is_ctx_reg(env, insn->dst_reg) ?
|
|
|
+ "context" : "packet");
|
|
|
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);
|
|
|
+ BPF_SIZE(insn->code), BPF_READ, -1, true);
|
|
|
if (err)
|
|
|
return err;
|
|
|
|
|
|
/* check whether atomic_add can write into the same memory */
|
|
|
return check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
|
|
|
- BPF_SIZE(insn->code), BPF_WRITE, -1);
|
|
|
+ BPF_SIZE(insn->code), BPF_WRITE, -1, true);
|
|
|
}
|
|
|
|
|
|
/* when register 'regno' is passed into function that will read 'access_size'
|
|
@@ -2388,7 +2397,8 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn
|
|
|
* is inferred from register state.
|
|
|
*/
|
|
|
for (i = 0; i < meta.access_size; i++) {
|
|
|
- err = check_mem_access(env, insn_idx, meta.regno, i, BPF_B, BPF_WRITE, -1);
|
|
|
+ err = check_mem_access(env, insn_idx, meta.regno, i, BPF_B,
|
|
|
+ BPF_WRITE, -1, false);
|
|
|
if (err)
|
|
|
return err;
|
|
|
}
|
|
@@ -4632,7 +4642,7 @@ static int do_check(struct bpf_verifier_env *env)
|
|
|
*/
|
|
|
err = check_mem_access(env, insn_idx, insn->src_reg, insn->off,
|
|
|
BPF_SIZE(insn->code), BPF_READ,
|
|
|
- insn->dst_reg);
|
|
|
+ insn->dst_reg, false);
|
|
|
if (err)
|
|
|
return err;
|
|
|
|
|
@@ -4684,7 +4694,7 @@ static int do_check(struct bpf_verifier_env *env)
|
|
|
/* 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,
|
|
|
- insn->src_reg);
|
|
|
+ insn->src_reg, false);
|
|
|
if (err)
|
|
|
return err;
|
|
|
|
|
@@ -4719,7 +4729,7 @@ static int do_check(struct bpf_verifier_env *env)
|
|
|
/* 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,
|
|
|
- -1);
|
|
|
+ -1, false);
|
|
|
if (err)
|
|
|
return err;
|
|
|
|