mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-07-23 19:05:37 +00:00
Backport from Linux v4.11-rc3-812-gc6bf33827b7d to Linux 4.9.20: https://github.com/landlock-lsm/linux/commits/landlock-v6-linux-v4.9.20 Do not include documentation nor tests. See built documentation here: https://landlock-lsm.github.io/linux-doc/landlock-v6/security/landlock/index.html Signed-off-by: Mickaël Salaün <mic@digikod.net> Link: https://lkml.kernel.org/r/20170328234650.19695-1-mic@digikod.net
378 lines
11 KiB
Diff
378 lines
11 KiB
Diff
From ca8ae2066f8852a118e0885ab22d22e603001481 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= <mic@digikod.net>
|
|
Date: Wed, 29 Mar 2017 01:30:33 +0200
|
|
Subject: [PATCH 07/12] bpf: Define handle_fs and add a new helper
|
|
bpf_handle_fs_get_mode()
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
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 <mic@digikod.net>
|
|
Cc: Alexei Starovoitov <ast@kernel.org>
|
|
Cc: Andy Lutomirski <luto@amacapital.net>
|
|
Cc: Daniel Borkmann <daniel@iogearbox.net>
|
|
Cc: David S. Miller <davem@davemloft.net>
|
|
Cc: James Morris <james.l.morris@oracle.com>
|
|
Cc: Kees Cook <keescook@chromium.org>
|
|
Cc: Serge E. Hallyn <serge@hallyn.com>
|
|
Cc: Jann Horn <jann@thejh.net>
|
|
(cherry picked from commit 7cb1d72a1cca9442bc0b9c3eeff621b9d1709296)
|
|
---
|
|
include/linux/bpf.h | 33 +++++++++++++++++++++
|
|
include/uapi/linux/bpf.h | 17 +++++++++++
|
|
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 | 67 ++++++++++++++++++++++++++++++++++++++++++
|
|
8 files changed, 184 insertions(+), 1 deletion(-)
|
|
create mode 100644 kernel/bpf/helpers_fs.c
|
|
|
|
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
|
|
index d4b9ca479f79..d66843a2aafb 100644
|
|
--- a/include/linux/bpf.h
|
|
+++ b/include/linux/bpf.h
|
|
@@ -13,6 +13,11 @@
|
|
#include <linux/percpu.h>
|
|
#include <linux/err.h>
|
|
|
|
+/* FS helpers */
|
|
+#include <linux/dcache.h> /* struct dentry */
|
|
+#include <linux/fs.h> /* struct file, struct inode */
|
|
+#include <linux/path.h> /* struct path */
|
|
+
|
|
struct perf_event;
|
|
struct bpf_map;
|
|
|
|
@@ -80,6 +85,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 */
|
|
@@ -146,6 +153,9 @@ enum bpf_reg_type {
|
|
* map element.
|
|
*/
|
|
PTR_TO_MAP_VALUE_ADJ,
|
|
+
|
|
+ /* FS helpers */
|
|
+ CONST_PTR_TO_HANDLE_FS,
|
|
};
|
|
|
|
struct bpf_prog;
|
|
@@ -215,6 +225,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);
|
|
|
|
@@ -331,6 +361,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 f190be4f609f..6aebf7144e93 100644
|
|
--- a/include/uapi/linux/bpf.h
|
|
+++ b/include/uapi/linux/bpf.h
|
|
@@ -443,6 +443,23 @@ enum bpf_func_id {
|
|
*/
|
|
BPF_FUNC_set_hash_invalid,
|
|
|
|
+ BPF_FUNC_get_numa_node_id,
|
|
+ BPF_FUNC_skb_change_head,
|
|
+ BPF_FUNC_xdp_adjust_head,
|
|
+ BPF_FUNC_probe_read_str,
|
|
+ BPF_FUNC_get_socket_cookie,
|
|
+ BPF_FUNC_get_socket_uid,
|
|
+
|
|
+ /**
|
|
+ * 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
|
|
+ */
|
|
+ BPF_FUNC_handle_fs_get_mode,
|
|
+
|
|
__BPF_FUNC_MAX_ID,
|
|
};
|
|
|
|
diff --git a/kernel/bpf/Makefile b/kernel/bpf/Makefile
|
|
index eed911d091da..8fffb30ac7a1 100644
|
|
--- a/kernel/bpf/Makefile
|
|
+++ b/kernel/bpf/Makefile
|
|
@@ -1,6 +1,6 @@
|
|
obj-y := core.o
|
|
|
|
-obj-$(CONFIG_BPF_SYSCALL) += syscall.o verifier.o inode.o helpers.o
|
|
+obj-$(CONFIG_BPF_SYSCALL) += syscall.o verifier.o inode.o helpers.o helpers_fs.o
|
|
obj-$(CONFIG_BPF_SYSCALL) += hashtab.o arraymap.o percpu_freelist.o
|
|
ifeq ($(CONFIG_PERF_EVENTS),y)
|
|
obj-$(CONFIG_BPF_SYSCALL) += stackmap.o
|
|
diff --git a/kernel/bpf/helpers_fs.c b/kernel/bpf/helpers_fs.c
|
|
new file mode 100644
|
|
index 000000000000..d524d382adeb
|
|
--- /dev/null
|
|
+++ b/kernel/bpf/helpers_fs.c
|
|
@@ -0,0 +1,52 @@
|
|
+/*
|
|
+ * BPF filesystem helpers
|
|
+ *
|
|
+ * Copyright © 2017 Mickaël Salaün <mic@digikod.net>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License version 2, as
|
|
+ * published by the Free Software Foundation.
|
|
+ */
|
|
+
|
|
+#include <linux/bpf.h> /* struct bpf_handle_fs */
|
|
+#include <linux/errno.h>
|
|
+#include <linux/filter.h> /* BPF_CALL*() */
|
|
+
|
|
+BPF_CALL_1(bpf_handle_fs_get_mode, struct bpf_handle_fs *, handle_fs)
|
|
+{
|
|
+ if (WARN_ON(!handle_fs))
|
|
+ return -EFAULT;
|
|
+ if (!handle_fs->file) {
|
|
+ /* file can be null for anonymous mmap */
|
|
+ WARN_ON(handle_fs->type != BPF_HANDLE_FS_TYPE_FILE);
|
|
+ return -ENOENT;
|
|
+ }
|
|
+ switch (handle_fs->type) {
|
|
+ case BPF_HANDLE_FS_TYPE_FILE:
|
|
+ if (WARN_ON(!handle_fs->file->f_inode))
|
|
+ return -ENOENT;
|
|
+ return handle_fs->file->f_inode->i_mode;
|
|
+ case BPF_HANDLE_FS_TYPE_INODE:
|
|
+ return handle_fs->inode->i_mode;
|
|
+ case BPF_HANDLE_FS_TYPE_PATH:
|
|
+ if (WARN_ON(!handle_fs->path->dentry ||
|
|
+ !handle_fs->path->dentry->d_inode))
|
|
+ return -ENOENT;
|
|
+ return handle_fs->path->dentry->d_inode->i_mode;
|
|
+ case BPF_HANDLE_FS_TYPE_DENTRY:
|
|
+ if (WARN_ON(!handle_fs->dentry->d_inode))
|
|
+ return -ENOENT;
|
|
+ return handle_fs->dentry->d_inode->i_mode;
|
|
+ case BPF_HANDLE_FS_TYPE_NONE:
|
|
+ default:
|
|
+ WARN_ON(1);
|
|
+ return -EFAULT;
|
|
+ }
|
|
+}
|
|
+
|
|
+const struct bpf_func_proto bpf_handle_fs_get_mode_proto = {
|
|
+ .func = bpf_handle_fs_get_mode,
|
|
+ .gpl_only = true,
|
|
+ .ret_type = RET_INTEGER,
|
|
+ .arg1_type = ARG_CONST_PTR_TO_HANDLE_FS,
|
|
+};
|
|
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
|
|
index f5f082de2f7f..7cecf5099207 100644
|
|
--- a/kernel/bpf/verifier.c
|
|
+++ b/kernel/bpf/verifier.c
|
|
@@ -188,6 +188,7 @@ static const char * const reg_type_str[] = {
|
|
[CONST_IMM] = "imm",
|
|
[PTR_TO_PACKET] = "pkt",
|
|
[PTR_TO_PACKET_END] = "pkt_end",
|
|
+ [CONST_PTR_TO_HANDLE_FS] = "handle_fs",
|
|
};
|
|
|
|
static void print_verifier_state(struct bpf_verifier_state *state)
|
|
@@ -520,6 +521,7 @@ static bool is_spillable_regtype(enum bpf_reg_type type)
|
|
case PTR_TO_PACKET_END:
|
|
case FRAME_PTR:
|
|
case CONST_PTR_TO_MAP:
|
|
+ case CONST_PTR_TO_HANDLE_FS:
|
|
return true;
|
|
default:
|
|
return false;
|
|
@@ -981,6 +983,10 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno,
|
|
expected_type = PTR_TO_CTX;
|
|
if (type != expected_type)
|
|
goto err_type;
|
|
+ } else if (arg_type == ARG_CONST_PTR_TO_HANDLE_FS) {
|
|
+ expected_type = CONST_PTR_TO_HANDLE_FS;
|
|
+ if (type != expected_type)
|
|
+ goto err_type;
|
|
} else if (arg_type == ARG_PTR_TO_STACK ||
|
|
arg_type == ARG_PTR_TO_RAW_STACK) {
|
|
expected_type = PTR_TO_STACK;
|
|
diff --git a/samples/bpf/bpf_helpers.h b/samples/bpf/bpf_helpers.h
|
|
index dadd5161bd91..d962a5d76725 100644
|
|
--- a/samples/bpf/bpf_helpers.h
|
|
+++ b/samples/bpf/bpf_helpers.h
|
|
@@ -57,6 +57,8 @@ static int (*bpf_skb_set_tunnel_opt)(void *ctx, void *md, int size) =
|
|
(void *) BPF_FUNC_skb_set_tunnel_opt;
|
|
static unsigned long long (*bpf_get_prandom_u32)(void) =
|
|
(void *) BPF_FUNC_get_prandom_u32;
|
|
+static long long (*bpf_handle_fs_get_mode)(void *handle_fs) =
|
|
+ (void *) BPF_FUNC_handle_fs_get_mode;
|
|
|
|
/* llvm builtin functions that eBPF C program may use to
|
|
* emit BPF_LD_ABS and BPF_LD_IND instructions
|
|
diff --git a/security/landlock/init.c b/security/landlock/init.c
|
|
index 0a97026f1c07..914895d08320 100644
|
|
--- a/security/landlock/init.c
|
|
+++ b/security/landlock/init.c
|
|
@@ -78,6 +78,12 @@ static inline const struct bpf_func_proto *bpf_landlock_func_proto(
|
|
case BPF_FUNC_map_lookup_elem:
|
|
return &bpf_map_lookup_elem_proto;
|
|
|
|
+ /* event_fs */
|
|
+ case BPF_FUNC_handle_fs_get_mode:
|
|
+ if (event_fs)
|
|
+ return &bpf_handle_fs_get_mode_proto;
|
|
+ return NULL;
|
|
+
|
|
/* ability_write */
|
|
case BPF_FUNC_map_delete_elem:
|
|
if (ability_write)
|
|
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
|
|
index 0167f61cb3ba..6aebf7144e93 100644
|
|
--- a/tools/include/uapi/linux/bpf.h
|
|
+++ b/tools/include/uapi/linux/bpf.h
|
|
@@ -393,6 +393,73 @@ enum bpf_func_id {
|
|
*/
|
|
BPF_FUNC_probe_write_user,
|
|
|
|
+ /**
|
|
+ * bpf_current_task_under_cgroup(map, index) - Check cgroup2 membership of current task
|
|
+ * @map: pointer to bpf_map in BPF_MAP_TYPE_CGROUP_ARRAY type
|
|
+ * @index: index of the cgroup in the bpf_map
|
|
+ * Return:
|
|
+ * == 0 current failed the cgroup2 descendant test
|
|
+ * == 1 current succeeded the cgroup2 descendant test
|
|
+ * < 0 error
|
|
+ */
|
|
+ BPF_FUNC_current_task_under_cgroup,
|
|
+
|
|
+ /**
|
|
+ * bpf_skb_change_tail(skb, len, flags)
|
|
+ * The helper will resize the skb to the given new size,
|
|
+ * to be used f.e. with control messages.
|
|
+ * @skb: pointer to skb
|
|
+ * @len: new skb length
|
|
+ * @flags: reserved
|
|
+ * Return: 0 on success or negative error
|
|
+ */
|
|
+ BPF_FUNC_skb_change_tail,
|
|
+
|
|
+ /**
|
|
+ * bpf_skb_pull_data(skb, len)
|
|
+ * The helper will pull in non-linear data in case the
|
|
+ * skb is non-linear and not all of len are part of the
|
|
+ * linear section. Only needed for read/write with direct
|
|
+ * packet access.
|
|
+ * @skb: pointer to skb
|
|
+ * @len: len to make read/writeable
|
|
+ * Return: 0 on success or negative error
|
|
+ */
|
|
+ BPF_FUNC_skb_pull_data,
|
|
+
|
|
+ /**
|
|
+ * bpf_csum_update(skb, csum)
|
|
+ * Adds csum into skb->csum in case of CHECKSUM_COMPLETE.
|
|
+ * @skb: pointer to skb
|
|
+ * @csum: csum to add
|
|
+ * Return: csum on success or negative error
|
|
+ */
|
|
+ BPF_FUNC_csum_update,
|
|
+
|
|
+ /**
|
|
+ * bpf_set_hash_invalid(skb)
|
|
+ * Invalidate current skb>hash.
|
|
+ * @skb: pointer to skb
|
|
+ */
|
|
+ BPF_FUNC_set_hash_invalid,
|
|
+
|
|
+ BPF_FUNC_get_numa_node_id,
|
|
+ BPF_FUNC_skb_change_head,
|
|
+ BPF_FUNC_xdp_adjust_head,
|
|
+ BPF_FUNC_probe_read_str,
|
|
+ BPF_FUNC_get_socket_cookie,
|
|
+ BPF_FUNC_get_socket_uid,
|
|
+
|
|
+ /**
|
|
+ * 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
|
|
+ */
|
|
+ BPF_FUNC_handle_fs_get_mode,
|
|
+
|
|
__BPF_FUNC_MAX_ID,
|
|
};
|
|
|
|
--
|
|
2.11.0
|
|
|