diff mbox series

[1/2] exec: Don't set group_exit_task during a coredump

Message ID 87k1026h4x.fsf@x220.int.ebiederm.org (mailing list archive)
State New, archived
Headers show
Series exec: s/group_exit_task/group_exec_task/ for clarity | expand

Commit Message

Eric W. Biederman June 19, 2020, 6:32 p.m. UTC
Instead test SIGNAL_GROUP_COREDUMP in signal_group_exit().  This
results in clearer easier to understand logic.  This makes the code
easier to modify in the future as this leaves de_thread as the only
user of group_exit_task.

This is safe because there are only two places that set
SIGNAL_GROUP_COREDUMP.  In one place the code is setting
SIGNAL_GROUP_EXIT and SIGNAL_GROUP_COREDUMP together with the result
that signal_group_exit() will subsequently return true.  In the other
the location which is being changed SIGNAL_GROUP_COREDUMP is being set
along with signal_group_exit, which also causes subsequent calls of
signal_group_exit to return true.

Thus testing SIGNAL_GROUP_COREDUMP in signal_group_exit() results
in no change in behavior.

Only signal_group_exit tests group_exit_task so leaving as NULL
during a coredump and nothing uses the value of group_exit_task
that the coredump sets.  So not setting group_exit_task is
safe during a coredump.

I looked at the commit that introduced this behavior[1] and Oleg
describes that he was setting group_exit_task simply to cause
signal_group_exit to return true.  So no surprises come from the
history.

Cc: Oleg Nesterov <oleg@redhat.com>
[1] 6cd8f0acae34 ("coredump: ensure that SIGKILL always kills the dumping thread")
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
---
 fs/coredump.c                | 2 --
 include/linux/sched/signal.h | 2 +-
 2 files changed, 1 insertion(+), 3 deletions(-)

Comments

Linus Torvalds June 20, 2020, 6:58 p.m. UTC | #1
On Fri, Jun 19, 2020 at 11:36 AM Eric W. Biederman
<ebiederm@xmission.com> wrote:
>
> Instead test SIGNAL_GROUP_COREDUMP in signal_group_exit().

You say "instead", but the patch itself doesn't agree:

>  static inline int signal_group_exit(const struct signal_struct *sig)
>  {
> -       return  (sig->flags & SIGNAL_GROUP_EXIT) ||
> +       return  (sig->flags & (SIGNAL_GROUP_EXIT | SIGNAL_GROUP_COREDUMP)) ||
>                 (sig->group_exit_task != NULL);
>  }

it does it _in_addition_to_.

I think the whole test for "sig->group_exit_task != NULL" should be
removed for this commit to make sense.

               Linus
Oleg Nesterov June 22, 2020, 11:25 a.m. UTC | #2
On 06/19, Eric W. Biederman wrote:
>
> --- a/fs/coredump.c
> +++ b/fs/coredump.c
> @@ -369,7 +369,6 @@ static int zap_threads(struct task_struct *tsk, struct mm_struct *mm,
>  	spin_lock_irq(&tsk->sighand->siglock);
>  	if (!signal_group_exit(tsk->signal)) {
>  		mm->core_state = core_state;
> -		tsk->signal->group_exit_task = tsk;
>  		nr = zap_process(tsk, exit_code, 0);
>  		clear_tsk_thread_flag(tsk, TIF_SIGPENDING);
>  	}
> @@ -481,7 +480,6 @@ static void coredump_finish(struct mm_struct *mm, bool core_dumped)
>  	spin_lock_irq(&current->sighand->siglock);
>  	if (core_dumped && !__fatal_signal_pending(current))
>  		current->signal->group_exit_code |= 0x80;
> -	current->signal->group_exit_task = NULL;
>  	current->signal->flags = SIGNAL_GROUP_EXIT;
>  	spin_unlock_irq(&current->sighand->siglock);
>  
> diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h
> index 0ee5e696c5d8..92c72f5db111 100644
> --- a/include/linux/sched/signal.h
> +++ b/include/linux/sched/signal.h
> @@ -265,7 +265,7 @@ static inline void signal_set_stop_flags(struct signal_struct *sig,
>  /* If true, all threads except ->group_exit_task have pending SIGKILL */
>  static inline int signal_group_exit(const struct signal_struct *sig)
>  {
> -	return	(sig->flags & SIGNAL_GROUP_EXIT) ||
> +	return	(sig->flags & (SIGNAL_GROUP_EXIT | SIGNAL_GROUP_COREDUMP)) ||
>  		(sig->group_exit_task != NULL);
>  }

Looks correct.

Oleg.
Eric W. Biederman June 22, 2020, 4:20 p.m. UTC | #3
Linus Torvalds <torvalds@linux-foundation.org> writes:

> On Fri, Jun 19, 2020 at 11:36 AM Eric W. Biederman
> <ebiederm@xmission.com> wrote:
>>
>> Instead test SIGNAL_GROUP_COREDUMP in signal_group_exit().
>
> You say "instead", but the patch itself doesn't agree:
>
>>  static inline int signal_group_exit(const struct signal_struct *sig)
>>  {
>> -       return  (sig->flags & SIGNAL_GROUP_EXIT) ||
>> +       return  (sig->flags & (SIGNAL_GROUP_EXIT | SIGNAL_GROUP_COREDUMP)) ||
>>                 (sig->group_exit_task != NULL);
>>  }
>
> it does it _in_addition_to_.

Hmm.  I think I can change that line to:
>> Instead add a test for SIGNAL_GROUP_COREDUMP in signal_group_exit().

Does that read better?

> I think the whole test for "sig->group_exit_task != NULL" should be
> removed for this commit to make sense.

The code change is designed not to have a behavioral change in
signal_group_exit().  As de_thread also sets sig->group_exit_task
the test for sig->group_exit_task needs to remain in signal_group_exit()
for the behavior of signal_group_exit() to remain unchanged.



Why do you think the test sig->group_exit_task != NULL should be removed
for the commit to make sense?

Eric
Linus Torvalds June 22, 2020, 4:32 p.m. UTC | #4
On Mon, Jun 22, 2020 at 9:24 AM Eric W. Biederman <ebiederm@xmission.com> wrote:
>
> Why do you think the test sig->group_exit_task != NULL should be removed
> for the commit to make sense?

Because that's what your commit message _said_.

It still implies that with your changed language.

And honestly, wouldn't it be a lot more understandable if the state
was tracked with a single variable? The whole point of this series has
been "clarify exec".

So let's clarify it. There aren't that many places that set
sig->group_exit_task (whether renamed or not). How about we just
change _all_ of those to set 'sig->flags', and really clarify things?

                 Linus
diff mbox series

Patch

diff --git a/fs/coredump.c b/fs/coredump.c
index 7237f07ff6be..37b71c72ab3a 100644
--- a/fs/coredump.c
+++ b/fs/coredump.c
@@ -369,7 +369,6 @@  static int zap_threads(struct task_struct *tsk, struct mm_struct *mm,
 	spin_lock_irq(&tsk->sighand->siglock);
 	if (!signal_group_exit(tsk->signal)) {
 		mm->core_state = core_state;
-		tsk->signal->group_exit_task = tsk;
 		nr = zap_process(tsk, exit_code, 0);
 		clear_tsk_thread_flag(tsk, TIF_SIGPENDING);
 	}
@@ -481,7 +480,6 @@  static void coredump_finish(struct mm_struct *mm, bool core_dumped)
 	spin_lock_irq(&current->sighand->siglock);
 	if (core_dumped && !__fatal_signal_pending(current))
 		current->signal->group_exit_code |= 0x80;
-	current->signal->group_exit_task = NULL;
 	current->signal->flags = SIGNAL_GROUP_EXIT;
 	spin_unlock_irq(&current->sighand->siglock);
 
diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h
index 0ee5e696c5d8..92c72f5db111 100644
--- a/include/linux/sched/signal.h
+++ b/include/linux/sched/signal.h
@@ -265,7 +265,7 @@  static inline void signal_set_stop_flags(struct signal_struct *sig,
 /* If true, all threads except ->group_exit_task have pending SIGKILL */
 static inline int signal_group_exit(const struct signal_struct *sig)
 {
-	return	(sig->flags & SIGNAL_GROUP_EXIT) ||
+	return	(sig->flags & (SIGNAL_GROUP_EXIT | SIGNAL_GROUP_COREDUMP)) ||
 		(sig->group_exit_task != NULL);
 }