exec: Factor unshare_sighand out of de_thread and call it separately
authorEric W. Biederman <ebiederm@xmission.com>
Wed, 25 Mar 2020 15:00:21 +0000 (10:00 -0500)
committerEric W. Biederman <ebiederm@xmission.com>
Wed, 25 Mar 2020 15:00:21 +0000 (10:00 -0500)
This makes the code clearer and makes it easier to implement a mutex
that is not taken over any locations that may block indefinitely waiting
for userspace.

Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Reviewed-by: Bernd Edlinger <bernd.edlinger@hotmail.de>
Reviewed-by: Kees Cook <keescook@chromium.org>
Acked-by: Christian Brauner <christian.brauner@ubuntu.com>
Reviewed-by: Kirill Tkhai <ktkhai@virtuozzo.com>
Signed-off-by: Bernd Edlinger <bernd.edlinger@hotmail.de>
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
fs/exec.c

index c3f3479..ff74b9a 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1194,6 +1194,23 @@ no_thread_group:
        flush_itimer_signals();
 #endif
 
+       BUG_ON(!thread_group_leader(tsk));
+       return 0;
+
+killed:
+       /* protects against exit_notify() and __exit_signal() */
+       read_lock(&tasklist_lock);
+       sig->group_exit_task = NULL;
+       sig->notify_count = 0;
+       read_unlock(&tasklist_lock);
+       return -EAGAIN;
+}
+
+
+static int unshare_sighand(struct task_struct *me)
+{
+       struct sighand_struct *oldsighand = me->sighand;
+
        if (refcount_read(&oldsighand->count) != 1) {
                struct sighand_struct *newsighand;
                /*
@@ -1210,23 +1227,13 @@ no_thread_group:
 
                write_lock_irq(&tasklist_lock);
                spin_lock(&oldsighand->siglock);
-               rcu_assign_pointer(tsk->sighand, newsighand);
+               rcu_assign_pointer(me->sighand, newsighand);
                spin_unlock(&oldsighand->siglock);
                write_unlock_irq(&tasklist_lock);
 
                __cleanup_sighand(oldsighand);
        }
-
-       BUG_ON(!thread_group_leader(tsk));
        return 0;
-
-killed:
-       /* protects against exit_notify() and __exit_signal() */
-       read_lock(&tasklist_lock);
-       sig->group_exit_task = NULL;
-       sig->notify_count = 0;
-       read_unlock(&tasklist_lock);
-       return -EAGAIN;
 }
 
 char *__get_task_comm(char *buf, size_t buf_size, struct task_struct *tsk)
@@ -1264,13 +1271,19 @@ int flush_old_exec(struct linux_binprm * bprm)
        int retval;
 
        /*
-        * Make sure we have a private signal table and that
-        * we are unassociated from the previous thread group.
+        * Make this the only thread in the thread group.
         */
        retval = de_thread(me);
        if (retval)
                goto out;
 
+       /*
+        * Make the signal table private.
+        */
+       retval = unshare_sighand(me);
+       if (retval)
+               goto out;
+
        /*
         * Must be called _before_ exec_mmap() as bprm->mm is
         * not visibile until then. This also enables the update