Commit d720024e authored by Michael LeMay's avatar Michael LeMay Committed by Linus Torvalds

[PATCH] selinux: add hooks for key subsystem

Introduce SELinux hooks to support the access key retention subsystem
within the kernel.  Incorporate new flask headers from a modified version
of the SELinux reference policy, with support for the new security class
representing retained keys.  Extend the "key_alloc" security hook with a
task parameter representing the intended ownership context for the key
being allocated.  Attach security information to root's default keyrings
within the SELinux initialization routine.

Has passed David's testsuite.
Signed-off-by: default avatarMichael LeMay <mdlemay@epoch.ncsc.mil>
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Signed-off-by: default avatarJames Morris <jmorris@namei.org>
Acked-by: default avatarChris Wright <chrisw@sous-sol.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent f893afbe
...@@ -19,6 +19,7 @@ This document has the following sections: ...@@ -19,6 +19,7 @@ This document has the following sections:
- Key overview - Key overview
- Key service overview - Key service overview
- Key access permissions - Key access permissions
- SELinux support
- New procfs files - New procfs files
- Userspace system call interface - Userspace system call interface
- Kernel services - Kernel services
...@@ -232,6 +233,34 @@ For changing the ownership, group ID or permissions mask, being the owner of ...@@ -232,6 +233,34 @@ For changing the ownership, group ID or permissions mask, being the owner of
the key or having the sysadmin capability is sufficient. the key or having the sysadmin capability is sufficient.
===============
SELINUX SUPPORT
===============
The security class "key" has been added to SELinux so that mandatory access
controls can be applied to keys created within various contexts. This support
is preliminary, and is likely to change quite significantly in the near future.
Currently, all of the basic permissions explained above are provided in SELinux
as well; SE Linux is simply invoked after all basic permission checks have been
performed.
Each key is labeled with the same context as the task to which it belongs.
Typically, this is the same task that was running when the key was created.
The default keyrings are handled differently, but in a way that is very
intuitive:
(*) The user and user session keyrings that are created when the user logs in
are currently labeled with the context of the login manager.
(*) The keyrings associated with new threads are each labeled with the context
of their associated thread, and both session and process keyrings are
handled similarly.
Note, however, that the default keyrings associated with the root user are
labeled with the default kernel context, since they are created early in the
boot process, before root has a chance to log in.
================ ================
NEW PROCFS FILES NEW PROCFS FILES
================ ================
......
...@@ -241,8 +241,9 @@ extern void unregister_key_type(struct key_type *ktype); ...@@ -241,8 +241,9 @@ extern void unregister_key_type(struct key_type *ktype);
extern struct key *key_alloc(struct key_type *type, extern struct key *key_alloc(struct key_type *type,
const char *desc, const char *desc,
uid_t uid, gid_t gid, key_perm_t perm, uid_t uid, gid_t gid,
int not_in_quota); struct task_struct *ctx,
key_perm_t perm, int not_in_quota);
extern int key_payload_reserve(struct key *key, size_t datalen); extern int key_payload_reserve(struct key *key, size_t datalen);
extern int key_instantiate_and_link(struct key *key, extern int key_instantiate_and_link(struct key *key,
const void *data, const void *data,
...@@ -292,7 +293,9 @@ extern int key_unlink(struct key *keyring, ...@@ -292,7 +293,9 @@ extern int key_unlink(struct key *keyring,
struct key *key); struct key *key);
extern struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, extern 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);
extern int keyring_clear(struct key *keyring); extern int keyring_clear(struct key *keyring);
...@@ -313,7 +316,8 @@ extern void keyring_replace_payload(struct key *key, void *replacement); ...@@ -313,7 +316,8 @@ extern void keyring_replace_payload(struct key *key, void *replacement);
* the userspace interface * the userspace interface
*/ */
extern struct key root_user_keyring, root_session_keyring; extern struct key root_user_keyring, root_session_keyring;
extern int alloc_uid_keyring(struct user_struct *user); extern int alloc_uid_keyring(struct user_struct *user,
struct task_struct *ctx);
extern void switch_uid_keyring(struct user_struct *new_user); extern void switch_uid_keyring(struct user_struct *new_user);
extern int copy_keys(unsigned long clone_flags, struct task_struct *tsk); extern int copy_keys(unsigned long clone_flags, struct task_struct *tsk);
extern int copy_thread_group_keys(struct task_struct *tsk); extern int copy_thread_group_keys(struct task_struct *tsk);
...@@ -342,7 +346,7 @@ extern void key_init(void); ...@@ -342,7 +346,7 @@ extern void key_init(void);
#define make_key_ref(k) ({ NULL; }) #define make_key_ref(k) ({ NULL; })
#define key_ref_to_ptr(k) ({ NULL; }) #define key_ref_to_ptr(k) ({ NULL; })
#define is_key_possessed(k) 0 #define is_key_possessed(k) 0
#define alloc_uid_keyring(u) 0 #define alloc_uid_keyring(u,c) 0
#define switch_uid_keyring(u) do { } while(0) #define switch_uid_keyring(u) do { } while(0)
#define __install_session_keyring(t, k) ({ NULL; }) #define __install_session_keyring(t, k) ({ NULL; })
#define copy_keys(f,t) 0 #define copy_keys(f,t) 0
...@@ -355,6 +359,10 @@ extern void key_init(void); ...@@ -355,6 +359,10 @@ extern void key_init(void);
#define key_fsgid_changed(t) do { } while(0) #define key_fsgid_changed(t) do { } while(0)
#define key_init() do { } while(0) #define key_init() do { } while(0)
/* Initial keyrings */
extern struct key root_user_keyring;
extern struct key root_session_keyring;
#endif /* CONFIG_KEYS */ #endif /* CONFIG_KEYS */
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* _LINUX_KEY_H */ #endif /* _LINUX_KEY_H */
...@@ -1313,7 +1313,7 @@ struct security_operations { ...@@ -1313,7 +1313,7 @@ struct security_operations {
/* key management security hooks */ /* key management security hooks */
#ifdef CONFIG_KEYS #ifdef CONFIG_KEYS
int (*key_alloc)(struct key *key); int (*key_alloc)(struct key *key, struct task_struct *tsk);
void (*key_free)(struct key *key); void (*key_free)(struct key *key);
int (*key_permission)(key_ref_t key_ref, int (*key_permission)(key_ref_t key_ref,
struct task_struct *context, struct task_struct *context,
...@@ -3008,9 +3008,10 @@ static inline int security_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid ...@@ -3008,9 +3008,10 @@ static inline int security_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid
#ifdef CONFIG_KEYS #ifdef CONFIG_KEYS
#ifdef CONFIG_SECURITY #ifdef CONFIG_SECURITY
static inline int security_key_alloc(struct key *key) static inline int security_key_alloc(struct key *key,
struct task_struct *tsk)
{ {
return security_ops->key_alloc(key); return security_ops->key_alloc(key, tsk);
} }
static inline void security_key_free(struct key *key) static inline void security_key_free(struct key *key)
...@@ -3027,7 +3028,8 @@ static inline int security_key_permission(key_ref_t key_ref, ...@@ -3027,7 +3028,8 @@ static inline int security_key_permission(key_ref_t key_ref,
#else #else
static inline int security_key_alloc(struct key *key) static inline int security_key_alloc(struct key *key,
struct task_struct *tsk)
{ {
return 0; return 0;
} }
......
...@@ -148,7 +148,7 @@ struct user_struct * alloc_uid(uid_t uid) ...@@ -148,7 +148,7 @@ struct user_struct * alloc_uid(uid_t uid)
new->mq_bytes = 0; new->mq_bytes = 0;
new->locked_shm = 0; new->locked_shm = 0;
if (alloc_uid_keyring(new) < 0) { if (alloc_uid_keyring(new, current) < 0) {
kmem_cache_free(uid_cachep, new); kmem_cache_free(uid_cachep, new);
return NULL; return NULL;
} }
......
...@@ -860,7 +860,7 @@ static int dummy_setprocattr(struct task_struct *p, char *name, void *value, siz ...@@ -860,7 +860,7 @@ static int dummy_setprocattr(struct task_struct *p, char *name, void *value, siz
} }
#ifdef CONFIG_KEYS #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; return 0;
} }
......
...@@ -247,8 +247,8 @@ static inline void key_alloc_serial(struct key *key) ...@@ -247,8 +247,8 @@ static inline void key_alloc_serial(struct key *key)
* instantiate the key or discard it before returning * instantiate the key or discard it before returning
*/ */
struct key *key_alloc(struct key_type *type, const char *desc, struct key *key_alloc(struct key_type *type, const char *desc,
uid_t uid, gid_t gid, key_perm_t perm, uid_t uid, gid_t gid, struct task_struct *ctx,
int not_in_quota) key_perm_t perm, int not_in_quota)
{ {
struct key_user *user = NULL; struct key_user *user = NULL;
struct key *key; struct key *key;
...@@ -318,7 +318,7 @@ struct key *key_alloc(struct key_type *type, const char *desc, ...@@ -318,7 +318,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
#endif #endif
/* let the security module know about the key */ /* let the security module know about the key */
ret = security_key_alloc(key); ret = security_key_alloc(key, ctx);
if (ret < 0) if (ret < 0)
goto security_error; goto security_error;
...@@ -822,7 +822,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, ...@@ -822,7 +822,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
/* allocate a new key */ /* allocate a new key */
key = key_alloc(ktype, description, current->fsuid, current->fsgid, key = key_alloc(ktype, description, current->fsuid, current->fsgid,
perm, not_in_quota); current, perm, not_in_quota);
if (IS_ERR(key)) { if (IS_ERR(key)) {
key_ref = ERR_PTR(PTR_ERR(key)); key_ref = ERR_PTR(PTR_ERR(key));
goto error_3; goto error_3;
......
...@@ -240,13 +240,14 @@ static long keyring_read(const struct key *keyring, ...@@ -240,13 +240,14 @@ static long keyring_read(const struct key *keyring,
* allocate a keyring and link into the destination keyring * allocate a keyring and link into the destination keyring
*/ */
struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, 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; struct key *keyring;
int ret; int ret;
keyring = key_alloc(&key_type_keyring, description, keyring = key_alloc(&key_type_keyring, description,
uid, gid, uid, gid, ctx,
(KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL, (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL,
not_in_quota); not_in_quota);
......
...@@ -67,7 +67,8 @@ struct key root_session_keyring = { ...@@ -67,7 +67,8 @@ struct key root_session_keyring = {
/* /*
* allocate the keyrings to be associated with a UID * 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; struct key *uid_keyring, *session_keyring;
char buf[20]; char buf[20];
...@@ -76,7 +77,7 @@ int alloc_uid_keyring(struct user_struct *user) ...@@ -76,7 +77,7 @@ int alloc_uid_keyring(struct user_struct *user)
/* concoct a default session keyring */ /* concoct a default session keyring */
sprintf(buf, "_uid_ses.%u", user->uid); 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)) { if (IS_ERR(session_keyring)) {
ret = PTR_ERR(session_keyring); ret = PTR_ERR(session_keyring);
goto error; goto error;
...@@ -86,7 +87,7 @@ int alloc_uid_keyring(struct user_struct *user) ...@@ -86,7 +87,7 @@ int alloc_uid_keyring(struct user_struct *user)
* keyring */ * keyring */
sprintf(buf, "_uid.%u", user->uid); 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); session_keyring);
if (IS_ERR(uid_keyring)) { if (IS_ERR(uid_keyring)) {
key_put(session_keyring); key_put(session_keyring);
...@@ -143,7 +144,7 @@ int install_thread_keyring(struct task_struct *tsk) ...@@ -143,7 +144,7 @@ int install_thread_keyring(struct task_struct *tsk)
sprintf(buf, "_tid.%u", tsk->pid); 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)) { if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring); ret = PTR_ERR(keyring);
goto error; goto error;
...@@ -177,7 +178,7 @@ int install_process_keyring(struct task_struct *tsk) ...@@ -177,7 +178,7 @@ int install_process_keyring(struct task_struct *tsk)
if (!tsk->signal->process_keyring) { if (!tsk->signal->process_keyring) {
sprintf(buf, "_pid.%u", tsk->tgid); 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)) { if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring); ret = PTR_ERR(keyring);
goto error; goto error;
...@@ -217,7 +218,7 @@ static int install_session_keyring(struct task_struct *tsk, ...@@ -217,7 +218,7 @@ static int install_session_keyring(struct task_struct *tsk,
if (!keyring) { if (!keyring) {
sprintf(buf, "_ses.%u", tsk->tgid); 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)) if (IS_ERR(keyring))
return PTR_ERR(keyring); return PTR_ERR(keyring);
} }
...@@ -717,7 +718,7 @@ long join_session_keyring(const char *name) ...@@ -717,7 +718,7 @@ long join_session_keyring(const char *name)
keyring = find_keyring_by_name(name, 0); keyring = find_keyring_by_name(name, 0);
if (PTR_ERR(keyring) == -ENOKEY) { if (PTR_ERR(keyring) == -ENOKEY) {
/* not found - try and create a new one */ /* 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)) { if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring); ret = PTR_ERR(keyring);
goto error2; goto error2;
......
...@@ -48,7 +48,8 @@ static int call_sbin_request_key(struct key *key, ...@@ -48,7 +48,8 @@ static int call_sbin_request_key(struct key *key,
/* allocate a new session keyring */ /* allocate a new session keyring */
sprintf(desc, "_req.%u", key->serial); 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)) { if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring); ret = PTR_ERR(keyring);
goto error_alloc; goto error_alloc;
...@@ -137,7 +138,8 @@ static struct key *__request_key_construction(struct key_type *type, ...@@ -137,7 +138,8 @@ static struct key *__request_key_construction(struct key_type *type,
/* create a key and add it to the queue */ /* create a key and add it to the queue */
key = key_alloc(type, description, 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)) if (IS_ERR(key))
goto alloc_failed; goto alloc_failed;
......
...@@ -148,7 +148,7 @@ struct key *request_key_auth_new(struct key *target, const char *callout_info) ...@@ -148,7 +148,7 @@ struct key *request_key_auth_new(struct key *target, const char *callout_info)
sprintf(desc, "%x", target->serial); sprintf(desc, "%x", target->serial);
authkey = key_alloc(&key_type_request_key_auth, desc, 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_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH |
KEY_USR_VIEW, 1); KEY_USR_VIEW, 1);
if (IS_ERR(authkey)) { if (IS_ERR(authkey)) {
......
...@@ -4252,6 +4252,57 @@ static int selinux_setprocattr(struct task_struct *p, ...@@ -4252,6 +4252,57 @@ static int selinux_setprocattr(struct task_struct *p,
return size; 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 = { static struct security_operations selinux_ops = {
.ptrace = selinux_ptrace, .ptrace = selinux_ptrace,
.capget = selinux_capget, .capget = selinux_capget,
...@@ -4406,6 +4457,12 @@ static struct security_operations selinux_ops = { ...@@ -4406,6 +4457,12 @@ static struct security_operations selinux_ops = {
.xfrm_state_delete_security = selinux_xfrm_state_delete, .xfrm_state_delete_security = selinux_xfrm_state_delete,
.xfrm_policy_lookup = selinux_xfrm_policy_lookup, .xfrm_policy_lookup = selinux_xfrm_policy_lookup,
#endif #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) static __init int selinux_init(void)
...@@ -4441,6 +4498,13 @@ static __init int selinux_init(void) ...@@ -4441,6 +4498,13 @@ static __init int selinux_init(void)
} else { } else {
printk(KERN_INFO "SELinux: Starting in permissive mode\n"); 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; return 0;
} }
......
...@@ -242,3 +242,9 @@ ...@@ -242,3 +242,9 @@
S_(SECCLASS_PACKET, PACKET__SEND, "send") S_(SECCLASS_PACKET, PACKET__SEND, "send")
S_(SECCLASS_PACKET, PACKET__RECV, "recv") S_(SECCLASS_PACKET, PACKET__RECV, "recv")
S_(SECCLASS_PACKET, PACKET__RELABELTO, "relabelto") 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")
...@@ -959,3 +959,11 @@ ...@@ -959,3 +959,11 @@
#define PACKET__SEND 0x00000001UL #define PACKET__SEND 0x00000001UL
#define PACKET__RECV 0x00000002UL #define PACKET__RECV 0x00000002UL
#define PACKET__RELABELTO 0x00000004UL #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
...@@ -60,3 +60,4 @@ ...@@ -60,3 +60,4 @@
S_("netlink_kobject_uevent_socket") S_("netlink_kobject_uevent_socket")
S_("appletalk_socket") S_("appletalk_socket")
S_("packet") S_("packet")
S_("key")
...@@ -62,6 +62,7 @@ ...@@ -62,6 +62,7 @@
#define SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET 55 #define SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET 55
#define SECCLASS_APPLETALK_SOCKET 56 #define SECCLASS_APPLETALK_SOCKET 56
#define SECCLASS_PACKET 57 #define SECCLASS_PACKET 57
#define SECCLASS_KEY 58
/* /*
* Security identifier indices for initial entities * Security identifier indices for initial entities
......
...@@ -99,6 +99,11 @@ struct sk_security_struct { ...@@ -99,6 +99,11 @@ struct sk_security_struct {
u32 peer_sid; /* SID of peer */ 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; extern unsigned int selinux_checkreqprot;
#endif /* _SELINUX_OBJSEC_H_ */ #endif /* _SELINUX_OBJSEC_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment