sudo忽略从同一个脚本

时间:2017-12-29 22:27:26

标签: linux bash signals sudo kill

我试图弄清楚为什么这不起作用:

#!/bin/bash

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

我希望在kill之后,sudo命令及其子sleep进程将被终止,但它们不会被终止,如此所示脚本:

#!/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

当我运行它时会产生此输出(缓存sudo个信用卡):

jon@ubuntu:~$ ./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

脚本完成后(并且sudo sleep 60仍在运行), 可以使用相同的命令将其终止:

jon@ubuntu:~$ 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

jon@ubuntu:~$ sudo kill 46199

jon@ubuntu:~$ ps -F 46199
UID         PID   PPID  C    SZ   RSS PSR STIME TTY      STAT   TIME CMD

jon@ubuntu:~$

我注意到so.sh脚本退出后,sudo sleep 60的父进程ID已从脚本更改为init进程,我认为这很重要。在sudo sleep 60脚本仍在运行时,也可以从其他shell成功终止so.sh进程。

我还注意到在脚本中使用sudo kill -ABRT(而不是kill的默认SIGTERM)会成功终止sudo进程,所以我假设这与sudo处理SIGTERM的方式有关。但是,根据手册页,我认为它不应该做任何特别的事情:

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.

手册页中提到的SIGTERM的唯一特殊处理是signals that were sent by the command it is running;不是这里的情况。此外,我将上面脚本中的ps -F更改为ps -o blocked,caught,ignored,pending并输出

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

这似乎表明SIGTERM没有被阻止或忽略,那么为什么sudo sleep 60进程没有被终止?

我提出了几个解决方法(setsidsudo -b,杀死了孩子sleep进程而不是父sudo进程),所以我&# 39;我不寻找替代方法的答案。我只是想了解这里发生了什么。

如果重要:

jon@ubuntu:~$ 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
jon@ubuntu:~$ 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

2 个答案:

答案 0 :(得分: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

(如果您愿意,可以继续解码其余部分;有关特定于Linux的信号编号,请参阅/usr/include/asm-generic/signal.h;请注意,OSX和BSD上的数字定义不同但技术相同:捕获或阻止或其他信号在掩码中表示为1位。

因此,这意味着sudo正在抓住SIGTERM但却没有抓住SIGABRTSIGTERM未传递的事实必须与sudo代码本身有关。源代码(apt-get source sudo)有一些相当复杂的代码用于执行信号处理,包括一些有趣的调试技巧,你可以在sudo配置文件中打开它们来帮助你追踪正在发生的事情。

答案 1 :(得分:0)

我在sudo的源代码中发现以下注释

  /*  
 * 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.
 */