security, keys: convert key_user.usage from atomic_t to refcount_t
authorElena Reshetova <elena.reshetova@intel.com>
Fri, 31 Mar 2017 12:20:49 +0000 (15:20 +0300)
committerJames Morris <james.l.morris@oracle.com>
Mon, 3 Apr 2017 00:49:06 +0000 (10:49 +1000)
refcount_t type and corresponding API should be
used instead of atomic_t when the variable is used as
a reference counter. This allows to avoid accidental
refcounter overflows that might lead to use-after-free
situations.

Signed-off-by: Elena Reshetova <elena.reshetova@intel.com>
Signed-off-by: Hans Liljestrand <ishkamiel@gmail.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: David Windsor <dwindsor@gmail.com>
Acked-by: David Howells <dhowells@redhat.com>
Signed-off-by: James Morris <james.l.morris@oracle.com>
security/keys/internal.h
security/keys/key.c
security/keys/proc.c
security/keys/process_keys.c

index a2f4c0abb8d847325465131e7a4e219489b441e6..6bee06ae026dda8b33e4dfa8acdbe28da6f001a7 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/key-type.h>
 #include <linux/task_work.h>
 #include <linux/keyctl.h>
+#include <linux/refcount.h>
 
 struct iovec;
 
@@ -53,7 +54,7 @@ struct key_user {
        struct rb_node          node;
        struct mutex            cons_lock;      /* construction initiation lock */
        spinlock_t              lock;
-       atomic_t                usage;          /* for accessing qnkeys & qnbytes */
+       refcount_t              usage;          /* for accessing qnkeys & qnbytes */
        atomic_t                nkeys;          /* number of keys */
        atomic_t                nikeys;         /* number of instantiated keys */
        kuid_t                  uid;
index ff9244392d3536d137d55219cf4bf6504ffe4ed2..b4958b36fa27adbc653c010a8470965084e9a3e3 100644 (file)
@@ -93,7 +93,7 @@ try_again:
 
        /* if we get here, then the user record still hadn't appeared on the
         * second pass - so we use the candidate record */
-       atomic_set(&candidate->usage, 1);
+       refcount_set(&candidate->usage, 1);
        atomic_set(&candidate->nkeys, 0);
        atomic_set(&candidate->nikeys, 0);
        candidate->uid = uid;
@@ -110,7 +110,7 @@ try_again:
 
        /* okay - we found a user record for this UID */
 found:
-       atomic_inc(&user->usage);
+       refcount_inc(&user->usage);
        spin_unlock(&key_user_lock);
        kfree(candidate);
 out:
@@ -122,7 +122,7 @@ out:
  */
 void key_user_put(struct key_user *user)
 {
-       if (atomic_dec_and_lock(&user->usage, &key_user_lock)) {
+       if (refcount_dec_and_lock(&user->usage, &key_user_lock)) {
                rb_erase(&user->node, &key_user_tree);
                spin_unlock(&key_user_lock);
 
index 69199f18bfb31cb5eee9366b6404dd9b50a77b2e..bf08d02b6646ae2077b15903471bfb4575b04f5a 100644 (file)
@@ -340,7 +340,7 @@ static int proc_key_users_show(struct seq_file *m, void *v)
 
        seq_printf(m, "%5u: %5d %d/%d %d/%d %d/%d\n",
                   from_kuid_munged(seq_user_ns(m), user->uid),
-                  atomic_read(&user->usage),
+                  refcount_read(&user->usage),
                   atomic_read(&user->nkeys),
                   atomic_read(&user->nikeys),
                   user->qnkeys,
index b6fdd22205b169b663cdb00aecd5d214c7a376dd..44451af828c0df0bee4fb52453000514113d0109 100644 (file)
@@ -30,7 +30,7 @@ static DEFINE_MUTEX(key_user_keyring_mutex);
 
 /* The root user's tracking struct */
 struct key_user root_key_user = {
-       .usage          = ATOMIC_INIT(3),
+       .usage          = REFCOUNT_INIT(3),
        .cons_lock      = __MUTEX_INITIALIZER(root_key_user.cons_lock),
        .lock           = __SPIN_LOCK_UNLOCKED(root_key_user.lock),
        .nkeys          = ATOMIC_INIT(2),