This patch adds the open-coded iterator style process file iterator kfuncs bpf_iter_task_file_{new,next,destroy} that iterates over all files opened by the specified process. In addition, this patch adds bpf_iter_task_file_get_fd() getter to get the file descriptor corresponding to the file in the current iteration. The reference to struct file acquired by the previous bpf_iter_task_file_next() is released in the next bpf_iter_task_file_next(), and the last reference is released in the last bpf_iter_task_file_next() that returns NULL. In the bpf_iter_task_file_destroy(), if the iterator does not iterate to the end, then the last struct file reference is released at this time. Signed-off-by: Juntong Deng <juntong.deng@xxxxxxxxxxx> --- include/linux/bpf_crib.h | 10 ++++ kernel/bpf/crib/bpf_checkpoint.c | 88 ++++++++++++++++++++++++++++++++ kernel/bpf/crib/bpf_crib.c | 5 ++ 3 files changed, 103 insertions(+) diff --git a/include/linux/bpf_crib.h b/include/linux/bpf_crib.h index f667b740fcc2..468ae87fa1a5 100644 --- a/include/linux/bpf_crib.h +++ b/include/linux/bpf_crib.h @@ -13,4 +13,14 @@ #include <linux/btf_ids.h> #include <linux/filter.h> +struct bpf_iter_task_file { + __u64 __opaque[3]; +} __aligned(8); + +struct bpf_iter_task_file_kern { + struct task_struct *task; + struct file *file; + int fd; +} __aligned(8); + #endif /* _BPF_CRIB_H */ diff --git a/kernel/bpf/crib/bpf_checkpoint.c b/kernel/bpf/crib/bpf_checkpoint.c index efaca6bcdfe4..28ad26986053 100644 --- a/kernel/bpf/crib/bpf_checkpoint.c +++ b/kernel/bpf/crib/bpf_checkpoint.c @@ -7,7 +7,95 @@ */ #include <linux/bpf_crib.h> +#include <linux/fdtable.h> + +extern void bpf_file_release(struct file *file); __bpf_kfunc_start_defs(); +/** + * bpf_iter_task_file_new() - Initialize a new task file iterator for a task, + * used to iterate over all files opened by a specified task + * + * @it: The new bpf_iter_task_file to be created + * @task: A pointer pointing to a task to be iterated over + */ +__bpf_kfunc int bpf_iter_task_file_new(struct bpf_iter_task_file *it, + struct task_struct *task) +{ + struct bpf_iter_task_file_kern *kit = (void *)it; + + BUILD_BUG_ON(sizeof(struct bpf_iter_task_file_kern) > sizeof(struct bpf_iter_task_file)); + BUILD_BUG_ON(__alignof__(struct bpf_iter_task_file_kern) != + __alignof__(struct bpf_iter_task_file)); + + kit->task = task; + kit->fd = -1; + kit->file = NULL; + + return 0; +} + +/** + * bpf_iter_task_file_next() - Get the next file in bpf_iter_task_file + * + * bpf_iter_task_file_next() acquires a reference to the returned struct file. + * + * The reference to struct file acquired by the previous + * bpf_iter_task_file_next() is released in the next bpf_iter_task_file_next(), + * and the last reference is released in the last bpf_iter_task_file_next() + * that returns NULL. + * + * @it: The bpf_iter_task_file to be checked + * + * @returns a pointer to the struct file of the next file if further files + * are available, otherwise returns NULL. + */ +__bpf_kfunc struct file *bpf_iter_task_file_next(struct bpf_iter_task_file *it) +{ + struct bpf_iter_task_file_kern *kit = (void *)it; + + if (kit->file) + bpf_file_release(kit->file); + + kit->fd++; + + rcu_read_lock(); + kit->file = task_lookup_next_fdget_rcu(kit->task, &kit->fd); + rcu_read_unlock(); + + return kit->file; +} + +/** + * bpf_iter_task_file_get_fd() - Get the file descriptor + * corresponding to the file in the current iteration + * + * @it: The bpf_iter_task_file to be checked + * + * @returns the file descriptor + */ +__bpf_kfunc int bpf_iter_task_file_get_fd(struct bpf_iter_task_file *it) +{ + struct bpf_iter_task_file_kern *kit = (void *)it; + + return kit->fd; +} + +/** + * bpf_iter_task_file_destroy() - Destroy a bpf_iter_task_file + * + * If the iterator does not iterate to the end, then the last + * struct file reference is released at this time. + * + * @it: The bpf_iter_task_file to be destroyed + */ +__bpf_kfunc void bpf_iter_task_file_destroy(struct bpf_iter_task_file *it) +{ + struct bpf_iter_task_file_kern *kit = (void *)it; + + if (kit->file) + bpf_file_release(kit->file); +} + __bpf_kfunc_end_defs(); diff --git a/kernel/bpf/crib/bpf_crib.c b/kernel/bpf/crib/bpf_crib.c index 1c1729ddf233..b901d7d60290 100644 --- a/kernel/bpf/crib/bpf_crib.c +++ b/kernel/bpf/crib/bpf_crib.c @@ -52,6 +52,11 @@ BTF_KFUNCS_START(bpf_crib_kfuncs) BTF_ID_FLAGS(func, bpf_file_from_task_fd, KF_ACQUIRE | KF_TRUSTED_ARGS | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_file_release, KF_RELEASE) +BTF_ID_FLAGS(func, bpf_iter_task_file_new, KF_ITER_NEW | KF_TRUSTED_ARGS) +BTF_ID_FLAGS(func, bpf_iter_task_file_next, KF_ITER_NEXT | KF_RET_NULL) +BTF_ID_FLAGS(func, bpf_iter_task_file_get_fd, KF_ITER_GETTER) +BTF_ID_FLAGS(func, bpf_iter_task_file_destroy, KF_ITER_DESTROY) + BTF_KFUNCS_END(bpf_crib_kfuncs) static int bpf_prog_run_crib(struct bpf_prog *prog, -- 2.39.2