Guru Prasad Guru Prasad - 8 days ago 6
Linux Question

Signal handling in kernel-space

I've written a program that uses

SIGALRM
and a signal handler.

I'm now trying to add this as a test module within the kernel.

I found that I had to replace a lot of the functions that libc provides with their underlying syscalls..examples being
timer_create
with
sys_timer_create
timer_settime
with
sys_timer_settime
and so on.

However, I'm having issues with
sigaction
.

Compiling the kernel throws the following error

arch/arm/mach-vexpress/cpufreq_test.c:157:2: error: implicit declaration of function 'sys_sigaction' [-Werror=implicit-function-declaration]


I've attached the relevant code block below

int estimate_from_cycles() {
timer_t timer;
struct itimerspec old;

struct sigaction sig_action;
struct sigevent sig_event;
sigset_t sig_mask;

memset(&sig_action, 0, sizeof(struct sigaction));
sig_action.sa_handler = alarm_handler;
sigemptyset(&sig_action.sa_mask);

VERBOSE("Blocking signal %d\n", SIGALRM);
sigemptyset(&sig_mask);
sigaddset(&sig_mask, SIGALRM);

if(sys_sigaction(SIGALRM, &sig_action, NULL)) {
ERROR("Could not assign sigaction\n");
return -1;
}

if (sigprocmask(SIG_SETMASK, &sig_mask, NULL) == -1) {
ERROR("sigprocmask failed\n");
return -1;
}

memset (&sig_event, 0, sizeof (struct sigevent));
sig_event.sigev_notify = SIGEV_SIGNAL;
sig_event.sigev_signo = SIGALRM;
sig_event.sigev_value.sival_ptr = &timer;


if (sys_timer_create(CLOCK_PROCESS_CPUTIME_ID, &sig_event, &timer)) {
ERROR("Could not create timer\n");
return -1;
}

if (sigprocmask(SIG_UNBLOCK, &sig_mask, NULL) == -1) {
ERROR("sigprocmask unblock failed\n");
return -1;
}

cycles = 0;
VERBOSE("Entering main loop\n");

if(sys_timer_settime(timer, 0, &time_period, &old)) {
ERROR("Could not set timer\n");
return -1;
}

while(1) {
ADD(CYCLES_REGISTER, 1);
}
return 0;
}


Is such an approach of taking user-space code and changing the calls alone sufficient to run the code in kernel-space?

Answer

Is such an approach of taking user-space code and changing the calls alone sufficient to run the code in kernel-space?

Of course not! What are you doing is to call the implementation of a system call directly from kernel space, but there is not guarantee that they SYS_function has the same function definition as the system call. The correct approach is to search for the correct kernel routine that does what you need. Unless you are writing a driver or a kernel feature you don't nee to write kernel code. System calls must be only invoked from user space. Their main purpose is to offer a safe manner to access low level mechanisms offered by an operating system such as File System, Socket and so on.

Regarding signals. You had a TERRIBLE idea to try to use signal system calls from kernel space in order to receive a signal. A process sends a signal to another process and signal are meant to be used in user space, so between user space processes. Typically, what happens when you send a signal to another process is that, if the signal is not masked, the receiving process is stopped and the signal handler is executed. Note that in order to achieve this result two switches between user space and kernel space are required.

However, the kernel has its internal tasks which have exactly the same structure of a user space with some differences ( e.g. memory mapping, parent process, etc..). Of course you cannot send a signal from a user process to a kernel thread (imagine what happen if you send a SIGKILL to a crucial component). Since kernel threads have the same structure of user space thread, they can receive signal but its default behaviour is to drop them unless differently specified.

I'd recommend to change you code to try to send a signal from kernel space to user space rather than try to receive one. ( How would you send a signal to kernel space? which pid would you specify?). This may be a good starting point : http://people.ee.ethz.ch/~arkeller/linux/kernel_user_space_howto.html#toc6

You are having problem with sys_sigaction because this is the old definition of the system call. The correct definition should be sys_rt_sigaction. From the kernel source 3.12 :

 #ifdef CONFIG_OLD_SIGACTION
 asmlinkage long sys_sigaction(int, const struct old_sigaction __user *,
                                 struct old_sigaction __user *);
 #endif

 #ifndef CONFIG_ODD_RT_SIGACTION
 asmlinkage long sys_rt_sigaction(int,
                                  const struct sigaction __user *,
                                  struct sigaction __user *,
                                  size_t);
 #endif

BTW, you should not call any of them, they are meant to be called from user space.