Commit eed807f6 authored by Kumar Kartikeya Dwivedi's avatar Kumar Kartikeya Dwivedi Committed by Alexei Starovoitov

bpf: Tweak definition of KF_TRUSTED_ARGS

Instead of forcing all arguments to be referenced pointers with non-zero
reg->ref_obj_id, tweak the definition of KF_TRUSTED_ARGS to mean that
only PTR_TO_BTF_ID (and socket types translated to PTR_TO_BTF_ID) have
that constraint, and require their offset to be set to 0.

The rest of pointer types are also accomodated in this definition of
trusted pointers, but with more relaxed rules regarding offsets.

The inherent meaning of setting this flag is that all kfunc pointer
arguments have a guranteed lifetime, and kernel object pointers
(PTR_TO_BTF_ID, PTR_TO_CTX) are passed in their unmodified form (with
offset 0). In general, this is not true for PTR_TO_BTF_ID as it can be
obtained using pointer walks.
Signed-off-by: default avatarKumar Kartikeya Dwivedi <memxor@gmail.com>
Signed-off-by: default avatarLorenzo Bianconi <lorenzo@kernel.org>
Link: https://lore.kernel.org/r/cdede0043c47ed7a357f0a915d16f9ce06a1d589.1663778601.git.lorenzo@kernel.orgSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent 1d8b82c6
...@@ -137,14 +137,22 @@ KF_ACQUIRE and KF_RET_NULL flags. ...@@ -137,14 +137,22 @@ KF_ACQUIRE and KF_RET_NULL flags.
-------------------------- --------------------------
The KF_TRUSTED_ARGS flag is used for kfuncs taking pointer arguments. It The KF_TRUSTED_ARGS flag is used for kfuncs taking pointer arguments. It
indicates that the all pointer arguments will always be refcounted, and have indicates that the all pointer arguments will always have a guaranteed lifetime,
their offset set to 0. It can be used to enforce that a pointer to a refcounted and pointers to kernel objects are always passed to helpers in their unmodified
object acquired from a kfunc or BPF helper is passed as an argument to this form (as obtained from acquire kfuncs).
kfunc without any modifications (e.g. pointer arithmetic) such that it is
trusted and points to the original object. This flag is often used for kfuncs It can be used to enforce that a pointer to a refcounted object acquired from a
that operate (change some property, perform some operation) on an object that kfunc or BPF helper is passed as an argument to this kfunc without any
was obtained using an acquire kfunc. Such kfuncs need an unchanged pointer to modifications (e.g. pointer arithmetic) such that it is trusted and points to
ensure the integrity of the operation being performed on the expected object. the original object.
Meanwhile, it is also allowed pass pointers to normal memory to such kfuncs,
but those can have a non-zero offset.
This flag is often used for kfuncs that operate (change some property, perform
some operation) on an object that was obtained using an acquire kfunc. Such
kfuncs need an unchanged pointer to ensure the integrity of the operation being
performed on the expected object.
2.4.6 KF_SLEEPABLE flag 2.4.6 KF_SLEEPABLE flag
----------------------- -----------------------
......
...@@ -6227,7 +6227,7 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, ...@@ -6227,7 +6227,7 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
bool processing_call) bool processing_call)
{ {
enum bpf_prog_type prog_type = resolve_prog_type(env->prog); enum bpf_prog_type prog_type = resolve_prog_type(env->prog);
bool rel = false, kptr_get = false, trusted_arg = false; bool rel = false, kptr_get = false, trusted_args = false;
bool sleepable = false; bool sleepable = false;
struct bpf_verifier_log *log = &env->log; struct bpf_verifier_log *log = &env->log;
u32 i, nargs, ref_id, ref_obj_id = 0; u32 i, nargs, ref_id, ref_obj_id = 0;
...@@ -6265,7 +6265,7 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, ...@@ -6265,7 +6265,7 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
/* Only kfunc can be release func */ /* Only kfunc can be release func */
rel = kfunc_meta->flags & KF_RELEASE; rel = kfunc_meta->flags & KF_RELEASE;
kptr_get = kfunc_meta->flags & KF_KPTR_GET; kptr_get = kfunc_meta->flags & KF_KPTR_GET;
trusted_arg = kfunc_meta->flags & KF_TRUSTED_ARGS; trusted_args = kfunc_meta->flags & KF_TRUSTED_ARGS;
sleepable = kfunc_meta->flags & KF_SLEEPABLE; sleepable = kfunc_meta->flags & KF_SLEEPABLE;
} }
...@@ -6276,6 +6276,7 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, ...@@ -6276,6 +6276,7 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
enum bpf_arg_type arg_type = ARG_DONTCARE; enum bpf_arg_type arg_type = ARG_DONTCARE;
u32 regno = i + 1; u32 regno = i + 1;
struct bpf_reg_state *reg = &regs[regno]; struct bpf_reg_state *reg = &regs[regno];
bool obj_ptr = false;
t = btf_type_skip_modifiers(btf, args[i].type, NULL); t = btf_type_skip_modifiers(btf, args[i].type, NULL);
if (btf_type_is_scalar(t)) { if (btf_type_is_scalar(t)) {
...@@ -6323,10 +6324,17 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, ...@@ -6323,10 +6324,17 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
return -EINVAL; return -EINVAL;
} }
/* These register types have special constraints wrt ref_obj_id
* and offset checks. The rest of trusted args don't.
*/
obj_ptr = reg->type == PTR_TO_CTX || reg->type == PTR_TO_BTF_ID ||
reg2btf_ids[base_type(reg->type)];
/* Check if argument must be a referenced pointer, args + i has /* Check if argument must be a referenced pointer, args + i has
* been verified to be a pointer (after skipping modifiers). * been verified to be a pointer (after skipping modifiers).
* PTR_TO_CTX is ok without having non-zero ref_obj_id.
*/ */
if (is_kfunc && trusted_arg && !reg->ref_obj_id) { if (is_kfunc && trusted_args && (obj_ptr && reg->type != PTR_TO_CTX) && !reg->ref_obj_id) {
bpf_log(log, "R%d must be referenced\n", regno); bpf_log(log, "R%d must be referenced\n", regno);
return -EINVAL; return -EINVAL;
} }
...@@ -6335,7 +6343,7 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, ...@@ -6335,7 +6343,7 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
ref_tname = btf_name_by_offset(btf, ref_t->name_off); ref_tname = btf_name_by_offset(btf, ref_t->name_off);
/* Trusted args have the same offset checks as release arguments */ /* Trusted args have the same offset checks as release arguments */
if (trusted_arg || (rel && reg->ref_obj_id)) if ((trusted_args && obj_ptr) || (rel && reg->ref_obj_id))
arg_type |= OBJ_RELEASE; arg_type |= OBJ_RELEASE;
ret = check_func_arg_reg_off(env, reg, regno, arg_type); ret = check_func_arg_reg_off(env, reg, regno, arg_type);
if (ret < 0) if (ret < 0)
...@@ -6435,7 +6443,7 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, ...@@ -6435,7 +6443,7 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
reg_ref_t->name_off); reg_ref_t->name_off);
if (!btf_struct_ids_match(log, reg_btf, reg_ref_id, if (!btf_struct_ids_match(log, reg_btf, reg_ref_id,
reg->off, btf, ref_id, reg->off, btf, ref_id,
trusted_arg || (rel && reg->ref_obj_id))) { trusted_args || (rel && reg->ref_obj_id))) {
bpf_log(log, "kernel function %s args#%d expected pointer to %s %s but R%d has a pointer to %s %s\n", bpf_log(log, "kernel function %s args#%d expected pointer to %s %s but R%d has a pointer to %s %s\n",
func_name, i, func_name, i,
btf_type_str(ref_t), ref_tname, btf_type_str(ref_t), ref_tname,
......
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