All of lore.kernel.org
 help / color / mirror / Atom feed
From: David Drysdale <drysdale@google.com>
To: linux-security-module@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>,
	Meredydd Luff <meredydd@senatehouse.org>,
	Kees Cook <keescook@chromium.org>,
	James Morris <james.l.morris@oracle.com>,
	linux-api@vger.kernel.org, David Drysdale <drysdale@google.com>
Subject: [PATCH 09/11] capsicum: implementations of new LSM hooks
Date: Mon, 30 Jun 2014 11:28:09 +0100	[thread overview]
Message-ID: <1404124096-21445-10-git-send-email-drysdale@google.com> (raw)
In-Reply-To: <1404124096-21445-1-git-send-email-drysdale@google.com>

If the LSM does not provide implementations of the .file_lookup and
.file_install LSM hooks, always use the Capsicum implementations.

The Capsicum implementation of file_lookup checks for a Capsicum
capability wrapper file and unwraps to if the appropriate rights
are available.

The Capsicum implementation of file_install checks whether the file
has restricted rights associated with it.  If it does, it is replaced
with a Capsicum capability wrapper file before installation into the
fdtable.

Signed-off-by: David Drysdale <drysdale@google.com>
---
 include/linux/capsicum.h         |   7 ++
 include/uapi/asm-generic/errno.h |   3 +
 security/Makefile                |   2 +-
 security/capability.c            |  17 ++-
 security/capsicum.c              | 257 +++++++++++++++++++++++++++++++++++++++
 5 files changed, 283 insertions(+), 3 deletions(-)
 create mode 100644 security/capsicum.c

diff --git a/include/linux/capsicum.h b/include/linux/capsicum.h
index 74f79756097a..a3e7540f15e7 100644
--- a/include/linux/capsicum.h
+++ b/include/linux/capsicum.h
@@ -13,6 +13,13 @@ struct capsicum_rights {
 	unsigned int *ioctls;
 };
 
+/* LSM hook fallback functions */
+struct file *capsicum_file_lookup(struct file *file,
+				  const struct capsicum_rights *required_rights,
+				  const struct capsicum_rights **actual_rights);
+struct file *capsicum_file_install(const struct capsicum_rights *base_rights,
+				   struct file *file);
+
 #define CAP_LIST_END	0ULL
 
 #ifdef CONFIG_SECURITY_CAPSICUM
diff --git a/include/uapi/asm-generic/errno.h b/include/uapi/asm-generic/errno.h
index 1e1ea6e6e7a5..550570ed7b9f 100644
--- a/include/uapi/asm-generic/errno.h
+++ b/include/uapi/asm-generic/errno.h
@@ -110,4 +110,7 @@
 
 #define EHWPOISON	133	/* Memory page has hardware error */
 
+#define ECAPMODE        134     /* Not permitted in capability mode */
+#define ENOTCAPABLE     135     /* Capability FD rights insufficient */
+
 #endif
diff --git a/security/Makefile b/security/Makefile
index c5e1363ae136..e46d014a74b3 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -14,7 +14,7 @@ obj-y					+= commoncap.o
 obj-$(CONFIG_MMU)			+= min_addr.o
 
 # Object file lists
-obj-$(CONFIG_SECURITY)			+= security.o capability.o capsicum-rights.o
+obj-$(CONFIG_SECURITY)			+= security.o capability.o capsicum.o capsicum-rights.o
 obj-$(CONFIG_SECURITYFS)		+= inode.o
 obj-$(CONFIG_SECURITY_SELINUX)		+= selinux/
 obj-$(CONFIG_SECURITY_SMACK)		+= smack/
diff --git a/security/capability.c b/security/capability.c
index ad0d4de69944..11d5a1bd6e57 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -11,6 +11,7 @@
  */
 
 #include <linux/security.h>
+#include <linux/capsicum.h>
 
 static int cap_syslog(int type)
 {
@@ -917,9 +918,19 @@ static void cap_audit_rule_free(void *lsmrule)
 #define set_to_cap_if_null(ops, function)				\
 	do {								\
 		if (!ops->function) {					\
-			ops->function = cap_##function;			\
+			ops->function = cap_##function;		\
 			pr_debug("Had to override the " #function	\
-				 " security operation with the default.\n");\
+				 " security operation with the default "\
+				 "cap_" #function ".\n");		\
+			}						\
+	} while (0)
+#define set_to_capsicum_if_null(ops, function)				\
+	do {								\
+		if (!ops->function) {					\
+			ops->function = capsicum_##function;		\
+			pr_debug("Had to override the " #function	\
+				 " security operation with the default "\
+				 "capsicum_" #function ".\n");		\
 			}						\
 	} while (0)
 
@@ -1007,6 +1018,8 @@ void __init security_fixup_ops(struct security_operations *ops)
 	set_to_cap_if_null(ops, file_send_sigiotask);
 	set_to_cap_if_null(ops, file_receive);
 	set_to_cap_if_null(ops, file_open);
+	set_to_capsicum_if_null(ops, file_lookup);
+	set_to_capsicum_if_null(ops, file_install);
 	set_to_cap_if_null(ops, task_create);
 	set_to_cap_if_null(ops, task_free);
 	set_to_cap_if_null(ops, cred_alloc_blank);
diff --git a/security/capsicum.c b/security/capsicum.c
new file mode 100644
index 000000000000..83677eef3fb6
--- /dev/null
+++ b/security/capsicum.c
@@ -0,0 +1,257 @@
+/*
+ * Main implementation of Capsicum, a capability framework for UNIX.
+ *
+ * Copyright (C) 2012-2013 The Chromium OS Authors
+ *                         <chromium-os-dev@chromium.org>
+ *
+ * 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.
+ *
+ * See Documentation/security/capsicum.txt for information on Capsicum.
+ */
+
+#include <linux/anon_inodes.h>
+#include <linux/fs.h>
+#include <linux/fdtable.h>
+#include <linux/file.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/printk.h>
+#include <linux/slab.h>
+#include <linux/security.h>
+#include <linux/syscalls.h>
+#include <linux/capsicum.h>
+
+#include "capsicum-rights.h"
+
+#ifdef CONFIG_SECURITY_CAPSICUM
+/*
+ * Capsicum capability structure, holding the associated rights and underlying
+ * real file.  Capabilities are not stacked, i.e. underlying always points to a
+ * normal file not another Capsicum capability. Accessed via file->private_data.
+ */
+struct capsicum_capability {
+	struct capsicum_rights rights;
+	struct file *underlying;
+};
+
+static void capsicum_panic_not_unwrapped(void);
+static int capsicum_release(struct inode *i, struct file *capf);
+static int capsicum_show_fdinfo(struct seq_file *m, struct file *capf);
+
+#define panic_ptr ((void *)&capsicum_panic_not_unwrapped)
+static const struct file_operations capsicum_file_ops = {
+	.owner = NULL,
+	.llseek = panic_ptr,
+	.read = panic_ptr,
+	.write = panic_ptr,
+	.aio_read = panic_ptr,
+	.aio_write = panic_ptr,
+	.iterate = panic_ptr,
+	.poll = panic_ptr,
+	.unlocked_ioctl = panic_ptr,
+	.compat_ioctl = panic_ptr,
+	.mmap = panic_ptr,
+	.open = panic_ptr,
+	.flush = NULL,  /* This is called on close if implemented. */
+	.release = capsicum_release,  /* This is the only one we want. */
+	.fsync = panic_ptr,
+	.aio_fsync = panic_ptr,
+	.fasync = panic_ptr,
+	.lock = panic_ptr,
+	.sendpage = panic_ptr,
+	.get_unmapped_area = panic_ptr,
+	.check_flags = panic_ptr,
+	.flock = panic_ptr,
+	.splice_write = panic_ptr,
+	.splice_read = panic_ptr,
+	.setlease = panic_ptr,
+	.fallocate = panic_ptr,
+	.show_fdinfo = capsicum_show_fdinfo
+};
+
+static inline bool capsicum_is_cap(const struct file *file)
+{
+	return file->f_op == &capsicum_file_ops;
+}
+
+static struct capsicum_rights all_rights = {
+	.primary = {.cr_rights = {CAP_ALL0, CAP_ALL1} },
+	.fcntls = CAP_FCNTL_ALL,
+	.nioctls = -1,
+	.ioctls = NULL
+};
+
+static struct file *capsicum_cap_alloc(const struct capsicum_rights *rights,
+				       bool take_ioctls)
+{
+	int err;
+	struct file *capf;
+	/* memory to be freed on error exit: */
+	struct capsicum_capability *cap = NULL;
+	unsigned int *ioctls = (take_ioctls ? rights->ioctls : NULL);
+
+	BUG_ON((rights->nioctls > 0) != (rights->ioctls != NULL));
+
+	cap = kmalloc(sizeof(*cap), GFP_KERNEL);
+	if (!cap) {
+		err = -ENOMEM;
+		goto out_err;
+	}
+	cap->underlying = NULL;
+	cap->rights = *rights;
+	if (!take_ioctls && rights->nioctls > 0) {
+		cap->rights.ioctls = kmemdup(rights->ioctls,
+					rights->nioctls * sizeof(unsigned int),
+					GFP_KERNEL);
+		if (!cap->rights.ioctls) {
+			err = -ENOMEM;
+			goto out_err;
+		}
+		ioctls = cap->rights.ioctls;
+	}
+
+	capf = anon_inode_getfile("[capability]", &capsicum_file_ops, cap, 0);
+	if (IS_ERR(capf)) {
+		err = PTR_ERR(capf);
+		goto out_err;
+	}
+	return capf;
+
+out_err:
+	kfree(ioctls);
+	kfree(cap);
+	return ERR_PTR(err);
+}
+
+/*
+ * File operations functions.
+ */
+
+/*
+ * When we release a Capsicum capability, release our reference to the
+ * underlying (wrapped) file as well.
+ */
+static int capsicum_release(struct inode *i, struct file *capf)
+{
+	struct capsicum_capability *cap;
+
+	if (!capsicum_is_cap(capf))
+		return -EINVAL;
+
+	cap = capf->private_data;
+	BUG_ON(!cap);
+	if (cap->underlying)
+		fput(cap->underlying);
+	cap->underlying = NULL;
+	kfree(cap->rights.ioctls);
+	kfree(cap);
+	return 0;
+}
+
+static int capsicum_show_fdinfo(struct seq_file *m, struct file *capf)
+{
+	int i;
+	struct capsicum_capability *cap;
+
+	if (!capsicum_is_cap(capf))
+		return -EINVAL;
+
+	cap = capf->private_data;
+	BUG_ON(!cap);
+	seq_puts(m, "rights:");
+	for (i = 0; i < (CAP_RIGHTS_VERSION + 2); i++)
+		seq_printf(m, "\t%#016llx", cap->rights.primary.cr_rights[i]);
+	seq_puts(m, "\n");
+	seq_printf(m, " fcntls: %#08x\n", cap->rights.fcntls);
+	if (cap->rights.nioctls > 0) {
+		seq_puts(m, " ioctls:");
+		for (i = 0; i < cap->rights.nioctls; i++)
+			seq_printf(m, "\t%#08x", cap->rights.ioctls[i]);
+		seq_puts(m, "\n");
+	}
+	return 0;
+}
+
+static void capsicum_panic_not_unwrapped(void)
+{
+	/*
+	 * General Capsicum file operations should never be called, because the
+	 * relevant file should always be unwrapped and the underlying real file
+	 * used instead.
+	 */
+	panic("Called a file_operations member on a Capsicum wrapper");
+}
+
+/*
+ * LSM hook fallback functions.
+ */
+
+/*
+ * We are looking up a file by its file descriptor. If it is a Capsicum
+ * capability, and has the required rights, we unwrap it and return the
+ * underlying file.
+ */
+struct file *capsicum_file_lookup(struct file *file,
+				  const struct capsicum_rights *required_rights,
+				  const struct capsicum_rights **actual_rights)
+{
+	struct capsicum_capability *cap;
+
+	/* See if the file in question is a Capsicum capability. */
+	if (!capsicum_is_cap(file)) {
+		if (actual_rights)
+			*actual_rights = &all_rights;
+		return file;
+	}
+	cap = file->private_data;
+	if (required_rights &&
+	    !cap_rights_contains(&cap->rights, required_rights)) {
+		return ERR_PTR(-ENOTCAPABLE);
+	}
+	if (actual_rights)
+		*actual_rights = &cap->rights;
+	return cap->underlying;
+}
+EXPORT_SYMBOL(capsicum_file_lookup);
+
+struct file *capsicum_file_install(const struct capsicum_rights *base_rights,
+				   struct file *file)
+{
+	struct file *capf;
+	struct capsicum_capability *cap;
+	if (!base_rights || cap_rights_is_all(base_rights))
+		return file;
+
+	capf = capsicum_cap_alloc(base_rights, false);
+	if (IS_ERR(capf))
+		return capf;
+
+	if (!atomic_long_inc_not_zero(&file->f_count)) {
+		fput(capf);
+		return ERR_PTR(-EBADF);
+	}
+	cap = capf->private_data;
+	cap->underlying = file;
+	return capf;
+}
+EXPORT_SYMBOL(capsicum_file_install);
+
+#else
+
+struct file *capsicum_file_lookup(struct file *file,
+				  const struct capsicum_rights *required_rights,
+				  const struct capsicum_rights **actual_rights)
+{
+	return file;
+}
+
+struct file *
+capsicum_file_install(const const struct capsicum_rights *base_rights,
+		      struct file *file)
+{
+	return file;
+}
+
+#endif
-- 
2.0.0.526.g5318336


  parent reply	other threads:[~2014-06-30 10:31 UTC|newest]

Thread overview: 87+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-06-30 10:28 [RFC PATCH 00/11] Adding FreeBSD's Capsicum security framework (part 1) David Drysdale
2014-06-30 10:28 ` [PATCH 01/11] fs: add O_BENEATH_ONLY flag to openat(2) David Drysdale
2014-06-30 14:49   ` Andy Lutomirski
2014-06-30 15:49     ` David Drysdale
2014-06-30 15:53       ` Andy Lutomirski
2014-07-08 12:07         ` Christoph Hellwig
2014-07-08 12:07           ` Christoph Hellwig
2014-07-08 12:48           ` Meredydd Luff
2014-07-08 12:48             ` Meredydd Luff
2014-07-08 12:51             ` Christoph Hellwig
2014-07-08 12:51               ` Christoph Hellwig
2014-07-08 13:04               ` Meredydd Luff
2014-07-08 13:04                 ` Meredydd Luff
2014-07-08 13:12                 ` Christoph Hellwig
2014-06-30 20:40   ` Andi Kleen
2014-06-30 21:11     ` Andy Lutomirski
2014-07-01  9:53     ` David Drysdale
2014-07-01  9:53       ` David Drysdale
2014-07-01 18:58       ` Loganaden Velvindron
2014-07-08 12:03   ` Christoph Hellwig
2014-07-08 12:03     ` Christoph Hellwig
2014-07-08 16:54     ` David Drysdale
2014-07-08 16:54       ` David Drysdale
2014-07-09  8:48       ` Christoph Hellwig
2014-06-30 10:28 ` [PATCH 02/11] selftests: Add test of O_BENEATH_ONLY & openat(2) David Drysdale
2014-06-30 10:28   ` David Drysdale
2014-06-30 10:28 ` [PATCH 03/11] capsicum: rights values and structure definitions David Drysdale
2014-06-30 10:28   ` David Drysdale
2014-06-30 10:28 ` [PATCH 04/11] capsicum: implement fgetr() and friends David Drysdale
2014-06-30 10:28   ` David Drysdale
2014-06-30 10:28 ` [PATCH 05/11] capsicum: convert callers to use fgetr() etc David Drysdale
2014-06-30 10:28 ` [PATCH 06/11] capsicum: implement sockfd_lookupr() David Drysdale
2014-06-30 10:28 ` [PATCH 07/11] capsicum: convert callers to use sockfd_lookupr() etc David Drysdale
2014-06-30 10:28 ` [PATCH 08/11] capsicum: add new LSM hooks on FD/file conversion David Drysdale
2014-06-30 10:28 ` David Drysdale [this message]
2014-06-30 16:05   ` [PATCH 09/11] capsicum: implementations of new LSM hooks Andy Lutomirski
2014-06-30 16:05     ` Andy Lutomirski
2014-07-02 13:49     ` Paul Moore
2014-07-02 13:49       ` Paul Moore
2014-07-02 17:09       ` David Drysdale
2014-07-02 17:09         ` David Drysdale
2014-06-30 10:28 ` [PATCH 10/11] capsicum: invocation " David Drysdale
2014-06-30 10:28 ` [PATCH 11/11] capsicum: add syscalls to limit FD rights David Drysdale
2014-06-30 10:28 ` [PATCH 1/5] man-pages: open.2: describe O_BENEATH_ONLY flag David Drysdale
2014-06-30 22:22   ` Andy Lutomirski
2014-06-30 10:28 ` [PATCH 2/5] man-pages: capsicum.7: describe Capsicum capability framework David Drysdale
2014-06-30 10:28 ` [PATCH 3/5] man-pages: rights.7: Describe Capsicum primary rights David Drysdale
2014-06-30 10:28 ` [PATCH 4/5] man-pages: cap_rights_limit.2: limit FD rights for Capsicum David Drysdale
2014-06-30 14:53   ` Andy Lutomirski
2014-06-30 14:53     ` Andy Lutomirski
2014-06-30 15:35     ` David Drysdale
2014-06-30 15:35       ` David Drysdale
2014-06-30 16:06       ` Andy Lutomirski
2014-06-30 16:06         ` Andy Lutomirski
2014-06-30 16:32         ` David Drysdale
2014-06-30 10:28 ` [PATCH 5/5] man-pages: cap_rights_get: retrieve Capsicum fd rights David Drysdale
2014-06-30 22:28   ` Andy Lutomirski
2014-06-30 22:28     ` Andy Lutomirski
2014-07-01  9:19     ` David Drysdale
2014-07-01  9:19       ` David Drysdale
2014-07-01 14:18       ` Andy Lutomirski
2014-07-03  9:12 ` [RFC PATCH 00/11] Adding FreeBSD's Capsicum security framework (part 1) Paolo Bonzini
2014-07-03  9:12   ` [Qemu-devel] " Paolo Bonzini
2014-07-03 10:01   ` Loganaden Velvindron
2014-07-03 10:01     ` [Qemu-devel] " Loganaden Velvindron
2014-07-03 18:39   ` David Drysdale
2014-07-03 18:39     ` [Qemu-devel] " David Drysdale
2014-07-03 18:39     ` David Drysdale
2014-07-04  7:03     ` Paolo Bonzini
2014-07-04  7:03       ` [Qemu-devel] " Paolo Bonzini
2014-07-04  7:03       ` Paolo Bonzini
2014-07-07 10:29       ` David Drysdale
2014-07-07 10:29         ` [Qemu-devel] " David Drysdale
2014-07-07 12:20         ` Paolo Bonzini
2014-07-07 12:20           ` [Qemu-devel] " Paolo Bonzini
2014-07-07 14:11           ` David Drysdale
2014-07-07 14:11             ` [Qemu-devel] " David Drysdale
2014-07-07 14:11             ` David Drysdale
2014-07-07 22:33           ` Alexei Starovoitov
2014-07-07 22:33             ` [Qemu-devel] " Alexei Starovoitov
2014-07-07 22:33             ` Alexei Starovoitov
2014-07-08 14:58             ` Kees Cook
2014-07-08 14:58               ` [Qemu-devel] " Kees Cook
2014-07-08 14:58               ` Kees Cook
2014-08-16 15:41             ` Pavel Machek
2014-08-16 15:41               ` [Qemu-devel] " Pavel Machek
2014-08-16 15:41               ` Pavel Machek

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=1404124096-21445-10-git-send-email-drysdale@google.com \
    --to=drysdale@google.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=james.l.morris@oracle.com \
    --cc=keescook@chromium.org \
    --cc=linux-api@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-security-module@vger.kernel.org \
    --cc=meredydd@senatehouse.org \
    --cc=viro@zeniv.linux.org.uk \
    /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.