Skip to content

Instantly share code, notes, and snippets.

@stedolan
Created May 24, 2021 14:09
Show Gist options
  • Save stedolan/8978eed84b6c64b9796743f4549ea62c to your computer and use it in GitHub Desktop.
Save stedolan/8978eed84b6c64b9796743f4549ea62c to your computer and use it in GitHub Desktop.
linux:
NULL pointer: si_signo=11, si_status=0, si_code=1, si_pid=0, si_uid=0, si_addr=0x0
Unmapped address: si_signo=11, si_status=0, si_code=1, si_pid=131072, si_uid=0, si_addr=0x20000
Readonly address: si_signo=11, si_status=0, si_code=2, si_pid=1896829136, si_uid=21917, si_addr=0x559d710f50d0
Non-canonical address: si_signo=11, si_status=0, si_code=128, si_pid=0, si_uid=0, si_addr=0x0
kill(getpid(),SIGSEGV): si_signo=11, si_status=0, si_code=0, si_pid=900131, si_uid=1000, si_addr=0x3e8000dbc23
subprocess kill: si_signo=11, si_status=0, si_code=0, si_pid=900132, si_uid=1000, si_addr=0x3e8000dbc24
(on linux, si_pid/si_uid overlap si_addr, so you must use si_code to determine which is valid)
macos:
NULL pointer: si_signo=11, si_status=0, si_code=1, si_pid=0, si_uid=0, si_addr=0x0
Unmapped address: si_signo=11, si_status=0, si_code=1, si_pid=0, si_uid=0, si_addr=0x20000
Readonly address: si_signo=10, si_status=0, si_code=2, si_pid=0, si_uid=0, si_addr=0x1071bfc80
Non-canonical address: si_signo=11, si_status=0, si_code=0, si_pid=0, si_uid=0, si_addr=0x0
kill(getpid(),SIGSEGV): si_signo=11, si_status=0, si_code=0, si_pid=0, si_uid=0, si_addr=0x0
subprocess kill: si_signo=11, si_status=0, si_code=0, si_pid=0, si_uid=0, si_addr=0x0
(note that kill() and noncanonical addresses general indistinguishable results)
// unusually, this program doesn't work *unless* compiled with -O2
#define _GNU_SOURCE
#include <stddef.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>
#if defined(__x86_64__) && defined(__linux__)
#define PC(ctx) \
(((ucontext_t*)(ctx))->uc_mcontext.gregs[REG_RIP])
#else
#include <sys/ucontext.h>
#include <AvailabilityMacros.h>
#define CONTEXT_STATE(context) \
(((ucontext_t *)(context))->uc_mcontext->__ss)
#define PC(ctx) \
(CONTEXT_STATE(ctx).__rip)
//#error "unknown PC reg"
#endif
const char* msg;
siginfo_t infos[100];
const char* msgs[100];
int ninfos = 0;
void* volatile segfault_before;
void* volatile segfault_after;
static void handler(int sig, siginfo_t* info, void* uctx) {
msgs[ninfos] = msg;
infos[ninfos] = *info;
ninfos++;
if (PC(uctx) == (long long int)segfault_before)
PC(uctx) = (long long int)segfault_after;
}
__attribute__((noinline,optimize("O2"))) void deref(char* ptr) {
segfault_before = &&before;
segfault_after = &&after;
goto *segfault_before;
before:
*ptr = 1;
after:
return;
}
int main() {
struct sigaction act;
int i;
act.sa_sigaction = &handler;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_SIGINFO;
sigaction(SIGSEGV, &act, NULL);
msg = "NULL pointer";
deref(NULL);
msg = "Unmapped address";
deref((void*)0x20000);
msg = "Readonly address";
deref((void*)&main);
msg = "Non-canonical address";
deref((void*)0x1010101010101010);
msg = "kill(getpid(),SIGSEGV)";
kill(getpid(), SIGSEGV);
msg = "subprocess kill";
if (fork()==0){kill(getppid(),SIGSEGV);_exit(0);}
wait(NULL);
for (i = 0; i<ninfos; i++){
siginfo_t s = infos[i];
printf("%25s: si_signo=%d, si_status=%d, si_code=%d, si_pid=%ld, si_uid=%ld, si_addr=0x%lx\n", msgs[i],
s.si_signo, s.si_status, s.si_code, (long)s.si_pid, (long)s.si_uid, (unsigned long)s.si_addr);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment