[PATCH net-next v6 03/11] bpf: Define handle_fs and add a new helper bpf_handle_fs_get_mode()

2017-03-28 Thread Mickaël Salaün
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), \

[PATCH net-next v6 03/11] bpf: Define handle_fs and add a new helper bpf_handle_fs_get_mode()

2017-03-28 Thread Mickaël Salaün
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