On Fri, Jul 26, 2024 at 04:38:32PM -0700, Song Liu wrote: > 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. Thanks for the review! > > 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". Done. > > + */ > > +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? Right, but that's probably when building vmlinux.h using the latest pahole I imagine? Those not using the latest pahole will probably won't already see these BPF kfuncs within the generated vmlinux.h. > > /* 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. OK, just want to make it clear that it was a pointer to something that exists on the current stack frame. Happy to change the name to task or something. Done. > 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; > > +} > > + > [...] /M