2016-04-09 11 views
0

Ich versuche einen Signalaufruf von einem ladbaren Kernelmodul in eine Benutzeranwendung zu implementieren. Die Anwendung verwendet sigaction, um den Signalaufruf zu verarbeiten, und später muss sie sival_int verwenden, um verschiedene Aktionen von switch und case zu behandeln.Kernel: mit sigqueue-Funktionen

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); 
    ... 
} 

auf Kernel-Seite versuche ich (mit sigqueue_alloc() und sigqueue_free() zusammen) send_sigqueue() zu verwenden. Dies wird in include/linux/sched.h, line 2320 als extern deklariert und in kernel/signal.c, line 1560 definiert. Aber die Linker sagt diese Funktionen nicht definiert sind:

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

Hier kommt die verkürzte Quelle des 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); 
    ... 
} 

Warum es nicht verknüpfbar ist? Ist meine Vorgehensweise falsch?

+0

Um im Kernelmodul verwendbar zu sein, sollte das Symbol ** exportiert werden (EXPORT_SYMBOL). Einfache Definition in Header-Datei als * extern * ist nicht ausreichend. – Tsyvarev

+0

@Tsyvarev Ja, ich weiß. Aber die Funktion ist auch definiert. Aber warum verlinkt es nicht? – Alex44

+0

Ihr Modul ist nicht kompiliert mit 'kernel/signal.c', welches * die angegebene Funktion definiert. Das Modul sieht nur Header-Dateien, die es nur deklariert. In der 'modpost'-Phase, die dem * linking * des Moduls ähnelt, werden nur * exportierte * Symbole aufgelöst. Deshalb erhalten Sie * undefined symbol * error (warning) - angegebene Funktion wird weder von Ihrem Modul definiert, noch in der Modpost-Phase gelöst. – Tsyvarev

Antwort

0

Alle hilfreichen list_head oder Funktionen, die für Kernelmodule exportiert werden, werden als Adresse in der Datei System.map gefunden.

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

Diese Funktion-Pointer-Adressen können auf lokale Funktionen verwendet werden:

#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); 
    ... 
} 

Dies wird nur für diese spezielle Kernel-Version arbeiten und ist nicht sehr tragbar. Wenn es irgendein Makro oder eine andere Abhilfe gibt, erhalten diese Adressen oder Funktionen? Ist es eine gute Möglichkeit, auch die kernel/signal.c zu kompilieren?

Wenn jemand eine Möglichkeit, dies zu verbessern weiß. Bitte zögern Sie nicht zu kommentieren und zu bearbeiten.