summaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
Diffstat (limited to 'security')
-rw-r--r--security/Kconfig20
-rw-r--r--security/capability.c1
-rw-r--r--security/commoncap.c5
-rw-r--r--security/dummy.c34
-rw-r--r--security/inode.c11
-rw-r--r--security/keys/internal.h4
-rw-r--r--security/keys/key.c71
-rw-r--r--security/keys/keyctl.c63
-rw-r--r--security/keys/keyring.c28
-rw-r--r--security/keys/proc.c7
-rw-r--r--security/keys/process_keys.c69
-rw-r--r--security/keys/request_key.c64
-rw-r--r--security/keys/request_key_auth.c49
-rw-r--r--security/keys/user_defined.c25
-rw-r--r--security/root_plug.c1
-rw-r--r--security/seclvl.c1
-rw-r--r--security/security.c1
-rw-r--r--security/selinux/hooks.c194
-rw-r--r--security/selinux/include/av_perm_to_string.h9
-rw-r--r--security/selinux/include/av_permissions.h10
-rw-r--r--security/selinux/include/class_to_string.h1
-rw-r--r--security/selinux/include/flask.h1
-rw-r--r--security/selinux/include/objsec.h7
-rw-r--r--security/selinux/selinuxfs.c8
-rw-r--r--security/selinux/ss/services.c48
-rw-r--r--security/selinux/xfrm.c1
26 files changed, 567 insertions, 166 deletions
diff --git a/security/Kconfig b/security/Kconfig
index 34f593410d5..67785df264e 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -22,16 +22,22 @@ config KEYS
If you are unsure as to whether this is required, answer N.
config KEYS_DEBUG_PROC_KEYS
- bool "Enable the /proc/keys file by which all keys may be viewed"
+ bool "Enable the /proc/keys file by which keys may be viewed"
depends on KEYS
help
- This option turns on support for the /proc/keys file through which
- all the keys on the system can be listed.
+ This option turns on support for the /proc/keys file - through which
+ can be listed all the keys on the system that are viewable by the
+ reading process.
- This option is a slight security risk in that it makes it possible
- for anyone to see all the keys on the system. Normally the manager
- pretends keys that are inaccessible to a process don't exist as far
- as that process is concerned.
+ The only keys included in the list are those that grant View
+ permission to the reading process whether or not it possesses them.
+ Note that LSM security checks are still performed, and may further
+ filter out keys that the current process is not authorised to view.
+
+ Only key attributes are listed here; key payloads are not included in
+ the resulting table.
+
+ If you are unsure as to whether this is required, answer N.
config SECURITY
bool "Enable different security models"
diff --git a/security/capability.c b/security/capability.c
index f9b35cc0b24..b868e7eda5f 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -8,7 +8,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
diff --git a/security/commoncap.c b/security/commoncap.c
index 841eb4e5c62..f50fc298cf8 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -8,7 +8,6 @@
*/
#include <linux/capability.h>
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -33,9 +32,9 @@ int cap_netlink_send(struct sock *sk, struct sk_buff *skb)
EXPORT_SYMBOL(cap_netlink_send);
-int cap_netlink_recv(struct sk_buff *skb)
+int cap_netlink_recv(struct sk_buff *skb, int cap)
{
- if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN))
+ if (!cap_raised(NETLINK_CB(skb).eff_cap, cap))
return -EPERM;
return 0;
}
diff --git a/security/dummy.c b/security/dummy.c
index 64f6da0f422..bbbfda70e13 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -15,7 +15,6 @@
#undef DEBUG
#include <linux/capability.h>
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/mman.h>
@@ -191,7 +190,7 @@ static int dummy_sb_kern_mount (struct super_block *sb, void *data)
return 0;
}
-static int dummy_sb_statfs (struct super_block *sb)
+static int dummy_sb_statfs (struct dentry *dentry)
{
return 0;
}
@@ -506,6 +505,9 @@ static int dummy_task_getsid (struct task_struct *p)
return 0;
}
+static void dummy_task_getsecid (struct task_struct *p, u32 *secid)
+{ }
+
static int dummy_task_setgroups (struct group_info *group_info)
{
return 0;
@@ -516,6 +518,16 @@ static int dummy_task_setnice (struct task_struct *p, int nice)
return 0;
}
+static int dummy_task_setioprio (struct task_struct *p, int ioprio)
+{
+ return 0;
+}
+
+static int dummy_task_getioprio (struct task_struct *p)
+{
+ return 0;
+}
+
static int dummy_task_setrlimit (unsigned int resource, struct rlimit *new_rlim)
{
return 0;
@@ -532,13 +544,18 @@ static int dummy_task_getscheduler (struct task_struct *p)
return 0;
}
+static int dummy_task_movememory (struct task_struct *p)
+{
+ return 0;
+}
+
static int dummy_task_wait (struct task_struct *p)
{
return 0;
}
static int dummy_task_kill (struct task_struct *p, struct siginfo *info,
- int sig)
+ int sig, u32 secid)
{
return 0;
}
@@ -665,9 +682,9 @@ static int dummy_netlink_send (struct sock *sk, struct sk_buff *skb)
return 0;
}
-static int dummy_netlink_recv (struct sk_buff *skb)
+static int dummy_netlink_recv (struct sk_buff *skb, int cap)
{
- if (!cap_raised (NETLINK_CB (skb).eff_cap, CAP_NET_ADMIN))
+ if (!cap_raised (NETLINK_CB (skb).eff_cap, cap))
return -EPERM;
return 0;
}
@@ -860,7 +877,8 @@ static int dummy_setprocattr(struct task_struct *p, char *name, void *value, siz
}
#ifdef CONFIG_KEYS
-static inline int dummy_key_alloc(struct key *key)
+static inline int dummy_key_alloc(struct key *key, struct task_struct *ctx,
+ unsigned long flags)
{
return 0;
}
@@ -970,11 +988,15 @@ void security_fixup_ops (struct security_operations *ops)
set_to_dummy_if_null(ops, task_setpgid);
set_to_dummy_if_null(ops, task_getpgid);
set_to_dummy_if_null(ops, task_getsid);
+ set_to_dummy_if_null(ops, task_getsecid);
set_to_dummy_if_null(ops, task_setgroups);
set_to_dummy_if_null(ops, task_setnice);
+ set_to_dummy_if_null(ops, task_setioprio);
+ set_to_dummy_if_null(ops, task_getioprio);
set_to_dummy_if_null(ops, task_setrlimit);
set_to_dummy_if_null(ops, task_setscheduler);
set_to_dummy_if_null(ops, task_getscheduler);
+ set_to_dummy_if_null(ops, task_movememory);
set_to_dummy_if_null(ops, task_wait);
set_to_dummy_if_null(ops, task_kill);
set_to_dummy_if_null(ops, task_prctl);
diff --git a/security/inode.c b/security/inode.c
index 0f77b022366..47eb63480da 100644
--- a/security/inode.c
+++ b/security/inode.c
@@ -13,7 +13,6 @@
*/
/* #define DEBUG */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/mount.h>
@@ -135,11 +134,11 @@ static int fill_super(struct super_block *sb, void *data, int silent)
return simple_fill_super(sb, SECURITYFS_MAGIC, files);
}
-static struct super_block *get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name,
- void *data)
+static int get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name,
+ void *data, struct vfsmount *mnt)
{
- return get_sb_single(fs_type, flags, data, fill_super);
+ return get_sb_single(fs_type, flags, data, fill_super, mnt);
}
static struct file_system_type fs_type = {
@@ -224,7 +223,7 @@ struct dentry *securityfs_create_file(const char *name, mode_t mode,
pr_debug("securityfs: creating file '%s'\n",name);
- error = simple_pin_fs("securityfs", &mount, &mount_count);
+ error = simple_pin_fs(&fs_type, &mount, &mount_count);
if (error) {
dentry = ERR_PTR(error);
goto exit;
diff --git a/security/keys/internal.h b/security/keys/internal.h
index e066e605795..1bb416f4bbc 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -99,7 +99,9 @@ extern int install_process_keyring(struct task_struct *tsk);
extern struct key *request_key_and_link(struct key_type *type,
const char *description,
const char *callout_info,
- struct key *dest_keyring);
+ void *aux,
+ struct key *dest_keyring,
+ unsigned long flags);
/*
* request_key authorisation
diff --git a/security/keys/key.c b/security/keys/key.c
index b6061fa29da..80de8c3e9cc 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -11,15 +11,16 @@
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/poison.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/security.h>
#include <linux/workqueue.h>
+#include <linux/random.h>
#include <linux/err.h>
#include "internal.h"
static kmem_cache_t *key_jar;
-static key_serial_t key_serial_next = 3;
struct rb_root key_serial_tree; /* tree of keys indexed by serial */
DEFINE_SPINLOCK(key_serial_lock);
@@ -169,22 +170,23 @@ static void __init __key_insert_serial(struct key *key)
/*****************************************************************************/
/*
* assign a key the next unique serial number
- * - we work through all the serial numbers between 2 and 2^31-1 in turn and
- * then wrap
+ * - these are assigned randomly to avoid security issues through covert
+ * channel problems
*/
static inline void key_alloc_serial(struct key *key)
{
struct rb_node *parent, **p;
struct key *xkey;
- spin_lock(&key_serial_lock);
-
- /* propose a likely serial number and look for a hole for it in the
+ /* propose a random serial number and look for a hole for it in the
* serial number tree */
- key->serial = key_serial_next;
- if (key->serial < 3)
- key->serial = 3;
- key_serial_next = key->serial + 1;
+ do {
+ get_random_bytes(&key->serial, sizeof(key->serial));
+
+ key->serial >>= 1; /* negative numbers are not permitted */
+ } while (key->serial < 3);
+
+ spin_lock(&key_serial_lock);
parent = NULL;
p = &key_serial_tree.rb_node;
@@ -204,19 +206,18 @@ static inline void key_alloc_serial(struct key *key)
/* we found a key with the proposed serial number - walk the tree from
* that point looking for the next unused serial number */
- serial_exists:
+serial_exists:
for (;;) {
- key->serial = key_serial_next;
+ key->serial++;
if (key->serial < 2)
key->serial = 2;
- key_serial_next = key->serial + 1;
- if (!parent->rb_parent)
+ if (!rb_parent(parent))
p = &key_serial_tree.rb_node;
- else if (parent->rb_parent->rb_left == parent)
- p = &parent->rb_parent->rb_left;
+ else if (rb_parent(parent)->rb_left == parent)
+ p = &(rb_parent(parent)->rb_left);
else
- p = &parent->rb_parent->rb_right;
+ p = &(rb_parent(parent)->rb_right);
parent = rb_next(parent);
if (!parent)
@@ -228,7 +229,7 @@ static inline void key_alloc_serial(struct key *key)
}
/* we've found a suitable hole - arrange for this key to occupy it */
- insert_here:
+insert_here:
rb_link_node(&key->serial_node, parent, p);
rb_insert_color(&key->serial_node, &key_serial_tree);
@@ -247,8 +248,8 @@ static inline void key_alloc_serial(struct key *key)
* instantiate the key or discard it before returning
*/
struct key *key_alloc(struct key_type *type, const char *desc,
- uid_t uid, gid_t gid, key_perm_t perm,
- int not_in_quota)
+ uid_t uid, gid_t gid, struct task_struct *ctx,
+ key_perm_t perm, unsigned long flags)
{
struct key_user *user = NULL;
struct key *key;
@@ -269,12 +270,14 @@ struct key *key_alloc(struct key_type *type, const char *desc,
/* check that the user's quota permits allocation of another key and
* its description */
- if (!not_in_quota) {
+ if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) {
spin_lock(&user->lock);
- if (user->qnkeys + 1 >= KEYQUOTA_MAX_KEYS ||
- user->qnbytes + quotalen >= KEYQUOTA_MAX_BYTES
- )
- goto no_quota;
+ if (!(flags & KEY_ALLOC_QUOTA_OVERRUN)) {
+ if (user->qnkeys + 1 >= KEYQUOTA_MAX_KEYS ||
+ user->qnbytes + quotalen >= KEYQUOTA_MAX_BYTES
+ )
+ goto no_quota;
+ }
user->qnkeys++;
user->qnbytes += quotalen;
@@ -308,7 +311,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
key->payload.data = NULL;
key->security = NULL;
- if (!not_in_quota)
+ if (!(flags & KEY_ALLOC_NOT_IN_QUOTA))
key->flags |= 1 << KEY_FLAG_IN_QUOTA;
memset(&key->type_data, 0, sizeof(key->type_data));
@@ -318,7 +321,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
#endif
/* let the security module know about the key */
- ret = security_key_alloc(key);
+ ret = security_key_alloc(key, ctx, flags);
if (ret < 0)
goto security_error;
@@ -332,7 +335,7 @@ error:
security_error:
kfree(key->description);
kmem_cache_free(key_jar, key);
- if (!not_in_quota) {
+ if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) {
spin_lock(&user->lock);
user->qnkeys--;
user->qnbytes -= quotalen;
@@ -345,7 +348,7 @@ security_error:
no_memory_3:
kmem_cache_free(key_jar, key);
no_memory_2:
- if (!not_in_quota) {
+ if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) {
spin_lock(&user->lock);
user->qnkeys--;
user->qnbytes -= quotalen;
@@ -761,7 +764,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
const char *description,
const void *payload,
size_t plen,
- int not_in_quota)
+ unsigned long flags)
{
struct key_type *ktype;
struct key *keyring, *key = NULL;
@@ -822,7 +825,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
/* allocate a new key */
key = key_alloc(ktype, description, current->fsuid, current->fsgid,
- perm, not_in_quota);
+ current, perm, flags);
if (IS_ERR(key)) {
key_ref = ERR_PTR(PTR_ERR(key));
goto error_3;
@@ -907,6 +910,10 @@ void key_revoke(struct key *key)
* it */
down_write(&key->sem);
set_bit(KEY_FLAG_REVOKED, &key->flags);
+
+ if (key->type->revoke)
+ key->type->revoke(key);
+
up_write(&key->sem);
} /* end key_revoke() */
@@ -982,7 +989,7 @@ void unregister_key_type(struct key_type *ktype)
if (key->type == ktype) {
if (ktype->destroy)
ktype->destroy(key);
- memset(&key->payload, 0xbd, sizeof(key->payload));
+ memset(&key->payload, KEY_DESTROY, sizeof(key->payload));
}
}
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index ed71d86d2ce..d9ca15c109c 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -102,7 +102,7 @@ asmlinkage long sys_add_key(const char __user *_type,
/* create or update the requested key and add it to the target
* keyring */
key_ref = key_create_or_update(keyring_ref, type, description,
- payload, plen, 0);
+ payload, plen, KEY_ALLOC_IN_QUOTA);
if (!IS_ERR(key_ref)) {
ret = key_ref_to_ptr(key_ref)->serial;
key_ref_put(key_ref);
@@ -183,8 +183,9 @@ asmlinkage long sys_request_key(const char __user *_type,
}
/* do the search */
- key = request_key_and_link(ktype, description, callout_info,
- key_ref_to_ptr(dest_ref));
+ key = request_key_and_link(ktype, description, callout_info, NULL,
+ key_ref_to_ptr(dest_ref),
+ KEY_ALLOC_IN_QUOTA);
if (IS_ERR(key)) {
ret = PTR_ERR(key);
goto error5;
@@ -672,6 +673,7 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
*/
long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
{
+ struct key_user *newowner, *zapowner = NULL;
struct key *key;
key_ref_t key_ref;
long ret;
@@ -695,19 +697,50 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
if (!capable(CAP_SYS_ADMIN)) {
/* only the sysadmin can chown a key to some other UID */
if (uid != (uid_t) -1 && key->uid != uid)
- goto no_access;
+ goto error_put;
/* only the sysadmin can set the key's GID to a group other
* than one of those that the current process subscribes to */
if (gid != (gid_t) -1 && gid != key->gid && !in_group_p(gid))
- goto no_access;
+ goto error_put;
}
- /* change the UID (have to update the quotas) */
+ /* change the UID */
if (uid != (uid_t) -1 && uid != key->uid) {
- /* don't support UID changing yet */
- ret = -EOPNOTSUPP;
- goto no_access;
+ ret = -ENOMEM;
+ newowner = key_user_lookup(uid);
+ if (!newowner)
+ goto error_put;
+
+ /* transfer the quota burden to the new user */
+ if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) {
+ spin_lock(&newowner->lock);
+ if (newowner->qnkeys + 1 >= KEYQUOTA_MAX_KEYS ||
+ newowner->qnbytes + key->quotalen >=
+ KEYQUOTA_MAX_BYTES)
+ goto quota_overrun;
+
+ newowner->qnkeys++;
+ newowner->qnbytes += key->quotalen;
+ spin_unlock(&newowner->lock);
+
+ spin_lock(&key->user->lock);
+ key->user->qnkeys--;
+ key->user->qnbytes -= key->quotalen;
+ spin_unlock(&key->user->lock);
+ }
+
+ atomic_dec(&key->user->nkeys);
+ atomic_inc(&newowner->nkeys);
+
+ if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
+ atomic_dec(&key->user->nikeys);
+ atomic_inc(&newowner->nikeys);
+ }
+
+ zapowner = key->user;
+ key->user = newowner;
+ key->uid = uid;
}
/* change the GID */
@@ -716,12 +749,20 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
ret = 0;
- no_access:
+error_put:
up_write(&key->sem);
key_put(key);
- error:
+ if (zapowner)
+ key_user_put(zapowner);
+error:
return ret;
+quota_overrun:
+ spin_unlock(&newowner->lock);
+ zapowner = newowner;
+ ret = -EDQUOT;
+ goto error_put;
+
} /* end keyctl_chown_key() */
/*****************************************************************************/
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index bffa924c1f8..e8d02acc51e 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -49,6 +49,7 @@ static inline unsigned keyring_hash(const char *desc)
static int keyring_instantiate(struct key *keyring,
const void *data, size_t datalen);
static int keyring_match(const struct key *keyring, const void *criterion);
+static void keyring_revoke(struct key *keyring);
static void keyring_destroy(struct key *keyring);
static void keyring_describe(const struct key *keyring, struct seq_file *m);
static long keyring_read(const struct key *keyring,
@@ -59,6 +60,7 @@ struct key_type key_type_keyring = {
.def_datalen = sizeof(struct keyring_list),
.instantiate = keyring_instantiate,
.match = keyring_match,
+ .revoke = keyring_revoke,
.destroy = keyring_destroy,
.describe = keyring_describe,
.read = keyring_read,
@@ -240,15 +242,16 @@ static long keyring_read(const struct key *keyring,
* allocate a keyring and link into the destination keyring
*/
struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
- int not_in_quota, struct key *dest)
+ struct task_struct *ctx, unsigned long flags,
+ struct key *dest)
{
struct key *keyring;
int ret;
keyring = key_alloc(&key_type_keyring, description,
- uid, gid,
+ uid, gid, ctx,
(KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL,
- not_in_quota);
+ flags);
if (!IS_ERR(keyring)) {
ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL);
@@ -952,3 +955,22 @@ int keyring_clear(struct key *keyring)
} /* end keyring_clear() */
EXPORT_SYMBOL(keyring_clear);
+
+/*****************************************************************************/
+/*
+ * dispose of the links from a revoked keyring
+ * - called with the key sem write-locked
+ */
+static void keyring_revoke(struct key *keyring)
+{
+ struct keyring_list *klist = keyring->payload.subscriptions;
+
+ /* adjust the quota */
+ key_payload_reserve(keyring, 0);
+
+ if (klist) {
+ rcu_assign_pointer(keyring->payload.subscriptions, NULL);
+ call_rcu(&klist->rcu, keyring_clear_rcu_disposal);
+ }
+
+} /* end keyring_revoke() */
diff --git a/security/keys/proc.c b/security/keys/proc.c
index 12b750e51fb..686a9ee0c5d 100644
--- a/security/keys/proc.c
+++ b/security/keys/proc.c
@@ -137,6 +137,13 @@ static int proc_keys_show(struct seq_file *m, void *v)
struct timespec now;
unsigned long timo;
char xbuf[12];
+ int rc;
+
+ /* check whether the current task is allowed to view the key (assuming
+ * non-possession) */
+ rc = key_task_permission(make_key_ref(key, 0), current, KEY_VIEW);
+ if (rc < 0)
+ return 0;
now = current_kernel_time();
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index 217a0bef3c8..32150cf7c37 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -67,7 +67,8 @@ struct key root_session_keyring = {
/*
* allocate the keyrings to be associated with a UID
*/
-int alloc_uid_keyring(struct user_struct *user)
+int alloc_uid_keyring(struct user_struct *user,
+ struct task_struct *ctx)
{
struct key *uid_keyring, *session_keyring;
char buf[20];
@@ -76,7 +77,8 @@ int alloc_uid_keyring(struct user_struct *user)
/* concoct a default session keyring */
sprintf(buf, "_uid_ses.%u", user->uid);
- session_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, 0, NULL);
+ session_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, ctx,
+ KEY_ALLOC_IN_QUOTA, NULL);
if (IS_ERR(session_keyring)) {
ret = PTR_ERR(session_keyring);
goto error;
@@ -86,8 +88,8 @@ int alloc_uid_keyring(struct user_struct *user)
* keyring */
sprintf(buf, "_uid.%u", user->uid);
- uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, 0,
- session_keyring);
+ uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, ctx,
+ KEY_ALLOC_IN_QUOTA, session_keyring);
if (IS_ERR(uid_keyring)) {
key_put(session_keyring);
ret = PTR_ERR(uid_keyring);
@@ -143,7 +145,8 @@ int install_thread_keyring(struct task_struct *tsk)
sprintf(buf, "_tid.%u", tsk->pid);
- keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL);
+ keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk,
+ KEY_ALLOC_QUOTA_OVERRUN, NULL);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error;
@@ -177,7 +180,8 @@ int install_process_keyring(struct task_struct *tsk)
if (!tsk->signal->process_keyring) {
sprintf(buf, "_pid.%u", tsk->tgid);
- keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL);
+ keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk,
+ KEY_ALLOC_QUOTA_OVERRUN, NULL);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error;
@@ -208,6 +212,7 @@ error:
static int install_session_keyring(struct task_struct *tsk,
struct key *keyring)
{
+ unsigned long flags;
struct key *old;
char buf[20];
@@ -217,7 +222,12 @@ static int install_session_keyring(struct task_struct *tsk,
if (!keyring) {
sprintf(buf, "_ses.%u", tsk->tgid);
- keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL);
+ flags = KEY_ALLOC_QUOTA_OVERRUN;
+ if (tsk->signal->session_keyring)
+ flags = KEY_ALLOC_IN_QUOTA;
+
+ keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk,
+ flags, NULL);
if (IS_ERR(keyring))
return PTR_ERR(keyring);
}
@@ -390,6 +400,8 @@ key_ref_t search_process_keyrings(struct key_type *type,
struct request_key_auth *rka;
key_ref_t key_ref, ret, err;
+ might_sleep();
+
/* we want to return -EAGAIN or -ENOKEY if any of the keyrings were
* searchable, but we failed to find a key or we found a negative key;
* otherwise we want to return a sample error (probably -EACCES) if
@@ -495,27 +507,35 @@ key_ref_t search_process_keyrings(struct key_type *type,
*/
if (context->request_key_auth &&
context == current &&
- type != &key_type_request_key_auth &&
- key_validate(context->request_key_auth) == 0
+ type != &key_type_request_key_auth
) {
- rka = context->request_key_auth->payload.data;
+ /* defend against the auth key being revoked */
+ down_read(&context->request_key_auth->sem);
- key_ref = search_process_keyrings(type, description, match,
- rka->context);
+ if (key_validate(context->request_key_auth) == 0) {
+ rka = context->request_key_auth->payload.data;
- if (!IS_ERR(key_ref))
- goto found;
+ key_ref = search_process_keyrings(type, description,
+ match, rka->context);
- switch (PTR_ERR(key_ref)) {
- case -EAGAIN: /* no key */
- if (ret)
+ up_read(&context->request_key_auth->sem);
+
+ if (!IS_ERR(key_ref))
+ goto found;
+
+ switch (PTR_ERR(key_ref)) {
+ case -EAGAIN: /* no key */
+ if (ret)
+ break;
+ case -ENOKEY: /* negative key */
+ ret = key_ref;
break;
- case -ENOKEY: /* negative key */
- ret = key_ref;
- break;
- default:
- err = key_ref;
- break;
+ default:
+ err = key_ref;
+ break;
+ }
+ } else {
+ up_read(&context->request_key_auth->sem);
}
}
@@ -717,7 +737,8 @@ long join_session_keyring(const char *name)
keyring = find_keyring_by_name(name, 0);
if (PTR_ERR(keyring) == -ENOKEY) {
/* not found - try and create a new one */
- keyring = keyring_alloc(name, tsk->uid, tsk->gid, 0, NULL);
+ keyring = keyring_alloc(name, tsk->uid, tsk->gid, tsk,
+ KEY_ALLOC_IN_QUOTA, NULL);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error2;
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index f030a0ccbb9..f573ac189a0 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -1,6 +1,6 @@
/* request_key.c: request a key from userspace
*
- * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2004-6 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
@@ -33,7 +33,8 @@ DECLARE_WAIT_QUEUE_HEAD(request_key_conswq);
*/
static int call_sbin_request_key(struct key *key,
struct key *authkey,
- const char *op)
+ const char *op,
+ void *aux)
{
struct task_struct *tsk = current;
key_serial_t prkey, sskey;
@@ -48,7 +49,8 @@ static int call_sbin_request_key(struct key *key,
/* allocate a new session keyring */
sprintf(desc, "_req.%u", key->serial);
- keyring = keyring_alloc(desc, current->fsuid, current->fsgid, 1, NULL);
+ keyring = keyring_alloc(desc, current->fsuid, current->fsgid, current,
+ KEY_ALLOC_QUOTA_OVERRUN, NULL);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error_alloc;
@@ -125,7 +127,9 @@ error_alloc:
*/
static struct key *__request_key_construction(struct key_type *type,
const char *description,
- const char *callout_info)
+ const char *callout_info,
+ void *aux,
+ unsigned long flags)
{
request_key_actor_t actor;
struct key_construction cons;
@@ -133,11 +137,12 @@ static struct key *__request_key_construction(struct key_type *type,
struct key *key, *authkey;
int ret, negated;
- kenter("%s,%s,%s", type->name, description, callout_info);
+ kenter("%s,%s,%s,%lx", type->name, description, callout_info, flags);
/* create a key and add it to the queue */
key = key_alloc(type, description,
- current->fsuid, current->fsgid, KEY_POS_ALL, 0);
+ current->fsuid, current->fsgid, current, KEY_POS_ALL,
+ flags);
if (IS_ERR(key))
goto alloc_failed;
@@ -161,7 +166,7 @@ static struct key *__request_key_construction(struct key_type *type,
actor = call_sbin_request_key;
if (type->request_key)
actor = type->request_key;
- ret = actor(key, authkey, "create");
+ ret = actor(key, authkey, "create", aux);
if (ret < 0)
goto request_failed;
@@ -255,16 +260,18 @@ alloc_failed:
*/
static struct key *request_key_construction(struct key_type *type,
const char *description,
+ const char *callout_info,
+ void *aux,
struct key_user *user,
- const char *callout_info)
+ unsigned long flags)
{
struct key_construction *pcons;
struct key *key, *ckey;
DECLARE_WAITQUEUE(myself, current);
- kenter("%s,%s,{%d},%s",
- type->name, description, user->uid, callout_info);
+ kenter("%s,%s,{%d},%s,%lx",
+ type->name, description, user->uid, callout_info, flags);
/* see if there's such a key under construction already */
down_write(&key_construction_sem);
@@ -280,7 +287,8 @@ static struct key *request_key_construction(struct key_type *type,
}
/* see about getting userspace to construct the key */
- key = __request_key_construction(type, description, callout_info);
+ key = __request_key_construction(type, description, callout_info, aux,
+ flags);
error:
kleave(" = %p", key);
return key;
@@ -387,14 +395,17 @@ static void request_key_link(struct key *key, struct key *dest_keyring)
struct key *request_key_and_link(struct key_type *type,
const char *description,
const char *callout_info,
- struct key *dest_keyring)
+ void *aux,
+ struct key *dest_keyring,
+ unsigned long flags)
{
struct key_user *user;
struct key *key;
key_ref_t key_ref;
- kenter("%s,%s,%s,%p",
- type->name, description, callout_info, dest_keyring);
+ kenter("%s,%s,%s,%p,%p,%lx",
+ type->name, description, callout_info, aux,
+ dest_keyring, flags);
/* search all the process keyrings for a key */
key_ref = search_process_keyrings(type, description, type->match,
@@ -427,7 +438,8 @@ struct key *request_key_and_link(struct key_type *type,
/* ask userspace (returns NULL if it waited on a key
* being constructed) */
key = request_key_construction(type, description,
- user, callout_info);
+ callout_info, aux,
+ user, flags);
if (key)
break;
@@ -483,8 +495,28 @@ struct key *request_key(struct key_type *type,
const char *description,
const char *callout_info)
{
- return request_key_and_link(type, description, callout_info, NULL);
+ return request_key_and_link(type, description, callout_info, NULL,
+ NULL, KEY_ALLOC_IN_QUOTA);
} /* end request_key() */
EXPORT_SYMBOL(request_key);
+
+/*****************************************************************************/
+/*
+ * request a key with auxiliary data for the upcaller
+ * - search the process's keyrings
+ * - check the list of keys being created or updated
+ * - call out to userspace for a key if supplementary info was provided
+ */
+struct key *request_key_with_auxdata(struct key_type *type,
+ const char *description,
+ const char *callout_info,
+ void *aux)
+{
+ return request_key_and_link(type, description, callout_info, aux,
+ NULL, KEY_ALLOC_IN_QUOTA);
+
+} /* end request_key_with_auxdata() */
+
+EXPORT_SYMBOL(request_key_with_auxdata);
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c
index cce6ba6b032..cbf58a91b00 100644
--- a/security/keys/request_key_auth.c
+++ b/security/keys/request_key_auth.c
@@ -20,6 +20,7 @@
static int request_key_auth_instantiate(struct key *, const void *, size_t);
static void request_key_auth_describe(const struct key *, struct seq_file *);
+static void request_key_auth_revoke(struct key *);
static void request_key_auth_destroy(struct key *);
static long request_key_auth_read(const struct key *, char __user *, size_t);
@@ -31,6 +32,7 @@ struct key_type key_type_request_key_auth = {
.def_datalen = sizeof(struct request_key_auth),
.instantiate = request_key_auth_instantiate,
.describe = request_key_auth_describe,
+ .revoke = request_key_auth_revoke,
.destroy = request_key_auth_destroy,
.read = request_key_auth_read,
};
@@ -93,6 +95,24 @@ static long request_key_auth_read(const struct key *key,
/*****************************************************************************/
/*
+ * handle revocation of an authorisation token key
+ * - called with the key sem write-locked
+ */
+static void request_key_auth_revoke(struct key *key)
+{
+ struct request_key_auth *rka = key->payload.data;
+
+ kenter("{%d}", key->serial);
+
+ if (rka->context) {
+ put_task_struct(rka->context);
+ rka->context = NULL;
+ }
+
+} /* end request_key_auth_revoke() */
+
+/*****************************************************************************/
+/*
* destroy an instantiation authorisation token key
*/
static void request_key_auth_destroy(struct key *key)
@@ -101,6 +121,11 @@ static void request_key_auth_destroy(struct key *key)
kenter("{%d}", key->serial);
+ if (rka->context) {
+ put_task_struct(rka->context);
+ rka->context = NULL;
+ }
+
key_put(rka->target_key);
kfree(rka);
@@ -131,14 +156,26 @@ struct key *request_key_auth_new(struct key *target, const char *callout_info)
* another process */
if (current->request_key_auth) {
/* it is - use that instantiation context here too */
+ down_read(&current->request_key_auth->sem);
+
+ /* if the auth key has been revoked, then the key we're
+ * servicing is already instantiated */
+ if (test_bit(KEY_FLAG_REVOKED,
+ &current->request_key_auth->flags))
+ goto auth_key_revoked;
+
irka = current->request_key_auth->payload.data;
rka->context = irka->context;
rka->pid = irka->pid;
+ get_task_struct(rka->context);
+
+ up_read(&current->request_key_auth->sem);
}
else {
/* it isn't - use this process as the context */
rka->context = current;
rka->pid = current->pid;
+ get_task_struct(rka->context);
}
rka->target_key = key_get(target);
@@ -148,9 +185,9 @@ struct key *request_key_auth_new(struct key *target, const char *callout_info)
sprintf(desc, "%x", target->serial);
authkey = key_alloc(&key_type_request_key_auth, desc,
- current->fsuid, current->fsgid,
+ current->fsuid, current->fsgid, current,
KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH |
- KEY_USR_VIEW, 1);
+ KEY_USR_VIEW, KEY_ALLOC_NOT_IN_QUOTA);
if (IS_ERR(authkey)) {
ret = PTR_ERR(authkey);
goto error_alloc;
@@ -161,9 +198,15 @@ struct key *request_key_auth_new(struct key *target, const char *callout_info)
if (ret < 0)
goto error_inst;
- kleave(" = {%d})", authkey->serial);
+ kleave(" = {%d}", authkey->serial);
return authkey;
+auth_key_revoked:
+ up_read(&current->request_key_auth->sem);
+ kfree(rka);
+ kleave("= -EKEYREVOKED");
+ return ERR_PTR(-EKEYREVOKED);
+
error_inst:
key_revoke(authkey);
key_put(authkey);
diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c
index 8e71895b97a..5bbfdebb7ac 100644
--- a/security/keys/user_defined.c
+++ b/security/keys/user_defined.c
@@ -28,6 +28,7 @@ struct key_type key_type_user = {
.instantiate = user_instantiate,
.update = user_update,
.match = user_match,
+ .revoke = user_revoke,
.destroy = user_destroy,
.describe = user_describe,
.read = user_read,
@@ -67,6 +68,7 @@ error:
return ret;
} /* end user_instantiate() */
+
EXPORT_SYMBOL_GPL(user_instantiate);
/*****************************************************************************/
@@ -141,7 +143,28 @@ EXPORT_SYMBOL_GPL(user_match);
/*****************************************************************************/
/*
- * dispose of the data dangling from the corpse of a user
+ * dispose of the links from a revoked keyring
+ * - called with the key sem write-locked
+ */
+void user_revoke(struct key *key)
+{
+ struct user_key_payload *upayload = key->payload.data;
+
+ /* clear the quota */
+ key_payload_reserve(key, 0);
+
+ if (upayload) {
+ rcu_assign_pointer(key->payload.data, NULL);
+ call_rcu(&upayload->rcu, user_update_rcu_disposal);
+ }
+
+} /* end user_revoke() */
+
+EXPORT_SYMBOL(user_revoke);
+
+/*****************************************************************************/
+/*
+ * dispose of the data dangling from the corpse of a user key
*/
void user_destroy(struct key *key)
{
diff --git a/security/root_plug.c b/security/root_plug.c
index 07651def2f7..38dd4f3e641 100644
--- a/security/root_plug.c
+++ b/security/root_plug.c
@@ -22,7 +22,6 @@
* License.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
diff --git a/security/seclvl.c b/security/seclvl.c
index 441beaf1bbc..c26dd7de047 100644
--- a/security/seclvl.c
+++ b/security/seclvl.c
@@ -16,7 +16,6 @@
* (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
diff --git a/security/security.c b/security/security.c
index 51ef509710b..ee4e0701b6e 100644
--- a/security/security.c
+++ b/security/security.c
@@ -12,7 +12,6 @@
*/
#include <linux/capability.h>
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 54adc9d31e9..24caaeec889 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -18,7 +18,6 @@
* as published by the Free Software Foundation.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -69,6 +68,7 @@
#include <linux/sysctl.h>
#include <linux/audit.h>
#include <linux/string.h>
+#include <linux/selinux.h>
#include "avc.h"
#include "objsec.h"
@@ -1099,6 +1099,17 @@ static int may_create(struct inode *dir,
FILESYSTEM__ASSOCIATE, &ad);
}
+/* Check whether a task can create a key. */
+static int may_create_key(u32 ksid,
+ struct task_struct *ctx)
+{
+ struct task_security_struct *tsec;
+
+ tsec = ctx->security;
+
+ return avc_has_perm(tsec->sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL);
+}
+
#define MAY_LINK 0
#define MAY_UNLINK 1
#define MAY_RMDIR 2
@@ -1521,8 +1532,10 @@ static int selinux_bprm_set_security(struct linux_binprm *bprm)
/* Default to the current task SID. */
bsec->sid = tsec->sid;
- /* Reset create SID on execve. */
+ /* Reset fs, key, and sock SIDs on execve. */
tsec->create_sid = 0;
+ tsec->keycreate_sid = 0;
+ tsec->sockcreate_sid = 0;
if (tsec->exec_sid) {
newsid = tsec->exec_sid;
@@ -1903,13 +1916,13 @@ static int selinux_sb_kern_mount(struct super_block *sb, void *data)
return superblock_has_perm(current, sb, FILESYSTEM__MOUNT, &ad);
}
-static int selinux_sb_statfs(struct super_block *sb)
+static int selinux_sb_statfs(struct dentry *dentry)
{
struct avc_audit_data ad;
AVC_AUDIT_DATA_INIT(&ad,FS);
- ad.u.fs.dentry = sb->s_root;
- return superblock_has_perm(current, sb, FILESYSTEM__GETATTR, &ad);
+ ad.u.fs.dentry = dentry->d_sb->s_root;
+ return superblock_has_perm(current, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
}
static int selinux_mount(char * dev_name,
@@ -2574,9 +2587,11 @@ static int selinux_task_alloc_security(struct task_struct *tsk)
tsec2->osid = tsec1->osid;
tsec2->sid = tsec1->sid;
- /* Retain the exec and create SIDs across fork */
+ /* Retain the exec, fs, key, and sock SIDs across fork */
tsec2->exec_sid = tsec1->exec_sid;
tsec2->create_sid = tsec1->create_sid;
+ tsec2->keycreate_sid = tsec1->keycreate_sid;
+ tsec2->sockcreate_sid = tsec1->sockcreate_sid;
/* Retain ptracer SID across fork, if any.
This will be reset by the ptrace hook upon any
@@ -2628,6 +2643,11 @@ static int selinux_task_getsid(struct task_struct *p)
return task_has_perm(current, p, PROCESS__GETSESSION);
}
+static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
+{
+ selinux_get_task_sid(p, secid);
+}
+
static int selinux_task_setgroups(struct group_info *group_info)
{
/* See the comment for setuid above. */
@@ -2645,6 +2665,16 @@ static int selinux_task_setnice(struct task_struct *p, int nice)
return task_has_perm(current,p, PROCESS__SETSCHED);
}
+static int selinux_task_setioprio(struct task_struct *p, int ioprio)
+{
+ return task_has_perm(current, p, PROCESS__SETSCHED);
+}
+
+static int selinux_task_getioprio(struct task_struct *p)
+{
+ return task_has_perm(current, p, PROCESS__GETSCHED);
+}
+
static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim)
{
struct rlimit *old_rlim = current->signal->rlim + resource;
@@ -2674,12 +2704,19 @@ static int selinux_task_getscheduler(struct task_struct *p)
return task_has_perm(current, p, PROCESS__GETSCHED);
}
-static int selinux_task_kill(struct task_struct *p, struct siginfo *info, int sig)
+static int selinux_task_movememory(struct task_struct *p)
+{
+ return task_has_perm(current, p, PROCESS__SETSCHED);
+}
+
+static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
+ int sig, u32 secid)
{
u32 perm;
int rc;
+ struct task_security_struct *tsec;
- rc = secondary_ops->task_kill(p, info, sig);
+ rc = secondary_ops->task_kill(p, info, sig, secid);
if (rc)
return rc;
@@ -2690,8 +2727,12 @@ static int selinux_task_kill(struct task_struct *p, struct siginfo *info, int si
perm = PROCESS__SIGNULL; /* null signal; existence test */
else
perm = signal_to_av(sig);
-
- return task_has_perm(current, p, perm);
+ tsec = p->security;
+ if (secid)
+ rc = avc_has_perm(secid, tsec->sid, SECCLASS_PROCESS, perm, NULL);
+ else
+ rc = task_has_perm(current, p, perm);
+ return rc;
}
static int selinux_task_prctl(int option,
@@ -2916,12 +2957,14 @@ static int selinux_socket_create(int family, int type,
{
int err = 0;
struct task_security_struct *tsec;
+ u32 newsid;
if (kern)
goto out;
tsec = current->security;
- err = avc_has_perm(tsec->sid, tsec->sid,
+ newsid = tsec->sockcreate_sid ? : tsec->sid;
+ err = avc_has_perm(tsec->sid, newsid,
socket_type_to_security_class(family, type,
protocol), SOCKET__CREATE, NULL);
@@ -2934,12 +2977,14 @@ static void selinux_socket_post_create(struct socket *sock, int family,
{
struct inode_security_struct *isec;
struct task_security_struct *tsec;
+ u32 newsid;
isec = SOCK_INODE(sock)->i_security;
tsec = current->security;
+ newsid = tsec->sockcreate_sid ? : tsec->sid;
isec->sclass = socket_type_to_security_class(family, type, protocol);
- isec->sid = kern ? SECINITSID_KERNEL : tsec->sid;
+ isec->sid = kern ? SECINITSID_KERNEL : newsid;
isec->initialized = 1;
return;
@@ -3391,7 +3436,13 @@ out:
static int selinux_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata, u32 *seclen)
{
int err = 0;
- u32 peer_sid = selinux_socket_getpeer_dgram(skb);
+ u32 peer_sid;
+
+ if (skb->sk->sk_family == PF_UNIX)
+ selinux_get_inode_sid(SOCK_INODE(skb->sk->sk_socket),
+ &peer_sid);
+ else
+ peer_sid = selinux_socket_getpeer_dgram(skb);
if (peer_sid == SECSID_NULL)
return -EINVAL;
@@ -3403,8 +3454,6 @@ static int selinux_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata,
return 0;
}
-
-
static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
{
return sk_alloc_security(sk, family, priority);
@@ -3612,32 +3661,32 @@ static unsigned int selinux_ipv6_postroute_last(unsigned int hooknum,
static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
{
- struct task_security_struct *tsec;
- struct av_decision avd;
int err;
err = secondary_ops->netlink_send(sk, skb);
if (err)
return err;
- tsec = current->security;
-
- avd.allowed = 0;
- avc_has_perm_noaudit(tsec->sid, tsec->sid,
- SECCLASS_CAPABILITY, ~0, &avd);
- cap_mask(NETLINK_CB(skb).eff_cap, avd.allowed);
-
if (policydb_loaded_version >= POLICYDB_VERSION_NLCLASS)
err = selinux_nlmsg_perm(sk, skb);
return err;
}
-static int selinux_netlink_recv(struct sk_buff *skb)
+static int selinux_netlink_recv(struct sk_buff *skb, int capability)
{
- if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN))
- return -EPERM;
- return 0;
+ int err;
+ struct avc_audit_data ad;
+
+ err = secondary_ops->netlink_recv(skb, capability);
+ if (err)
+ return err;
+
+ AVC_AUDIT_DATA_INIT(&ad, CAP);
+ ad.u.cap = capability;
+
+ return avc_has_perm(NETLINK_CB(skb).sid, NETLINK_CB(skb).sid,
+ SECCLASS_CAPABILITY, CAP_TO_MASK(capability), &ad);
}
static int ipc_alloc_security(struct task_struct *task,
@@ -4140,6 +4189,10 @@ static int selinux_getprocattr(struct task_struct *p,
sid = tsec->exec_sid;
else if (!strcmp(name, "fscreate"))
sid = tsec->create_sid;
+ else if (!strcmp(name, "keycreate"))
+ sid = tsec->keycreate_sid;
+ else if (!strcmp(name, "sockcreate"))
+ sid = tsec->sockcreate_sid;
else
return -EINVAL;
@@ -4172,6 +4225,10 @@ static int selinux_setprocattr(struct task_struct *p,
error = task_has_perm(current, p, PROCESS__SETEXEC);
else if (!strcmp(name, "fscreate"))
error = task_has_perm(current, p, PROCESS__SETFSCREATE);
+ else if (!strcmp(name, "keycreate"))
+ error = task_has_perm(current, p, PROCESS__SETKEYCREATE);
+ else if (!strcmp(name, "sockcreate"))
+ error = task_has_perm(current, p, PROCESS__SETSOCKCREATE);
else if (!strcmp(name, "current"))
error = task_has_perm(current, p, PROCESS__SETCURRENT);
else
@@ -4201,6 +4258,13 @@ static int selinux_setprocattr(struct task_struct *p,
tsec->exec_sid = sid;
else if (!strcmp(name, "fscreate"))
tsec->create_sid = sid;
+ else if (!strcmp(name, "keycreate")) {
+ error = may_create_key(sid, p);
+ if (error)
+ return error;
+ tsec->keycreate_sid = sid;
+ } else if (!strcmp(name, "sockcreate"))
+ tsec->sockcreate_sid = sid;
else if (!strcmp(name, "current")) {
struct av_decision avd;
@@ -4252,6 +4316,61 @@ static int selinux_setprocattr(struct task_struct *p,
return size;
}
+#ifdef CONFIG_KEYS
+
+static int selinux_key_alloc(struct key *k, struct task_struct *tsk,
+ unsigned long flags)
+{
+ struct task_security_struct *tsec = tsk->security;
+ struct key_security_struct *ksec;
+
+ ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
+ if (!ksec)
+ return -ENOMEM;
+
+ ksec->obj = k;
+ if (tsec->keycreate_sid)
+ ksec->sid = tsec->keycreate_sid;
+ else
+ ksec->sid = tsec->sid;
+ k->security = ksec;
+
+ return 0;
+}
+
+static void selinux_key_free(struct key *k)
+{
+ struct key_security_struct *ksec = k->security;
+
+ k->security = NULL;
+ kfree(ksec);
+}
+
+static int selinux_key_permission(key_ref_t key_ref,
+ struct task_struct *ctx,
+ key_perm_t perm)
+{
+ struct key *key;
+ struct task_security_struct *tsec;
+ struct key_security_struct *ksec;
+
+ key = key_ref_to_ptr(key_ref);
+
+ tsec = ctx->security;
+ ksec = key->security;
+
+ /* if no specific permissions are requested, we skip the
+ permission check. No serious, additional covert channels
+ appear to be created. */
+ if (perm == 0)
+ return 0;
+
+ return avc_has_perm(tsec->sid, ksec->sid,
+ SECCLASS_KEY, perm, NULL);
+}
+
+#endif
+
static struct security_operations selinux_ops = {
.ptrace = selinux_ptrace,
.capget = selinux_capget,
@@ -4330,11 +4449,15 @@ static struct security_operations selinux_ops = {
.task_setpgid = selinux_task_setpgid,
.task_getpgid = selinux_task_getpgid,
.task_getsid = selinux_task_getsid,
+ .task_getsecid = selinux_task_getsecid,
.task_setgroups = selinux_task_setgroups,
.task_setnice = selinux_task_setnice,
+ .task_setioprio = selinux_task_setioprio,
+ .task_getioprio = selinux_task_getioprio,
.task_setrlimit = selinux_task_setrlimit,
.task_setscheduler = selinux_task_setscheduler,
.task_getscheduler = selinux_task_getscheduler,
+ .task_movememory = selinux_task_movememory,
.task_kill = selinux_task_kill,
.task_wait = selinux_task_wait,
.task_prctl = selinux_task_prctl,
@@ -4406,6 +4529,12 @@ static struct security_operations selinux_ops = {
.xfrm_state_delete_security = selinux_xfrm_state_delete,
.xfrm_policy_lookup = selinux_xfrm_policy_lookup,
#endif
+
+#ifdef CONFIG_KEYS
+ .key_alloc = selinux_key_alloc,
+ .key_free = selinux_key_free,
+ .key_permission = selinux_key_permission,
+#endif
};
static __init int selinux_init(void)
@@ -4441,6 +4570,15 @@ static __init int selinux_init(void)
} else {
printk(KERN_INFO "SELinux: Starting in permissive mode\n");
}
+
+#ifdef CONFIG_KEYS
+ /* Add security information to initial keyrings */
+ selinux_key_alloc(&root_user_keyring, current,
+ KEY_ALLOC_NOT_IN_QUOTA);
+ selinux_key_alloc(&root_session_keyring, current,
+ KEY_ALLOC_NOT_IN_QUOTA);
+#endif
+
return 0;
}
diff --git a/security/selinux/include/av_perm_to_string.h b/security/selinux/include/av_perm_to_string.h
index 70ee65a5881..7c9b5838083 100644
--- a/security/selinux/include/av_perm_to_string.h
+++ b/security/selinux/include/av_perm_to_string.h
@@ -72,6 +72,8 @@
S_(SECCLASS_PROCESS, PROCESS__EXECMEM, "execmem")
S_(SECCLASS_PROCESS, PROCESS__EXECSTACK, "execstack")
S_(SECCLASS_PROCESS, PROCESS__EXECHEAP, "execheap")
+ S_(SECCLASS_PROCESS, PROCESS__SETKEYCREATE, "setkeycreate")
+ S_(SECCLASS_PROCESS, PROCESS__SETSOCKCREATE, "setsockcreate")
S_(SECCLASS_MSGQ, MSGQ__ENQUEUE, "enqueue")
S_(SECCLASS_MSG, MSG__SEND, "send")
S_(SECCLASS_MSG, MSG__RECEIVE, "receive")
@@ -242,3 +244,10 @@
S_(SECCLASS_PACKET, PACKET__SEND, "send")
S_(SECCLASS_PACKET, PACKET__RECV, "recv")
S_(SECCLASS_PACKET, PACKET__RELABELTO, "relabelto")
+ S_(SECCLASS_KEY, KEY__VIEW, "view")
+ S_(SECCLASS_KEY, KEY__READ, "read")
+ S_(SECCLASS_KEY, KEY__WRITE, "write")
+ S_(SECCLASS_KEY, KEY__SEARCH, "search")
+ S_(SECCLASS_KEY, KEY__LINK, "link")
+ S_(SECCLASS_KEY, KEY__SETATTR, "setattr")
+ S_(SECCLASS_KEY, KEY__CREATE, "create")
diff --git a/security/selinux/include/av_permissions.h b/security/selinux/include/av_permissions.h
index 1d9cf3d306b..69fd4b48202 100644
--- a/security/selinux/include/av_permissions.h
+++ b/security/selinux/include/av_permissions.h
@@ -467,6 +467,8 @@
#define PROCESS__EXECMEM 0x02000000UL
#define PROCESS__EXECSTACK 0x04000000UL
#define PROCESS__EXECHEAP 0x08000000UL
+#define PROCESS__SETKEYCREATE 0x10000000UL
+#define PROCESS__SETSOCKCREATE 0x20000000UL
#define IPC__CREATE 0x00000001UL
#define IPC__DESTROY 0x00000002UL
@@ -959,3 +961,11 @@
#define PACKET__SEND 0x00000001UL
#define PACKET__RECV 0x00000002UL
#define PACKET__RELABELTO 0x00000004UL
+
+#define KEY__VIEW 0x00000001UL
+#define KEY__READ 0x00000002UL
+#define KEY__WRITE 0x00000004UL
+#define KEY__SEARCH 0x00000008UL
+#define KEY__LINK 0x00000010UL
+#define KEY__SETATTR 0x00000020UL
+#define KEY__CREATE 0x00000040UL
diff --git a/security/selinux/include/class_to_string.h b/security/selinux/include/class_to_string.h
index 3aec75fee4f..24303b61309 100644
--- a/security/selinux/include/class_to_string.h
+++ b/security/selinux/include/class_to_string.h
@@ -60,3 +60,4 @@
S_("netlink_kobject_uevent_socket")
S_("appletalk_socket")
S_("packet")
+ S_("key")
diff --git a/security/selinux/include/flask.h b/security/selinux/include/flask.h
index a0eb9e281d1..95887aed2a6 100644
--- a/security/selinux/include/flask.h
+++ b/security/selinux/include/flask.h
@@ -62,6 +62,7 @@
#define SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET 55
#define SECCLASS_APPLETALK_SOCKET 56
#define SECCLASS_PACKET 57
+#define SECCLASS_KEY 58
/*
* Security identifier indices for initial entities
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 54c03077888..cf54a304169 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -32,6 +32,8 @@ struct task_security_struct {
u32 sid; /* current SID */
u32 exec_sid; /* exec SID */
u32 create_sid; /* fscreate SID */
+ u32 keycreate_sid; /* keycreate SID */
+ u32 sockcreate_sid; /* fscreate SID */
u32 ptrace_sid; /* SID of ptrace parent */
};
@@ -99,6 +101,11 @@ struct sk_security_struct {
u32 peer_sid; /* SID of peer */
};
+struct key_security_struct {
+ struct key *obj; /* back pointer */
+ u32 sid; /* SID of key */
+};
+
extern unsigned int selinux_checkreqprot;
#endif /* _SELINUX_OBJSEC_H_ */
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 2e73d3279f2..00534c302ba 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -9,7 +9,6 @@
* the Free Software Foundation, version 2.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/pagemap.h>
#include <linux/slab.h>
@@ -1345,10 +1344,11 @@ err:
goto out;
}
-static struct super_block *sel_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int sel_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data,
+ struct vfsmount *mnt)
{
- return get_sb_single(fs_type, flags, data, sel_fill_super);
+ return get_sb_single(fs_type, flags, data, sel_fill_super, mnt);
}
static struct file_system_type sel_fs_type = {
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index c284dbb8b8c..d2e80e62ff0 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -1845,15 +1845,20 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr,
return -ENOTSUPP;
switch (field) {
- case AUDIT_SE_USER:
- case AUDIT_SE_ROLE:
- case AUDIT_SE_TYPE:
+ case AUDIT_SUBJ_USER:
+ case AUDIT_SUBJ_ROLE:
+ case AUDIT_SUBJ_TYPE:
+ case AUDIT_OBJ_USER:
+ case AUDIT_OBJ_ROLE:
+ case AUDIT_OBJ_TYPE:
/* only 'equals' and 'not equals' fit user, role, and type */
if (op != AUDIT_EQUAL && op != AUDIT_NOT_EQUAL)
return -EINVAL;
break;
- case AUDIT_SE_SEN:
- case AUDIT_SE_CLR:
+ case AUDIT_SUBJ_SEN:
+ case AUDIT_SUBJ_CLR:
+ case AUDIT_OBJ_LEV_LOW:
+ case AUDIT_OBJ_LEV_HIGH:
/* we do not allow a range, indicated by the presense of '-' */
if (strchr(rulestr, '-'))
return -EINVAL;
@@ -1874,29 +1879,34 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr,
tmprule->au_seqno = latest_granting;
switch (field) {
- case AUDIT_SE_USER:
+ case AUDIT_SUBJ_USER:
+ case AUDIT_OBJ_USER:
userdatum = hashtab_search(policydb.p_users.table, rulestr);
if (!userdatum)
rc = -EINVAL;
else
tmprule->au_ctxt.user = userdatum->value;
break;
- case AUDIT_SE_ROLE:
+ case AUDIT_SUBJ_ROLE:
+ case AUDIT_OBJ_ROLE:
roledatum = hashtab_search(policydb.p_roles.table, rulestr);
if (!roledatum)
rc = -EINVAL;
else
tmprule->au_ctxt.role = roledatum->value;
break;
- case AUDIT_SE_TYPE:
+ case AUDIT_SUBJ_TYPE:
+ case AUDIT_OBJ_TYPE:
typedatum = hashtab_search(policydb.p_types.table, rulestr);
if (!typedatum)
rc = -EINVAL;
else
tmprule->au_ctxt.type = typedatum->value;
break;
- case AUDIT_SE_SEN:
- case AUDIT_SE_CLR:
+ case AUDIT_SUBJ_SEN:
+ case AUDIT_SUBJ_CLR:
+ case AUDIT_OBJ_LEV_LOW:
+ case AUDIT_OBJ_LEV_HIGH:
rc = mls_from_string(rulestr, &tmprule->au_ctxt, GFP_ATOMIC);
break;
}
@@ -1948,7 +1958,8 @@ int selinux_audit_rule_match(u32 ctxid, u32 field, u32 op,
/* a field/op pair that is not caught here will simply fall through
without a match */
switch (field) {
- case AUDIT_SE_USER:
+ case AUDIT_SUBJ_USER:
+ case AUDIT_OBJ_USER:
switch (op) {
case AUDIT_EQUAL:
match = (ctxt->user == rule->au_ctxt.user);
@@ -1958,7 +1969,8 @@ int selinux_audit_rule_match(u32 ctxid, u32 field, u32 op,
break;
}
break;
- case AUDIT_SE_ROLE:
+ case AUDIT_SUBJ_ROLE:
+ case AUDIT_OBJ_ROLE:
switch (op) {
case AUDIT_EQUAL:
match = (ctxt->role == rule->au_ctxt.role);
@@ -1968,7 +1980,8 @@ int selinux_audit_rule_match(u32 ctxid, u32 field, u32 op,
break;
}
break;
- case AUDIT_SE_TYPE:
+ case AUDIT_SUBJ_TYPE:
+ case AUDIT_OBJ_TYPE:
switch (op) {
case AUDIT_EQUAL:
match = (ctxt->type == rule->au_ctxt.type);
@@ -1978,9 +1991,12 @@ int selinux_audit_rule_match(u32 ctxid, u32 field, u32 op,
break;
}
break;
- case AUDIT_SE_SEN:
- case AUDIT_SE_CLR:
- level = (op == AUDIT_SE_SEN ?
+ case AUDIT_SUBJ_SEN:
+ case AUDIT_SUBJ_CLR:
+ case AUDIT_OBJ_LEV_LOW:
+ case AUDIT_OBJ_LEV_HIGH:
+ level = ((field == AUDIT_SUBJ_SEN ||
+ field == AUDIT_OBJ_LEV_LOW) ?
&ctxt->range.level[0] : &ctxt->range.level[1]);
switch (op) {
case AUDIT_EQUAL:
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c
index 6633fb05931..6c985ced810 100644
--- a/security/selinux/xfrm.c
+++ b/security/selinux/xfrm.c
@@ -26,7 +26,6 @@
* 2. Emulating a reasonable SO_PEERSEC across machines
* 3. Testing addition of sk_policy's with security context via setsockopt
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>