summaryrefslogtreecommitdiffstats
path: root/kernel/pid.c
diff options
context:
space:
mode:
authorJoel Fernandes (Google) <joel@joelfernandes.org>2019-07-16 19:30:06 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2019-07-16 22:23:24 -0400
commitf57e515a1b56325a28a0972c632a623a9c84590c (patch)
tree62ec1f15fb12f43288b4246780642fbfa9c1c025 /kernel/pid.c
parent156e0b1a8112b76e351684ac948c59757037ac36 (diff)
kernel/pid.c: convert struct pid count to refcount_t
struct pid's count is an atomic_t field used as a refcount. Use refcount_t for it which is basically atomic_t but does additional checking to prevent use-after-free bugs. For memory ordering, the only change is with the following: - if ((atomic_read(&pid->count) == 1) || - atomic_dec_and_test(&pid->count)) { + if (refcount_dec_and_test(&pid->count)) { kmem_cache_free(ns->pid_cachep, pid); Here the change is from: Fully ordered --> RELEASE + ACQUIRE (as per refcount-vs-atomic.rst) This ACQUIRE should take care of making sure the free happens after the refcount_dec_and_test(). The above hunk also removes atomic_read() since it is not needed for the code to work and it is unclear how beneficial it is. The removal lets refcount_dec_and_test() check for cases where get_pid() happened before the object was freed. Link: http://lkml.kernel.org/r/20190701183826.191936-1-joel@joelfernandes.org Signed-off-by: Joel Fernandes (Google) <joel@joelfernandes.org> Reviewed-by: Andrea Parri <andrea.parri@amarulasolutions.com> Reviewed-by: Kees Cook <keescook@chromium.org> Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Cc: Matthew Wilcox <willy@infradead.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Will Deacon <will.deacon@arm.com> Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Cc: Elena Reshetova <elena.reshetova@intel.com> Cc: Jann Horn <jannh@google.com> Cc: Eric W. Biederman <ebiederm@xmission.com> Cc: KJ Tsanaktsidis <ktsanaktsidis@zendesk.com> Cc: Michal Hocko <mhocko@suse.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/pid.c')
-rw-r--r--kernel/pid.c9
1 files changed, 4 insertions, 5 deletions
diff --git a/kernel/pid.c b/kernel/pid.c
index 16263b526560..0a9f2e437217 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -37,14 +37,14 @@
37#include <linux/init_task.h> 37#include <linux/init_task.h>
38#include <linux/syscalls.h> 38#include <linux/syscalls.h>
39#include <linux/proc_ns.h> 39#include <linux/proc_ns.h>
40#include <linux/proc_fs.h> 40#include <linux/refcount.h>
41#include <linux/anon_inodes.h> 41#include <linux/anon_inodes.h>
42#include <linux/sched/signal.h> 42#include <linux/sched/signal.h>
43#include <linux/sched/task.h> 43#include <linux/sched/task.h>
44#include <linux/idr.h> 44#include <linux/idr.h>
45 45
46struct pid init_struct_pid = { 46struct pid init_struct_pid = {
47 .count = ATOMIC_INIT(1), 47 .count = REFCOUNT_INIT(1),
48 .tasks = { 48 .tasks = {
49 { .first = NULL }, 49 { .first = NULL },
50 { .first = NULL }, 50 { .first = NULL },
@@ -108,8 +108,7 @@ void put_pid(struct pid *pid)
108 return; 108 return;
109 109
110 ns = pid->numbers[pid->level].ns; 110 ns = pid->numbers[pid->level].ns;
111 if ((atomic_read(&pid->count) == 1) || 111 if (refcount_dec_and_test(&pid->count)) {
112 atomic_dec_and_test(&pid->count)) {
113 kmem_cache_free(ns->pid_cachep, pid); 112 kmem_cache_free(ns->pid_cachep, pid);
114 put_pid_ns(ns); 113 put_pid_ns(ns);
115 } 114 }
@@ -212,7 +211,7 @@ struct pid *alloc_pid(struct pid_namespace *ns)
212 } 211 }
213 212
214 get_pid_ns(ns); 213 get_pid_ns(ns);
215 atomic_set(&pid->count, 1); 214 refcount_set(&pid->count, 1);
216 for (type = 0; type < PIDTYPE_MAX; ++type) 215 for (type = 0; type < PIDTYPE_MAX; ++type)
217 INIT_HLIST_HEAD(&pid->tasks[type]); 216 INIT_HLIST_HEAD(&pid->tasks[type]);
218 217