All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Mickaël Salaün" <mic@digikod.net>
To: linux-kernel@vger.kernel.org
Cc: "Mickaël Salaün" <mic@digikod.net>,
	"Alexei Starovoitov" <ast@kernel.org>,
	"Andy Lutomirski" <luto@amacapital.net>,
	"Daniel Borkmann" <daniel@iogearbox.net>,
	"Daniel Mack" <daniel@zonque.org>,
	"David Drysdale" <drysdale@google.com>,
	"David S . Miller" <davem@davemloft.net>,
	"Eric W . Biederman" <ebiederm@xmission.com>,
	"James Morris" <james.l.morris@oracle.com>,
	"Jann Horn" <jann@thejh.net>, "Kees Cook" <keescook@chromium.org>,
	"Paul Moore" <pmoore@redhat.com>,
	"Sargun Dhillon" <sargun@sargun.me>,
	"Serge E . Hallyn" <serge@hallyn.com>,
	"Tejun Heo" <tj@kernel.org>, "Thomas Graf" <tgraf@suug.ch>,
	"Will Drewry" <wad@chromium.org>,
	kernel-hardening@lists.openwall.com, linux-api@vger.kernel.org,
	linux-security-module@vger.kernel.org, netdev@vger.kernel.org,
	cgroups@vger.kernel.org
Subject: [RFC v4 07/18] landlock: Add LSM hooks
Date: Wed, 26 Oct 2016 08:56:43 +0200	[thread overview]
Message-ID: <20161026065654.19166-8-mic@digikod.net> (raw)
In-Reply-To: <20161026065654.19166-1-mic@digikod.net>

Add 8 file system-related hooks:
* file_open
* file_permission
* mmap_file
* inode_create
* inode_link
* inode_unlink
* inode_permission
* inode_getattr

This hook arguments are available to the Landlock rules in the eBPF
context as pointers. This pointers are an abstraction over the
underlying raw types. For now, the ARG_CONST_PTR_TO_LANDLOCK_ARG_FS type
is used for struct file, struct inode and struct path pointers.

Changes since v3:
* split commit
* 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

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>
---
 include/linux/bpf.h        |   2 +
 include/linux/lsm_hooks.h  |   5 ++
 include/uapi/linux/bpf.h   |  10 ++-
 kernel/bpf/verifier.c      |   6 ++
 security/landlock/common.h |  18 +++++
 security/landlock/lsm.c    | 173 +++++++++++++++++++++++++++++++++++++++++++++
 security/security.c        |   1 +
 7 files changed, 214 insertions(+), 1 deletion(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 2cca9fc8b72b..e7ce49642f50 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -88,6 +88,7 @@ enum bpf_arg_type {
 	ARG_ANYTHING,		/* any (initialized) argument is ok */
 
 	ARG_CONST_PTR_TO_LANDLOCK_HANDLE_FS,	/* pointer to Landlock FS map handle */
+	ARG_CONST_PTR_TO_LANDLOCK_ARG_FS,	/* pointer to Landlock FS hook argument */
 };
 
 /* type of values returned from helper functions */
@@ -157,6 +158,7 @@ enum bpf_reg_type {
 
 	/* Landlock */
 	CONST_PTR_TO_LANDLOCK_HANDLE_FS,
+	CONST_PTR_TO_LANDLOCK_ARG_FS,
 };
 
 struct bpf_prog;
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 558adfa5c8a8..069af34301d4 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1933,5 +1933,10 @@ void __init loadpin_add_hooks(void);
 #else
 static inline void loadpin_add_hooks(void) { };
 #endif
+#ifdef CONFIG_SECURITY_LANDLOCK
+extern void __init landlock_add_hooks(void);
+#else
+static inline void __init landlock_add_hooks(void) { }
+#endif /* CONFIG_SECURITY_LANDLOCK */
 
 #endif /* ! __LINUX_LSM_HOOKS_H */
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 335616ab63ff..b6b531a868c0 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -563,8 +563,16 @@ struct xdp_md {
 /* LSM hooks */
 enum landlock_hook {
 	LANDLOCK_HOOK_UNSPEC,
+	LANDLOCK_HOOK_FILE_OPEN,
+	LANDLOCK_HOOK_FILE_PERMISSION,
+	LANDLOCK_HOOK_MMAP_FILE,
+	LANDLOCK_HOOK_INODE_CREATE,
+	LANDLOCK_HOOK_INODE_LINK,
+	LANDLOCK_HOOK_INODE_UNLINK,
+	LANDLOCK_HOOK_INODE_PERMISSION,
+	LANDLOCK_HOOK_INODE_GETATTR,
 };
-#define _LANDLOCK_HOOK_LAST LANDLOCK_HOOK_UNSPEC
+#define _LANDLOCK_HOOK_LAST LANDLOCK_HOOK_INODE_GETATTR
 
 /* eBPF context and functions allowed for a rule */
 #define _LANDLOCK_SUBTYPE_ACCESS_MASK		((1ULL << 0) - 1)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 9b921a9afa3c..32b7941476ec 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -189,6 +189,7 @@ static const char * const reg_type_str[] = {
 	[PTR_TO_PACKET]		= "pkt",
 	[PTR_TO_PACKET_END]	= "pkt_end",
 	[CONST_PTR_TO_LANDLOCK_HANDLE_FS] = "landlock_handle_fs",
+	[CONST_PTR_TO_LANDLOCK_ARG_FS]	= "landlock_arg_fs",
 };
 
 static void print_verifier_state(struct bpf_verifier_state *state)
@@ -515,6 +516,7 @@ static bool is_spillable_regtype(enum bpf_reg_type type)
 	case FRAME_PTR:
 	case CONST_PTR_TO_MAP:
 	case CONST_PTR_TO_LANDLOCK_HANDLE_FS:
+	case CONST_PTR_TO_LANDLOCK_ARG_FS:
 		return true;
 	default:
 		return false;
@@ -980,6 +982,10 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno,
 		expected_type = CONST_PTR_TO_LANDLOCK_HANDLE_FS;
 		if (type != expected_type)
 			goto err_type;
+	} else if (arg_type == ARG_CONST_PTR_TO_LANDLOCK_ARG_FS) {
+		expected_type = CONST_PTR_TO_LANDLOCK_ARG_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/security/landlock/common.h b/security/landlock/common.h
index 0b5aad4a7aaa..dd64e6391dd8 100644
--- a/security/landlock/common.h
+++ b/security/landlock/common.h
@@ -12,6 +12,24 @@
 #define _SECURITY_LANDLOCK_COMMON_H
 
 #include <linux/bpf.h> /* enum landlock_hook */
+#include <linux/fs.h> /* struct file, struct inode */
+#include <linux/path.h> /* struct path */
+
+enum landlock_argtype {
+	LANDLOCK_ARGTYPE_NONE,
+	LANDLOCK_ARGTYPE_FILE,
+	LANDLOCK_ARGTYPE_INODE,
+	LANDLOCK_ARGTYPE_PATH,
+};
+
+struct landlock_arg_fs {
+	enum landlock_argtype type;
+	union {
+		struct file *file;
+		struct inode *inode;
+		const struct path *path;
+	};
+};
 
 /**
  * get_index - get an index for the rules of struct landlock_hooks
diff --git a/security/landlock/lsm.c b/security/landlock/lsm.c
index d7564540c493..b3d154275be6 100644
--- a/security/landlock/lsm.c
+++ b/security/landlock/lsm.c
@@ -15,9 +15,99 @@
 #include <linux/kernel.h> /* FIELD_SIZEOF() */
 #include <linux/landlock.h>
 #include <linux/lsm_hooks.h>
+#include <linux/types.h> /* uintptr_t */
+
+/* hook arguments */
+#include <linux/dcache.h> /* struct dentry */
+#include <linux/fs.h> /* struct inode */
+#include <linux/path.h> /* struct path */
 
 #include "common.h"
 
+#define MAP0(s, m, ...)
+#define MAP1(s, m, d, t, a) m(d, t, a)
+#define MAP2(s, m, d, t, a, ...) m(d, t, a) s() MAP1(s, m, __VA_ARGS__)
+#define MAP3(s, m, d, t, a, ...) m(d, t, a) s() MAP2(s, m, __VA_ARGS__)
+#define MAP4(s, m, d, t, a, ...) m(d, t, a) s() MAP3(s, m, __VA_ARGS__)
+#define MAP5(s, m, d, t, a, ...) m(d, t, a) s() MAP4(s, m, __VA_ARGS__)
+#define MAP6(s, m, d, t, a, ...) m(d, t, a) s() MAP5(s, m, __VA_ARGS__)
+
+/* separators */
+#define SEP_COMMA() ,
+#define SEP_NONE()
+
+/* arguments */
+#define ARG_MAP(n, ...) MAP##n(SEP_COMMA, __VA_ARGS__)
+#define ARG_REGTYPE(d, t, a) d##_REGTYPE
+#define ARG_TA(d, t, a) t a
+#define ARG_GET(d, t, a) ((u64) d##_GET(a))
+
+/* declarations */
+#define DEC_MAP(n, ...) MAP##n(SEP_NONE, DEC, __VA_ARGS__)
+#define DEC(d, t, a) d##_DEC(a)
+
+#define LANDLOCK_HOOKx(X, NAME, CNAME, ...)				\
+	static inline int landlock_hook_##NAME(				\
+		ARG_MAP(X, ARG_TA, __VA_ARGS__))			\
+	{								\
+		DEC_MAP(X, __VA_ARGS__)					\
+		__u64 args[6] = {					\
+			ARG_MAP(X, ARG_GET, __VA_ARGS__)		\
+		};							\
+		return landlock_enforce(LANDLOCK_HOOK_##CNAME, args);	\
+	}								\
+	static inline bool __is_valid_access_hook_##CNAME(		\
+			int off, int size, enum bpf_access_type type,	\
+			enum bpf_reg_type *reg_type,			\
+			union bpf_prog_subtype *prog_subtype)		\
+	{								\
+		enum bpf_reg_type arg_types[6] = {			\
+			ARG_MAP(X, ARG_REGTYPE, __VA_ARGS__)		\
+		};							\
+		return __is_valid_access(off, size, type, reg_type,	\
+				arg_types, prog_subtype);		\
+	}								\
+
+#define LANDLOCK_HOOK1(NAME, ...) LANDLOCK_HOOKx(1, NAME, __VA_ARGS__)
+#define LANDLOCK_HOOK2(NAME, ...) LANDLOCK_HOOKx(2, NAME, __VA_ARGS__)
+#define LANDLOCK_HOOK3(NAME, ...) LANDLOCK_HOOKx(3, NAME, __VA_ARGS__)
+#define LANDLOCK_HOOK4(NAME, ...) LANDLOCK_HOOKx(4, NAME, __VA_ARGS__)
+#define LANDLOCK_HOOK5(NAME, ...) LANDLOCK_HOOKx(5, NAME, __VA_ARGS__)
+#define LANDLOCK_HOOK6(NAME, ...) LANDLOCK_HOOKx(6, NAME, __VA_ARGS__)
+
+#define LANDLOCK_HOOK_INIT(NAME) LSM_HOOK_INIT(NAME, landlock_hook_##NAME)
+
+/* LANDLOCK_WRAPARG_NONE */
+#define LANDLOCK_WRAPARG_NONE_REGTYPE	NOT_INIT
+#define LANDLOCK_WRAPARG_NONE_DEC(arg)
+#define LANDLOCK_WRAPARG_NONE_GET(arg)	0
+
+/* LANDLOCK_WRAPARG_RAW */
+#define LANDLOCK_WRAPARG_RAW_REGTYPE	UNKNOWN_VALUE
+#define LANDLOCK_WRAPARG_RAW_DEC(arg)
+#define LANDLOCK_WRAPARG_RAW_GET(arg)	arg
+
+/* LANDLOCK_WRAPARG_FILE */
+#define LANDLOCK_WRAPARG_FILE_REGTYPE	CONST_PTR_TO_LANDLOCK_ARG_FS
+#define LANDLOCK_WRAPARG_FILE_DEC(arg)			\
+	const struct landlock_arg_fs wrap_##arg =	\
+	{ .type = LANDLOCK_ARGTYPE_FILE, .file = arg };
+#define LANDLOCK_WRAPARG_FILE_GET(arg)	(uintptr_t)&wrap_##arg
+
+/* LANDLOCK_WRAPARG_INODE */
+#define LANDLOCK_WRAPARG_INODE_REGTYPE	CONST_PTR_TO_LANDLOCK_ARG_FS
+#define LANDLOCK_WRAPARG_INODE_DEC(arg)			\
+	const struct landlock_arg_fs wrap_##arg =	\
+	{ .type = LANDLOCK_ARGTYPE_INODE, .inode = arg };
+#define LANDLOCK_WRAPARG_INODE_GET(arg)	(uintptr_t)&wrap_##arg
+
+/* LANDLOCK_WRAPARG_PATH */
+#define LANDLOCK_WRAPARG_PATH_REGTYPE	CONST_PTR_TO_LANDLOCK_ARG_FS
+#define LANDLOCK_WRAPARG_PATH_DEC(arg)			\
+	const struct landlock_arg_fs wrap_##arg =	\
+	{ .type = LANDLOCK_ARGTYPE_PATH, .path = arg };
+#define LANDLOCK_WRAPARG_PATH_GET(arg)	(uintptr_t)&wrap_##arg
+
 /**
  * landlock_run_prog - run Landlock program for a syscall
  *
@@ -127,6 +217,72 @@ static bool __is_valid_access(int off, int size, enum bpf_access_type type,
 	return true;
 }
 
+LANDLOCK_HOOK2(file_open, FILE_OPEN,
+	LANDLOCK_WRAPARG_FILE, struct file *, file,
+	LANDLOCK_WRAPARG_NONE, const struct cred *, cred
+)
+
+LANDLOCK_HOOK2(file_permission, FILE_PERMISSION,
+	LANDLOCK_WRAPARG_FILE, struct file *, file,
+	LANDLOCK_WRAPARG_RAW, int, mask
+)
+
+LANDLOCK_HOOK4(mmap_file, MMAP_FILE,
+	LANDLOCK_WRAPARG_FILE, struct file *, file,
+	LANDLOCK_WRAPARG_RAW, unsigned long, reqprot,
+	LANDLOCK_WRAPARG_RAW, unsigned long, prot,
+	LANDLOCK_WRAPARG_RAW, unsigned long, flags
+)
+
+/* a directory inode contains only one dentry */
+LANDLOCK_HOOK3(inode_create, INODE_CREATE,
+	LANDLOCK_WRAPARG_INODE, struct inode *, dir,
+	LANDLOCK_WRAPARG_NONE, struct dentry *, dentry,
+	LANDLOCK_WRAPARG_RAW, umode_t, mode
+)
+
+LANDLOCK_HOOK3(inode_link, INODE_LINK,
+	LANDLOCK_WRAPARG_NONE, struct dentry *, old_dentry,
+	LANDLOCK_WRAPARG_INODE, struct inode *, dir,
+	LANDLOCK_WRAPARG_NONE, struct dentry *, new_dentry
+)
+
+LANDLOCK_HOOK2(inode_unlink, INODE_UNLINK,
+	LANDLOCK_WRAPARG_INODE, struct inode *, dir,
+	LANDLOCK_WRAPARG_NONE, struct dentry *, dentry
+)
+
+LANDLOCK_HOOK2(inode_permission, INODE_PERMISSION,
+	LANDLOCK_WRAPARG_INODE, struct inode *, inode,
+	LANDLOCK_WRAPARG_RAW, int, mask
+)
+
+LANDLOCK_HOOK1(inode_getattr, INODE_GETATTR,
+	LANDLOCK_WRAPARG_PATH, const struct path *, path
+)
+
+static struct security_hook_list landlock_hooks[] = {
+	LANDLOCK_HOOK_INIT(file_open),
+	LANDLOCK_HOOK_INIT(file_permission),
+	LANDLOCK_HOOK_INIT(mmap_file),
+	LANDLOCK_HOOK_INIT(inode_create),
+	LANDLOCK_HOOK_INIT(inode_link),
+	LANDLOCK_HOOK_INIT(inode_unlink),
+	LANDLOCK_HOOK_INIT(inode_permission),
+	LANDLOCK_HOOK_INIT(inode_getattr),
+};
+
+void __init landlock_add_hooks(void)
+{
+	pr_info("landlock: Becoming ready to sandbox with seccomp\n");
+	security_add_hooks(landlock_hooks, ARRAY_SIZE(landlock_hooks));
+}
+
+#define LANDLOCK_CASE_ACCESS_HOOK(CNAME)			\
+	case LANDLOCK_HOOK_##CNAME:				\
+		return __is_valid_access_hook_##CNAME(		\
+				off, size, type, reg_type, prog_subtype);
+
 static inline bool bpf_landlock_is_valid_access(int off, int size,
 		enum bpf_access_type type, enum bpf_reg_type *reg_type,
 		union bpf_prog_subtype *prog_subtype)
@@ -134,6 +290,14 @@ static inline bool bpf_landlock_is_valid_access(int off, int size,
 	enum landlock_hook hook = prog_subtype->landlock_rule.hook;
 
 	switch (hook) {
+	LANDLOCK_CASE_ACCESS_HOOK(FILE_OPEN)
+	LANDLOCK_CASE_ACCESS_HOOK(FILE_PERMISSION)
+	LANDLOCK_CASE_ACCESS_HOOK(MMAP_FILE)
+	LANDLOCK_CASE_ACCESS_HOOK(INODE_CREATE)
+	LANDLOCK_CASE_ACCESS_HOOK(INODE_LINK)
+	LANDLOCK_CASE_ACCESS_HOOK(INODE_UNLINK)
+	LANDLOCK_CASE_ACCESS_HOOK(INODE_PERMISSION)
+	LANDLOCK_CASE_ACCESS_HOOK(INODE_GETATTR)
 	case LANDLOCK_HOOK_UNSPEC:
 	default:
 		return false;
@@ -146,6 +310,15 @@ static inline bool bpf_landlock_is_valid_subtype(
 	enum landlock_hook hook = prog_subtype->landlock_rule.hook;
 
 	switch (hook) {
+	case LANDLOCK_HOOK_FILE_OPEN:
+	case LANDLOCK_HOOK_FILE_PERMISSION:
+	case LANDLOCK_HOOK_MMAP_FILE:
+	case LANDLOCK_HOOK_INODE_CREATE:
+	case LANDLOCK_HOOK_INODE_LINK:
+	case LANDLOCK_HOOK_INODE_UNLINK:
+	case LANDLOCK_HOOK_INODE_PERMISSION:
+	case LANDLOCK_HOOK_INODE_GETATTR:
+		break;
 	case LANDLOCK_HOOK_UNSPEC:
 	default:
 		return false;
diff --git a/security/security.c b/security/security.c
index f825304f04a7..92f0f1f209b6 100644
--- a/security/security.c
+++ b/security/security.c
@@ -61,6 +61,7 @@ int __init security_init(void)
 	capability_add_hooks();
 	yama_add_hooks();
 	loadpin_add_hooks();
+	landlock_add_hooks();
 
 	/*
 	 * Load all the remaining security modules.
-- 
2.9.3

WARNING: multiple messages have this Message-ID (diff)
From: "Mickaël Salaün" <mic@digikod.net>
To: linux-kernel@vger.kernel.org
Cc: "Mickaël Salaün" <mic@digikod.net>,
	"Alexei Starovoitov" <ast@kernel.org>,
	"Andy Lutomirski" <luto@amacapital.net>,
	"Daniel Borkmann" <daniel@iogearbox.net>,
	"Daniel Mack" <daniel@zonque.org>,
	"David Drysdale" <drysdale@google.com>,
	"David S . Miller" <davem@davemloft.net>,
	"Eric W . Biederman" <ebiederm@xmission.com>,
	"James Morris" <james.l.morris@oracle.com>,
	"Jann Horn" <jann@thejh.net>, "Kees Cook" <keescook@chromium.org>,
	"Paul Moore" <pmoore@redhat.com>,
	"Sargun Dhillon" <sargun@sargun.me>,
	"Serge E . Hallyn" <serge@hallyn.com>,
	"Tejun Heo" <tj@kernel.org>, "Thomas Graf" <tgraf@suug.ch>,
	"Will Drewry" <wad@chromium.org>,
	kernel-hardening@lists.openwall.com, linux-api@vger.kernel.org,
	linux-security-module@vger.kernel.org, netdev@vger.kernel.org,
	cgroups@vger.kernel.org
Subject: [kernel-hardening] [RFC v4 07/18] landlock: Add LSM hooks
Date: Wed, 26 Oct 2016 08:56:43 +0200	[thread overview]
Message-ID: <20161026065654.19166-8-mic@digikod.net> (raw)
In-Reply-To: <20161026065654.19166-1-mic@digikod.net>

Add 8 file system-related hooks:
* file_open
* file_permission
* mmap_file
* inode_create
* inode_link
* inode_unlink
* inode_permission
* inode_getattr

This hook arguments are available to the Landlock rules in the eBPF
context as pointers. This pointers are an abstraction over the
underlying raw types. For now, the ARG_CONST_PTR_TO_LANDLOCK_ARG_FS type
is used for struct file, struct inode and struct path pointers.

Changes since v3:
* split commit
* 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

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>
---
 include/linux/bpf.h        |   2 +
 include/linux/lsm_hooks.h  |   5 ++
 include/uapi/linux/bpf.h   |  10 ++-
 kernel/bpf/verifier.c      |   6 ++
 security/landlock/common.h |  18 +++++
 security/landlock/lsm.c    | 173 +++++++++++++++++++++++++++++++++++++++++++++
 security/security.c        |   1 +
 7 files changed, 214 insertions(+), 1 deletion(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 2cca9fc8b72b..e7ce49642f50 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -88,6 +88,7 @@ enum bpf_arg_type {
 	ARG_ANYTHING,		/* any (initialized) argument is ok */
 
 	ARG_CONST_PTR_TO_LANDLOCK_HANDLE_FS,	/* pointer to Landlock FS map handle */
+	ARG_CONST_PTR_TO_LANDLOCK_ARG_FS,	/* pointer to Landlock FS hook argument */
 };
 
 /* type of values returned from helper functions */
@@ -157,6 +158,7 @@ enum bpf_reg_type {
 
 	/* Landlock */
 	CONST_PTR_TO_LANDLOCK_HANDLE_FS,
+	CONST_PTR_TO_LANDLOCK_ARG_FS,
 };
 
 struct bpf_prog;
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 558adfa5c8a8..069af34301d4 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1933,5 +1933,10 @@ void __init loadpin_add_hooks(void);
 #else
 static inline void loadpin_add_hooks(void) { };
 #endif
+#ifdef CONFIG_SECURITY_LANDLOCK
+extern void __init landlock_add_hooks(void);
+#else
+static inline void __init landlock_add_hooks(void) { }
+#endif /* CONFIG_SECURITY_LANDLOCK */
 
 #endif /* ! __LINUX_LSM_HOOKS_H */
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 335616ab63ff..b6b531a868c0 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -563,8 +563,16 @@ struct xdp_md {
 /* LSM hooks */
 enum landlock_hook {
 	LANDLOCK_HOOK_UNSPEC,
+	LANDLOCK_HOOK_FILE_OPEN,
+	LANDLOCK_HOOK_FILE_PERMISSION,
+	LANDLOCK_HOOK_MMAP_FILE,
+	LANDLOCK_HOOK_INODE_CREATE,
+	LANDLOCK_HOOK_INODE_LINK,
+	LANDLOCK_HOOK_INODE_UNLINK,
+	LANDLOCK_HOOK_INODE_PERMISSION,
+	LANDLOCK_HOOK_INODE_GETATTR,
 };
-#define _LANDLOCK_HOOK_LAST LANDLOCK_HOOK_UNSPEC
+#define _LANDLOCK_HOOK_LAST LANDLOCK_HOOK_INODE_GETATTR
 
 /* eBPF context and functions allowed for a rule */
 #define _LANDLOCK_SUBTYPE_ACCESS_MASK		((1ULL << 0) - 1)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 9b921a9afa3c..32b7941476ec 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -189,6 +189,7 @@ static const char * const reg_type_str[] = {
 	[PTR_TO_PACKET]		= "pkt",
 	[PTR_TO_PACKET_END]	= "pkt_end",
 	[CONST_PTR_TO_LANDLOCK_HANDLE_FS] = "landlock_handle_fs",
+	[CONST_PTR_TO_LANDLOCK_ARG_FS]	= "landlock_arg_fs",
 };
 
 static void print_verifier_state(struct bpf_verifier_state *state)
@@ -515,6 +516,7 @@ static bool is_spillable_regtype(enum bpf_reg_type type)
 	case FRAME_PTR:
 	case CONST_PTR_TO_MAP:
 	case CONST_PTR_TO_LANDLOCK_HANDLE_FS:
+	case CONST_PTR_TO_LANDLOCK_ARG_FS:
 		return true;
 	default:
 		return false;
@@ -980,6 +982,10 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno,
 		expected_type = CONST_PTR_TO_LANDLOCK_HANDLE_FS;
 		if (type != expected_type)
 			goto err_type;
+	} else if (arg_type == ARG_CONST_PTR_TO_LANDLOCK_ARG_FS) {
+		expected_type = CONST_PTR_TO_LANDLOCK_ARG_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/security/landlock/common.h b/security/landlock/common.h
index 0b5aad4a7aaa..dd64e6391dd8 100644
--- a/security/landlock/common.h
+++ b/security/landlock/common.h
@@ -12,6 +12,24 @@
 #define _SECURITY_LANDLOCK_COMMON_H
 
 #include <linux/bpf.h> /* enum landlock_hook */
+#include <linux/fs.h> /* struct file, struct inode */
+#include <linux/path.h> /* struct path */
+
+enum landlock_argtype {
+	LANDLOCK_ARGTYPE_NONE,
+	LANDLOCK_ARGTYPE_FILE,
+	LANDLOCK_ARGTYPE_INODE,
+	LANDLOCK_ARGTYPE_PATH,
+};
+
+struct landlock_arg_fs {
+	enum landlock_argtype type;
+	union {
+		struct file *file;
+		struct inode *inode;
+		const struct path *path;
+	};
+};
 
 /**
  * get_index - get an index for the rules of struct landlock_hooks
diff --git a/security/landlock/lsm.c b/security/landlock/lsm.c
index d7564540c493..b3d154275be6 100644
--- a/security/landlock/lsm.c
+++ b/security/landlock/lsm.c
@@ -15,9 +15,99 @@
 #include <linux/kernel.h> /* FIELD_SIZEOF() */
 #include <linux/landlock.h>
 #include <linux/lsm_hooks.h>
+#include <linux/types.h> /* uintptr_t */
+
+/* hook arguments */
+#include <linux/dcache.h> /* struct dentry */
+#include <linux/fs.h> /* struct inode */
+#include <linux/path.h> /* struct path */
 
 #include "common.h"
 
+#define MAP0(s, m, ...)
+#define MAP1(s, m, d, t, a) m(d, t, a)
+#define MAP2(s, m, d, t, a, ...) m(d, t, a) s() MAP1(s, m, __VA_ARGS__)
+#define MAP3(s, m, d, t, a, ...) m(d, t, a) s() MAP2(s, m, __VA_ARGS__)
+#define MAP4(s, m, d, t, a, ...) m(d, t, a) s() MAP3(s, m, __VA_ARGS__)
+#define MAP5(s, m, d, t, a, ...) m(d, t, a) s() MAP4(s, m, __VA_ARGS__)
+#define MAP6(s, m, d, t, a, ...) m(d, t, a) s() MAP5(s, m, __VA_ARGS__)
+
+/* separators */
+#define SEP_COMMA() ,
+#define SEP_NONE()
+
+/* arguments */
+#define ARG_MAP(n, ...) MAP##n(SEP_COMMA, __VA_ARGS__)
+#define ARG_REGTYPE(d, t, a) d##_REGTYPE
+#define ARG_TA(d, t, a) t a
+#define ARG_GET(d, t, a) ((u64) d##_GET(a))
+
+/* declarations */
+#define DEC_MAP(n, ...) MAP##n(SEP_NONE, DEC, __VA_ARGS__)
+#define DEC(d, t, a) d##_DEC(a)
+
+#define LANDLOCK_HOOKx(X, NAME, CNAME, ...)				\
+	static inline int landlock_hook_##NAME(				\
+		ARG_MAP(X, ARG_TA, __VA_ARGS__))			\
+	{								\
+		DEC_MAP(X, __VA_ARGS__)					\
+		__u64 args[6] = {					\
+			ARG_MAP(X, ARG_GET, __VA_ARGS__)		\
+		};							\
+		return landlock_enforce(LANDLOCK_HOOK_##CNAME, args);	\
+	}								\
+	static inline bool __is_valid_access_hook_##CNAME(		\
+			int off, int size, enum bpf_access_type type,	\
+			enum bpf_reg_type *reg_type,			\
+			union bpf_prog_subtype *prog_subtype)		\
+	{								\
+		enum bpf_reg_type arg_types[6] = {			\
+			ARG_MAP(X, ARG_REGTYPE, __VA_ARGS__)		\
+		};							\
+		return __is_valid_access(off, size, type, reg_type,	\
+				arg_types, prog_subtype);		\
+	}								\
+
+#define LANDLOCK_HOOK1(NAME, ...) LANDLOCK_HOOKx(1, NAME, __VA_ARGS__)
+#define LANDLOCK_HOOK2(NAME, ...) LANDLOCK_HOOKx(2, NAME, __VA_ARGS__)
+#define LANDLOCK_HOOK3(NAME, ...) LANDLOCK_HOOKx(3, NAME, __VA_ARGS__)
+#define LANDLOCK_HOOK4(NAME, ...) LANDLOCK_HOOKx(4, NAME, __VA_ARGS__)
+#define LANDLOCK_HOOK5(NAME, ...) LANDLOCK_HOOKx(5, NAME, __VA_ARGS__)
+#define LANDLOCK_HOOK6(NAME, ...) LANDLOCK_HOOKx(6, NAME, __VA_ARGS__)
+
+#define LANDLOCK_HOOK_INIT(NAME) LSM_HOOK_INIT(NAME, landlock_hook_##NAME)
+
+/* LANDLOCK_WRAPARG_NONE */
+#define LANDLOCK_WRAPARG_NONE_REGTYPE	NOT_INIT
+#define LANDLOCK_WRAPARG_NONE_DEC(arg)
+#define LANDLOCK_WRAPARG_NONE_GET(arg)	0
+
+/* LANDLOCK_WRAPARG_RAW */
+#define LANDLOCK_WRAPARG_RAW_REGTYPE	UNKNOWN_VALUE
+#define LANDLOCK_WRAPARG_RAW_DEC(arg)
+#define LANDLOCK_WRAPARG_RAW_GET(arg)	arg
+
+/* LANDLOCK_WRAPARG_FILE */
+#define LANDLOCK_WRAPARG_FILE_REGTYPE	CONST_PTR_TO_LANDLOCK_ARG_FS
+#define LANDLOCK_WRAPARG_FILE_DEC(arg)			\
+	const struct landlock_arg_fs wrap_##arg =	\
+	{ .type = LANDLOCK_ARGTYPE_FILE, .file = arg };
+#define LANDLOCK_WRAPARG_FILE_GET(arg)	(uintptr_t)&wrap_##arg
+
+/* LANDLOCK_WRAPARG_INODE */
+#define LANDLOCK_WRAPARG_INODE_REGTYPE	CONST_PTR_TO_LANDLOCK_ARG_FS
+#define LANDLOCK_WRAPARG_INODE_DEC(arg)			\
+	const struct landlock_arg_fs wrap_##arg =	\
+	{ .type = LANDLOCK_ARGTYPE_INODE, .inode = arg };
+#define LANDLOCK_WRAPARG_INODE_GET(arg)	(uintptr_t)&wrap_##arg
+
+/* LANDLOCK_WRAPARG_PATH */
+#define LANDLOCK_WRAPARG_PATH_REGTYPE	CONST_PTR_TO_LANDLOCK_ARG_FS
+#define LANDLOCK_WRAPARG_PATH_DEC(arg)			\
+	const struct landlock_arg_fs wrap_##arg =	\
+	{ .type = LANDLOCK_ARGTYPE_PATH, .path = arg };
+#define LANDLOCK_WRAPARG_PATH_GET(arg)	(uintptr_t)&wrap_##arg
+
 /**
  * landlock_run_prog - run Landlock program for a syscall
  *
@@ -127,6 +217,72 @@ static bool __is_valid_access(int off, int size, enum bpf_access_type type,
 	return true;
 }
 
+LANDLOCK_HOOK2(file_open, FILE_OPEN,
+	LANDLOCK_WRAPARG_FILE, struct file *, file,
+	LANDLOCK_WRAPARG_NONE, const struct cred *, cred
+)
+
+LANDLOCK_HOOK2(file_permission, FILE_PERMISSION,
+	LANDLOCK_WRAPARG_FILE, struct file *, file,
+	LANDLOCK_WRAPARG_RAW, int, mask
+)
+
+LANDLOCK_HOOK4(mmap_file, MMAP_FILE,
+	LANDLOCK_WRAPARG_FILE, struct file *, file,
+	LANDLOCK_WRAPARG_RAW, unsigned long, reqprot,
+	LANDLOCK_WRAPARG_RAW, unsigned long, prot,
+	LANDLOCK_WRAPARG_RAW, unsigned long, flags
+)
+
+/* a directory inode contains only one dentry */
+LANDLOCK_HOOK3(inode_create, INODE_CREATE,
+	LANDLOCK_WRAPARG_INODE, struct inode *, dir,
+	LANDLOCK_WRAPARG_NONE, struct dentry *, dentry,
+	LANDLOCK_WRAPARG_RAW, umode_t, mode
+)
+
+LANDLOCK_HOOK3(inode_link, INODE_LINK,
+	LANDLOCK_WRAPARG_NONE, struct dentry *, old_dentry,
+	LANDLOCK_WRAPARG_INODE, struct inode *, dir,
+	LANDLOCK_WRAPARG_NONE, struct dentry *, new_dentry
+)
+
+LANDLOCK_HOOK2(inode_unlink, INODE_UNLINK,
+	LANDLOCK_WRAPARG_INODE, struct inode *, dir,
+	LANDLOCK_WRAPARG_NONE, struct dentry *, dentry
+)
+
+LANDLOCK_HOOK2(inode_permission, INODE_PERMISSION,
+	LANDLOCK_WRAPARG_INODE, struct inode *, inode,
+	LANDLOCK_WRAPARG_RAW, int, mask
+)
+
+LANDLOCK_HOOK1(inode_getattr, INODE_GETATTR,
+	LANDLOCK_WRAPARG_PATH, const struct path *, path
+)
+
+static struct security_hook_list landlock_hooks[] = {
+	LANDLOCK_HOOK_INIT(file_open),
+	LANDLOCK_HOOK_INIT(file_permission),
+	LANDLOCK_HOOK_INIT(mmap_file),
+	LANDLOCK_HOOK_INIT(inode_create),
+	LANDLOCK_HOOK_INIT(inode_link),
+	LANDLOCK_HOOK_INIT(inode_unlink),
+	LANDLOCK_HOOK_INIT(inode_permission),
+	LANDLOCK_HOOK_INIT(inode_getattr),
+};
+
+void __init landlock_add_hooks(void)
+{
+	pr_info("landlock: Becoming ready to sandbox with seccomp\n");
+	security_add_hooks(landlock_hooks, ARRAY_SIZE(landlock_hooks));
+}
+
+#define LANDLOCK_CASE_ACCESS_HOOK(CNAME)			\
+	case LANDLOCK_HOOK_##CNAME:				\
+		return __is_valid_access_hook_##CNAME(		\
+				off, size, type, reg_type, prog_subtype);
+
 static inline bool bpf_landlock_is_valid_access(int off, int size,
 		enum bpf_access_type type, enum bpf_reg_type *reg_type,
 		union bpf_prog_subtype *prog_subtype)
@@ -134,6 +290,14 @@ static inline bool bpf_landlock_is_valid_access(int off, int size,
 	enum landlock_hook hook = prog_subtype->landlock_rule.hook;
 
 	switch (hook) {
+	LANDLOCK_CASE_ACCESS_HOOK(FILE_OPEN)
+	LANDLOCK_CASE_ACCESS_HOOK(FILE_PERMISSION)
+	LANDLOCK_CASE_ACCESS_HOOK(MMAP_FILE)
+	LANDLOCK_CASE_ACCESS_HOOK(INODE_CREATE)
+	LANDLOCK_CASE_ACCESS_HOOK(INODE_LINK)
+	LANDLOCK_CASE_ACCESS_HOOK(INODE_UNLINK)
+	LANDLOCK_CASE_ACCESS_HOOK(INODE_PERMISSION)
+	LANDLOCK_CASE_ACCESS_HOOK(INODE_GETATTR)
 	case LANDLOCK_HOOK_UNSPEC:
 	default:
 		return false;
@@ -146,6 +310,15 @@ static inline bool bpf_landlock_is_valid_subtype(
 	enum landlock_hook hook = prog_subtype->landlock_rule.hook;
 
 	switch (hook) {
+	case LANDLOCK_HOOK_FILE_OPEN:
+	case LANDLOCK_HOOK_FILE_PERMISSION:
+	case LANDLOCK_HOOK_MMAP_FILE:
+	case LANDLOCK_HOOK_INODE_CREATE:
+	case LANDLOCK_HOOK_INODE_LINK:
+	case LANDLOCK_HOOK_INODE_UNLINK:
+	case LANDLOCK_HOOK_INODE_PERMISSION:
+	case LANDLOCK_HOOK_INODE_GETATTR:
+		break;
 	case LANDLOCK_HOOK_UNSPEC:
 	default:
 		return false;
diff --git a/security/security.c b/security/security.c
index f825304f04a7..92f0f1f209b6 100644
--- a/security/security.c
+++ b/security/security.c
@@ -61,6 +61,7 @@ int __init security_init(void)
 	capability_add_hooks();
 	yama_add_hooks();
 	loadpin_add_hooks();
+	landlock_add_hooks();
 
 	/*
 	 * Load all the remaining security modules.
-- 
2.9.3

  parent reply	other threads:[~2016-10-26  7:01 UTC|newest]

Thread overview: 70+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-10-26  6:56 [RFC v4 00/18] Landlock LSM: Unprivileged sandboxing Mickaël Salaün
2016-10-26  6:56 ` [kernel-hardening] " Mickaël Salaün
2016-10-26  6:56 ` [RFC v4 01/18] landlock: Add Kconfig Mickaël Salaün
2016-10-26  6:56   ` [kernel-hardening] " Mickaël Salaün
2016-10-26  6:56   ` Mickaël Salaün
2016-10-26  6:56 ` [RFC v4 02/18] bpf: Move u64_to_ptr() to BPF headers and inline it Mickaël Salaün
2016-10-26  6:56   ` [kernel-hardening] " Mickaël Salaün
2016-10-26  7:19   ` Arnd Bergmann
2016-10-26  7:19     ` [kernel-hardening] " Arnd Bergmann
2016-10-26 13:52     ` David Sterba
2016-10-26 13:52       ` David Sterba
2016-10-26  6:56 ` [RFC v4 03/18] bpf,landlock: Add a new arraymap type to deal with (Landlock) handles Mickaël Salaün
2016-10-26  6:56   ` [kernel-hardening] " Mickaël Salaün
2016-10-26 19:01   ` Jann Horn
2016-10-26 19:01     ` Jann Horn
2016-10-26 20:03     ` Mickaël Salaün
2016-10-26 20:03       ` Mickaël Salaün
2016-10-26 20:16       ` [kernel-hardening] " Jann Horn
2016-10-26 20:16         ` Jann Horn
2016-10-26  6:56 ` [RFC v4 04/18] bpf,landlock: Add eBPF program subtype and is_valid_subtype() verifier Mickaël Salaün
2016-10-26  6:56   ` [kernel-hardening] " Mickaël Salaün
2016-10-26  6:56 ` [RFC v4 05/18] bpf,landlock: Define an eBPF program type for Landlock Mickaël Salaün
2016-10-26  6:56   ` [kernel-hardening] " Mickaël Salaün
2016-10-26  6:56 ` [RFC v4 06/18] fs: Constify path_is_under()'s arguments Mickaël Salaün
2016-10-26  6:56   ` [kernel-hardening] " Mickaël Salaün
2016-10-26  6:56   ` Mickaël Salaün
2016-10-26  6:56 ` Mickaël Salaün [this message]
2016-10-26  6:56   ` [kernel-hardening] [RFC v4 07/18] landlock: Add LSM hooks Mickaël Salaün
2016-10-26  6:56 ` [RFC v4 08/18] landlock: Handle file comparisons Mickaël Salaün
2016-10-26  6:56   ` [kernel-hardening] " Mickaël Salaün
2016-10-26  6:56 ` [RFC v4 09/18] landlock: Add manager functions Mickaël Salaün
2016-10-26  6:56   ` [kernel-hardening] " Mickaël Salaün
2016-10-26  6:56 ` [RFC v4 10/18] seccomp: Split put_seccomp_filter() with put_seccomp() Mickaël Salaün
2016-10-26  6:56   ` [kernel-hardening] " Mickaël Salaün
2016-10-26  6:56 ` [RFC v4 11/18] seccomp,landlock: Handle Landlock hooks per process hierarchy Mickaël Salaün
2016-10-26  6:56   ` [kernel-hardening] " Mickaël Salaün
2016-10-26  6:56   ` Mickaël Salaün
2016-10-26  6:56 ` [RFC v4 12/18] bpf: Cosmetic change for bpf_prog_attach() Mickaël Salaün
2016-10-26  6:56   ` [kernel-hardening] " Mickaël Salaün
2016-10-26  6:56 ` [RFC v4 13/18] bpf/cgroup: Replace struct bpf_prog with struct bpf_object Mickaël Salaün
2016-10-26  6:56   ` [kernel-hardening] " Mickaël Salaün
2016-10-26  6:56 ` [RFC v4 14/18] bpf/cgroup: Make cgroup_bpf_update() return an error code Mickaël Salaün
2016-10-26  6:56   ` [kernel-hardening] " Mickaël Salaün
2016-10-26  6:56 ` [RFC v4 15/18] bpf/cgroup: Move capability check Mickaël Salaün
2016-10-26  6:56   ` [kernel-hardening] " Mickaël Salaün
2016-10-26  6:56   ` Mickaël Salaün
2016-10-26  6:56 ` [RFC v4 16/18] bpf/cgroup,landlock: Handle Landlock hooks per cgroup Mickaël Salaün
2016-10-26  6:56   ` [kernel-hardening] " Mickaël Salaün
2016-10-26  6:56   ` Mickaël Salaün
2016-10-26  6:56 ` [RFC v4 17/18] landlock: Add update and debug access flags Mickaël Salaün
2016-10-26  6:56   ` [kernel-hardening] " Mickaël Salaün
2016-10-26  6:56   ` Mickaël Salaün
2016-10-26  6:56 ` [RFC v4 18/18] samples/landlock: Add sandbox example Mickaël Salaün
2016-10-26  6:56   ` [kernel-hardening] " Mickaël Salaün
2016-10-26  6:56   ` Mickaël Salaün
2016-10-26 14:52 ` [RFC v4 00/18] Landlock LSM: Unprivileged sandboxing Jann Horn
2016-10-26 14:52   ` [kernel-hardening] " Jann Horn
2016-10-26 16:56   ` Mickaël Salaün
2016-10-26 16:56     ` [kernel-hardening] " Mickaël Salaün
2016-10-26 17:24     ` Mickaël Salaün
2016-10-26 17:24       ` [kernel-hardening] " Mickaël Salaün
2016-11-13 14:23 ` Mickaël Salaün
2016-11-13 14:23   ` [kernel-hardening] " Mickaël Salaün
2016-11-14 10:35   ` Sargun Dhillon
2016-11-14 10:35     ` [kernel-hardening] " Sargun Dhillon
2016-11-14 10:35     ` Sargun Dhillon
2016-11-14 20:51     ` Mickaël Salaün
2016-11-14 20:51       ` [kernel-hardening] " Mickaël Salaün
2016-11-14 20:51       ` Mickaël Salaün
2016-11-14 20:51       ` Mickaël Salaün

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20161026065654.19166-8-mic@digikod.net \
    --to=mic@digikod.net \
    --cc=ast@kernel.org \
    --cc=cgroups@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=daniel@zonque.org \
    --cc=davem@davemloft.net \
    --cc=drysdale@google.com \
    --cc=ebiederm@xmission.com \
    --cc=james.l.morris@oracle.com \
    --cc=jann@thejh.net \
    --cc=keescook@chromium.org \
    --cc=kernel-hardening@lists.openwall.com \
    --cc=linux-api@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-security-module@vger.kernel.org \
    --cc=luto@amacapital.net \
    --cc=netdev@vger.kernel.org \
    --cc=pmoore@redhat.com \
    --cc=sargun@sargun.me \
    --cc=serge@hallyn.com \
    --cc=tgraf@suug.ch \
    --cc=tj@kernel.org \
    --cc=wad@chromium.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.