当非root用户向root用户的进程发送信号时会发生什么?


33

我想知道UNIX信号的安全性。

SIGKILL会杀死进程。那么,当非root用户的进程向root用户的进程发送信号时会发生什么呢?该过程是否仍执行信号处理程序?

我遵循公认的答案(古卢姆语言),然后输入man capabilites,我发现了很多有关Linux内核的知识。来自man capabilities

NAME

   capabilities - overview of Linux capabilities
DESCRIPTION

   For the purpose of performing permission checks, traditional UNIX
   implementations distinguish two categories of processes: privileged
   processes (whose effective user ID is 0, referred to as superuser or
   root), and unprivileged processes (whose effective UID is nonzero).
   Privileged processes bypass all kernel permission checks, while
   unprivileged processes are subject to full permission checking based
   on the process's credentials (usually: effective UID, effective GID,
   and supplementary group list).

   Starting with kernel 2.2, Linux divides the privileges traditionally
   associated with superuser into distinct units, known as capabilities,
   which can be independently enabled and disabled.  Capabilities are a
   per-thread attribute.

5
除了SIGKILL,它是一种特殊情况,并且完全由内核管理,信号只是一个请求。接收过程可以对他们做任何他们想做的事情。
chepner '16

3
@chepner除了SIGKILL SIGSTOP ...
jlliagre

1
@chepner接收过程必须主动决定要处理信号。如果接收过程还没有这样做,那么默认情况下,许多信号将以完全相同的方式杀死该过程SIGKILL。最初SIGINTSIGKILLSIGTERM具有完全相同的效果,唯一的区别是接收过程可以为其中一些更改此默认设置。
卡巴斯德(Kasperd)'16

Answers:


34

在Linux上,它取决于文件功能。

采取以下简单的mykill.c来源:

#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <stdlib.h>

void exit_usage(const char *prog) {
        printf("usage: %s -<signal> <pid>\n", prog);
        exit(1);
}

int main(int argc, char **argv) {
        pid_t pid;
        int sig;

        if (argc != 3)
                exit_usage(argv[0]);

        sig = atoi(argv[1]);
        pid = atoi(argv[2]);

        if (sig >= 0 || pid < 2)
                exit_usage(argv[0]);

        if (kill(pid, -sig) == -1) {
                perror("failed");
                return 1;
        }
        printf("successfully sent signal %d to process %d\n", -sig, pid);

        return 0;
}

建立它:

gcc -Wall mykill.c -o /tmp/mykill

现在,以root用户身份在后台启动睡眠过程:

root@horny:/root# /bin/sleep 3600 &
[1] 16098

现在,以普通用户的身份尝试杀死它:

demouser@horny:/home/demouser$ ps aux | grep sleep
root     16098  0.0  0.0  11652   696 pts/20   S    15:06   0:00 sleep 500

demouser@horny:/home/demouser$ /tmp/mykill -9 16098
failed: Operation not permitted

现在,以root用户身份更改/tmp/mykill上限:

root@horny:/root# setcap cap_kill+ep /tmp/mykill

然后以普通用户身份再试一次:

demouser@horny:/home/demouser$ /tmp/mykill -9 16098
successfully sent signal 9 to process 16098

最后,/tmp/mykill出于明显原因,请删除;)


3
按照您的提示,输入“
manabilities

24

没有:

strace kill -HUP 1
[...]
kill(1, SIGHUP)    = -1 EPERM (Operation not permitted)
[...]

1
这种安全性是由os级完成还是在用户的信号处理程序中进行了硬编码?
lovespring '16

3
@lovespring内核不会将信号传递给目标进程。syscall返回一个错误,并且被忽略。
Hauke Laging '16

一般来说,这是不正确的。这取决于功能。
gollum

1
@psmears是的,但是其他人也有类似的概念(例如solaris的“特权”)。因此,答案“无”绝对是错误的。
gollum

1
@gollum:这不是完全错误的(毕竟,这是所有Unix系列OS上的默认行为,并且在许多操作系统中,只有一种可能,例如,包括较旧的Linux内核),但您说对了,它是不完整的-只是提到在有关通用Unix的问题中,“能力”没有更详细地介绍它们的支持位置也不完整:)
psmears,2016年

5

kill(2) 手册页说明:

Linux笔记

在不同的内核版本中,Linux对非特权进程向另一个进程发送信号所需的权限实施了不同的规则。在内核1.0到1.2.2中,如果发送方的有效用户ID与接收方的有效用户ID相匹配,或者发送方的实际用户ID与接收方的真实用户ID相匹配,则可以发送信号。从内核1.2.3到1.3.77,如果发送方的有效用户ID与接收方的实际或有效用户ID相匹配,则可以发送信号。符合POSIX.1-2001的当前规则已在内核1.3.78中采用。


1.3.78是1.3的最古老的历史。可以追溯到1995年左右。1.3是直到2.0的开发系列(1996年)
vonbrand

-1

信号将传送,但进程所有者属于root。因此,其他用户无权终止该过程,因此您将收到权限错误问题。

仅当您拥有流程的所有权(专有权利)时,才能终止流程。


不,sys_kill返回-1,而errno将为-EPERM。
彼得说恢复莫妮卡
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.