[PATCH net-next v6 03/11] bpf: Define handle_fs and add a new helper bpf_handle_fs_get_mode()
Add an eBPF function bpf_handle_fs_get_mode(handle_fs) to get the mode of a an abstract object wrapping either a file, a dentry, a path, or an inode. Changes since v5: * cosmetic fixes and rebase Changes since v4: * use a file abstraction (handle) to wrap inode, dentry, path and file structs * remove bpf_landlock_cmp_fs_beneath() * rename the BPF helper and move it to kernel/bpf/ * tighten helpers accessible by a Landlock rule Changes since v3: * remove bpf_landlock_cmp_fs_prop() (suggested by Alexie Starovoitov) * add hooks dealing with struct inode and struct path pointers: inode_permission and inode_getattr * add abstraction over eBPF helper arguments thanks to wrapping structs * add bpf_landlock_get_fs_mode() helper to check file type and mode * merge WARN_ON() (suggested by Kees Cook) * fix and update bpf_helpers.h * use BPF_CALL_* for eBPF helpers (suggested by Alexie Starovoitov) * make handle arraymap safe (RCU) and remove buggy synchronize_rcu() * factor out the arraymay walk * use size_t to index array (suggested by Jann Horn) Changes since v2: * add MNT_INTERNAL check to only add file handle from user-visible FS (e.g. no anonymous inode) * replace struct file* with struct path* in map_landlock_handle * add BPF protos * fix bpf_landlock_cmp_fs_prop_with_struct_file() Signed-off-by: Mickaël SalaünCc: Alexei Starovoitov Cc: Andy Lutomirski Cc: Daniel Borkmann Cc: David S. Miller Cc: James Morris Cc: Kees Cook Cc: Serge E. Hallyn Cc: Jann Horn --- include/linux/bpf.h| 33 +++ include/uapi/linux/bpf.h | 10 +++- kernel/bpf/Makefile| 2 +- kernel/bpf/helpers_fs.c| 52 ++ kernel/bpf/verifier.c | 6 + samples/bpf/bpf_helpers.h | 2 ++ security/landlock/init.c | 6 + tools/include/uapi/linux/bpf.h | 10 +++- 8 files changed, 118 insertions(+), 3 deletions(-) create mode 100644 kernel/bpf/helpers_fs.c diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 1cb407bd8ef7..a2e53c22e450 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -15,6 +15,11 @@ #include #include +/* FS helpers */ +#include /* struct dentry */ +#include /* struct file, struct inode */ +#include /* struct path */ + struct perf_event; struct bpf_map; @@ -84,6 +89,8 @@ enum bpf_arg_type { ARG_PTR_TO_CTX, /* pointer to context */ ARG_ANYTHING, /* any (initialized) argument is ok */ + + ARG_CONST_PTR_TO_HANDLE_FS, /* pointer to an abstract FS struct */ }; /* type of values returned from helper functions */ @@ -150,6 +157,9 @@ enum bpf_reg_type { * map element. */ PTR_TO_MAP_VALUE_ADJ, + + /* FS helpers */ + CONST_PTR_TO_HANDLE_FS, }; struct bpf_prog; @@ -222,6 +232,26 @@ struct bpf_event_entry { struct rcu_head rcu; }; +/* FS helpers */ +enum bpf_handle_fs_type { + BPF_HANDLE_FS_TYPE_NONE, + BPF_HANDLE_FS_TYPE_FILE, + BPF_HANDLE_FS_TYPE_INODE, + BPF_HANDLE_FS_TYPE_PATH, + BPF_HANDLE_FS_TYPE_DENTRY, +}; + +struct bpf_handle_fs { + enum bpf_handle_fs_type type; + union { + struct file *file; + struct inode *inode; + const struct path *path; + struct dentry *dentry; + }; +}; + + u64 bpf_tail_call(u64 ctx, u64 r2, u64 index, u64 r4, u64 r5); u64 bpf_get_stackid(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5); @@ -362,6 +392,9 @@ extern const struct bpf_func_proto bpf_skb_vlan_push_proto; extern const struct bpf_func_proto bpf_skb_vlan_pop_proto; extern const struct bpf_func_proto bpf_get_stackid_proto; +/* FS helpers */ +extern const struct bpf_func_proto bpf_handle_fs_get_mode_proto; + /* Shared helpers among cBPF and eBPF. */ void bpf_user_rnd_init_once(void); u64 bpf_user_rnd_u32(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5); diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 619b1f8707cc..d35948634667 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -483,6 +483,13 @@ union bpf_attr { * @skb: pointer to skb * Return: uid of the socket owner on success or 0 if the socket pointer * inside sk_buff is NULL + * + * s64 bpf_handle_fs_get_mode(handle_fs) + * Get the mode of a struct bpf_handle_fs + * fs: struct bpf_handle_fs address + * Return: + * >= 0 file mode + * < 0 error */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -532,7 +539,8 @@ union bpf_attr { FN(xdp_adjust_head),\ FN(probe_read_str), \ FN(get_socket_cookie), \ - FN(get_socket_uid), + FN(get_socket_uid), \
[PATCH net-next v6 03/11] bpf: Define handle_fs and add a new helper bpf_handle_fs_get_mode()
Add an eBPF function bpf_handle_fs_get_mode(handle_fs) to get the mode of a an abstract object wrapping either a file, a dentry, a path, or an inode. Changes since v5: * cosmetic fixes and rebase Changes since v4: * use a file abstraction (handle) to wrap inode, dentry, path and file structs * remove bpf_landlock_cmp_fs_beneath() * rename the BPF helper and move it to kernel/bpf/ * tighten helpers accessible by a Landlock rule Changes since v3: * remove bpf_landlock_cmp_fs_prop() (suggested by Alexie Starovoitov) * add hooks dealing with struct inode and struct path pointers: inode_permission and inode_getattr * add abstraction over eBPF helper arguments thanks to wrapping structs * add bpf_landlock_get_fs_mode() helper to check file type and mode * merge WARN_ON() (suggested by Kees Cook) * fix and update bpf_helpers.h * use BPF_CALL_* for eBPF helpers (suggested by Alexie Starovoitov) * make handle arraymap safe (RCU) and remove buggy synchronize_rcu() * factor out the arraymay walk * use size_t to index array (suggested by Jann Horn) Changes since v2: * add MNT_INTERNAL check to only add file handle from user-visible FS (e.g. no anonymous inode) * replace struct file* with struct path* in map_landlock_handle * add BPF protos * fix bpf_landlock_cmp_fs_prop_with_struct_file() Signed-off-by: Mickaël Salaün Cc: Alexei Starovoitov Cc: Andy Lutomirski Cc: Daniel Borkmann Cc: David S. Miller Cc: James Morris Cc: Kees Cook Cc: Serge E. Hallyn Cc: Jann Horn --- include/linux/bpf.h| 33 +++ include/uapi/linux/bpf.h | 10 +++- kernel/bpf/Makefile| 2 +- kernel/bpf/helpers_fs.c| 52 ++ kernel/bpf/verifier.c | 6 + samples/bpf/bpf_helpers.h | 2 ++ security/landlock/init.c | 6 + tools/include/uapi/linux/bpf.h | 10 +++- 8 files changed, 118 insertions(+), 3 deletions(-) create mode 100644 kernel/bpf/helpers_fs.c diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 1cb407bd8ef7..a2e53c22e450 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -15,6 +15,11 @@ #include #include +/* FS helpers */ +#include /* struct dentry */ +#include /* struct file, struct inode */ +#include /* struct path */ + struct perf_event; struct bpf_map; @@ -84,6 +89,8 @@ enum bpf_arg_type { ARG_PTR_TO_CTX, /* pointer to context */ ARG_ANYTHING, /* any (initialized) argument is ok */ + + ARG_CONST_PTR_TO_HANDLE_FS, /* pointer to an abstract FS struct */ }; /* type of values returned from helper functions */ @@ -150,6 +157,9 @@ enum bpf_reg_type { * map element. */ PTR_TO_MAP_VALUE_ADJ, + + /* FS helpers */ + CONST_PTR_TO_HANDLE_FS, }; struct bpf_prog; @@ -222,6 +232,26 @@ struct bpf_event_entry { struct rcu_head rcu; }; +/* FS helpers */ +enum bpf_handle_fs_type { + BPF_HANDLE_FS_TYPE_NONE, + BPF_HANDLE_FS_TYPE_FILE, + BPF_HANDLE_FS_TYPE_INODE, + BPF_HANDLE_FS_TYPE_PATH, + BPF_HANDLE_FS_TYPE_DENTRY, +}; + +struct bpf_handle_fs { + enum bpf_handle_fs_type type; + union { + struct file *file; + struct inode *inode; + const struct path *path; + struct dentry *dentry; + }; +}; + + u64 bpf_tail_call(u64 ctx, u64 r2, u64 index, u64 r4, u64 r5); u64 bpf_get_stackid(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5); @@ -362,6 +392,9 @@ extern const struct bpf_func_proto bpf_skb_vlan_push_proto; extern const struct bpf_func_proto bpf_skb_vlan_pop_proto; extern const struct bpf_func_proto bpf_get_stackid_proto; +/* FS helpers */ +extern const struct bpf_func_proto bpf_handle_fs_get_mode_proto; + /* Shared helpers among cBPF and eBPF. */ void bpf_user_rnd_init_once(void); u64 bpf_user_rnd_u32(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5); diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 619b1f8707cc..d35948634667 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -483,6 +483,13 @@ union bpf_attr { * @skb: pointer to skb * Return: uid of the socket owner on success or 0 if the socket pointer * inside sk_buff is NULL + * + * s64 bpf_handle_fs_get_mode(handle_fs) + * Get the mode of a struct bpf_handle_fs + * fs: struct bpf_handle_fs address + * Return: + * >= 0 file mode + * < 0 error */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -532,7 +539,8 @@ union bpf_attr { FN(xdp_adjust_head),\ FN(probe_read_str), \ FN(get_socket_cookie), \ - FN(get_socket_uid), + FN(get_socket_uid), \ + FN(handle_fs_get_mode), /* integer value in 'imm' field of BPF_CALL instruction selects which helper * function eBPF program intends to call diff --git