Signals

SEGV信號的使用

  • November 22, 2021

據我了解,SEGV作業系統會發送一個信號來通知程序它已嘗試進行非法記憶體訪問。但我注意到也可以SEGV從另一個程序(例如kill -s SEGV pid)向一個程序發送信號。

因此我想知道,能夠向SEGV另一個程序發送信號有什麼用?

此外,是否有一個程序知道SEGV信號是由作業系統還是由另一個程序發送的?

因此我想知道,能夠將 SEGV 信號發送到另一個程序有什麼用?

我想有人可以手動發送它進行測試。但是即使最初沒有想到它的用途,我們也不知道是否有人會提出用途,然後任意限制就會成為阻礙。

此外,是否有一個程序知道 SEGV 信號是由作業系統還是由另一個程序發送的?

是的,正如Catch which user sent kill signalsigaction()中提到的,使用標誌設置的信號處理程序可以從結構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

(請注意,某些不適用於相關案例的欄位包含垃圾。)

引用自:https://unix.stackexchange.com/questions/678536