私が理解したように、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 では、プロセスにどのシグナルを送信できるかという制限はありません。プロセスの所有権に基づいてのみシグナルを制限します。
通常、信号源を確認する方法はありません。