sudo ignores SIGTERM sent from same script

Refresh

1 weeks ago

Views

195 time

1

I'm trying to figure out why this doesn't work:

#!/bin/bash

sudo sleep 60 &
sudo_pid=$!
sudo kill $sudo_pid

I'd expect that after the kill, the sudo command and its child sleep process would be terminated, but they aren't, as shown by this script:

#!/bin/bash

sudo sleep 60 &
sudo_pid=$!
sudo kill $sudo_pid

if ps -p $sudo_pid > /dev/null; then
    sudo kill $sudo_pid
else
    echo "No sudo process running"
    exit 1
fi

if ps -p $sudo_pid > /dev/null; then
    echo "sudo (pid $sudo_pid) is still running"
    ps -F $sudo_pid
else
    echo "sudo successfully killed"
fi

Which yields this output when I run it (with sudo creds cached):

[email protected]:~$ ./so.sh 
sudo (pid 46199) is still running
UID         PID   PPID  C    SZ   RSS PSR STIME TTY      STAT   TIME CMD
root      46199  46198  0 14764  3984   3 13:37 pts/0    S+     0:00 sudo sleep 60

After the script completes (and sudo sleep 60 is still running), it is possible to kill it with the identical command:

[email protected]:~$ ps -F 46199
UID         PID   PPID  C    SZ   RSS PSR STIME TTY      STAT   TIME CMD
root      46199      1  0 14764  3984   3 13:37 pts/0    S      0:00 sudo sleep 60

[email protected]:~$ sudo kill 46199

[email protected]:~$ ps -F 46199
UID         PID   PPID  C    SZ   RSS PSR STIME TTY      STAT   TIME CMD

[email protected]:~$

I notice that after the so.sh script exits, the parent process ID for sudo sleep 60 has changed from the script to the init process, which I think is significant. It's also possible to successfully kill the sudo sleep 60 process from a different shell while the so.sh script is still running.

I also noticed that using sudo kill -ABRT in the script (as opposed to kill's default SIGTERM) does successfully kill the sudo process, so I assume that is has something to do with the way sudo handles SIGTERM. However, based on the man page, I don't think it should be doing anything special:

Signal handling
  When the command is run as a child of the sudo process, sudo will relay
  signals it receives to the command.  The SIGINT and SIGQUIT signals are
  only relayed when the command is being run in a new pty or when the sig‐
  nal was sent by a user process, not the kernel.  This prevents the com‐
  mand from receiving SIGINT twice each time the user enters control-C.

The only special handling of SIGTERM mentioned in the man page is for signals that were sent by the command it is running; not the case here. Furthermore, I changed the ps -F in above script to ps -o blocked,caught,ignored,pending and it output

sudo (pid 46429) is still running
         BLOCKED           CAUGHT          IGNORED          PENDING
0000000000000000 00000001800b7a07 0000000000000000 0000000000000000

Which seems to indicate that SIGTERM isn't being blocked or ignored, so why isn't the sudo sleep 60 process getting terminated?

I've come up with several workarounds (setsid, sudo -b, killing the child sleep process rather than the parent sudo process), so I'm not looking for alternate approach answers. I just want to understand what's going on here.

In case it matters:

[email protected]:~$ uname -a
Linux ubuntu 4.13.0-16-generic #19-Ubuntu SMP Wed Oct 11 18:35:14 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
[email protected]:~$ sudo --version
Sudo version 1.8.20p2
Sudoers policy plugin version 1.8.20p2
Sudoers file grammar version 46
Sudoers I/O plugin version 1.8.20p2
Jon

2 answers

1

Маска сигнала бит для любого заданного сигнала:

(1ULL << ((signal_number) - 1))

(для стандартных сигналов в диапазоне 1-32 в любом случае, дополнительные сигналы в «реальное время» наборы сигналов и обрабатываются несколько иначе, несмотря на то же самое относится). Так интересная часть CAUGHTмаски:

...7a07

что (+ при поймано, - за не пойман, в расширенной части):

xxx7: signals 1, 2, 3, but not 4: +SIGHUP  +SIGINT  +SIGQUIT -SIGILL
xx0x: not 5-8:                    -SIGTRAP -SIGABRT -SIGBUS  -SIGFPE
xaxx: not 9, 10, not 11, 12:      -SIGKILL +SIGUSR1 -SIGSEGV +SIGUSR2
7xxx: 13, 14, 15, not 16:         +SIGPIPE +SIGALRM +SIGTERM -SIGSTKFLT

(вы можете продолжить декодирование остальных , если вы хотите, см /usr/include/asm-generic/signal.hдля Linux-определенных номеров сигналов, обратите внимание , что числовые определения отличаются от OSX и BSD , но техника та же: пойманы или заблокирован или любые сигналы представляются в виде 1-бит в маска).

Таким образом, это означает , что sudoловит , SIGTERMно не ловить SIGABRT. Тот факт , что SIGTERMне передается должны иметь что - то делать с sudoсамим кодом. Источник ( apt-get source sudo) имеет некоторые довольно сложный код делает обработку сигнала, в том числе некоторых интересных трюков отладки вы можете включить в конфигурационном файле SUDO , чтобы помочь вам отследить , что происходит.

0

Я нашел следующие комментарии в исходном коде Судо

  /*  
 * Do not forward signals sent by a process in the command's process
 * group, as we don't want the command to indirectly kill itself.
 * For example, this can happen with some versions of reboot that
 * call kill(-1, SIGTERM) to kill all other processes.
 */