summaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
Diffstat (limited to 'security')
-rw-r--r--security/Kconfig35
-rw-r--r--security/apparmor/Kconfig31
-rw-r--r--security/apparmor/Makefile2
-rw-r--r--security/apparmor/apparmorfs.c681
-rw-r--r--security/apparmor/audit.c98
-rw-r--r--security/apparmor/capability.c26
-rw-r--r--security/apparmor/context.c107
-rw-r--r--security/apparmor/crypto.c39
-rw-r--r--security/apparmor/domain.c139
-rw-r--r--security/apparmor/file.c80
-rw-r--r--security/apparmor/include/apparmor.h82
-rw-r--r--security/apparmor/include/apparmorfs.h21
-rw-r--r--security/apparmor/include/audit.h152
-rw-r--r--security/apparmor/include/context.h84
-rw-r--r--security/apparmor/include/crypto.h5
-rw-r--r--security/apparmor/include/domain.h4
-rw-r--r--security/apparmor/include/file.h9
-rw-r--r--security/apparmor/include/lib.h194
-rw-r--r--security/apparmor/include/match.h26
-rw-r--r--security/apparmor/include/path.h53
-rw-r--r--security/apparmor/include/policy.h203
-rw-r--r--security/apparmor/include/policy_ns.h147
-rw-r--r--security/apparmor/include/policy_unpack.h28
-rw-r--r--security/apparmor/include/secid.h (renamed from security/apparmor/include/sid.h)18
-rw-r--r--security/apparmor/ipc.c18
-rw-r--r--security/apparmor/lib.c111
-rw-r--r--security/apparmor/lsm.c327
-rw-r--r--security/apparmor/match.c47
-rw-r--r--security/apparmor/nulldfa.in1
-rw-r--r--security/apparmor/policy.c826
-rw-r--r--security/apparmor/policy_ns.c346
-rw-r--r--security/apparmor/policy_unpack.c257
-rw-r--r--security/apparmor/procattr.c38
-rw-r--r--security/apparmor/resource.c19
-rw-r--r--security/apparmor/secid.c55
-rw-r--r--security/apparmor/sid.c55
-rw-r--r--security/commoncap.c8
-rw-r--r--security/inode.c26
-rw-r--r--security/integrity/evm/evm_main.c2
-rw-r--r--security/integrity/ima/ima.h2
-rw-r--r--security/integrity/ima/ima_api.c23
-rw-r--r--security/integrity/ima/ima_main.c14
-rw-r--r--security/keys/dh.c2
-rw-r--r--security/keys/encrypted-keys/encrypted.c8
-rw-r--r--security/keys/internal.h1
-rw-r--r--security/keys/keyctl.c2
-rw-r--r--security/keys/persistent.c2
-rw-r--r--security/keys/process_keys.c1
-rw-r--r--security/keys/request_key.c7
-rw-r--r--security/keys/trusted.c4
-rw-r--r--security/keys/user_defined.c6
-rw-r--r--security/loadpin/loadpin.c2
-rw-r--r--security/security.c48
-rw-r--r--security/selinux/hooks.c395
-rw-r--r--security/selinux/include/classmap.h64
-rw-r--r--security/selinux/include/objsec.h10
-rw-r--r--security/selinux/include/security.h5
-rw-r--r--security/selinux/selinuxfs.c106
-rw-r--r--security/selinux/ss/ebitmap.c2
-rw-r--r--security/selinux/ss/policydb.c2
-rw-r--r--security/selinux/ss/services.c7
-rw-r--r--security/smack/smack.h3
-rw-r--r--security/smack/smack_lsm.c149
-rw-r--r--security/smack/smackfs.c5
-rw-r--r--security/tomoyo/domain.c2
-rw-r--r--security/tomoyo/group.c2
-rw-r--r--security/tomoyo/tomoyo.c2
-rw-r--r--security/tomoyo/util.c2
-rw-r--r--security/yama/yama_lsm.c2
69 files changed, 3407 insertions, 1873 deletions
diff --git a/security/Kconfig b/security/Kconfig
index 118f4549404e..d900f47eaa68 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -158,6 +158,41 @@ config HARDENED_USERCOPY_PAGESPAN
been removed. This config is intended to be used only while
trying to find such users.
+config STATIC_USERMODEHELPER
+ bool "Force all usermode helper calls through a single binary"
+ help
+ By default, the kernel can call many different userspace
+ binary programs through the "usermode helper" kernel
+ interface. Some of these binaries are statically defined
+ either in the kernel code itself, or as a kernel configuration
+ option. However, some of these are dynamically created at
+ runtime, or can be modified after the kernel has started up.
+ To provide an additional layer of security, route all of these
+ calls through a single executable that can not have its name
+ changed.
+
+ Note, it is up to this single binary to then call the relevant
+ "real" usermode helper binary, based on the first argument
+ passed to it. If desired, this program can filter and pick
+ and choose what real programs are called.
+
+ If you wish for all usermode helper programs are to be
+ disabled, choose this option and then set
+ STATIC_USERMODEHELPER_PATH to an empty string.
+
+config STATIC_USERMODEHELPER_PATH
+ string "Path to the static usermode helper binary"
+ depends on STATIC_USERMODEHELPER
+ default "/sbin/usermode-helper"
+ help
+ The binary called by the kernel when any usermode helper
+ program is wish to be run. The "real" application's name will
+ be in the first argument passed to this program on the command
+ line.
+
+ If you wish for all usermode helper programs to be disabled,
+ specify an empty string here (i.e. "").
+
source security/selinux/Kconfig
source security/smack/Kconfig
source security/tomoyo/Kconfig
diff --git a/security/apparmor/Kconfig b/security/apparmor/Kconfig
index be5e9414a295..b6b68a7750ce 100644
--- a/security/apparmor/Kconfig
+++ b/security/apparmor/Kconfig
@@ -36,7 +36,6 @@ config SECURITY_APPARMOR_HASH
select CRYPTO
select CRYPTO_SHA1
default y
-
help
This option selects whether introspection of loaded policy
is available to userspace via the apparmor filesystem.
@@ -45,7 +44,6 @@ config SECURITY_APPARMOR_HASH_DEFAULT
bool "Enable policy hash introspection by default"
depends on SECURITY_APPARMOR_HASH
default y
-
help
This option selects whether sha1 hashing of loaded policy
is enabled by default. The generation of sha1 hashes for
@@ -54,3 +52,32 @@ config SECURITY_APPARMOR_HASH_DEFAULT
however it can slow down policy load on some devices. In
these cases policy hashing can be disabled by default and
enabled only if needed.
+
+config SECURITY_APPARMOR_DEBUG
+ bool "Build AppArmor with debug code"
+ depends on SECURITY_APPARMOR
+ default n
+ help
+ Build apparmor with debugging logic in apparmor. Not all
+ debugging logic will necessarily be enabled. A submenu will
+ provide fine grained control of the debug options that are
+ available.
+
+config SECURITY_APPARMOR_DEBUG_ASSERTS
+ bool "Build AppArmor with debugging asserts"
+ depends on SECURITY_APPARMOR_DEBUG
+ default y
+ help
+ Enable code assertions made with AA_BUG. These are primarily
+ function entry preconditions but also exist at other key
+ points. If the assert is triggered it will trigger a WARN
+ message.
+
+config SECURITY_APPARMOR_DEBUG_MESSAGES
+ bool "Debug messages enabled by default"
+ depends on SECURITY_APPARMOR_DEBUG
+ default n
+ help
+ Set the default value of the apparmor.debug kernel parameter.
+ When enabled, various debug messages will be logged to
+ the kernel message buffer.
diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
index d693df874818..ad369a7aac24 100644
--- a/security/apparmor/Makefile
+++ b/security/apparmor/Makefile
@@ -4,7 +4,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
- resource.o sid.o file.o
+ resource.o secid.o file.o policy_ns.o
apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
clean-files := capability_names.h rlim_names.h
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 5923d5665209..41073f70eb41 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -18,9 +18,12 @@
#include <linux/module.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>
+#include <linux/mount.h>
#include <linux/namei.h>
#include <linux/capability.h>
#include <linux/rcupdate.h>
+#include <uapi/linux/major.h>
+#include <linux/fs.h>
#include "include/apparmor.h"
#include "include/apparmorfs.h"
@@ -28,7 +31,9 @@
#include "include/context.h"
#include "include/crypto.h"
#include "include/policy.h"
+#include "include/policy_ns.h"
#include "include/resource.h"
+#include "include/policy_unpack.h"
/**
* aa_mangle_name - mangle a profile name to std profile layout form
@@ -37,7 +42,7 @@
*
* Returns: length of mangled name
*/
-static int mangle_name(char *name, char *target)
+static int mangle_name(const char *name, char *target)
{
char *t = target;
@@ -71,7 +76,6 @@ static int mangle_name(char *name, char *target)
/**
* aa_simple_write_to_buffer - common routine for getting policy from user
- * @op: operation doing the user buffer copy
* @userbuf: user buffer to copy data from (NOT NULL)
* @alloc_size: size of user buffer (REQUIRES: @alloc_size >= @copy_size)
* @copy_size: size of data to copy from user buffer
@@ -80,31 +84,29 @@ static int mangle_name(char *name, char *target)
* Returns: kernel buffer containing copy of user buffer data or an
* ERR_PTR on failure.
*/
-static char *aa_simple_write_to_buffer(int op, const char __user *userbuf,
- size_t alloc_size, size_t copy_size,
- loff_t *pos)
+static struct aa_loaddata *aa_simple_write_to_buffer(const char __user *userbuf,
+ size_t alloc_size,
+ size_t copy_size,
+ loff_t *pos)
{
- char *data;
+ struct aa_loaddata *data;
- BUG_ON(copy_size > alloc_size);
+ AA_BUG(copy_size > alloc_size);
if (*pos != 0)
/* only writes from pos 0, that is complete writes */
return ERR_PTR(-ESPIPE);
- /*
- * Don't allow profile load/replace/remove from profiles that don't
- * have CAP_MAC_ADMIN
- */
- if (!aa_may_manage_policy(op))
- return ERR_PTR(-EACCES);
-
/* freed by caller to simple_write_to_buffer */
- data = kvmalloc(alloc_size);
+ data = kvmalloc(sizeof(*data) + alloc_size);
if (data == NULL)
return ERR_PTR(-ENOMEM);
+ kref_init(&data->count);
+ data->size = copy_size;
+ data->hash = NULL;
+ data->abi = 0;
- if (copy_from_user(data, userbuf, copy_size)) {
+ if (copy_from_user(data->data, userbuf, copy_size)) {
kvfree(data);
return ERR_PTR(-EFAULT);
}
@@ -112,25 +114,43 @@ static char *aa_simple_write_to_buffer(int op, const char __user *userbuf,
return data;
}
-
-/* .load file hook fn to load policy */
-static ssize_t profile_load(struct file *f, const char __user *buf, size_t size,
- loff_t *pos)
+static ssize_t policy_update(int binop, const char __user *buf, size_t size,
+ loff_t *pos, struct aa_ns *ns)
{
- char *data;
ssize_t error;
+ struct aa_loaddata *data;
+ struct aa_profile *profile = aa_current_profile();
+ const char *op = binop == PROF_ADD ? OP_PROF_LOAD : OP_PROF_REPL;
+ /* high level check about policy management - fine grained in
+ * below after unpack
+ */
+ error = aa_may_manage_policy(profile, ns, op);
+ if (error)
+ return error;
- data = aa_simple_write_to_buffer(OP_PROF_LOAD, buf, size, size, pos);
-
+ data = aa_simple_write_to_buffer(buf, size, size, pos);
error = PTR_ERR(data);
if (!IS_ERR(data)) {
- error = aa_replace_profiles(data, size, PROF_ADD);
- kvfree(data);
+ error = aa_replace_profiles(ns ? ns : profile->ns, profile,
+ binop, data);
+ aa_put_loaddata(data);
}
return error;
}
+/* .load file hook fn to load policy */
+static ssize_t profile_load(struct file *f, const char __user *buf, size_t size,
+ loff_t *pos)
+{
+ struct aa_ns *ns = aa_get_ns(f->f_inode->i_private);
+ int error = policy_update(PROF_ADD, buf, size, pos, ns);
+
+ aa_put_ns(ns);
+
+ return error;
+}
+
static const struct file_operations aa_fs_profile_load = {
.write = profile_load,
.llseek = default_llseek,
@@ -140,15 +160,10 @@ static const struct file_operations aa_fs_profile_load = {
static ssize_t profile_replace(struct file *f, const char __user *buf,
size_t size, loff_t *pos)
{
- char *data;
- ssize_t error;
+ struct aa_ns *ns = aa_get_ns(f->f_inode->i_private);
+ int error = policy_update(PROF_REPLACE, buf, size, pos, ns);
- data = aa_simple_write_to_buffer(OP_PROF_REPL, buf, size, size, pos);
- error = PTR_ERR(data);
- if (!IS_ERR(data)) {
- error = aa_replace_profiles(data, size, PROF_REPLACE);
- kvfree(data);
- }
+ aa_put_ns(ns);
return error;
}
@@ -162,22 +177,34 @@ static const struct file_operations aa_fs_profile_replace = {
static ssize_t profile_remove(struct file *f, const char __user *buf,
size_t size, loff_t *pos)
{
- char *data;
+ struct aa_loaddata *data;
+ struct aa_profile *profile;
ssize_t error;
+ struct aa_ns *ns = aa_get_ns(f->f_inode->i_private);
+
+ profile = aa_current_profile();
+ /* high level check about policy management - fine grained in
+ * below after unpack
+ */
+ error = aa_may_manage_policy(profile, ns, OP_PROF_RM);
+ if (error)
+ goto out;
/*
* aa_remove_profile needs a null terminated string so 1 extra
* byte is allocated and the copied data is null terminated.
*/
- data = aa_simple_write_to_buffer(OP_PROF_RM, buf, size + 1, size, pos);
+ data = aa_simple_write_to_buffer(buf, size + 1, size, pos);
error = PTR_ERR(data);
if (!IS_ERR(data)) {
- data[size] = 0;
- error = aa_remove_profiles(data, size);
- kvfree(data);
+ data->data[size] = 0;
+ error = aa_remove_profiles(ns ? ns : profile->ns, profile,
+ data->data, size);
+ aa_put_loaddata(data);
}
-
+ out:
+ aa_put_ns(ns);
return error;
}
@@ -186,6 +213,144 @@ static const struct file_operations aa_fs_profile_remove = {
.llseek = default_llseek,
};
+/**
+ * query_data - queries a policy and writes its data to buf
+ * @buf: the resulting data is stored here (NOT NULL)
+ * @buf_len: size of buf
+ * @query: query string used to retrieve data
+ * @query_len: size of query including second NUL byte
+ *
+ * The buffers pointed to by buf and query may overlap. The query buffer is
+ * parsed before buf is written to.
+ *
+ * The query should look like "<LABEL>\0<KEY>\0", where <LABEL> is the name of
+ * the security confinement context and <KEY> is the name of the data to
+ * retrieve. <LABEL> and <KEY> must not be NUL-terminated.
+ *
+ * Don't expect the contents of buf to be preserved on failure.
+ *
+ * Returns: number of characters written to buf or -errno on failure
+ */
+static ssize_t query_data(char *buf, size_t buf_len,
+ char *query, size_t query_len)
+{
+ char *out;
+ const char *key;
+ struct aa_profile *profile;
+ struct aa_data *data;
+ u32 bytes, blocks;
+ __le32 outle32;
+
+ if (!query_len)
+ return -EINVAL; /* need a query */
+
+ key = query + strnlen(query, query_len) + 1;
+ if (key + 1 >= query + query_len)
+ return -EINVAL; /* not enough space for a non-empty key */
+ if (key + strnlen(key, query + query_len - key) >= query + query_len)
+ return -EINVAL; /* must end with NUL */
+
+ if (buf_len < sizeof(bytes) + sizeof(blocks))
+ return -EINVAL; /* not enough space */
+
+ profile = aa_current_profile();
+
+ /* We are going to leave space for two numbers. The first is the total
+ * number of bytes we are writing after the first number. This is so
+ * users can read the full output without reallocation.
+ *
+ * The second number is the number of data blocks we're writing. An
+ * application might be confined by multiple policies having data in
+ * the same key.
+ */
+ memset(buf, 0, sizeof(bytes) + sizeof(blocks));
+ out = buf + sizeof(bytes) + sizeof(blocks);
+
+ blocks = 0;
+ if (profile->data) {
+ data = rhashtable_lookup_fast(profile->data, &key,
+ profile->data->p);
+
+ if (data) {
+ if (out + sizeof(outle32) + data->size > buf + buf_len)
+ return -EINVAL; /* not enough space */
+ outle32 = __cpu_to_le32(data->size);
+ memcpy(out, &outle32, sizeof(outle32));
+ out += sizeof(outle32);
+ memcpy(out, data->data, data->size);
+ out += data->size;
+ blocks++;
+ }
+ }
+
+ outle32 = __cpu_to_le32(out - buf - sizeof(bytes));
+ memcpy(buf, &outle32, sizeof(outle32));
+ outle32 = __cpu_to_le32(blocks);
+ memcpy(buf + sizeof(bytes), &outle32, sizeof(outle32));
+
+ return out - buf;
+}
+
+#define QUERY_CMD_DATA "data\0"
+#define QUERY_CMD_DATA_LEN 5
+
+/**
+ * aa_write_access - generic permissions and data query
+ * @file: pointer to open apparmorfs/access file
+ * @ubuf: user buffer containing the complete query string (NOT NULL)
+ * @count: size of ubuf
+ * @ppos: position in the file (MUST BE ZERO)
+ *
+ * Allows for one permissions or data query per open(), write(), and read()
+ * sequence. The only queries currently supported are label-based queries for
+ * permissions or data.
+ *
+ * For permissions queries, ubuf must begin with "label\0", followed by the
+ * profile query specific format described in the query_label() function
+ * documentation.
+ *
+ * For data queries, ubuf must have the form "data\0<LABEL>\0<KEY>\0", where
+ * <LABEL> is the name of the security confinement context and <KEY> is the
+ * name of the data to retrieve.
+ *
+ * Returns: number of bytes written or -errno on failure
+ */
+static ssize_t aa_write_access(struct file *file, const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ char *buf;
+ ssize_t len;
+
+ if (*ppos)
+ return -ESPIPE;
+
+ buf = simple_transaction_get(file, ubuf, count);
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
+
+ if (count > QUERY_CMD_DATA_LEN &&
+ !memcmp(buf, QUERY_CMD_DATA, QUERY_CMD_DATA_LEN)) {
+ len = query_data(buf, SIMPLE_TRANSACTION_LIMIT,
+ buf + QUERY_CMD_DATA_LEN,
+ count - QUERY_CMD_DATA_LEN);
+ } else
+ len = -EINVAL;
+
+ if (len < 0)
+ return len;
+
+ simple_transaction_set(file, len);
+
+ return count;
+}
+
+static const struct file_operations aa_fs_access = {
+ .write = aa_write_access,
+ .read = simple_transaction_read,
+ .release = simple_transaction_release,
+ .llseek = generic_file_llseek,
+};
+
static int aa_fs_seq_show(struct seq_file *seq, void *v)
{
struct aa_fs_entry *fs_file = seq->private;
@@ -227,12 +392,12 @@ const struct file_operations aa_fs_seq_file_ops = {
static int aa_fs_seq_profile_open(struct inode *inode, struct file *file,
int (*show)(struct seq_file *, void *))
{
- struct aa_replacedby *r = aa_get_replacedby(inode->i_private);
- int error = single_open(file, show, r);
+ struct aa_proxy *proxy = aa_get_proxy(inode->i_private);
+ int error = single_open(file, show, proxy);
if (error) {
file->private_data = NULL;
- aa_put_replacedby(r);
+ aa_put_proxy(proxy);
}
return error;
@@ -242,14 +407,14 @@ static int aa_fs_seq_profile_release(struct inode *inode, struct file *file)
{
struct seq_file *seq = (struct seq_file *) file->private_data;
if (seq)
- aa_put_replacedby(seq->private);
+ aa_put_proxy(seq->private);
return single_release(inode, file);
}
static int aa_fs_seq_profname_show(struct seq_file *seq, void *v)
{
- struct aa_replacedby *r = seq->private;
- struct aa_profile *profile = aa_get_profile_rcu(&r->profile);
+ struct aa_proxy *proxy = seq->private;
+ struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile);
seq_printf(seq, "%s\n", profile->base.name);
aa_put_profile(profile);
@@ -271,8 +436,8 @@ static const struct file_operations aa_fs_profname_fops = {
static int aa_fs_seq_profmode_show(struct seq_file *seq, void *v)
{
- struct aa_replacedby *r = seq->private;
- struct aa_profile *profile = aa_get_profile_rcu(&r->profile);
+ struct aa_proxy *proxy = seq->private;
+ struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile);
seq_printf(seq, "%s\n", aa_profile_mode_names[profile->mode]);
aa_put_profile(profile);
@@ -294,8 +459,8 @@ static const struct file_operations aa_fs_profmode_fops = {
static int aa_fs_seq_profattach_show(struct seq_file *seq, void *v)
{
- struct aa_replacedby *r = seq->private;
- struct aa_profile *profile = aa_get_profile_rcu(&r->profile);
+ struct aa_proxy *proxy = seq->private;
+ struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile);
if (profile->attach)
seq_printf(seq, "%s\n", profile->attach);
else if (profile->xmatch)
@@ -322,8 +487,8 @@ static const struct file_operations aa_fs_profattach_fops = {
static int aa_fs_seq_hash_show(struct seq_file *seq, void *v)
{
- struct aa_replacedby *r = seq->private;
- struct aa_profile *profile = aa_get_profile_rcu(&r->profile);
+ struct aa_proxy *proxy = seq->private;
+ struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile);
unsigned int i, size = aa_hash_size();
if (profile->hash) {
@@ -349,6 +514,145 @@ static const struct file_operations aa_fs_seq_hash_fops = {
.release = single_release,
};
+
+static int aa_fs_seq_show_ns_level(struct seq_file *seq, void *v)
+{
+ struct aa_ns *ns = aa_current_profile()->ns;
+
+ seq_printf(seq, "%d\n", ns->level);
+
+ return 0;
+}
+
+static int aa_fs_seq_open_ns_level(struct inode *inode, struct file *file)
+{
+ return single_open(file, aa_fs_seq_show_ns_level, inode->i_private);
+}
+
+static const struct file_operations aa_fs_ns_level = {
+ .owner = THIS_MODULE,
+ .open = aa_fs_seq_open_ns_level,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int aa_fs_seq_show_ns_name(struct seq_file *seq, void *v)
+{
+ struct aa_ns *ns = aa_current_profile()->ns;
+
+ seq_printf(seq, "%s\n", ns->base.name);
+
+ return 0;
+}
+
+static int aa_fs_seq_open_ns_name(struct inode *inode, struct file *file)
+{
+ return single_open(file, aa_fs_seq_show_ns_name, inode->i_private);
+}
+
+static const struct file_operations aa_fs_ns_name = {
+ .owner = THIS_MODULE,
+ .open = aa_fs_seq_open_ns_name,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int rawdata_release(struct inode *inode, struct file *file)
+{
+ /* TODO: switch to loaddata when profile switched to symlink */
+ aa_put_loaddata(file->p