- Key overview
        - Key service overview
        - Key access permissions
+       - SELinux support
        - New procfs files
        - Userspace system call interface
        - Kernel services
 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
 ================
 
 
 extern 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);
 extern int key_payload_reserve(struct key *key, size_t datalen);
 extern int key_instantiate_and_link(struct key *key,
                                    const void *data,
                      struct key *key);
 
 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);
 
  * the userspace interface
  */
 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 int copy_keys(unsigned long clone_flags, struct task_struct *tsk);
 extern int copy_thread_group_keys(struct task_struct *tsk);
 #define make_key_ref(k)                        ({ NULL; })
 #define key_ref_to_ptr(k)              ({ NULL; })
 #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 __install_session_keyring(t, k)        ({ NULL; })
 #define copy_keys(f,t)                 0
 #define key_fsgid_changed(t)           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 /* __KERNEL__ */
 #endif /* _LINUX_KEY_H */
 
 
        /* key management security hooks */
 #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);
        int (*key_permission)(key_ref_t key_ref,
                              struct task_struct *context,
 
 #ifdef CONFIG_KEYS
 #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)
 
 #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;
 }
 
                new->mq_bytes = 0;
                new->locked_shm = 0;
 
-               if (alloc_uid_keyring(new) < 0) {
+               if (alloc_uid_keyring(new, current) < 0) {
                        kmem_cache_free(uid_cachep, new);
                        return NULL;
                }
 
 }
 
 #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;
 }
 
  *   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;
 #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;
 
 
        /* 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;
 
  * 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);
 
 
 /*
  * 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];
        /* 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;
         * 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);
 
        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;
        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;
        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);
        }
        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;
 
        /* 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;
 
        /* 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;
 
 
        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)) {
 
        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,
        .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)
        } 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;
 }
 
 
    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")
 
 #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
+
 
     S_("netlink_kobject_uevent_socket")
     S_("appletalk_socket")
     S_("packet")
+    S_("key")
 
 #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
 
        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_ */