diff options
Diffstat (limited to 'security')
-rw-r--r-- | security/Kconfig | 20 | ||||
-rw-r--r-- | security/capability.c | 1 | ||||
-rw-r--r-- | security/commoncap.c | 5 | ||||
-rw-r--r-- | security/dummy.c | 34 | ||||
-rw-r--r-- | security/inode.c | 11 | ||||
-rw-r--r-- | security/keys/internal.h | 4 | ||||
-rw-r--r-- | security/keys/key.c | 71 | ||||
-rw-r--r-- | security/keys/keyctl.c | 63 | ||||
-rw-r--r-- | security/keys/keyring.c | 28 | ||||
-rw-r--r-- | security/keys/proc.c | 7 | ||||
-rw-r--r-- | security/keys/process_keys.c | 69 | ||||
-rw-r--r-- | security/keys/request_key.c | 64 | ||||
-rw-r--r-- | security/keys/request_key_auth.c | 49 | ||||
-rw-r--r-- | security/keys/user_defined.c | 25 | ||||
-rw-r--r-- | security/root_plug.c | 1 | ||||
-rw-r--r-- | security/seclvl.c | 1 | ||||
-rw-r--r-- | security/security.c | 1 | ||||
-rw-r--r-- | security/selinux/hooks.c | 194 | ||||
-rw-r--r-- | security/selinux/include/av_perm_to_string.h | 9 | ||||
-rw-r--r-- | security/selinux/include/av_permissions.h | 10 | ||||
-rw-r--r-- | security/selinux/include/class_to_string.h | 1 | ||||
-rw-r--r-- | security/selinux/include/flask.h | 1 | ||||
-rw-r--r-- | security/selinux/include/objsec.h | 7 | ||||
-rw-r--r-- | security/selinux/selinuxfs.c | 8 | ||||
-rw-r--r-- | security/selinux/ss/services.c | 48 | ||||
-rw-r--r-- | security/selinux/xfrm.c | 1 |
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(¤t->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, + ¤t->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(¤t->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(¤t->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> |