Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to send signal from kernel to user space

My kernel module code needs to send signal [def.] to a user land program, to transfer its execution to registered signal handler.

I know how to send signal between two user land processes, but I can not find any example online regarding the said task.

To be specific, my intended task might require an interface like below (once error != 1, code line int a=10 should not be executed):

void __init m_start(){
    ...
    if(error){
        send_signal_to_userland_process(SIGILL)
    }
    int a = 10;
    ...
}

module_init(m_start())
like image 518
Richard Avatar asked Jul 26 '15 22:07

Richard


People also ask

How do I transfer data from kernel space to user space?

The function copy_to_user is used to copy data from the kernel address space to the address space of the user program. For example, to copy a buffer which has been allocated with kmalloc to the buffer provided by the user.

Can kernel send signals internally?

A signal is generated either by the kernel internally (for example, SIGSEGV when an invalid address is accessed, or SIGQUIT when you hit Ctrl + \ ), or by a program using the kill syscall (or several related ones).

Can the kernel send a signal to a process?

A signal is a notification to a process that an event has occurred. Signals are sometimes described as software interrupts, because in most cases, they interrupt the normal flow of execution of a program and their arrival is unpredictable. A signal can be sent by Kernel or a Process.

How do I access user space from kernel?

Whilst a user-space program is not allowed to access kernel memory, it is possible for the kernel to access user memory. However, the kernel must never execute user-space memory and it must also never access user-space memory without explicit expectation to do so.


2 Answers

An example I used in the past to send signal to user space from hardware interrupt in kernel space. That was just as follows:

KERNEL SPACE

#include <asm/siginfo.h>    //siginfo
#include <linux/rcupdate.h> //rcu_read_lock
#include <linux/sched.h>    //find_task_by_pid_type

static int pid; // Stores application PID in user space

#define SIG_TEST 44

Some "includes" and definitions are needed. Basically, you need the PID of the application in user space.

struct siginfo info;
struct task_struct *t;

memset(&info, 0, sizeof(struct siginfo));
info.si_signo = SIG_TEST;
// This is bit of a trickery: SI_QUEUE is normally used by sigqueue from user space,    and kernel space should use SI_KERNEL. 
// But if SI_KERNEL is used the real_time data  is not delivered to the user space signal handler function. */
info.si_code = SI_QUEUE;
// real time signals may have 32 bits of data.
info.si_int = 1234; // Any value you want to send
rcu_read_lock();
// find the task with that pid
t = pid_task(find_pid_ns(pid, &init_pid_ns), PIDTYPE_PID);
if (t != NULL) {
    rcu_read_unlock();      
    if (send_sig_info(SIG_TEST, &info, t) < 0) // send signal
        printk("send_sig_info error\n");
} else {
     printk("pid_task error\n");
     rcu_read_unlock();
    //return -ENODEV;
}

The previous code prepare the signal structure and send it. Bear in mind that you need the application's PID. In my case the application from user space send its PID through ioctl driver procedure:

static long dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) {
    ioctl_arg_t args;
    switch (cmd) {
        case IOCTL_SET_VARIABLES:
              if (copy_from_user(&args, (ioctl_arg_t *)arg, sizeof(ioctl_arg_t))) return -EACCES;
              pid = args.pid;
        break;

USER SPACE

Define and implement the callback function:

#define SIG_TEST 44

void signalFunction(int n, siginfo_t *info, void *unused) {
    printf("received value %d\n", info->si_int);
}

In main procedure:

int  fd = open("/dev/YourModule", O_RDWR); 
if (fd < 0) return -1;

args.pid       = getpid();
ioctl(fd, IOCTL_SET_VARIABLES, &args); // send the our PID as argument

struct sigaction sig;

sig.sa_sigaction = signalFunction; // Callback function
sig.sa_flags = SA_SIGINFO;
sigaction(SIG_TEST, &sig, NULL);

I hope it helps, despite the fact the answer is a bit long, but it is easy to understand.

like image 54
omotto Avatar answered Dec 03 '22 07:12

omotto


You can use, e.g., kill_pid(declared in <linux/sched.h>) for send signal to the specified process. To form parameters to it, see implementation of sys_kill (defined as SYSCALL_DEFINE2(kill) in kernel/signal.c).

Note, that it is almost useless to send signal from the kernel to the current process: kernel code should return before user-space program ever sees signal fired.

like image 40
Tsyvarev Avatar answered Dec 03 '22 05:12

Tsyvarev