How to send signal from kernel to user space

2019-06-27 08:39发布

问题:

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())

回答1:

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.



回答2:

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.



回答3:

Your interface is violating the spirit of Linux. Don't do that..... A system call (in particular those related to your driver) should only fail with errno (see syscalls(2)...); consider eventfd(2) or netlink(7) for such asynchronous kernel <-> userland communications (and expect user code to be able to poll(2) them).

A kernel module could fail to be loaded. I'm not familiar with the details (never coded any kernel modules) but this hello2.c example suggests that the module init function can return a non zero error code on failure.

People are really expecting that signals (which is a difficult and painful concept) are behaving as documented in signal(7) and what you want to do does not fit in that picture. So a well behaved kernel module should never asynchronously send any signal to processes.

If your kernel module is not behaving nicely your users would be pissed off and won't use it.

If you want to fork your experimental kernel (e.g. for research purposes), don't expect it to be used a lot; only then could you realistically break signal behavior like you intend to do, and you could code things which don't fit into the kernel module picture (e.g. add a new syscall). See also kernelnewbies.