security, keys: convert key_user.usage from atomic_t to refcount_t
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>
This commit is contained in:
parent
fff292914d
commit
ddb99e118e
@ -17,6 +17,7 @@
|
|||||||
#include <linux/key-type.h>
|
#include <linux/key-type.h>
|
||||||
#include <linux/task_work.h>
|
#include <linux/task_work.h>
|
||||||
#include <linux/keyctl.h>
|
#include <linux/keyctl.h>
|
||||||
|
#include <linux/refcount.h>
|
||||||
|
|
||||||
struct iovec;
|
struct iovec;
|
||||||
|
|
||||||
@ -53,7 +54,7 @@ struct key_user {
|
|||||||
struct rb_node node;
|
struct rb_node node;
|
||||||
struct mutex cons_lock; /* construction initiation lock */
|
struct mutex cons_lock; /* construction initiation lock */
|
||||||
spinlock_t 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 nkeys; /* number of keys */
|
||||||
atomic_t nikeys; /* number of instantiated keys */
|
atomic_t nikeys; /* number of instantiated keys */
|
||||||
kuid_t uid;
|
kuid_t uid;
|
||||||
|
@ -93,7 +93,7 @@ try_again:
|
|||||||
|
|
||||||
/* if we get here, then the user record still hadn't appeared on the
|
/* if we get here, then the user record still hadn't appeared on the
|
||||||
* second pass - so we use the candidate record */
|
* 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->nkeys, 0);
|
||||||
atomic_set(&candidate->nikeys, 0);
|
atomic_set(&candidate->nikeys, 0);
|
||||||
candidate->uid = uid;
|
candidate->uid = uid;
|
||||||
@ -110,7 +110,7 @@ try_again:
|
|||||||
|
|
||||||
/* okay - we found a user record for this UID */
|
/* okay - we found a user record for this UID */
|
||||||
found:
|
found:
|
||||||
atomic_inc(&user->usage);
|
refcount_inc(&user->usage);
|
||||||
spin_unlock(&key_user_lock);
|
spin_unlock(&key_user_lock);
|
||||||
kfree(candidate);
|
kfree(candidate);
|
||||||
out:
|
out:
|
||||||
@ -122,7 +122,7 @@ out:
|
|||||||
*/
|
*/
|
||||||
void key_user_put(struct key_user *user)
|
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);
|
rb_erase(&user->node, &key_user_tree);
|
||||||
spin_unlock(&key_user_lock);
|
spin_unlock(&key_user_lock);
|
||||||
|
|
||||||
|
@ -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",
|
seq_printf(m, "%5u: %5d %d/%d %d/%d %d/%d\n",
|
||||||
from_kuid_munged(seq_user_ns(m), user->uid),
|
from_kuid_munged(seq_user_ns(m), user->uid),
|
||||||
atomic_read(&user->usage),
|
refcount_read(&user->usage),
|
||||||
atomic_read(&user->nkeys),
|
atomic_read(&user->nkeys),
|
||||||
atomic_read(&user->nikeys),
|
atomic_read(&user->nikeys),
|
||||||
user->qnkeys,
|
user->qnkeys,
|
||||||
|
@ -30,7 +30,7 @@ static DEFINE_MUTEX(key_user_keyring_mutex);
|
|||||||
|
|
||||||
/* The root user's tracking struct */
|
/* The root user's tracking struct */
|
||||||
struct key_user root_key_user = {
|
struct key_user root_key_user = {
|
||||||
.usage = ATOMIC_INIT(3),
|
.usage = REFCOUNT_INIT(3),
|
||||||
.cons_lock = __MUTEX_INITIALIZER(root_key_user.cons_lock),
|
.cons_lock = __MUTEX_INITIALIZER(root_key_user.cons_lock),
|
||||||
.lock = __SPIN_LOCK_UNLOCKED(root_key_user.lock),
|
.lock = __SPIN_LOCK_UNLOCKED(root_key_user.lock),
|
||||||
.nkeys = ATOMIC_INIT(2),
|
.nkeys = ATOMIC_INIT(2),
|
||||||
|
Loading…
Reference in New Issue
Block a user