据我了解,SEGV
操作系统发送一个信号来通知进程它已尝试非法内存访问。但我注意到也可以SEGV
从另一个进程向一个进程发送信号(例如kill -s SEGV pid
)。
因此我想知道,能够SEGV
向另一个进程发送信号有什么用?
此外,进程是否可以知道信号是SEGV
由操作系统还是另一个进程发送的?
答案1
因此我想知道,能够向另一个进程发送 SEGV 信号有什么用?
我想有人可以手动发送它进行测试。但即使最初没有想到它的用途,我们也永远不知道是否有人会想出一种用途,然后任意的限制就会成为障碍。
此外,进程是否可以知道 SEGV 信号是由操作系统还是另一个进程发送的?
是的,正如中提到的捕获哪个用户发送终止信号sigaction()
,使用该标志设置的信号处理程序SA_SIGINFO
可以从结构中读取许多详细信息siginfo_t
。其中包含发送信号的原因 ( si_code
),如果适用,还包含发送用户和 PID ( si_uid
, si_pid
)。
请参阅手册页:https://man7.org/linux/man-pages/man2/sigaction.2.html
这是一个简单的测试程序,它为 SIGSEGV 设置一个处理程序并将其发送给自身,首先使用 ,kill()
然后触发无效的内存访问:
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void action(int sig, siginfo_t *si, void *p)
{
printf("sig: %d\n", sig);
printf("si_signo: %d\n", si->si_signo);
char *reason = "?";
switch (si->si_code) {
case SI_USER: reason = "Signal sent by user"; break;
case SI_TKILL: reason = "Signal sent by user (tkill)"; break;
case SI_KERNEL: reason = "Signal sent by kernel"; break;
case SEGV_MAPERR:
reason = "SIGSEGV - Address not mapped to object"; break;
case SEGV_ACCERR:
reason = "SIGSEGV - Invalid permissions for mapped object"; break;
}
printf("si_code: %d (%s)\n", si->si_code, reason);
printf("si_pid: %d\n", (int) si->si_pid);
printf("si_uid: %d\n", (int) si->si_uid);
printf("si_addr: 0x%016lx\n", (unsigned long) si->si_addr);
if (si->si_code != SI_USER && si->si_code != SI_TKILL) {
// if it's an actual error, exit instead of
// returning to repeat the error
_exit(1);
}
}
int main(void)
{
struct sigaction sa = {0};
sa.sa_sigaction = action;
sa.sa_flags = SA_SIGINFO;
int ret = sigaction(SIGSEGV, &sa, NULL);
if (ret == -1) {
perror("sigaction");
exit(1);
}
printf("raising SIGSEGV manually\n");
kill(getpid(), SIGSEGV);
printf("\n");
printf("trying to trigger SIGSEGV\n");
volatile int *p = (int *) 0xdeadbeef;
(void) *p;
}
我的系统上的输出是:
raising SIGSEGV manually
sig: 11
si_signo: 11
si_code: 0 (Signal sent by user)
si_pid: 13868
si_uid: 1000
si_addr: 0x000003e80000362c
trying to trigger SIGSEGV
sig: 11
si_signo: 11
si_code: 1 (SIGSEGV - Address not mapped to object)
si_pid: -559038737
si_uid: 0
si_addr: 0x00000000deadbeef
(请注意,某些不适用于相关案例的字段包含垃圾。)
答案2
Unix 对可以向进程发送哪些信号没有限制。它仅根据进程所有权限制信号。
一般来说,没有办法确定信号的来源。