pids: make task_tgid_nr_ns() safe
authorOleg Nesterov <oleg@redhat.com>
Mon, 21 Aug 2017 15:35:02 +0000 (17:35 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 25 Aug 2017 00:12:21 +0000 (17:12 -0700)
commit dd1c1f2f2028a7b851f701fc6a8ebe39dcb95e7c upstream.

This was reported many times, and this was even mentioned in commit
52ee2dfdd4f5 ("pids: refactor vnr/nr_ns helpers to make them safe") but
somehow nobody bothered to fix the obvious problem: task_tgid_nr_ns() is
not safe because task->group_leader points to nowhere after the exiting
task passes exit_notify(), rcu_read_lock() can not help.

We really need to change __unhash_process() to nullify group_leader,
parent, and real_parent, but this needs some cleanups.  Until then we
can turn task_tgid_nr_ns() into another user of __task_pid_nr_ns() and
fix the problem.

Reported-by: Troy Kensinger <tkensinger@google.com>
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
include/linux/pid.h
include/linux/sched.h
kernel/pid.c

index 23705a5..97b745d 100644 (file)
@@ -8,7 +8,9 @@ enum pid_type
        PIDTYPE_PID,
        PIDTYPE_PGID,
        PIDTYPE_SID,
-       PIDTYPE_MAX
+       PIDTYPE_MAX,
+       /* only valid to __task_pid_nr_ns() */
+       __PIDTYPE_TGID
 };
 
 /*
index 14f58cf..a4d0afc 100644 (file)
@@ -2132,31 +2132,8 @@ static inline pid_t task_tgid_nr(struct task_struct *tsk)
        return tsk->tgid;
 }
 
-pid_t task_tgid_nr_ns(struct task_struct *tsk, struct pid_namespace *ns);
-
-static inline pid_t task_tgid_vnr(struct task_struct *tsk)
-{
-       return pid_vnr(task_tgid(tsk));
-}
-
 
 static inline int pid_alive(const struct task_struct *p);
-static inline pid_t task_ppid_nr_ns(const struct task_struct *tsk, struct pid_namespace *ns)
-{
-       pid_t pid = 0;
-
-       rcu_read_lock();
-       if (pid_alive(tsk))
-               pid = task_tgid_nr_ns(rcu_dereference(tsk->real_parent), ns);
-       rcu_read_unlock();
-
-       return pid;
-}
-
-static inline pid_t task_ppid_nr(const struct task_struct *tsk)
-{
-       return task_ppid_nr_ns(tsk, &init_pid_ns);
-}
 
 static inline pid_t task_pgrp_nr_ns(struct task_struct *tsk,
                                        struct pid_namespace *ns)
@@ -2181,6 +2158,33 @@ static inline pid_t task_session_vnr(struct task_struct *tsk)
        return __task_pid_nr_ns(tsk, PIDTYPE_SID, NULL);
 }
 
+static inline pid_t task_tgid_nr_ns(struct task_struct *tsk, struct pid_namespace *ns)
+{
+       return __task_pid_nr_ns(tsk, __PIDTYPE_TGID, ns);
+}
+
+static inline pid_t task_tgid_vnr(struct task_struct *tsk)
+{
+       return __task_pid_nr_ns(tsk, __PIDTYPE_TGID, NULL);
+}
+
+static inline pid_t task_ppid_nr_ns(const struct task_struct *tsk, struct pid_namespace *ns)
+{
+       pid_t pid = 0;
+
+       rcu_read_lock();
+       if (pid_alive(tsk))
+               pid = task_tgid_nr_ns(rcu_dereference(tsk->real_parent), ns);
+       rcu_read_unlock();
+
+       return pid;
+}
+
+static inline pid_t task_ppid_nr(const struct task_struct *tsk)
+{
+       return task_ppid_nr_ns(tsk, &init_pid_ns);
+}
+
 /* obsolete, do not use */
 static inline pid_t task_pgrp_nr(struct task_struct *tsk)
 {
index f66162f..693a643 100644 (file)
@@ -526,8 +526,11 @@ pid_t __task_pid_nr_ns(struct task_struct *task, enum pid_type type,
        if (!ns)
                ns = task_active_pid_ns(current);
        if (likely(pid_alive(task))) {
-               if (type != PIDTYPE_PID)
+               if (type != PIDTYPE_PID) {
+                       if (type == __PIDTYPE_TGID)
+                               type = PIDTYPE_PID;
                        task = task->group_leader;
+               }
                nr = pid_nr_ns(rcu_dereference(task->pids[type].pid), ns);
        }
        rcu_read_unlock();
@@ -536,12 +539,6 @@ pid_t __task_pid_nr_ns(struct task_struct *task, enum pid_type type,
 }
 EXPORT_SYMBOL(__task_pid_nr_ns);
 
-pid_t task_tgid_nr_ns(struct task_struct *tsk, struct pid_namespace *ns)
-{
-       return pid_nr_ns(task_tgid(tsk), ns);
-}
-EXPORT_SYMBOL(task_tgid_nr_ns);
-
 struct pid_namespace *task_active_pid_ns(struct task_struct *tsk)
 {
        return ns_of_pid(task_pid(tsk));