Commit 6788ab23 authored by Daniel Borkmann's avatar Daniel Borkmann

bpf: Generally fix helper register offset check

Right now the assertion on check_ptr_off_reg() is only enforced for register
types PTR_TO_CTX (and open coded also for PTR_TO_BTF_ID), however, this is
insufficient since many other PTR_TO_* register types such as PTR_TO_FUNC do
not handle/expect register offsets when passed to helper functions.

Given this can slip-through easily when adding new types, make this an explicit
allow-list and reject all other current and future types by default if this is
encountered.

Also, extend check_ptr_off_reg() to handle PTR_TO_BTF_ID as well instead of
duplicating it. For PTR_TO_BTF_ID, reg->off is used for BTF to match expected
BTF ids if struct offset is used. This part still needs to be allowed, but the
dynamic off from the tnum must be rejected.

Fixes: 69c087ba ("bpf: Add bpf_for_each_map_elem() helper")
Fixes: eaa6bcb7 ("bpf: Introduce bpf_per_cpu_ptr()")
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Acked-by: default avatarJohn Fastabend <john.fastabend@gmail.com>
Acked-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent d400a6cf
...@@ -3969,14 +3969,15 @@ static int get_callee_stack_depth(struct bpf_verifier_env *env, ...@@ -3969,14 +3969,15 @@ static int get_callee_stack_depth(struct bpf_verifier_env *env,
} }
#endif #endif
int check_ptr_off_reg(struct bpf_verifier_env *env, static int __check_ptr_off_reg(struct bpf_verifier_env *env,
const struct bpf_reg_state *reg, int regno) const struct bpf_reg_state *reg, int regno,
bool fixed_off_ok)
{ {
/* Access to this pointer-typed register or passing it to a helper /* Access to this pointer-typed register or passing it to a helper
* is only allowed in its original, unmodified form. * is only allowed in its original, unmodified form.
*/ */
if (reg->off) { if (!fixed_off_ok && reg->off) {
verbose(env, "dereference of modified %s ptr R%d off=%d disallowed\n", verbose(env, "dereference of modified %s ptr R%d off=%d disallowed\n",
reg_type_str(env, reg->type), regno, reg->off); reg_type_str(env, reg->type), regno, reg->off);
return -EACCES; return -EACCES;
...@@ -3994,6 +3995,12 @@ int check_ptr_off_reg(struct bpf_verifier_env *env, ...@@ -3994,6 +3995,12 @@ int check_ptr_off_reg(struct bpf_verifier_env *env,
return 0; return 0;
} }
int check_ptr_off_reg(struct bpf_verifier_env *env,
const struct bpf_reg_state *reg, int regno)
{
return __check_ptr_off_reg(env, reg, regno, false);
}
static int __check_buffer_access(struct bpf_verifier_env *env, static int __check_buffer_access(struct bpf_verifier_env *env,
const char *buf_info, const char *buf_info,
const struct bpf_reg_state *reg, const struct bpf_reg_state *reg,
...@@ -5245,12 +5252,6 @@ static int check_reg_type(struct bpf_verifier_env *env, u32 regno, ...@@ -5245,12 +5252,6 @@ static int check_reg_type(struct bpf_verifier_env *env, u32 regno,
kernel_type_name(btf_vmlinux, *arg_btf_id)); kernel_type_name(btf_vmlinux, *arg_btf_id));
return -EACCES; return -EACCES;
} }
if (!tnum_is_const(reg->var_off) || reg->var_off.value) {
verbose(env, "R%d is a pointer to in-kernel struct with non-zero offset\n",
regno);
return -EACCES;
}
} }
return 0; return 0;
...@@ -5305,10 +5306,26 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg, ...@@ -5305,10 +5306,26 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
if (err) if (err)
return err; return err;
if (type == PTR_TO_CTX) { switch ((u32)type) {
err = check_ptr_off_reg(env, reg, regno); case SCALAR_VALUE:
/* Pointer types where reg offset is explicitly allowed: */
case PTR_TO_PACKET:
case PTR_TO_PACKET_META:
case PTR_TO_MAP_KEY:
case PTR_TO_MAP_VALUE:
case PTR_TO_MEM:
case PTR_TO_MEM | MEM_RDONLY:
case PTR_TO_BUF:
case PTR_TO_BUF | MEM_RDONLY:
case PTR_TO_STACK:
break;
/* All the rest must be rejected: */
default:
err = __check_ptr_off_reg(env, reg, regno,
type == PTR_TO_BTF_ID);
if (err < 0) if (err < 0)
return err; return err;
break;
} }
skip_type_check: skip_type_check:
......
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