4

Following this Interfacing Linux Signals article, i have been trying to use sys_rt_sigaction in amd64, but always get memory access error when sending the signal. struct sigaction works when using C/C++ function sigaction.

What is wrong in sys_rt_sigaction call?

C/C++ with ASM code:

#include<signal.h>
#include<stdio.h>
#include<time.h>

void handler(int){printf("handler\n");}
void restorer(){asm volatile("mov $15,%%rax\nsyscall":::"rax");}

struct sigaction act{handler};
timespec ts{10,0};

int main(){
 act.sa_flags=0x04000000;
 act.sa_restorer=&restorer;
 //*
 asm volatile("\
 mov $13,%%rax\n\
 mov %0,%%rdi\n\
 mov %1,%%rsi\n\
 mov %2,%%rdx\n\
 mov $8,%%r10\n\
 syscall\n\
 mov %%rax,%%rdi\n\
 mov $60,%%rax\n\
#syscall\n\
 "::"i"(7),"p"(&act),"p"(0):"rax","rdi","rsi","rdx","r10");
 /**/

 /*
 sigaction(7,&act,0);
 /**/

 nanosleep(&ts,0);
}

Compile

g++ -o bin -std=c++11
g++ -o bin -std=c++11 -no-pie

Send signal

kill -7 `pidof bin`
ncomputers
  • 3,680
  • 1
  • 15
  • 16

1 Answers1

11

In x86-64 linux, it's mandatory to supply a sa_restorer and you haven't done so.

The relevant part of kernel source:

            /* x86-64 should always use SA_RESTORER. */
            if (ksig->ka.sa.sa_flags & SA_RESTORER) {
                    put_user_ex(ksig->ka.sa.sa_restorer, &frame->pretcode);
            } else {
                    /* could use a vstub here */
                    err |= -EFAULT;
            }

The C library wrapper does this for you:

  kact.sa_flags = act->sa_flags | SA_RESTORER;

  kact.sa_restorer = &restore_rt;

With the updated code you do indeed have a restorer, but you have two problems: it's broken and you pass it wrong. Looking at the above mentioned C library source you can find this comment:

/* The difference here is that the sigaction structure used in the
   kernel is not the same as we use in the libc.  Therefore we must
   translate it here.  */

Also, you can't have a C++ function as restorer due to the function prologue. Furthermore, calling printf from a signal handler is not supported (but works here). Finally, as David Wohlferd pointed out, your clobbers are wrong. All in all, the following could be a reworked version:

#include<stdio.h>
#include<unistd.h>
#include<time.h>

void handler(int){
    const char msg[] = "handler\n";
    write(0, msg, sizeof(msg));
}

extern "C" void restorer();
asm volatile("restorer:mov $15,%rax\nsyscall");

struct kernel_sigaction {
        void (*k_sa_handler) (int);
        unsigned long sa_flags;
        void (*sa_restorer) (void);
        unsigned long sa_mask;
};

struct kernel_sigaction act{handler};
timespec ts{10,0};

int main(){
 act.sa_flags=0x04000000;
 act.sa_restorer=&restorer;

 asm volatile("\
 mov $13,%%rax\n\
 mov %0,%%rdi\n\
 mov %1,%%rsi\n\
 mov %2,%%rdx\n\
 mov $8,%%r10\n\
 syscall\n\
 "::"i"(7),"p"(&act),"p"(0):"rax","rcx", "rdi","rsi","rdx","r8", "r9", "r10", "r11");

 nanosleep(&ts,0);
}

It's still hacky, and you shouldn't really be doing it this way, obviously.

Jester
  • 56,577
  • 4
  • 81
  • 125
  • Hi, thanks a lot for your help :D Before posting this question i have already tried to use a `restorer` in so many ways with the same result :( Maybe besides of the `restorer`, something else is missing? I suspect something related to the `mask` or `flags`, but never found what. – ncomputers Feb 21 '17 at 00:10
  • I can't comment on code not shown. You do need a restorer otherwise you will hit that `EFAULT`. Presumably you have written the restorer wrong, when you used that. – Jester Feb 21 '17 at 00:13
  • ok, i will work on that after making a pause, in order to rest the mind, hehe :D thanks – ncomputers Feb 21 '17 at 00:14
  • 1
    AFAIK, the kernel may clobber them. All the docs say that the same convention applies as in user space except for the `rcx` change and the added `r11` clobber. At least on my system, the value seems preserved, but better safe than sorry :) – Jester Sep 29 '17 at 14:54
  • Actually I stand corrected.I removed the last two comments. When I read the exceptions section (previously) in the ABI I assumed that *instead* (exception) of the regular convention of register saving - _RCX_, and _R11_ (along with _RAX_ for a return value) were the only ones not preserved. The ABI is a bit ambiguous, but after reviewing the Linux kernel source it is clear that all the other caller preserved registers (volatile registers) of the regular user land calling convention seem to apply. – Michael Petch Sep 29 '17 at 21:05