On Fri, Jul 26, 2024 at 1:56 AM Matt Bobrowski <mattbobrowski@xxxxxxxxxx> wrote: > > Add a bunch of negative selftests responsible for asserting that the > BPF verifier successfully rejects a BPF program load when the > underlying BPF program misuses one of the newly introduced VFS based > BPF kfuncs. Negative tests are great. Thanks for adding them. A few nitpicks below. [...] > diff --git a/tools/testing/selftests/bpf/bpf_experimental.h b/tools/testing/selftests/bpf/bpf_experimental.h > index 828556cdc2f0..8a1ed62b4ed1 100644 > --- a/tools/testing/selftests/bpf/bpf_experimental.h > +++ b/tools/testing/selftests/bpf/bpf_experimental.h > @@ -195,6 +195,32 @@ extern void bpf_iter_task_vma_destroy(struct bpf_iter_task_vma *it) __ksym; > */ > extern void bpf_throw(u64 cookie) __ksym; > > +/* Description > + * Acquire a reference on the exe_file member field belonging to the > + * mm_struct that is nested within the supplied task_struct. The supplied > + * task_struct must be trusted/referenced. > + * Returns > + * A referenced file pointer pointing to the exe_file member field of the > + * mm_struct nested in the supplied task_struct, or NULL. > + */ > +extern struct file *bpf_get_task_exe_file(struct task_struct *task) __ksym; > + > +/* Description > + * Release a reference on the supplied file. The supplied file must be > + * trusted/referenced. Probably replace "trusted/referenced" with "acquired". > + */ > +extern void bpf_put_file(struct file *file) __ksym; > + > +/* Description > + * Resolve a pathname for the supplied path and store it in the supplied > + * buffer. The supplied path must be trusted/referenced. > + * Returns > + * A positive integer corresponding to the length of the resolved pathname, > + * including the NULL termination character, stored in the supplied > + * buffer. On error, a negative integer is returned. > + */ > +extern int bpf_path_d_path(struct path *path, char *buf, size_t buf__sz) __ksym; > + In my environment, we already have these declarations in vmlinux.h. So maybe we don't need to add them manually? > /* This macro must be used to mark the exception callback corresponding to the > * main program. For example: > * > diff --git a/tools/testing/selftests/bpf/prog_tests/verifier.c b/tools/testing/selftests/bpf/prog_tests/verifier.c > index 67a49d12472c..14d74ba2188e 100644 > --- a/tools/testing/selftests/bpf/prog_tests/verifier.c > +++ b/tools/testing/selftests/bpf/prog_tests/verifier.c > @@ -85,6 +85,7 @@ > #include "verifier_value_or_null.skel.h" > #include "verifier_value_ptr_arith.skel.h" > #include "verifier_var_off.skel.h" > +#include "verifier_vfs_reject.skel.h" > #include "verifier_xadd.skel.h" > #include "verifier_xdp.skel.h" > #include "verifier_xdp_direct_packet_access.skel.h" > @@ -205,6 +206,7 @@ void test_verifier_value(void) { RUN(verifier_value); } > void test_verifier_value_illegal_alu(void) { RUN(verifier_value_illegal_alu); } > void test_verifier_value_or_null(void) { RUN(verifier_value_or_null); } > void test_verifier_var_off(void) { RUN(verifier_var_off); } > +void test_verifier_vfs_reject(void) { RUN(verifier_vfs_reject); } > void test_verifier_xadd(void) { RUN(verifier_xadd); } > void test_verifier_xdp(void) { RUN(verifier_xdp); } > void test_verifier_xdp_direct_packet_access(void) { RUN(verifier_xdp_direct_packet_access); } > diff --git a/tools/testing/selftests/bpf/progs/verifier_vfs_reject.c b/tools/testing/selftests/bpf/progs/verifier_vfs_reject.c > new file mode 100644 > index 000000000000..27666a8ef78a > --- /dev/null > +++ b/tools/testing/selftests/bpf/progs/verifier_vfs_reject.c > @@ -0,0 +1,196 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* Copyright (c) 2024 Google LLC. */ > + > +#include <vmlinux.h> > +#include <bpf/bpf_helpers.h> > +#include <bpf/bpf_tracing.h> > +#include <linux/limits.h> > + > +#include "bpf_misc.h" > +#include "bpf_experimental.h" > + > +static char buf[PATH_MAX]; > + > +SEC("lsm.s/file_open") > +__failure __msg("Possibly NULL pointer passed to trusted arg0") > +int BPF_PROG(get_task_exe_file_kfunc_null) > +{ > + struct file *acquired; > + > + /* Can't pass a NULL pointer to bpf_get_task_exe_file(). */ > + acquired = bpf_get_task_exe_file(NULL); > + if (!acquired) > + return 0; > + > + bpf_put_file(acquired); > + return 0; > +} > + > +SEC("lsm.s/inode_getxattr") > +__failure __msg("arg#0 pointer type STRUCT task_struct must point to scalar, or struct with scalar") > +int BPF_PROG(get_task_exe_file_kfunc_fp) > +{ > + u64 x; > + struct file *acquired; > + struct task_struct *fp; "fp" is a weird name for a task_struct pointer. Other than these: Acked-by: Song Liu <song@xxxxxxxxxx> > + > + fp = (struct task_struct *)&x; > + /* Can't pass random frame pointer to bpf_get_task_exe_file(). */ > + acquired = bpf_get_task_exe_file(fp); > + if (!acquired) > + return 0; > + > + bpf_put_file(acquired); > + return 0; > +} > + [...]