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
next prev parent reply other threads:[~2014-06-30 10:31 UTC|newest]
Thread overview: 53+ 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:48 ` Meredydd Luff
2014-07-08 12:51 ` Christoph Hellwig
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 18:58 ` Loganaden Velvindron
2014-07-08 12:03 ` Christoph Hellwig
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 ` [PATCH 03/11] capsicum: rights values and structure definitions David Drysdale
2014-06-30 10:28 ` [PATCH 04/11] capsicum: implement fgetr() and friends 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-07-02 13:49 ` Paul Moore
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 15:35 ` David Drysdale
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-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 10:01 ` Loganaden Velvindron
2014-07-03 18:39 ` David Drysdale
2014-07-04 7:03 ` Paolo Bonzini
2014-07-07 10:29 ` David Drysdale
2014-07-07 12:20 ` Paolo Bonzini
2014-07-07 14:11 ` David Drysdale
2014-07-07 22:33 ` Alexei Starovoitov
2014-07-08 14:58 ` Kees Cook
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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®