From: Eric W. Biederman <hidden> Date: 2020-03-08 21:38:41
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" <redacted>
---
fs/exec.c | 39 ++++++++++++++++++++++++++-------------
1 file changed, 26 insertions(+), 13 deletions(-)
@@ -1194,6 +1194,23 @@ static int de_thread(struct task_struct *tsk)flush_itimer_signals();#endif+BUG_ON(!thread_group_leader(tsk));+return0;++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;+}+++staticintunshare_sighand(structtask_struct*me)+{+structsighand_struct*oldsighand=me->sighand;+if(refcount_read(&oldsighand->count)!=1){structsighand_struct*newsighand;/*
@@ -1210,23 +1227,13 @@ static int de_thread(struct task_struct *tsk)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));return0;--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_tbuf_size,structtask_struct*tsk)
@@ -1264,13 +1271,19 @@ int flush_old_exec(struct linux_binprm * bprm)intretval;/*-*Makesurewehaveaprivatesignaltableandthat-*weareunassociatedfromthepreviousthreadgroup.+*Makethistheonlythreadinthethreadgroup.*/retval=de_thread(me);if(retval)gotoout;+/*+*Makethesignaltableprivate.+*/+retval=unshare_sighand(me);+if(retval)+gotoout;+/**Mustbecalled_before_exec_mmap()asbprm->mmis*notvisibileuntilthen.Thisalsoenablestheupdate
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" <redacted>
@@ -1194,6 +1194,23 @@ static int de_thread(struct task_struct *tsk)flush_itimer_signals();#endif+BUG_ON(!thread_group_leader(tsk));+return0;++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;+}+++staticintunshare_sighand(structtask_struct*me)+{+structsighand_struct*oldsighand=me->sighand;+if(refcount_read(&oldsighand->count)!=1){structsighand_struct*newsighand;/*
@@ -1210,23 +1227,13 @@ static int de_thread(struct task_struct *tsk)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));return0;--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_tbuf_size,structtask_struct*tsk)
@@ -1264,13 +1271,19 @@ int flush_old_exec(struct linux_binprm * bprm)intretval;/*-*Makesurewehaveaprivatesignaltableandthat-*weareunassociatedfromthepreviousthreadgroup.+*Makethistheonlythreadinthethreadgroup.*/retval=de_thread(me);if(retval)gotoout;+/*+*Makethesignaltableprivate.+*/+retval=unshare_sighand(me);+if(retval)+gotoout;+/**Mustbecalled_before_exec_mmap()asbprm->mmis*notvisibileuntilthen.Thisalsoenablestheupdate
On Sun, Mar 08, 2020 at 04:36:17PM -0500, Eric W. Biederman wrote:
quoted hunk
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" <redacted>
---
fs/exec.c | 39 ++++++++++++++++++++++++++-------------
1 file changed, 26 insertions(+), 13 deletions(-)
@@ -1194,6 +1194,23 @@ static int de_thread(struct task_struct *tsk)flush_itimer_signals();#endif
Semi-related (existing behavior): in de_thread(), what keeps the thread
group from changing? i.e.:
if (thread_group_empty(tsk))
goto no_thread_group;
/*
* Kill all other threads in the thread group.
*/
spin_lock_irq(lock);
... kill other threads under lock ...
Why is the thread_group_emtpy() test not under lock?
+ BUG_ON(!thread_group_leader(tsk));
+ return 0;
+
+killed:
+ /* protects against exit_notify() and __exit_signal() */
I wonder if include/linux/sched/task.h's definition of tasklist_lock
should explicitly gain note about group_exit_task and notify_count,
or, alternatively, signal.h's section on these fields should gain a
comment? tasklist_lock is unmentioned in signal.h... :(
@@ -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
On Sun, Mar 08, 2020 at 04:36:17PM -0500, Eric W. Biederman wrote:
quoted
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" <redacted>
---
fs/exec.c | 39 ++++++++++++++++++++++++++-------------
1 file changed, 26 insertions(+), 13 deletions(-)
@@ -1194,6 +1194,23 @@ static int de_thread(struct task_struct *tsk)flush_itimer_signals();#endif
Semi-related (existing behavior): in de_thread(), what keeps the thread
group from changing? i.e.:
if (thread_group_empty(tsk))
goto no_thread_group;
/*
* Kill all other threads in the thread group.
*/
spin_lock_irq(lock);
... kill other threads under lock ...
Why is the thread_group_emtpy() test not under lock?
A new thread cannot created when only one thread is executing,
right?
quoted
+ BUG_ON(!thread_group_leader(tsk));
+ return 0;
+
+killed:
+ /* protects against exit_notify() and __exit_signal() */
I wonder if include/linux/sched/task.h's definition of tasklist_lock
should explicitly gain note about group_exit_task and notify_count,
or, alternatively, signal.h's section on these fields should gain a
comment? tasklist_lock is unmentioned in signal.h... :(
@@ -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
On Tue, Mar 10, 2020 at 09:34:03PM +0100, Bernd Edlinger wrote:
On 3/10/20 9:29 PM, Kees Cook wrote:
quoted
On Sun, Mar 08, 2020 at 04:36:17PM -0500, Eric W. Biederman wrote:
quoted
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" <redacted>
---
fs/exec.c | 39 ++++++++++++++++++++++++++-------------
1 file changed, 26 insertions(+), 13 deletions(-)
@@ -1194,6 +1194,23 @@ static int de_thread(struct task_struct *tsk)flush_itimer_signals();#endif
Semi-related (existing behavior): in de_thread(), what keeps the thread
group from changing? i.e.:
if (thread_group_empty(tsk))
goto no_thread_group;
/*
* Kill all other threads in the thread group.
*/
spin_lock_irq(lock);
... kill other threads under lock ...
Why is the thread_group_emtpy() test not under lock?
A new thread cannot created when only one thread is executing,
right?
*face palm* Yes, of course. :) I'm thinking too hard.
--
Kees Cook
From: Christian Brauner <hidden> Date: 2020-03-10 21:22:08
On Sun, Mar 08, 2020 at 04:36:17PM -0500, Eric W. Biederman wrote:
quoted hunk
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" <redacted>
---
fs/exec.c | 39 ++++++++++++++++++++++++++-------------
1 file changed, 26 insertions(+), 13 deletions(-)
@@ -1194,6 +1194,23 @@ static int de_thread(struct task_struct *tsk)flush_itimer_signals();#endif+BUG_ON(!thread_group_leader(tsk));+return0;++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;+}+++staticintunshare_sighand(structtask_struct*me)+{+structsighand_struct*oldsighand=me->sighand;+if(refcount_read(&oldsighand->count)!=1){structsighand_struct*newsighand;/*
@@ -1210,23 +1227,13 @@ static int de_thread(struct task_struct *tsk)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);}
This is fine for now but we share an aweful lot of code with
copy_sighand(). We should earmark this to look into consolidating the
core operations into a common helper called from both copy_sighand() and
unshare_sighand() maybe even dumbing it down to one helper. But not
needed for now.
Otherwise:
Acked-by: Christian Brauner <redacted>