On 2021/8/5 6:44 AM, Andrii Nakryiko wrote: > On Wed, Aug 4, 2021 at 3:35 PM Daniel Borkmann <daniel@xxxxxxxxxxxxx> wrote: >> >> On 7/27/21 3:25 PM, Hengqi Chen wrote: >>> Add vfs_* and security_* to bpf_d_path allowlist, so that we can use >>> bpf_d_path helper to extract full file path from these functions' arguments. >>> This will help tools like BCC's filetop[1]/filelife to get full file path. >>> >>> [1] https://github.com/iovisor/bcc/issues/3527 >>> >>> Acked-by: Yonghong Song <yhs@xxxxxx> >>> Signed-off-by: Hengqi Chen <hengqi.chen@xxxxxxxxx> >>> --- >>> kernel/trace/bpf_trace.c | 60 +++++++++++++++++++++++++++++++++++++--- >>> 1 file changed, 56 insertions(+), 4 deletions(-) >>> >>> diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c >>> index c5e0b6a64091..e7b24abcf3bf 100644 >>> --- a/kernel/trace/bpf_trace.c >>> +++ b/kernel/trace/bpf_trace.c >>> @@ -849,18 +849,70 @@ BPF_CALL_3(bpf_d_path, struct path *, path, char *, buf, u32, sz) >>> >>> BTF_SET_START(btf_allowlist_d_path) >>> #ifdef CONFIG_SECURITY >>> +BTF_ID(func, security_bprm_check) >>> +BTF_ID(func, security_bprm_committed_creds) >>> +BTF_ID(func, security_bprm_committing_creds) >>> +BTF_ID(func, security_bprm_creds_for_exec) >>> +BTF_ID(func, security_bprm_creds_from_file) >>> +BTF_ID(func, security_file_alloc) >> >> Did you actually try these out, e.g. attaching BPF progs invoking bpf_d_path() to all >> these, then generate some workload like kernel build for testing? >> >> I presume not, since something like security_file_alloc() would crash the kernel. Right >> before it's called in __alloc_file() we fetch a struct file from kmemcache, and only >> populate f->f_cred there. Most LSMs, for example, only populate their secblob through the >> callback. If you call bpf_d_path(&file->f_path, ...) with it, you'll crash in d_path() >> when path->dentry->d_op is checked.. given f->f_path is all zeroed structure at that >> point. >> >> Please do your due diligence and invest each of them manually, maybe the best way is >> to hack up small selftests for each enabled function that our CI can test run? Bit of a >> one-time effort, but at least it ensures that those additions are sane & checked. > > I think it's actually a pretty fun exercise and a good selftest to > have. We can have a selftest which will attach a simple BPF program > just to grab a contents of btf_allowlist_d_path (with typeless ksyms, > for instance). Then for each BTF ID in there, as a subtest, attach > another BPF object with fentry BPF program doing something with > d_path. > > Hengqi, you'd need to have few variants for each possible position of > file or path struct (e.g., file as first arg; as second arg; etc, same > for hooks working with path directly), but I don't think that's going > to be a lot of them. > > So as Daniel said, a bit of a work, but we'll have a much better > confidence that we are not accidentally opening a big kernel crashing > loophole. > Thanks for the review and suggestions. Will test them locally and add selftest for these changes. >> >>> +BTF_ID(func, security_file_fcntl) >>> +BTF_ID(func, security_file_free) >>> +BTF_ID(func, security_file_ioctl) >>> +BTF_ID(func, security_file_lock) >>> +BTF_ID(func, security_file_open) >>> BTF_ID(func, security_file_permission) >>> +BTF_ID(func, security_file_receive) >>> +BTF_ID(func, security_file_set_fowner) >>> BTF_ID(func, security_inode_getattr) >>> -BTF_ID(func, security_file_open) >>> +BTF_ID(func, security_sb_mount) >>> #endif >>> #ifdef CONFIG_SECURITY_PATH >>> +BTF_ID(func, security_path_chmod) >>> +BTF_ID(func, security_path_chown) >>> +BTF_ID(func, security_path_chroot) >>> +BTF_ID(func, security_path_link) >>> +BTF_ID(func, security_path_mkdir) >>> +BTF_ID(func, security_path_mknod) >>> +BTF_ID(func, security_path_notify) >>> +BTF_ID(func, security_path_rename) >>> +BTF_ID(func, security_path_rmdir) >>> +BTF_ID(func, security_path_symlink) >>> BTF_ID(func, security_path_truncate) >>> +BTF_ID(func, security_path_unlink) >>> #endif >>> -BTF_ID(func, vfs_truncate) >>> -BTF_ID(func, vfs_fallocate) >>> BTF_ID(func, dentry_open) >>> -BTF_ID(func, vfs_getattr) >>> BTF_ID(func, filp_close) >>> +BTF_ID(func, vfs_cancel_lock) >>> +BTF_ID(func, vfs_clone_file_range) >>> +BTF_ID(func, vfs_copy_file_range) >>> +BTF_ID(func, vfs_dedupe_file_range) >>> +BTF_ID(func, vfs_dedupe_file_range_one) >>> +BTF_ID(func, vfs_fadvise) >>> +BTF_ID(func, vfs_fallocate) >>> +BTF_ID(func, vfs_fchmod) >>> +BTF_ID(func, vfs_fchown) >>> +BTF_ID(func, vfs_fsync) >>> +BTF_ID(func, vfs_fsync_range) >>> +BTF_ID(func, vfs_getattr) >>> +BTF_ID(func, vfs_getattr_nosec) >>> +BTF_ID(func, vfs_iocb_iter_read) >>> +BTF_ID(func, vfs_iocb_iter_write) >>> +BTF_ID(func, vfs_ioctl) >>> +BTF_ID(func, vfs_iter_read) >>> +BTF_ID(func, vfs_iter_write) >>> +BTF_ID(func, vfs_llseek) >>> +BTF_ID(func, vfs_lock_file) >>> +BTF_ID(func, vfs_open) >>> +BTF_ID(func, vfs_read) >>> +BTF_ID(func, vfs_readv) >>> +BTF_ID(func, vfs_setlease) >>> +BTF_ID(func, vfs_setpos) >>> +BTF_ID(func, vfs_statfs) >>> +BTF_ID(func, vfs_test_lock) >>> +BTF_ID(func, vfs_truncate) >>> +BTF_ID(func, vfs_utimes) >>> +BTF_ID(func, vfs_write) >>> +BTF_ID(func, vfs_writev) >>> BTF_SET_END(btf_allowlist_d_path) >>> >>> static bool bpf_d_path_allowed(const struct bpf_prog *prog) >>> >>