From 826e190f319d2d6ed0c3d2ae1fff7a592fadef37 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Wed, 28 May 2014 09:50:14 -0600 Subject: [PATCH] Ignore signals sent by the command's process group, not just the command itself. If we cannot determine the process group ID of the sender (as it may no longer exist), just check the process ID. --- src/exec.c | 54 ++++++++++++++++++++++++++++++++------------------ src/exec_pty.c | 21 +++++++++++++------- 2 files changed, 49 insertions(+), 26 deletions(-) diff --git a/src/exec.c b/src/exec.c index c170dfada..f513e5b19 100644 --- a/src/exec.c +++ b/src/exec.c @@ -865,13 +865,20 @@ handler(int s, siginfo_t *info, void *context) unsigned char signo = (unsigned char)s; /* - * If the signal came from the command we ran, just ignore - * it since we don't want the child to indirectly kill itself. - * This can happen with, e.g. BSD-derived versions of reboot - * that call kill(-1, SIGTERM) to kill all other processes. + * Do not forward signals sent by a process in the command's process + * group, do not forward it as we don't want the child to indirectly + * kill itself. For example, this can happen with some versions of + * reboot that call kill(-1, SIGTERM) to kill all other processes. */ - if (info != NULL && info->si_code == SI_USER && info->si_pid == cmnd_pid) - return; + if (info != NULL && info->si_code == SI_USER) { + pid_t si_pgrp = getpgid(info->si_pid); + if (si_pgrp != (pid_t)-1) { + if (si_pgrp == ppgrp || si_pgrp == cmnd_pid) + return; + } else if (info->si_pid == cmnd_pid) { + return; + } + } /* * The pipe is non-blocking, if we overflow the kernel's pipe @@ -910,22 +917,31 @@ static void handler_user_only(int s, siginfo_t *info, void *context) { unsigned char signo = (unsigned char)s; + pid_t si_pgrp; /* - * Only forward user-generated signals not sent by the command. - * Signals sent by the kernel may include SIGTSTP when the user - * presses ^Z. Curses programs often trap ^Z and send SIGTSTP - * to their pgrp, so we don't want to send an extra SIGTSTP. + * Only forward user-generated signals not sent by a process in + * the command's own process group. Signals sent by the kernel + * may include SIGTSTP when the user presses ^Z. Curses programs + * often trap ^Z and send SIGTSTP to their own pgrp, so we don't + * want to send an extra SIGTSTP. */ - if (info != NULL && info->si_code == SI_USER && info->si_pid != cmnd_pid) { - /* - * The pipe is non-blocking, if we overflow the kernel's pipe - * buffer we drop the signal. This is not a problem in practice. - */ - while (write(signal_pipe[1], &signo, sizeof(signo)) == -1) { - if (errno != EINTR) - break; - } + if (info == NULL || info->si_code != SI_USER) + return; + if ((si_pgrp = getpgid(info->si_pid)) != (pid_t)-1) { + if (si_pgrp == ppgrp || si_pgrp == cmnd_pid) + return; + } else if (info->si_pid == cmnd_pid) { + return; + } + + /* + * The pipe is non-blocking, if we overflow the kernel's pipe + * buffer we drop the signal. This is not a problem in practice. + */ + while (write(signal_pipe[1], &signo, sizeof(signo)) == -1) { + if (errno != EINTR) + break; } } #endif /* SA_SIGINFO */ diff --git a/src/exec_pty.c b/src/exec_pty.c index 77ed418ec..32ae0983e 100644 --- a/src/exec_pty.c +++ b/src/exec_pty.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2013 Todd C. Miller + * Copyright (c) 2009-2014 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -136,13 +136,20 @@ mon_handler(int s, siginfo_t *info, void *context) unsigned char signo = (unsigned char)s; /* - * If the signal came from the command we ran, just ignore - * it since we don't want the command to indirectly kill itself. - * This can happen with, e.g. BSD-derived versions of reboot - * that call kill(-1, SIGTERM) to kill all other processes. + * If the signal came from the process group of the command we ran, + * do not forward it as we don't want the child to indirectly kill + * itself. This can happen with, e.g., BSD-derived versions of + * reboot that call kill(-1, SIGTERM) to kill all other processes. */ - if (info != NULL && info->si_code == SI_USER && info->si_pid == cmnd_pid) - return; + if (info != NULL && info->si_code == SI_USER) { + pid_t si_pgrp = getpgid(info->si_pid); + if (si_pgrp != (pid_t)-1) { + if (si_pgrp == cmnd_pgrp) + return; + } else if (info->si_pid == cmnd_pid) { + return; + } + } /* * The pipe is non-blocking, if we overflow the kernel's pipe