All of lore.kernel.org
 help / color / mirror / Atom feed
From: KP Singh <kpsingh@chromium.org>
To: linux-kernel@vger.kernel.org, bpf@vger.kernel.org,
	linux-security-module@vger.kernel.org
Cc: "Alexei Starovoitov" <ast@kernel.org>,
	"Daniel Borkmann" <daniel@iogearbox.net>,
	"James Morris" <jmorris@namei.org>,
	"Kees Cook" <keescook@chromium.org>,
	"Thomas Garnier" <thgarnie@chromium.org>,
	"Michael Halcrow" <mhalcrow@google.com>,
	"Paul Turner" <pjt@google.com>,
	"Brendan Gregg" <brendan.d.gregg@gmail.com>,
	"Jann Horn" <jannh@google.com>,
	"Matthew Garrett" <mjg59@google.com>,
	"Christian Brauner" <christian@brauner.io>,
	"Mickaël Salaün" <mic@digikod.net>,
	"Florent Revest" <revest@chromium.org>,
	"Brendan Jackman" <jackmanb@chromium.org>,
	"Martin KaFai Lau" <kafai@fb.com>,
	"Song Liu" <songliubraving@fb.com>, "Yonghong Song" <yhs@fb.com>,
	"Serge E. Hallyn" <serge@hallyn.com>,
	"Mauro Carvalho Chehab" <mchehab+samsung@kernel.org>,
	"David S. Miller" <davem@davemloft.net>,
	"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
	"Nicolas Ferre" <nicolas.ferre@microchip.com>,
	"Stanislav Fomichev" <sdf@google.com>,
	"Quentin Monnet" <quentin.monnet@netronome.com>,
	"Andrey Ignatov" <rdna@fb.com>, "Joe Stringer" <joe@wand.net.nz>
Subject: [PATCH bpf-next v1 07/13] bpf: lsm: Implement attach, detach and execution.
Date: Fri, 20 Dec 2019 16:42:02 +0100	[thread overview]
Message-ID: <20191220154208.15895-8-kpsingh@chromium.org> (raw)
In-Reply-To: <20191220154208.15895-1-kpsingh@chromium.org>

From: KP Singh <kpsingh@google.com>

A user space program can attach an eBPF program by:

  hook_fd = open("/sys/kernel/security/bpf/bprm_check_security",
		 O_RDWR|O_CLOEXEC)
  prog_fd = bpf(BPF_PROG_LOAD, ...)
  bpf(BPF_PROG_ATTACH, hook_fd, prog_fd)

The following permissions are required to attach a program to a hook:

- CAP_SYS_ADMIN to load eBPF programs
- CAP_MAC_ADMIN (to update the policy of an LSM)
- The securityfs file being a valid hook and writable (O_RDWR)

When such an attach call is received, the attachment logic looks up the
dentry and appends the program to the bpf_prog_array.

The BPF programs are stored in a bpf_prog_array and writes to the array
are guarded by a mutex. The eBPF programs are executed as a part of the
LSM hook they are attached to. If any of the eBPF programs return
an error (-ENOPERM) the action represented by the hook is denied.

Signed-off-by: KP Singh <kpsingh@google.com>
---
 MAINTAINERS             |   1 +
 include/linux/bpf_lsm.h |  13 ++++
 kernel/bpf/syscall.c    |   5 +-
 security/bpf/lsm_fs.c   |  19 +++++-
 security/bpf/ops.c      | 134 ++++++++++++++++++++++++++++++++++++++++
 5 files changed, 169 insertions(+), 3 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 3b82d8ff21fb..681ae39bb2f0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3181,6 +3181,7 @@ L:	linux-security-module@vger.kernel.org
 L:	bpf@vger.kernel.org
 S:	Maintained
 F:	security/bpf/
+F:	include/linux/bpf_lsm.h
 
 BROADCOM B44 10/100 ETHERNET DRIVER
 M:	Michael Chan <michael.chan@broadcom.com>
diff --git a/include/linux/bpf_lsm.h b/include/linux/bpf_lsm.h
index 76f81e642dc2..c029f2b8d6fd 100644
--- a/include/linux/bpf_lsm.h
+++ b/include/linux/bpf_lsm.h
@@ -7,6 +7,19 @@
 
 #ifdef CONFIG_SECURITY_BPF
 extern int bpf_lsm_fs_initialized;
+int bpf_lsm_attach(const union bpf_attr *attr, struct bpf_prog *prog);
+int bpf_lsm_detach(const union bpf_attr *attr);
+#else
+static inline int bpf_lsm_attach(const union bpf_attr *attr,
+				 struct bpf_prog *prog)
+{
+	return -EINVAL;
+}
+
+static inline int bpf_lsm_detach(const union bpf_attr *attr)
+{
+	return -EINVAL;
+}
 #endif /* CONFIG_SECURITY_BPF */
 
 #endif /* _LINUX_BPF_LSM_H */
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 4fcaf6042c07..8897b774973f 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -4,6 +4,7 @@
 #include <linux/bpf.h>
 #include <linux/bpf_trace.h>
 #include <linux/bpf_lirc.h>
+#include <linux/bpf_lsm.h>
 #include <linux/btf.h>
 #include <linux/syscalls.h>
 #include <linux/slab.h>
@@ -2132,7 +2133,7 @@ static int bpf_prog_attach(const union bpf_attr *attr)
 		ret = lirc_prog_attach(attr, prog);
 		break;
 	case BPF_PROG_TYPE_LSM:
-		ret = -EINVAL;
+		ret = bpf_lsm_attach(attr, prog);
 		break;
 	case BPF_PROG_TYPE_FLOW_DISSECTOR:
 		ret = skb_flow_dissector_bpf_prog_attach(attr, prog);
@@ -2200,6 +2201,8 @@ static int bpf_prog_detach(const union bpf_attr *attr)
 	case BPF_CGROUP_SETSOCKOPT:
 		ptype = BPF_PROG_TYPE_CGROUP_SOCKOPT;
 		break;
+	case BPF_LSM_MAC:
+		return bpf_lsm_detach(attr);
 	default:
 		return -EINVAL;
 	}
diff --git a/security/bpf/lsm_fs.c b/security/bpf/lsm_fs.c
index 49165394ef7d..b271e9582d0f 100644
--- a/security/bpf/lsm_fs.c
+++ b/security/bpf/lsm_fs.c
@@ -9,6 +9,8 @@
 #include <linux/file.h>
 #include <linux/fs.h>
 #include <linux/types.h>
+#include <linux/filter.h>
+#include <linux/bpf.h>
 #include <linux/security.h>
 #include <linux/bpf_lsm.h>
 
@@ -28,6 +30,19 @@ bool is_bpf_lsm_hook_file(struct file *f)
 
 static void __init free_hook(struct bpf_lsm_hook *h)
 {
+	struct bpf_prog_array_item *item;
+	/*
+	 * This function is __init so we are guaranteed that there will be
+	 * no concurrent access.
+	 */
+	struct bpf_prog_array *progs = rcu_dereference_raw(h->progs);
+
+	if (progs) {
+		for (item = progs->items; item->prog; item++)
+			bpf_prog_put(item->prog);
+		bpf_prog_array_free(progs);
+	}
+
 	securityfs_remove(h->h_dentry);
 	h->h_dentry = NULL;
 }
@@ -36,8 +51,8 @@ static int __init init_hook(struct bpf_lsm_hook *h, struct dentry *parent)
 {
 	struct dentry *h_dentry;
 
-	h_dentry = securityfs_create_file(h->name, 0600, parent,
-			NULL, &hook_ops);
+	h_dentry = securityfs_create_file(h->name, 0600,
+					  parent, NULL, &hook_ops);
 	if (IS_ERR(h_dentry))
 		return PTR_ERR(h_dentry);
 
diff --git a/security/bpf/ops.c b/security/bpf/ops.c
index 2fa3ebdf598d..eb8a8db28109 100644
--- a/security/bpf/ops.c
+++ b/security/bpf/ops.c
@@ -4,11 +4,145 @@
  * Copyright 2019 Google LLC.
  */
 
+#include <linux/err.h>
+#include <linux/types.h>
 #include <linux/filter.h>
 #include <linux/bpf.h>
+#include <linux/security.h>
+#include <linux/bpf_lsm.h>
+
+#include "bpf_lsm.h"
+#include "fs.h"
+
+static struct bpf_lsm_hook *get_hook_from_fd(int fd)
+{
+	struct bpf_lsm_hook *h;
+	struct fd f;
+	int ret;
+
+	/*
+	 * Only CAP_MAC_ADMIN users are allowed to make changes to LSM hooks
+	 */
+	if (!capable(CAP_MAC_ADMIN))
+		return ERR_PTR(-EPERM);
+
+
+	f = fdget(fd);
+	if (!f.file)
+		return ERR_PTR(-EBADF);
+
+
+	if (!is_bpf_lsm_hook_file(f.file)) {
+		ret = -EINVAL;
+		goto error;
+	}
+
+	/*
+	 * It's wrong to attach the program to the hook if the file is not
+	 * opened for a writing. Note that, this is an EBADF and not an EPERM
+	 * because the file has been opened with an incorrect mode.
+	 */
+	if (!(f.file->f_mode & FMODE_WRITE)) {
+		ret = -EBADF;
+		goto error;
+	}
+
+	/*
+	 * The securityfs dentry never disappears, so we don't need to take a
+	 * reference to it.
+	 */
+	h = file_dentry(f.file)->d_fsdata;
+	if (WARN_ON(!h)) {
+		ret = -EINVAL;
+		goto error;
+	}
+	fdput(f);
+	return h;
+
+error:
+	fdput(f);
+	return ERR_PTR(ret);
+}
+
+int bpf_lsm_attach(const union bpf_attr *attr, struct bpf_prog *prog)
+{
+	struct bpf_prog_array *old_array;
+	struct bpf_prog_array *new_array;
+	struct bpf_lsm_hook *h;
+	int ret = 0;
+
+	h = get_hook_from_fd(attr->target_fd);
+	if (IS_ERR(h))
+		return PTR_ERR(h);
+
+	mutex_lock(&h->mutex);
+	old_array = rcu_dereference_protected(h->progs,
+					      lockdep_is_held(&h->mutex));
+
+	ret = bpf_prog_array_copy(old_array, NULL, prog, &new_array);
+	if (ret < 0)
+		goto unlock;
+
+	rcu_assign_pointer(h->progs, new_array);
+	bpf_prog_array_free(old_array);
+
+unlock:
+	mutex_unlock(&h->mutex);
+	return ret;
+}
+
+int bpf_lsm_detach(const union bpf_attr *attr)
+{
+	struct bpf_prog_array *old_array, *new_array;
+	struct bpf_prog *prog;
+	struct bpf_lsm_hook *h;
+	int ret = 0;
+
+	if (attr->attach_flags)
+		return -EINVAL;
+
+	h = get_hook_from_fd(attr->target_fd);
+	if (IS_ERR(h))
+		return PTR_ERR(h);
+
+	prog = bpf_prog_get_type(attr->attach_bpf_fd,
+				 BPF_PROG_TYPE_LSM);
+	if (IS_ERR(prog))
+		return PTR_ERR(prog);
+
+	mutex_lock(&h->mutex);
+	old_array = rcu_dereference_protected(h->progs,
+					      lockdep_is_held(&h->mutex));
+
+	ret = bpf_prog_array_copy(old_array, prog, NULL, &new_array);
+	if (ret)
+		goto unlock;
+
+	rcu_assign_pointer(h->progs, new_array);
+	bpf_prog_array_free(old_array);
+unlock:
+	bpf_prog_put(prog);
+	mutex_unlock(&h->mutex);
+	return ret;
+}
 
 const struct bpf_prog_ops lsm_prog_ops = {
 };
 
+static const struct bpf_func_proto *get_bpf_func_proto(enum bpf_func_id
+		func_id, const struct bpf_prog *prog)
+{
+	switch (func_id) {
+	case BPF_FUNC_map_lookup_elem:
+		return &bpf_map_lookup_elem_proto;
+	case BPF_FUNC_get_current_pid_tgid:
+		return &bpf_get_current_pid_tgid_proto;
+	default:
+		return NULL;
+	}
+}
+
 const struct bpf_verifier_ops lsm_verifier_ops = {
+	.get_func_proto = get_bpf_func_proto,
+	.is_valid_access = btf_ctx_access,
 };
-- 
2.20.1


  parent reply	other threads:[~2019-12-20 15:42 UTC|newest]

Thread overview: 74+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-12-20 15:41 [PATCH bpf-next v1 00/13] MAC and Audit policy using eBPF (KRSI) KP Singh
2019-12-20 15:41 ` [PATCH bpf-next v1 01/13] bpf: Refactor BPF_EVENT context macros to its own header KP Singh
2019-12-20 20:10   ` Andrii Nakryiko
2019-12-20 20:26     ` KP Singh
2019-12-20 15:41 ` [PATCH bpf-next v1 02/13] bpf: lsm: Add a skeleton and config options KP Singh
2020-01-07 21:13   ` James Morris
2019-12-20 15:41 ` [PATCH bpf-next v1 03/13] bpf: lsm: Introduce types for eBPF based LSM KP Singh
2019-12-20 15:41 ` [PATCH bpf-next v1 04/13] bpf: lsm: Allow btf_id based attachment for LSM hooks KP Singh
2019-12-23 23:54   ` Andrii Nakryiko
2019-12-30 19:22     ` KP Singh
2019-12-20 15:42 ` [PATCH bpf-next v1 05/13] tools/libbpf: Add support in libbpf for BPF_PROG_TYPE_LSM KP Singh
2019-12-24  0:07   ` Andrii Nakryiko
2019-12-24  0:09     ` Andrii Nakryiko
2020-01-03 23:59     ` KP Singh
2019-12-20 15:42 ` [PATCH bpf-next v1 06/13] bpf: lsm: Init Hooks and create files in securityfs KP Singh
2019-12-24  6:28   ` Andrii Nakryiko
2019-12-30 15:37     ` KP Singh
2019-12-30 18:52       ` Andrii Nakryiko
2019-12-30 19:20       ` Kees Cook
2020-01-03 23:53         ` KP Singh
2020-01-07 21:22   ` James Morris
2019-12-20 15:42 ` KP Singh [this message]
2019-12-24  5:48   ` [PATCH bpf-next v1 07/13] bpf: lsm: Implement attach, detach and execution Andrii Nakryiko
2020-01-07 21:27   ` James Morris
2019-12-20 15:42 ` [PATCH bpf-next v1 08/13] bpf: lsm: Show attached program names in hook read handler KP Singh
2020-01-07 21:28   ` James Morris
2019-12-20 15:42 ` [PATCH bpf-next v1 09/13] bpf: lsm: Add a helper function bpf_lsm_event_output KP Singh
2019-12-24  6:36   ` Andrii Nakryiko
2019-12-30 15:11     ` KP Singh
2019-12-30 18:56       ` Andrii Nakryiko
2019-12-20 15:42 ` [PATCH bpf-next v1 10/13] bpf: lsm: Handle attachment of the same program KP Singh
2019-12-24  6:38   ` Andrii Nakryiko
2020-01-08 18:21   ` James Morris
2019-12-20 15:42 ` [PATCH bpf-next v1 11/13] tools/libbpf: Add bpf_program__attach_lsm KP Singh
2019-12-24  6:44   ` Andrii Nakryiko
2020-01-08 18:24   ` James Morris
2019-12-20 15:42 ` [PATCH bpf-next v1 12/13] bpf: lsm: Add selftests for BPF_PROG_TYPE_LSM KP Singh
2019-12-24  6:49   ` Andrii Nakryiko
2020-01-04  0:09     ` KP Singh
2020-01-09 17:59       ` Andrii Nakryiko
2020-01-08 18:25   ` James Morris
2019-12-20 15:42 ` [PATCH bpf-next v1 13/13] bpf: lsm: Add Documentation KP Singh
2019-12-20 17:17 ` [PATCH bpf-next v1 00/13] MAC and Audit policy using eBPF (KRSI) Casey Schaufler
2019-12-20 17:38   ` KP Singh
2019-12-30 19:15     ` Kees Cook
2020-01-08 15:25       ` Stephen Smalley
2020-01-08 18:58         ` James Morris
2020-01-08 19:33           ` Stephen Smalley
2020-01-09 18:11             ` James Morris
2020-01-09 18:23               ` Greg Kroah-Hartman
2020-01-09 18:58               ` Stephen Smalley
2020-01-09 19:07                 ` James Morris
2020-01-09 19:43                   ` KP Singh
2020-01-09 19:47                     ` Stephen Smalley
2020-01-10 15:27                       ` KP Singh
2020-01-10 17:48                         ` James Morris
2020-01-10 17:53                         ` Alexei Starovoitov
2020-01-14 16:54                           ` Stephen Smalley
2020-01-14 17:42                             ` Stephen Smalley
2020-01-15  2:48                               ` Alexei Starovoitov
2020-01-15 13:59                                 ` Stephen Smalley
2020-01-15 14:09                                   ` Greg Kroah-Hartman
2020-01-15 22:23                                     ` Alexei Starovoitov
2020-01-09 19:11               ` KP Singh
2020-01-08 18:27       ` James Morris
2019-12-20 22:46 ` Mickaël Salaün
2019-12-30 19:30   ` Kees Cook
2019-12-31 12:11     ` Mickaël Salaün
2019-12-22  1:27 ` Alexei Starovoitov
2019-12-30 14:58   ` KP Singh
2019-12-30 19:14     ` Andrii Nakryiko
2019-12-24  6:51 ` Andrii Nakryiko
2019-12-30 15:04   ` KP Singh
2019-12-30 18:58     ` Andrii Nakryiko

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=20191220154208.15895-8-kpsingh@chromium.org \
    --to=kpsingh@chromium.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=brendan.d.gregg@gmail.com \
    --cc=christian@brauner.io \
    --cc=daniel@iogearbox.net \
    --cc=davem@davemloft.net \
    --cc=gregkh@linuxfoundation.org \
    --cc=jackmanb@chromium.org \
    --cc=jannh@google.com \
    --cc=jmorris@namei.org \
    --cc=joe@wand.net.nz \
    --cc=kafai@fb.com \
    --cc=keescook@chromium.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-security-module@vger.kernel.org \
    --cc=mchehab+samsung@kernel.org \
    --cc=mhalcrow@google.com \
    --cc=mic@digikod.net \
    --cc=mjg59@google.com \
    --cc=nicolas.ferre@microchip.com \
    --cc=pjt@google.com \
    --cc=quentin.monnet@netronome.com \
    --cc=rdna@fb.com \
    --cc=revest@chromium.org \
    --cc=sdf@google.com \
    --cc=serge@hallyn.com \
    --cc=songliubraving@fb.com \
    --cc=thgarnie@chromium.org \
    --cc=yhs@fb.com \
    /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.