Catching SIGINT in kernel space - c

In my kernel module I have a function to start a firmware update via sysfs-attribute. This function blocks until the update returned successfully or after a timeout. The problem now is when I generate an interrupt by pressing Ctlr+c on the keyboard the function returns. This leaves the buffer with my payload for the update in an undefined state generating unwanted behaviour when restarting the update process.
I know from userspace that you can register a singal_handler to catch those specific signals like SIGINT in my case:
signal(SIGINT,my_sig_int_handler)
Is there something similar in the kernelspace? I also read that one should not use signal() at all because of compatibility issues but what would be the alternative?
I already tried to work with the function by registering my signal-handler function in my sysfs-function but it seems that the handler doesn't get executed:
static void sig_handler(int sig)
{
printk("SIGINT received\n");
// set global flag to inform other thread that uupdate was interrupted;
}
static ssize_t update_function(struct device *dev, struct device_attribute *dev_attr, const char *buf, size_t count)
{
__sighandler_t sa_handler = sig_handler;
kernel_sigaction(SIGINT,sa_handler);
// set flag to start update in other thread ....
}
In the linux-kernel sources I can't find examples where kernel_signal is used with a handler_function. Can anyone give me a hint on how to solve my problem?

Related

How to trigger a memory range access exception?

How can a program signal itself when it does a write access to a configurable memory region?
This would be something similar to the data-breakpoint feature found in some debuggers. POSIX compliance is desired but not required as long as it works on Linux.
Here there is an illustrative code of what I would like:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
void configure_trap(void *FROM, void *TO){
/*
Set a trap on write access to any memory location from
address FROM to address TO.
When the trap is triggered, send SIGTRAP to the process.
There is no need for an answer to have the full code, just
an indication on how to proceed.
*/
}
char *ptr;
void trap_signal_handler(int signum){
if(ptr[123] == 'x'){
printf("Invalid value in ptr[123] !!!\n");
/*
Print a backtrace using libunwind. (Not part of this question.)
*/
}
}
void some_function(){
ptr[123] = 'x';
/*
This write access could be performed directly in this function or
another function called directly or indirectly by this one and it
could reside in this program or in an external library or could even
be performed in a system call.
trap_signal_handler should be called at this point.
After the signal handler has been executed, program should resume
normal operation.
*/
}
int main(){
struct sigaction sa = { .sa_handler = trap_signal_handler };
sigaction(SIGTRAP, &sa, NULL);
ptr = malloc(1024);
configure_trap(&ptr[123], &ptr[123]);
some_function();
return(0);
}
Thanks!
First, use mprotect() to mark a page read-only. Then when it is written, SIGSEGV will be raised. You will have installed a signal handler for this, and if it is done using sigaction you can know what address was accessed by inspecting si_addr. For more on this, see: C SIGSEGV Handler & Mprotect
Note that mprotect() has a granularity of one page, meaning if you try to protect a single byte, you will actually have protected 4 KB (if that's your page size).
Use the https://github.com/vicencb/qdbp project.
It first mprotects the memory page as read-only.
When a SIGSEGV is raised it single steps your program one instruction at a time until the one that caused the write to the read-only memory.
Then it calls your callback.

Does the thundering herd issue still exist in epoll of new Linux kernel?

I saw that fs/eventpoll.c in the kernel source code is written like this:
static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
int maxevents, long timeout)
{
....
init_waitqueue_entry(&wait, current);
__add_wait_queue_exclusive(&ep->wq, &wait); // *** NB
....
}
Does that "exclusive" mean that only one wait item (process or thread in userspace) will be waked up?
But when I wrote some test code, I saw that the thundering herd problem still exists.
And WHY can't it be solved? Thanks!
In the kernel code we can see in include/linux/wait.h that __add_wait_queue_exclusive() adds the entry to the head of the list:
__add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t *wait)
{
wait->flags |= WQ_FLAG_EXCLUSIVE;
__add_wait_queue(q, wait);
}
When it comes to waking up static void __wake_up_common() in sched/wait.c does wake only the first tasks that are not exclusive and the first exclusive one.
So normally only one tasks gets woken up.
It depends on whether you are using the same epfd. The flag WQ_FLAG_EXCLUSIVE is works only for the TASKs waiting on the same eventpoll.
If your testing code use different epfd monitor on the same socket, YES, the issue exists.

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?
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.
You're working in kernel space so you should start thinking like you're working in kernel space instead of trying to port a userspace hack into the kernel. If you need to call the sys_* family of functions in kernel space, 99.95% of the time, you're already doing something very, very wrong.
Instead of while (1), have it break the loop on a volatile variable and start a thread that simply sleeps and change the value of the variable when it finishes.
I.e.
void some_function(volatile int *condition) {
sleep(x);
*condition = 0;
}
volatile int condition = 1;
start_thread(some_function, &condition);
while(condition) {
ADD(CYCLES_REGISTER, 1);
}
However, what you're doing (I'm assuming you're trying to get the number of cycles the CPU is operating at) is inherently impossible on a preemptive kernel like Linux without a lot of hacking. If you keep interrupts on, your cycle count will be inaccurate since your kernel thread may be switched out at any time. If you turn interrupts off, other threads won't run and your code will just infinite loop and hang the kernel.
Are you sure you can't simply use the BogoMIPs value from the kernel? It is essentially what you're trying to measure but the kernel does it very early in the boot process and does it right.

signal user application from kernel

I have been pulling my hairs for real strange issue. The kernel module is unable to send signal to user application (or user app is unable to receive) without printk, have to do dummy printk after or before sending the signal.
Actually, it works great even with empty printk. But, i am trying to understand whats happening.
Any thoughts?
Here is whats happening:
A - kernel)
Char device type module gets interrupt.
It extracts the data and send signal to user.
/* have to do printk here */
Return IRQ handle.
B- user)
Receives the signal.
issues a system call and read the data from char device's buffer . (copy_to_user)
kernel:
void irq_handler(){
int i;
for(i =0; i < 32; i++)
GPIOdata[i] = read_gpio_status(i);
struct task_struct *p = find_task_by_pid(processinfo.pid);
if (NULL == p)
return;
send_sig(SIGUSR1, p, 0);
/* have to add printk here */
return IRQ_HANDLED
}
user:
void signal_handler(int sig) {
char data[32];
ioctl(fd, READ_Data_from_Char_device, &data);
}
If you are using signal not sigaction for setting handler, then remember, that signal removes handler after getting a signal. And you should mask the signal, so it will not interrupt your process when running inside signal handler. I'ma also not sure about system call ioctl inside handler (look at man7 signal under section Async-signal-safe functions).
Calls to printk might slow down execution of other operations (because they are blocked on I/O or buffering) around these calls, so they can make synchronization slower (thus any mistakes in synchronization may not occur).

Signal handler for SIGALRM does not work even if resetting in the handler

The example code of section 10.6, the expected result is:
after several iterations, the static structure used by getpwnam will be corrupted, and the program will terminate with SIGSEGV signal.
But on my platform, Fedora 11, gcc (GCC) 4.4.0, the result is
[Langzi#Freedom apue]$ ./corrupt
in sig_alarm
I can see the output from sig_alarm only once, and the program seems hung up for some reason, but it does exist, and still running.
But when I try to use gdb to run the program, it seems OK, I will see the output from sig_alarm at regular intervals.
And from my manual, it said the signal handler will be set to SIG_DEF after the signal is handled, and system will not block the signal. So at the beginning of my signal handler I reset the signal handler.
Maybe I should use sigaction instead, but I only want to know the reason about the difference between normal running and gdb running.
Any advice and help will be appreciated.
following is my code:
#include "apue.h"
#include <pwd.h>
void sig_alarm(int signo);
int main()
{
struct passwd *pwdptr;
signal(SIGALRM, sig_alarm);
alarm(1);
for(;;) {
if ((pwdptr = getpwnam("Zhijin")) == NULL)
err_sys("getpwnam error");
if (strcmp("Zhijin", pwdptr->pw_name) != 0) {
printf("data corrupted, pw_name: %s\n", pwdptr->pw_name);
}
}
}
void sig_alarm(int signo)
{
signal(SIGALRM, sig_alarm);
struct passwd *rootptr;
printf("in sig_alarm\n");
if ((rootptr = getpwnam("root")) == NULL)
err_sys("getpwnam error");
alarm(1);
}
According to the standard, you're really not allowed to do much in a signal handler. All you are guaranteed to be able to do in the signal-handling function, without causing undefined behavior, is to call signal, and to assign a value to a volatile static object of the type sig_atomic_t.
The first few times I ran this program, on Ubuntu Linux, it looked like your call to alarm in the signal handler didn't work, so the loop in main just kept running after the first alarm. When I tried it later, the program ran the signal handler a few times, and then hung. All this is consistent with undefined behavior: the program fails, sometimes, and in various more or less interesting ways.
It is not uncommon for programs that have undefined behavior to work differently in the debugger. The debugger is a different environment, and your program and data could for example be laid out in memory in a different way, so errors can manifest themselves in a different way, or not at all.
I got the program to work by adding a variable:
volatile sig_atomic_t got_interrupt = 0;
And then I changed your signal handler to this very simple one:
void sig_alarm(int signo) {
got_interrupt = 1;
}
And then I inserted the actual work into the infinite loop in main:
if (got_interrupt) {
got_interrupt = 0;
signal(SIGALRM, sig_alarm);
struct passwd *rootptr;
printf("in sig_alarm\n");
if ((rootptr = getpwnam("root")) == NULL)
perror("getpwnam error");
alarm(1);
}
I think the "apue" you mention is the book "Advanced Programming in the UNIX Environment", which I don't have here, so I don't know if the purpose of this example is to show that you shouldn't mess around with things inside of a signal handler, or just that signals can cause problems by interrupting the normal work of the program.
According to the spec, the function getpwnam is not reentrant and is not guaranteed to be thread safe. Since you are accessing the structure in two different threads of control (signal handlers are effectively running in a different thread context), you are running into this issue. Whenever you have concurrent or parallel execution (as when using pthreads or when using a signal handler), you must be sure not to modify shared state (e.g. the structure owned by 'getpwnam'), and if you do, then appropriate locking/synchronization must be used.
Additionally, the signal function has been deprecated in favor of the sigaction function. In order to ensure portable behavior when registering signal handlers, you should always use the sigaction invocation.
Using the sigaction function, you can use the SA_RESETHAND flag to reset the default handler. You can also use the sigprocmask function to enable/disable the delivery of signals without modifying their handlers.
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void sigalrm_handler(int);
int main()
{
signal(SIGALRM, sigalrm_handler);
alarm(3);
while(1)
{
}
return 0;
}
void sigalrm_handler(int sign)
{
printf("I am alive. Catch the sigalrm %d!\n",sign);
alarm(3);
}
For example, my code is runing in main doing nothing and every 3 seconds my program says im alive x)
I think that if you do as i done calling in the handler function alarm with value 3, the problem is resolved :)

Resources