[RFC PATCH bpf-next RESEND 02/16] bpf: Add KF_ITER_GETTER and KF_ITER_SETTER flags

From: Juntong Deng
Date: Thu Jul 11 2024 - 07:25:29 EST


Currently the only iterator flags are KF_ITER_NEW, KF_ITER_NEXT,
KF_ITER_DESTROY, but we cannot get the iterator status information or
change the iterator status through constructor, next method, destructor.

For example, when iterating over process files, in addition to getting
a pointer to struct file, we may also want to get the file descriptor
corresponding to struct file.

Another example is when iterating over packet data, in addition to
getting the data, we may want to change the buffer we set.

In this patch, add KF_ITER_GETTER for getting iterator status
information and KF_ITER_SETTER for changing iterator status.

Signed-off-by: Juntong Deng <juntong.deng@xxxxxxxxxxx>
---
include/linux/btf.h | 4 +++-
kernel/bpf/btf.c | 30 +++++++++++++++++++++---------
kernel/bpf/verifier.c | 3 ++-
3 files changed, 26 insertions(+), 11 deletions(-)

diff --git a/include/linux/btf.h b/include/linux/btf.h
index cffb43133c68..323a74489562 100644
--- a/include/linux/btf.h
+++ b/include/linux/btf.h
@@ -70,11 +70,13 @@
#define KF_SLEEPABLE (1 << 5) /* kfunc may sleep */
#define KF_DESTRUCTIVE (1 << 6) /* kfunc performs destructive actions */
#define KF_RCU (1 << 7) /* kfunc takes either rcu or trusted pointer arguments */
-/* only one of KF_ITER_{NEW,NEXT,DESTROY} could be specified per kfunc */
+/* only one of KF_ITER_{NEW,NEXT,DESTROY,GETTER,SETTER} could be specified per kfunc */
#define KF_ITER_NEW (1 << 8) /* kfunc implements BPF iter constructor */
#define KF_ITER_NEXT (1 << 9) /* kfunc implements BPF iter next method */
#define KF_ITER_DESTROY (1 << 10) /* kfunc implements BPF iter destructor */
#define KF_RCU_PROTECTED (1 << 11) /* kfunc should be protected by rcu cs when they are invoked */
+#define KF_ITER_GETTER (1 << 12) /* kfunc implements BPF iter getter */
+#define KF_ITER_SETTER (1 << 13) /* kfunc implements BPF iter setter */

/*
* Tag marking a kernel function as a kfunc. This is meant to minimize the
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 306349ee3d6a..d053f058bd91 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -8054,14 +8054,15 @@ BTF_TRACING_TYPE_xxx
static int btf_check_iter_kfuncs(struct btf *btf, const char *func_name,
const struct btf_type *func, u32 func_flags)
{
- u32 flags = func_flags & (KF_ITER_NEW | KF_ITER_NEXT | KF_ITER_DESTROY);
+ u32 flags = func_flags & (KF_ITER_NEW | KF_ITER_NEXT | KF_ITER_DESTROY |
+ KF_ITER_GETTER | KF_ITER_SETTER);
const char *name, *sfx, *iter_name;
const struct btf_param *arg;
const struct btf_type *t;
char exp_name[128];
u32 nr_args;

- /* exactly one of KF_ITER_{NEW,NEXT,DESTROY} can be set */
+ /* exactly one of KF_ITER_{NEW,NEXT,DESTROY,GETTER,SETTER} can be set */
if (!flags || (flags & (flags - 1)))
return -EINVAL;

@@ -8088,7 +8089,7 @@ static int btf_check_iter_kfuncs(struct btf *btf, const char *func_name,
if (t->size == 0 || (t->size % 8))
return -EINVAL;

- /* validate bpf_iter_<type>_{new,next,destroy}(struct bpf_iter_<type> *)
+ /* validate bpf_iter_<type>_{new,next,destroy,get,set}(struct bpf_iter_<type> *)
* naming pattern
*/
iter_name = name + sizeof(ITER_PREFIX) - 1;
@@ -8096,15 +8097,25 @@ static int btf_check_iter_kfuncs(struct btf *btf, const char *func_name,
sfx = "new";
else if (flags & KF_ITER_NEXT)
sfx = "next";
- else /* (flags & KF_ITER_DESTROY) */
+ else if (flags & KF_ITER_DESTROY)
sfx = "destroy";
+ else if (flags & KF_ITER_GETTER)
+ sfx = "get";
+ else /* (flags & KF_ITER_SETTER) */
+ sfx = "set";

snprintf(exp_name, sizeof(exp_name), "bpf_iter_%s_%s", iter_name, sfx);
- if (strcmp(func_name, exp_name))
- return -EINVAL;
+ if (flags & (KF_ITER_NEW | KF_ITER_NEXT | KF_ITER_DESTROY)) {
+ if (strcmp(func_name, exp_name))
+ return -EINVAL;
+ } else { /* (flags & (KF_ITER_GETTER | KF_ITER_SETTER)) */
+ /* only check prefix */
+ if (strncmp(func_name, exp_name, strlen(exp_name)))
+ return -EINVAL;
+ }

- /* only iter constructor should have extra arguments */
- if (!(flags & KF_ITER_NEW) && nr_args != 1)
+ /* only iter constructor and setter should have extra arguments */
+ if (!(flags & (KF_ITER_NEW | KF_ITER_SETTER)) && nr_args != 1)
return -EINVAL;

if (flags & KF_ITER_NEXT) {
@@ -8144,7 +8155,8 @@ static int btf_check_kfunc_protos(struct btf *btf, u32 func_id, u32 func_flags)
if (!func || !btf_type_is_func_proto(func))
return -EINVAL;

- if (func_flags & (KF_ITER_NEW | KF_ITER_NEXT | KF_ITER_DESTROY)) {
+ if (func_flags & (KF_ITER_NEW | KF_ITER_NEXT | KF_ITER_DESTROY |
+ KF_ITER_GETTER | KF_ITER_SETTER)) {
err = btf_check_iter_kfuncs(btf, func_name, func, func_flags);
if (err)
return err;
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 3d6306c363b7..51302a256c30 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -7813,7 +7813,8 @@ static u32 iter_ref_obj_id(struct bpf_verifier_env *env, struct bpf_reg_state *r

static bool is_iter_kfunc(struct bpf_kfunc_call_arg_meta *meta)
{
- return meta->kfunc_flags & (KF_ITER_NEW | KF_ITER_NEXT | KF_ITER_DESTROY);
+ return meta->kfunc_flags & (KF_ITER_NEW | KF_ITER_NEXT | KF_ITER_DESTROY |
+ KF_ITER_GETTER | KF_ITER_SETTER);
}

static bool is_iter_new_kfunc(struct bpf_kfunc_call_arg_meta *meta)
--
2.39.2