diff options
Diffstat (limited to 'security')
-rw-r--r-- | security/dummy.c | 16 | ||||
-rw-r--r-- | security/inode.c | 8 | ||||
-rw-r--r-- | security/keys/key.c | 20 | ||||
-rw-r--r-- | security/keys/keyring.c | 5 | ||||
-rw-r--r-- | security/keys/process_keys.c | 57 | ||||
-rw-r--r-- | security/keys/request_key.c | 6 | ||||
-rw-r--r-- | security/keys/request_key_auth.c | 47 | ||||
-rw-r--r-- | security/selinux/hooks.c | 82 | ||||
-rw-r--r-- | security/selinux/include/av_perm_to_string.h | 6 | ||||
-rw-r--r-- | security/selinux/include/av_permissions.h | 8 | ||||
-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 | 5 | ||||
-rw-r--r-- | security/selinux/selinuxfs.c | 7 | ||||
-rw-r--r-- | security/selinux/ss/services.c | 2 |
15 files changed, 221 insertions, 50 deletions
diff --git a/security/dummy.c b/security/dummy.c index 64f6da0f422e..c3c5493581e2 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -191,7 +191,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; } @@ -516,6 +516,11 @@ 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_setrlimit (unsigned int resource, struct rlimit *new_rlim) { return 0; @@ -532,6 +537,11 @@ 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; @@ -860,7 +870,7 @@ 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) { return 0; } @@ -972,9 +982,11 @@ void security_fixup_ops (struct security_operations *ops) set_to_dummy_if_null(ops, task_getsid); 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_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 0f77b0223662..e6fc29ac8564 100644 --- a/security/inode.c +++ b/security/inode.c @@ -135,11 +135,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 = { diff --git a/security/keys/key.c b/security/keys/key.c index b6061fa29da7..51f851557389 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -211,12 +211,12 @@ static inline void key_alloc_serial(struct key *key) 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) @@ -247,8 +247,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, int not_in_quota) { struct key_user *user = NULL; struct key *key; @@ -318,7 +318,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); if (ret < 0) goto security_error; @@ -822,7 +822,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, not_in_quota); if (IS_ERR(key)) { key_ref = ERR_PTR(PTR_ERR(key)); goto error_3; @@ -907,6 +907,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() */ diff --git a/security/keys/keyring.c b/security/keys/keyring.c index bffa924c1f88..1357207fc9df 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c @@ -240,13 +240,14 @@ 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, int not_in_quota, + 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); diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 217a0bef3c82..4d9825f9962c 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,7 @@ 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, 0, NULL); if (IS_ERR(session_keyring)) { ret = PTR_ERR(session_keyring); goto error; @@ -86,7 +87,7 @@ 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, + uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, ctx, 0, session_keyring); if (IS_ERR(uid_keyring)) { key_put(session_keyring); @@ -143,7 +144,7 @@ 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, 1, NULL); if (IS_ERR(keyring)) { ret = PTR_ERR(keyring); goto error; @@ -177,7 +178,7 @@ 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, 1, NULL); if (IS_ERR(keyring)) { ret = PTR_ERR(keyring); goto error; @@ -217,7 +218,7 @@ 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); + keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk, 1, NULL); if (IS_ERR(keyring)) return PTR_ERR(keyring); } @@ -390,6 +391,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 +498,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 +728,7 @@ 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, 0, 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 f030a0ccbb93..eab66a06ca53 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c @@ -48,7 +48,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, 1, NULL); if (IS_ERR(keyring)) { ret = PTR_ERR(keyring); goto error_alloc; @@ -137,7 +138,8 @@ static struct key *__request_key_construction(struct key_type *type, /* 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, 0); if (IS_ERR(key)) goto alloc_failed; diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c index cce6ba6b0323..cb9817ced3fd 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,7 +185,7 @@ 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); if (IS_ERR(authkey)) { @@ -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/selinux/hooks.c b/security/selinux/hooks.c index 54adc9d31e92..79c16e31c884 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1903,13 +1903,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, @@ -2645,6 +2645,11 @@ 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_setrlimit(unsigned int resource, struct rlimit *new_rlim) { struct rlimit *old_rlim = current->signal->rlim + resource; @@ -2674,6 +2679,11 @@ static int selinux_task_getscheduler(struct task_struct *p) return task_has_perm(current, p, PROCESS__GETSCHED); } +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 perm; @@ -4252,6 +4262,57 @@ 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) +{ + 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; + 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, @@ -4332,9 +4393,11 @@ static struct security_operations selinux_ops = { .task_getsid = selinux_task_getsid, .task_setgroups = selinux_task_setgroups, .task_setnice = selinux_task_setnice, + .task_setioprio = selinux_task_setioprio, .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 +4469,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 +4510,13 @@ 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 */ + security_key_alloc(&root_user_keyring, current); + security_key_alloc(&root_session_keyring, current); +#endif + return 0; } diff --git a/security/selinux/include/av_perm_to_string.h b/security/selinux/include/av_perm_to_string.h index 70ee65a58817..bc020bde6c86 100644 --- a/security/selinux/include/av_perm_to_string.h +++ b/security/selinux/include/av_perm_to_string.h @@ -242,3 +242,9 @@ 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") diff --git a/security/selinux/include/av_permissions.h b/security/selinux/include/av_permissions.h index 1d9cf3d306bc..1205227a3a33 100644 --- a/security/selinux/include/av_permissions.h +++ b/security/selinux/include/av_permissions.h @@ -959,3 +959,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 + diff --git a/security/selinux/include/class_to_string.h b/security/selinux/include/class_to_string.h index 3aec75fee4f7..24303b61309f 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 a0eb9e281d18..95887aed2a68 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 54c030778882..8f5547ad1856 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -99,6 +99,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 2e73d3279f2d..7029bbc9bef8 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -1345,10 +1345,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 c284dbb8b8c0..e9548bc049e1 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -1980,7 +1980,7 @@ int selinux_audit_rule_match(u32 ctxid, u32 field, u32 op, break; case AUDIT_SE_SEN: case AUDIT_SE_CLR: - level = (op == AUDIT_SE_SEN ? + level = (field == AUDIT_SE_SEN ? &ctxt->range.level[0] : &ctxt->range.level[1]); switch (op) { case AUDIT_EQUAL: |