I'm learning Linux syscalls and I have a problem with invoking syscall 13:
rt_sigaction(int sig, const struct sigaction __user * act, struct sigaction __user * oact, size_t sigsetsize)
on 64 bit Linux in assembly. I have used the C wrapper for this function (sigaction()) and it worked fine, but when I tried to make a direct syscall with the code below it failed. I have made other direct syscalls with this approach and only this syscall has failed to work.
I suspect that the pointer to sigint_handler() function is being passed incorrectly to the kernel but I'm not sure.
I can't use C system libraries in my project so getting this specific syscall to work with assembly invocation is my goal here.
The C code I'm running:
#define _POSIX_SOURCE
#include <stddef.h>
#include <stdint.h>
#include <linux/signal.h>
#include <linux/unistd.h>
#include <string.h>
#include <syscall.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
// SYSCALL_4 simply injects the assembly to make the syscall directly
#define SYSCALL_4(sys_num, a1,a2,a3,a4) \ ({ \
int64_t sys_ret; \
__asm __volatile ( \
"movq %1, %%rax\n\t"\
"movq %2, %%rdi\n\t"\
"movq %3, %%rsi\n\t"\
"movq %4, %%rdx\n\t"\
"movq %5, %%r10\n\t"\
"syscall\n\t" \
"movq %%rax, %0\n\t"\
: "=g" (sys_ret)\
: "g"(sys_num), "g" (a1) , "g" (a2), "g" (a3), "g" (a4)\
: "cc", "memory", "%rax", "%rdi", "%rsi", "%rdx", "%rcx", "%r11", "%r10"\ );\
sys_ret; \ })
struct kernel_sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
void sigint_handler(int signo) {
printf("In SIGINT handler ...\n");
}
int main(void) {
struct kernel_sigaction sig;
int64_t ret = SYSCALL_4(13, SIGINT, 0, &sig, sizeof(sigset_t)); //__NR_rt_sigaction
if (ret < 0)
{
fprintf(stderr,"Unable to install SIGINT handler\n");
errno = -ret;
perror(0);
exit(1);
}
sig.sa_handler = sigint_handler;
ret = SYSCALL_4(13, SIGINT, &sig, 0, sizeof(sigset_t)); //__NR_rt_sigaction
if (ret < 0) //doesnt fail here
{
fprintf(stderr,"Unable to install SIGINT handler\n");
errno = -ret;
perror(0);
exit(1);
}
printf("Sleeping for 30 seconds ...\n");
sleep(30); //seems to fail here
printf("Waking up ...\n"); //supposed to print after SIGINT handler
exit(0);
}
and on console:
> gcc -Wall -march=native -std=c11 -O0 P1c_inline.c -o P1c_inline.out
> ./P1c_inline.out
Sleeping for 30 seconds ...
^CSegmentation fault (core dumped)