c - 内核 : using sigqueue-functions

标签 c linux-kernel signals linux-device-driver kernel-module

我尝试实现从可加载内核模块到用户应用程序的信号调用。该应用程序使用 sigaction处理信号调用,稍后它将使用 sival_int通过 switch 处理不同的操作和case .

void signalHandler_function (int signum,
                             siginfo_t *siginfo,
                             void *ucontext)
{
   printf("signum: %i\n", signum);
   printf("sigval: %d\n", siginfo->si_value.sival_int);
}

int main(){
   int ret;
   int pid = getpid();
   char pidc[4];
   struct sigaction sig;

   memcpy(pidc,&pid,4);

   // configure signal handler
   sig.sa_flags = SA_SIGINFO;
   sig.sa_sigaction = signalHandler_function;
   sigaction(SIGIO, &sig, NULL);

   g_fdCharDev = open(EXPDEV_DEVPATHNAME, O_RDWR);

   printf("My process ID : %d\n", pid);
   ret = write(g_fdCharDev, &pid, 1);
   ...
}

在内核方面,我尝试使用 send_sigqueue() (与 sigqueue_alloc()sigqueue_free() 一起)。这是在 include/linux/sched.h, line 2320 中声明的如extern并在 kernel/signal.c, line 1560 中定义。但链接器说这个函数未定义:

make -C /lib/modules/3.19.0-58-generic/build/ M=/home/alex/git/Kernel3/SignalHandling modules
make[1]: Verzeichnis »/usr/src/linux-headers-3.19.0-58-generic« wird betreten
  CC [M]  /home/alex/git/Kernel3/SignalHandling/ExpDev.o
  Building modules, stage 2.
  MODPOST 1 modules
WARNING: "sigqueue_free" [/home/alex/git/Kernel3/SignalHandling/ExpDev.ko] undefined!
WARNING: "sigqueue_alloc" [/home/alex/git/Kernel3/SignalHandling/ExpDev.ko] undefined!
WARNING: "send_sigqueue" [/home/alex/git/Kernel3/SignalHandling/ExpDev.ko] undefined!
  CC      /home/alex/git/Kernel3/SignalHandling/ExpDev.mod.o
  LD [M]  /home/alex/git/Kernel3/SignalHandling/ExpDev.ko
make[1]: Verzeichnis »/usr/src/linux-headers-3.19.0-58-generic« wird verlassen
Process terminated with status 0 (0 minute(s), 0 second(s))
0 error(s), 0 warning(s) (0 minute(s), 0 second(s))

这是 LKM 的简短源代码:

#include <linux/init.h>   /// Macros used to mark up functions e.g. __init __exit
#include <linux/module.h> /// Core header for loading LKMs into the kernel
#include <linux/device.h> /// Header to support the kernel Driver Model
#include <linux/kernel.h> /// Contains types, macros, functions for the kernel
#include <linux/fs.h>     /// Header for the Linux file system support
#include <asm/uaccess.h>  /// Required for the copy to user function
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/rcupdate.h>
#include <linux/slab.h>

struct siginfo *g_sig_info;
static struct sigqueue *g_sigqueue;
int g_usp_pid;
struct task_struct *g_sig_task;

static int __init expdev_init(void)
{
  ...
  // setup signal
  g_sigqueue = sigqueue_alloc();
  g_sigqueue->info.si_signo = SIGIO;
  g_sigqueue->info.si_signo = SI_QUEUE;
  g_sigqueue->info.si_errno = 0;
  ...
}

static void __exit expdev_exit(void)
{
  sigqueue_free(g_sigqueue);
  ...
}

static ssize_t dev_write(struct file *filep,
                         const char *buffer,
                         size_t len,
                         loff_t *offset)
{
  ...
  memcpy(&g_usp_pid,buffer,4); // we know the PID comes with the buffer

  // find task to the given PID
  rcu_read_lock();
  g_sig_task = pid_task(find_pid_ns(g_usp_pid, &init_pid_ns),
                        PIDTYPE_PID);

  //send signal to user land
  g_sigqueue->info.si_value.sival_int = 33;
  ret = send_sigqueue(g_sigqueue, g_sig_task, 0);
  ...
}

为什么无法链接?难道是我的方法不对?

最佳答案

为内核模块导出的任何有用的 list_head 或函数都可以作为 System.map 文件中的地址找到。

$ sudo grep sigqueue /boot/System.map-3.19.0-58-generic
ffffffff81084880 T sigqueue_alloc
ffffffff810848b0 T sigqueue_free
ffffffff81084920 T send_sigqueue

此函数指针地址可用于本地函数:

#include <linux/init.h>   /// Macros used to mark up functions e.g. __init __exit
#include <linux/module.h> /// Core header for loading LKMs into the kernel
#include <linux/device.h> /// Header to support the kernel Driver Model
#include <linux/kernel.h> /// Contains types, macros, functions for the kernel
#include <linux/fs.h>     /// Header for the Linux file system support
#include <asm/uaccess.h>  /// Required for the copy to user function
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/rcupdate.h>
#include <linux/slab.h>

struct siginfo *g_sig_info;
static struct sigqueue *g_sigqueue;
int g_usp_pid;
struct task_struct *g_sig_task;

// ffffffff81084920 T send_sigqueue
int (*send_sigqueue_ptr)( struct sigqueue *,
                          struct task_struct *,
                          int group) = (void*)0xffffffff81084920;
// ffffffff81084880 T sigqueue_alloc
struct sigqueue *(*sigqueue_alloc_ptr)(void) = (void*)0xffffffff81084880;
// ffffffff810848b0 T sigqueue_free
void (*sigqueue_free_ptr)(struct sigqueue *) = (void*)0xffffffff810848b0;

static int __init expdev_init(void)
{
  ...
  // setup signal
  g_sigqueue = sigqueue_alloc_ptr();
  g_sigqueue->info.si_signo = SIGIO;
  g_sigqueue->info.si_code  = SI_QUEUE;
  g_sigqueue->info.si_errno = 0;
  ...
}

static void __exit expdev_exit(void)
{
  sigqueue_free_ptr(g_sigqueue);
  ...
}

static ssize_t dev_write(struct file *filep,
                         const char *buffer,
                         size_t len,
                         loff_t *offset)
{
  ...
  memcpy(&g_usp_pid,buffer,4); // we know the PID comes with the buffer

  // find task to the given PID
  rcu_read_lock();
  g_sig_task = pid_task(find_pid_ns(g_usp_pid, &init_pid_ns),
                        PIDTYPE_PID);

  //send signal to user land
  g_sigqueue->info.si_value.sival_int = 33;
  ret = send_sigqueue_ptr(g_sigqueue, g_sig_task, 0);
  ...
}

这仅适用于这个特殊的内核版本,并且不太可移植。是否有任何宏或其他解决方法可以获取此地址或函数?这也是编译 kernel/signal.c 的好方法吗?

如果有人知道改善这一点的方法。请随意评论和编辑。

关于c - 内核 : using sigqueue-functions,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36520957/

相关文章:

linux - Linux 内核中的 WaitForMultipleObjects 等价物

c/fork/signals/关闭不同进程中打开的套接字的最佳实践

c - C 中的静态和外部内联函数

c - 为什么在这个程序中出现段错误

c - 我在函数中正确实现指针吗?

linux - netlink 和大端格式

c - 从内核空间中的线程调度

linux - POSIX 线程何时取消不立即?

c++ - Linux 编程接口(interface)中的信号处理程序示例

c - 尝试使用按值调用和按引用调用来构造...代码编译没有任何错误..但打印垃圾值?