Walking file->f_inode out of an acquired file must not outlive bpf_put_file(). Add a reject test where the inode is used as a trusted argument after the file's reference is released and an accept test where it is read before. Signed-off-by: Justin Suess --- .../selftests/bpf/progs/verifier_vfs_accept.c | 17 +++++++++++++++++ .../selftests/bpf/progs/verifier_vfs_reject.c | 19 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/verifier_vfs_accept.c b/tools/testing/selftests/bpf/progs/verifier_vfs_accept.c index f519ba5f4ea2..d7e4fc658fea 100644 --- a/tools/testing/selftests/bpf/progs/verifier_vfs_accept.c +++ b/tools/testing/selftests/bpf/progs/verifier_vfs_accept.c @@ -123,4 +123,21 @@ int BPF_PROG(trusted_field_used_in_rcu_cs, struct linux_binprm *bprm) return 0; } +SEC("lsm.s/file_open") +__success +int BPF_PROG(trusted_field_used_before_put) +{ + struct task_struct *task = bpf_get_current_task_btf(); + struct file *file = bpf_get_task_exe_file(task); + ino_t ino; + + if (!file) + return 0; + + ino = file->f_inode->i_ino; + bpf_put_file(file); + __sink(ino); + return 0; +} + char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/verifier_vfs_reject.c b/tools/testing/selftests/bpf/progs/verifier_vfs_reject.c index b71ef8ac1798..c35cf9800f0f 100644 --- a/tools/testing/selftests/bpf/progs/verifier_vfs_reject.c +++ b/tools/testing/selftests/bpf/progs/verifier_vfs_reject.c @@ -203,4 +203,23 @@ int BPF_PROG(trusted_field_escapes_rcu_cs, struct linux_binprm *bprm) subprog_trusted_inode(inode); return 0; } + +SEC("lsm.s/file_open") +__failure __msg("R1 type=scalar expected=ptr_, trusted_ptr_, rcu_ptr_") +int BPF_PROG(trusted_field_outlives_parent_reference) +{ + struct task_struct *task = bpf_get_current_task_btf(); + struct file *file = bpf_get_task_exe_file(task); + struct inode *inode; + + if (!file) + return 0; + + inode = file->f_inode; + bpf_put_file(file); + + /* inode was pinned by file's reference and died with it. */ + subprog_trusted_inode(inode); + return 0; +} char _license[] SEC("license") = "GPL"; -- 2.55.0