KEYS: Improve /proc/keys
authorDavid Howells <dhowells@redhat.com>
Fri, 11 Mar 2011 17:57:23 +0000 (17:57 +0000)
committerJames Morris <jmorris@namei.org>
Thu, 17 Mar 2011 00:59:32 +0000 (11:59 +1100)
Improve /proc/keys by:

 (1) Don't attempt to summarise the payload of a negated key.  It won't have
     one.  To this end, a helper function - key_is_instantiated() has been
     added that allows the caller to find out whether the key is positively
     instantiated (as opposed to being uninstantiated or negatively
     instantiated).

 (2) Do show keys that are negative, expired or revoked rather than hiding
     them.  This requires an override flag (no_state_check) to be passed to
     search_my_process_keyrings() and keyring_search_aux() to suppress this
     check.

     Without this, keys that are possessed by the caller, but only grant
     permissions to the caller if possessed are skipped as the possession check
     fails.

     Keys that are visible due to user, group or other checks are visible with
     or without this patch.

Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: James Morris <jmorris@namei.org>
include/linux/key.h
net/dns_resolver/dns_key.c
security/keys/internal.h
security/keys/keyring.c
security/keys/proc.c
security/keys/process_keys.c
security/keys/request_key.c
security/keys/request_key_auth.c
security/keys/user_defined.c

index b2bb01719561f0d3de11945a9dba0a78744b8acc..ef19b99aff98d426c8e9b355a31360675daf9669 100644 (file)
@@ -276,6 +276,19 @@ static inline key_serial_t key_serial(struct key *key)
        return key ? key->serial : 0;
 }
 
+/**
+ * key_is_instantiated - Determine if a key has been positively instantiated
+ * @key: The key to check.
+ *
+ * Return true if the specified key has been positively instantiated, false
+ * otherwise.
+ */
+static inline bool key_is_instantiated(const struct key *key)
+{
+       return test_bit(KEY_FLAG_INSTANTIATED, &key->flags) &&
+               !test_bit(KEY_FLAG_NEGATIVE, &key->flags);
+}
+
 #define rcu_dereference_key(KEY)                                       \
        (rcu_dereference_protected((KEY)->payload.rcudata,              \
                                   rwsem_is_locked(&((struct key *)(KEY))->sem)))
index cfa7a5e1c5c98ca4592e09588a3a80bc1ba24d10..fa000d26dc6097220fe8bf53ed7cfc822afc31a0 100644 (file)
@@ -212,10 +212,12 @@ static void dns_resolver_describe(const struct key *key, struct seq_file *m)
        int err = key->type_data.x[0];
 
        seq_puts(m, key->description);
-       if (err)
-               seq_printf(m, ": %d", err);
-       else
-               seq_printf(m, ": %u", key->datalen);
+       if (key_is_instantiated(key)) {
+               if (err)
+                       seq_printf(m, ": %d", err);
+               else
+                       seq_printf(m, ": %u", key->datalen);
+       }
 }
 
 /*
index 07a025f8190233faf66a384816dea03754ee770a..f375152a2500b1d747d7128517430d2401f3a4ce 100644 (file)
@@ -109,11 +109,13 @@ extern key_ref_t keyring_search_aux(key_ref_t keyring_ref,
                                    const struct cred *cred,
                                    struct key_type *type,
                                    const void *description,
-                                   key_match_func_t match);
+                                   key_match_func_t match,
+                                   bool no_state_check);
 
 extern key_ref_t search_my_process_keyrings(struct key_type *type,
                                            const void *description,
                                            key_match_func_t match,
+                                           bool no_state_check,
                                            const struct cred *cred);
 extern key_ref_t search_process_keyrings(struct key_type *type,
                                         const void *description,
index cdd2f3f88c8879280a7607c1be655d5487d652c4..a06ffab38568809f5187970261888d6a9e673f18 100644 (file)
@@ -176,13 +176,15 @@ static void keyring_describe(const struct key *keyring, struct seq_file *m)
        else
                seq_puts(m, "[anon]");
 
-       rcu_read_lock();
-       klist = rcu_dereference(keyring->payload.subscriptions);
-       if (klist)
-               seq_printf(m, ": %u/%u", klist->nkeys, klist->maxkeys);
-       else
-               seq_puts(m, ": empty");
-       rcu_read_unlock();
+       if (key_is_instantiated(keyring)) {
+               rcu_read_lock();
+               klist = rcu_dereference(keyring->payload.subscriptions);
+               if (klist)
+                       seq_printf(m, ": %u/%u", klist->nkeys, klist->maxkeys);
+               else
+                       seq_puts(m, ": empty");
+               rcu_read_unlock();
+       }
 }
 
 /*
@@ -271,6 +273,7 @@ struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
  * @type: The type of key to search for.
  * @description: Parameter for @match.
  * @match: Function to rule on whether or not a key is the one required.
+ * @no_state_check: Don't check if a matching key is bad
  *
  * Search the supplied keyring tree for a key that matches the criteria given.
  * The root keyring and any linked keyrings must grant Search permission to the
@@ -303,7 +306,8 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
                             const struct cred *cred,
                             struct key_type *type,
                             const void *description,
-                            key_match_func_t match)
+                            key_match_func_t match,
+                            bool no_state_check)
 {
        struct {
                struct keyring_list *keylist;
@@ -345,6 +349,8 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
        kflags = keyring->flags;
        if (keyring->type == type && match(keyring, description)) {
                key = keyring;
+               if (no_state_check)
+                       goto found;
 
                /* check it isn't negative and hasn't expired or been
                 * revoked */
@@ -384,11 +390,13 @@ descend:
                        continue;
 
                /* skip revoked keys and expired keys */
-               if (kflags & (1 << KEY_FLAG_REVOKED))
-                       continue;
+               if (!no_state_check) {
+                       if (kflags & (1 << KEY_FLAG_REVOKED))
+                               continue;
 
-               if (key->expiry && now.tv_sec >= key->expiry)
-                       continue;
+                       if (key->expiry && now.tv_sec >= key->expiry)
+                               continue;
+               }
 
                /* keys that don't match */
                if (!match(key, description))
@@ -399,6 +407,9 @@ descend:
                                        cred, KEY_SEARCH) < 0)
                        continue;
 
+               if (no_state_check)
+                       goto found;
+
                /* we set a different error code if we pass a negative key */
                if (kflags & (1 << KEY_FLAG_NEGATIVE)) {
                        err = key->type_data.reject_error;
@@ -478,7 +489,7 @@ key_ref_t keyring_search(key_ref_t keyring,
                return ERR_PTR(-ENOKEY);
 
        return keyring_search_aux(keyring, current->cred,
-                                 type, description, type->match);
+                                 type, description, type->match, false);
 }
 EXPORT_SYMBOL(keyring_search);
 
index 525cf8a29cdde86c5c58557fd73ceb49e9c73dec..49bbc97943ad8b804e22ff69150083a0f891ffd5 100644 (file)
@@ -199,7 +199,7 @@ static int proc_keys_show(struct seq_file *m, void *v)
        if (key->perm & KEY_POS_VIEW) {
                skey_ref = search_my_process_keyrings(key->type, key,
                                                      lookup_user_key_possessed,
-                                                     cred);
+                                                     true, cred);
                if (!IS_ERR(skey_ref)) {
                        key_ref_put(skey_ref);
                        key_ref = make_key_ref(key, 1);
index 930634e4514973ac0f79acc7037138acb576a2c3..6c0480db8885b6393b8f4bfea75b8d35ce3015d3 100644 (file)
@@ -331,6 +331,7 @@ void key_fsgid_changed(struct task_struct *tsk)
 key_ref_t search_my_process_keyrings(struct key_type *type,
                                     const void *description,
                                     key_match_func_t match,
+                                    bool no_state_check,
                                     const struct cred *cred)
 {
        key_ref_t key_ref, ret, err;
@@ -350,7 +351,7 @@ key_ref_t search_my_process_keyrings(struct key_type *type,
        if (cred->thread_keyring) {
                key_ref = keyring_search_aux(
                        make_key_ref(cred->thread_keyring, 1),
-                       cred, type, description, match);
+                       cred, type, description, match, no_state_check);
                if (!IS_ERR(key_ref))
                        goto found;
 
@@ -371,7 +372,7 @@ key_ref_t search_my_process_keyrings(struct key_type *type,
        if (cred->tgcred->process_keyring) {
                key_ref = keyring_search_aux(
                        make_key_ref(cred->tgcred->process_keyring, 1),
-                       cred, type, description, match);
+                       cred, type, description, match, no_state_check);
                if (!IS_ERR(key_ref))
                        goto found;
 
@@ -395,7 +396,7 @@ key_ref_t search_my_process_keyrings(struct key_type *type,
                        make_key_ref(rcu_dereference(
                                             cred->tgcred->session_keyring),
                                     1),
-                       cred, type, description, match);
+                       cred, type, description, match, no_state_check);
                rcu_read_unlock();
 
                if (!IS_ERR(key_ref))
@@ -417,7 +418,7 @@ key_ref_t search_my_process_keyrings(struct key_type *type,
        else if (cred->user->session_keyring) {
                key_ref = keyring_search_aux(
                        make_key_ref(cred->user->session_keyring, 1),
-                       cred, type, description, match);
+                       cred, type, description, match, no_state_check);
                if (!IS_ERR(key_ref))
                        goto found;
 
@@ -459,7 +460,8 @@ key_ref_t search_process_keyrings(struct key_type *type,
 
        might_sleep();
 
-       key_ref = search_my_process_keyrings(type, description, match, cred);
+       key_ref = search_my_process_keyrings(type, description, match,
+                                            false, cred);
        if (!IS_ERR(key_ref))
                goto found;
        err = key_ref;
index df3c0417ee4062ffebac5cb6f3ad30d84fc66a6b..b18a71745901811120e51e6b33624b9e77a98891 100644 (file)
@@ -530,8 +530,7 @@ struct key *request_key_and_link(struct key_type *type,
               dest_keyring, flags);
 
        /* search all the process keyrings for a key */
-       key_ref = search_process_keyrings(type, description, type->match,
-                                         cred);
+       key_ref = search_process_keyrings(type, description, type->match, cred);
 
        if (!IS_ERR(key_ref)) {
                key = key_ref_to_ptr(key_ref);
index 68164031a74e0bc225844037ceedd45a40fc94cb..f6337c9082ebf6eae8cc0292c6042e5a6350f70f 100644 (file)
@@ -59,7 +59,8 @@ static void request_key_auth_describe(const struct key *key,
 
        seq_puts(m, "key:");
        seq_puts(m, key->description);
-       seq_printf(m, " pid:%d ci:%zu", rka->pid, rka->callout_len);
+       if (key_is_instantiated(key))
+               seq_printf(m, " pid:%d ci:%zu", rka->pid, rka->callout_len);
 }
 
 /*
index c6ca8662a4685bd162205938eafae39bef25fbbf..63bb1aaffc0a056d316d5631b14dc761467c7534 100644 (file)
@@ -169,8 +169,8 @@ EXPORT_SYMBOL_GPL(user_destroy);
 void user_describe(const struct key *key, struct seq_file *m)
 {
        seq_puts(m, key->description);
-
-       seq_printf(m, ": %u", key->datalen);
+       if (key_is_instantiated(key))
+               seq_printf(m, ": %u", key->datalen);
 }
 
 EXPORT_SYMBOL_GPL(user_describe);