diff options
author | Sebastian Andrzej Siewior <bigeasy@linutronix.de> | 2018-08-22 00:55:38 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-08-22 13:52:46 -0400 |
commit | fc37191272a972d449bab3d8247cf52cadf5d4e6 (patch) | |
tree | 17510f69e906aacff6c2a5c89f72ac4f17fb40f4 | |
parent | 060288a7320b2837a8ff2af1b3643bdbd5e568f6 (diff) |
userns: use refcount_t for reference counting instead atomic_t
refcount_t type and corresponding API should be used instead of atomic_t
wh en the variable is used as a reference counter. This avoids accidental
refcounter overflows that might lead to use-after-free situations.
Link: http://lkml.kernel.org/r/20180703200141.28415-6-bigeasy@linutronix.de
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Suggested-by: Peter Zijlstra <peterz@infradead.org>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Andrew Morton <akpm@linux-foundation.org>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | include/linux/sched/user.h | 5 | ||||
-rw-r--r-- | kernel/user.c | 8 |
2 files changed, 7 insertions, 6 deletions
diff --git a/include/linux/sched/user.h b/include/linux/sched/user.h index 96fe289c4c6e..39ad98c09c58 100644 --- a/include/linux/sched/user.h +++ b/include/linux/sched/user.h | |||
@@ -4,6 +4,7 @@ | |||
4 | 4 | ||
5 | #include <linux/uidgid.h> | 5 | #include <linux/uidgid.h> |
6 | #include <linux/atomic.h> | 6 | #include <linux/atomic.h> |
7 | #include <linux/refcount.h> | ||
7 | #include <linux/ratelimit.h> | 8 | #include <linux/ratelimit.h> |
8 | 9 | ||
9 | struct key; | 10 | struct key; |
@@ -12,7 +13,7 @@ struct key; | |||
12 | * Some day this will be a full-fledged user tracking system.. | 13 | * Some day this will be a full-fledged user tracking system.. |
13 | */ | 14 | */ |
14 | struct user_struct { | 15 | struct user_struct { |
15 | atomic_t __count; /* reference count */ | 16 | refcount_t __count; /* reference count */ |
16 | atomic_t processes; /* How many processes does this user have? */ | 17 | atomic_t processes; /* How many processes does this user have? */ |
17 | atomic_t sigpending; /* How many pending signals does this user have? */ | 18 | atomic_t sigpending; /* How many pending signals does this user have? */ |
18 | #ifdef CONFIG_FANOTIFY | 19 | #ifdef CONFIG_FANOTIFY |
@@ -59,7 +60,7 @@ extern struct user_struct root_user; | |||
59 | extern struct user_struct * alloc_uid(kuid_t); | 60 | extern struct user_struct * alloc_uid(kuid_t); |
60 | static inline struct user_struct *get_uid(struct user_struct *u) | 61 | static inline struct user_struct *get_uid(struct user_struct *u) |
61 | { | 62 | { |
62 | atomic_inc(&u->__count); | 63 | refcount_inc(&u->__count); |
63 | return u; | 64 | return u; |
64 | } | 65 | } |
65 | extern void free_uid(struct user_struct *); | 66 | extern void free_uid(struct user_struct *); |
diff --git a/kernel/user.c b/kernel/user.c index 36288d840675..5f65ef195259 100644 --- a/kernel/user.c +++ b/kernel/user.c | |||
@@ -96,7 +96,7 @@ static DEFINE_SPINLOCK(uidhash_lock); | |||
96 | 96 | ||
97 | /* root_user.__count is 1, for init task cred */ | 97 | /* root_user.__count is 1, for init task cred */ |
98 | struct user_struct root_user = { | 98 | struct user_struct root_user = { |
99 | .__count = ATOMIC_INIT(1), | 99 | .__count = REFCOUNT_INIT(1), |
100 | .processes = ATOMIC_INIT(1), | 100 | .processes = ATOMIC_INIT(1), |
101 | .sigpending = ATOMIC_INIT(0), | 101 | .sigpending = ATOMIC_INIT(0), |
102 | .locked_shm = 0, | 102 | .locked_shm = 0, |
@@ -123,7 +123,7 @@ static struct user_struct *uid_hash_find(kuid_t uid, struct hlist_head *hashent) | |||
123 | 123 | ||
124 | hlist_for_each_entry(user, hashent, uidhash_node) { | 124 | hlist_for_each_entry(user, hashent, uidhash_node) { |
125 | if (uid_eq(user->uid, uid)) { | 125 | if (uid_eq(user->uid, uid)) { |
126 | atomic_inc(&user->__count); | 126 | refcount_inc(&user->__count); |
127 | return user; | 127 | return user; |
128 | } | 128 | } |
129 | } | 129 | } |
@@ -170,7 +170,7 @@ void free_uid(struct user_struct *up) | |||
170 | return; | 170 | return; |
171 | 171 | ||
172 | local_irq_save(flags); | 172 | local_irq_save(flags); |
173 | if (atomic_dec_and_lock(&up->__count, &uidhash_lock)) | 173 | if (refcount_dec_and_lock(&up->__count, &uidhash_lock)) |
174 | free_user(up, flags); | 174 | free_user(up, flags); |
175 | else | 175 | else |
176 | local_irq_restore(flags); | 176 | local_irq_restore(flags); |
@@ -191,7 +191,7 @@ struct user_struct *alloc_uid(kuid_t uid) | |||
191 | goto out_unlock; | 191 | goto out_unlock; |
192 | 192 | ||
193 | new->uid = uid; | 193 | new->uid = uid; |
194 | atomic_set(&new->__count, 1); | 194 | refcount_set(&new->__count, 1); |
195 | ratelimit_state_init(&new->ratelimit, HZ, 100); | 195 | ratelimit_state_init(&new->ratelimit, HZ, 100); |
196 | ratelimit_set_flags(&new->ratelimit, RATELIMIT_MSG_ON_RELEASE); | 196 | ratelimit_set_flags(&new->ratelimit, RATELIMIT_MSG_ON_RELEASE); |
197 | 197 | ||