Skip to content

Commit 6c831c4

Browse files
Byte-LabAlexei Starovoitov
authored andcommitted
bpf: Treat KF_RELEASE kfuncs as KF_TRUSTED_ARGS
KF_RELEASE kfuncs are not currently treated as having KF_TRUSTED_ARGS, even though they have a superset of the requirements of KF_TRUSTED_ARGS. Like KF_TRUSTED_ARGS, KF_RELEASE kfuncs require a 0-offset argument, and don't allow NULL-able arguments. Unlike KF_TRUSTED_ARGS which require _either_ an argument with ref_obj_id > 0, _or_ (ref->type & BPF_REG_TRUSTED_MODIFIERS) (and no unsafe modifiers allowed), KF_RELEASE only allows for ref_obj_id > 0. Because KF_RELEASE today doesn't automatically imply KF_TRUSTED_ARGS, some of these requirements are enforced in different ways that can make the behavior of the verifier feel unpredictable. For example, a KF_RELEASE kfunc with a NULL-able argument will currently fail in the verifier with a message like, "arg#0 is ptr_or_null_ expected ptr_ or socket" rather than "Possibly NULL pointer passed to trusted arg0". Our intention is the same, but the semantics are different due to implemenetation details that kfunc authors and BPF program writers should not need to care about. Let's make the behavior of the verifier more consistent and intuitive by having KF_RELEASE kfuncs imply the presence of KF_TRUSTED_ARGS. Our eventual goal is to have all kfuncs assume KF_TRUSTED_ARGS by default anyways, so this takes us a step in that direction. Note that it does not make sense to assume KF_TRUSTED_ARGS for all KF_ACQUIRE kfuncs. KF_ACQUIRE kfuncs can have looser semantics than KF_RELEASE, with e.g. KF_RCU | KF_RET_NULL. We may want to have KF_ACQUIRE imply KF_TRUSTED_ARGS _unless_ KF_RCU is specified, but that can be left to another patch set, and there are no such subtleties to address for KF_RELEASE. Signed-off-by: David Vernet <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent fb2211a commit 6c831c4

File tree

8 files changed

+27
-16
lines changed

8 files changed

+27
-16
lines changed

Documentation/bpf/kfuncs.rst

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -179,9 +179,10 @@ both are orthogonal to each other.
179179
---------------------
180180

181181
The KF_RELEASE flag is used to indicate that the kfunc releases the pointer
182-
passed in to it. There can be only one referenced pointer that can be passed in.
183-
All copies of the pointer being released are invalidated as a result of invoking
184-
kfunc with this flag.
182+
passed in to it. There can be only one referenced pointer that can be passed
183+
in. All copies of the pointer being released are invalidated as a result of
184+
invoking kfunc with this flag. KF_RELEASE kfuncs automatically receive the
185+
protection afforded by the KF_TRUSTED_ARGS flag described below.
185186

186187
2.4.4 KF_KPTR_GET flag
187188
----------------------

kernel/bpf/cpumask.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,7 @@ __diag_pop();
402402

403403
BTF_SET8_START(cpumask_kfunc_btf_ids)
404404
BTF_ID_FLAGS(func, bpf_cpumask_create, KF_ACQUIRE | KF_RET_NULL)
405-
BTF_ID_FLAGS(func, bpf_cpumask_release, KF_RELEASE | KF_TRUSTED_ARGS)
405+
BTF_ID_FLAGS(func, bpf_cpumask_release, KF_RELEASE)
406406
BTF_ID_FLAGS(func, bpf_cpumask_acquire, KF_ACQUIRE | KF_TRUSTED_ARGS)
407407
BTF_ID_FLAGS(func, bpf_cpumask_first, KF_RCU)
408408
BTF_ID_FLAGS(func, bpf_cpumask_first_zero, KF_RCU)

kernel/bpf/verifier.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9307,7 +9307,7 @@ static bool is_kfunc_release(struct bpf_kfunc_call_arg_meta *meta)
93079307

93089308
static bool is_kfunc_trusted_args(struct bpf_kfunc_call_arg_meta *meta)
93099309
{
9310-
return meta->kfunc_flags & KF_TRUSTED_ARGS;
9310+
return (meta->kfunc_flags & KF_TRUSTED_ARGS) || is_kfunc_release(meta);
93119311
}
93129312

93139313
static bool is_kfunc_sleepable(struct bpf_kfunc_call_arg_meta *meta)

net/bpf/test_run.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,11 @@ bpf_kfunc_call_test_acquire(unsigned long *scalar_ptr)
606606
return &prog_test_struct;
607607
}
608608

609+
__bpf_kfunc void bpf_kfunc_call_test_offset(struct prog_test_ref_kfunc *p)
610+
{
611+
WARN_ON_ONCE(1);
612+
}
613+
609614
__bpf_kfunc struct prog_test_member *
610615
bpf_kfunc_call_memb_acquire(void)
611616
{
@@ -800,6 +805,7 @@ BTF_ID_FLAGS(func, bpf_kfunc_call_test_mem_len_fail2)
800805
BTF_ID_FLAGS(func, bpf_kfunc_call_test_ref, KF_TRUSTED_ARGS | KF_RCU)
801806
BTF_ID_FLAGS(func, bpf_kfunc_call_test_destructive, KF_DESTRUCTIVE)
802807
BTF_ID_FLAGS(func, bpf_kfunc_call_test_static_unused_arg)
808+
BTF_ID_FLAGS(func, bpf_kfunc_call_test_offset)
803809
BTF_SET8_END(test_sk_check_kfunc_ids)
804810

805811
static void *bpf_test_init(const union bpf_attr *kattr, u32 user_size,

tools/testing/selftests/bpf/progs/cgrp_kfunc_failure.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ int BPF_PROG(cgrp_kfunc_get_unreleased, struct cgroup *cgrp, const char *path)
206206
}
207207

208208
SEC("tp_btf/cgroup_mkdir")
209-
__failure __msg("expects refcounted")
209+
__failure __msg("Possibly NULL pointer passed to trusted arg0")
210210
int BPF_PROG(cgrp_kfunc_release_untrusted, struct cgroup *cgrp, const char *path)
211211
{
212212
struct __cgrps_kfunc_map_value *v;
@@ -234,7 +234,7 @@ int BPF_PROG(cgrp_kfunc_release_fp, struct cgroup *cgrp, const char *path)
234234
}
235235

236236
SEC("tp_btf/cgroup_mkdir")
237-
__failure __msg("arg#0 is ptr_or_null_ expected ptr_ or socket")
237+
__failure __msg("Possibly NULL pointer passed to trusted arg0")
238238
int BPF_PROG(cgrp_kfunc_release_null, struct cgroup *cgrp, const char *path)
239239
{
240240
struct __cgrps_kfunc_map_value local, *v;

tools/testing/selftests/bpf/progs/task_kfunc_failure.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ int BPF_PROG(task_kfunc_get_unreleased, struct task_struct *task, u64 clone_flag
206206
}
207207

208208
SEC("tp_btf/task_newtask")
209-
__failure __msg("arg#0 is untrusted_ptr_or_null_ expected ptr_ or socket")
209+
__failure __msg("Possibly NULL pointer passed to trusted arg0")
210210
int BPF_PROG(task_kfunc_release_untrusted, struct task_struct *task, u64 clone_flags)
211211
{
212212
struct __tasks_kfunc_map_value *v;
@@ -234,7 +234,7 @@ int BPF_PROG(task_kfunc_release_fp, struct task_struct *task, u64 clone_flags)
234234
}
235235

236236
SEC("tp_btf/task_newtask")
237-
__failure __msg("arg#0 is ptr_or_null_ expected ptr_ or socket")
237+
__failure __msg("Possibly NULL pointer passed to trusted arg0")
238238
int BPF_PROG(task_kfunc_release_null, struct task_struct *task, u64 clone_flags)
239239
{
240240
struct __tasks_kfunc_map_value local, *v;
@@ -277,7 +277,7 @@ int BPF_PROG(task_kfunc_release_unacquired, struct task_struct *task, u64 clone_
277277
}
278278

279279
SEC("tp_btf/task_newtask")
280-
__failure __msg("arg#0 is ptr_or_null_ expected ptr_ or socket")
280+
__failure __msg("Possibly NULL pointer passed to trusted arg0")
281281
int BPF_PROG(task_kfunc_from_pid_no_null_check, struct task_struct *task, u64 clone_flags)
282282
{
283283
struct task_struct *acquired;

tools/testing/selftests/bpf/verifier/calls.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@
109109
},
110110
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
111111
.result = REJECT,
112-
.errstr = "arg#0 is ptr_or_null_ expected ptr_ or socket",
112+
.errstr = "Possibly NULL pointer passed to trusted arg0",
113113
.fixup_kfunc_btf_id = {
114114
{ "bpf_kfunc_call_test_acquire", 3 },
115115
{ "bpf_kfunc_call_test_release", 5 },
@@ -165,19 +165,23 @@
165165
BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8),
166166
BPF_ST_MEM(BPF_DW, BPF_REG_1, 0, 0),
167167
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, BPF_PSEUDO_KFUNC_CALL, 0, 0),
168+
BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
168169
BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
169170
BPF_EXIT_INSN(),
170171
BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
171-
BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_1, 16),
172172
BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -4),
173173
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, BPF_PSEUDO_KFUNC_CALL, 0, 0),
174174
BPF_MOV64_IMM(BPF_REG_0, 0),
175+
BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
176+
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, BPF_PSEUDO_KFUNC_CALL, 0, 0),
177+
BPF_MOV64_IMM(BPF_REG_0, 0),
175178
BPF_EXIT_INSN(),
176179
},
177180
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
178181
.fixup_kfunc_btf_id = {
179182
{ "bpf_kfunc_call_test_acquire", 3 },
180-
{ "bpf_kfunc_call_test_release", 9 },
183+
{ "bpf_kfunc_call_test_offset", 9 },
184+
{ "bpf_kfunc_call_test_release", 12 },
181185
},
182186
.result_unpriv = REJECT,
183187
.result = REJECT,

tools/testing/selftests/bpf/verifier/ref_tracking.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@
142142
.kfunc = "bpf",
143143
.expected_attach_type = BPF_LSM_MAC,
144144
.flags = BPF_F_SLEEPABLE,
145-
.errstr = "arg#0 is ptr_or_null_ expected ptr_ or socket",
145+
.errstr = "Possibly NULL pointer passed to trusted arg0",
146146
.fixup_kfunc_btf_id = {
147147
{ "bpf_lookup_user_key", 2 },
148148
{ "bpf_key_put", 4 },
@@ -163,7 +163,7 @@
163163
.kfunc = "bpf",
164164
.expected_attach_type = BPF_LSM_MAC,
165165
.flags = BPF_F_SLEEPABLE,
166-
.errstr = "arg#0 is ptr_or_null_ expected ptr_ or socket",
166+
.errstr = "Possibly NULL pointer passed to trusted arg0",
167167
.fixup_kfunc_btf_id = {
168168
{ "bpf_lookup_system_key", 1 },
169169
{ "bpf_key_put", 3 },
@@ -182,7 +182,7 @@
182182
.kfunc = "bpf",
183183
.expected_attach_type = BPF_LSM_MAC,
184184
.flags = BPF_F_SLEEPABLE,
185-
.errstr = "arg#0 pointer type STRUCT bpf_key must point to scalar, or struct with scalar",
185+
.errstr = "Possibly NULL pointer passed to trusted arg0",
186186
.fixup_kfunc_btf_id = {
187187
{ "bpf_key_put", 1 },
188188
},

0 commit comments

Comments
 (0)