내가 이해한 바에 따르면 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에서는 프로세스에 어떤 신호를 보낼 수 있는지에 대한 제한이 없습니다. 프로세스 소유권을 기준으로만 신호를 제한합니다.
일반적으로 신호 소스를 확인할 수 있는 방법은 없습니다.