Search code examples
clinux-kernellinux-device-driverpid

My Linux kernel module is not receiving the correct User-space Application PID


I am developing Linux kernel module which is communicating with my user-space C application. In this module, I am creating a thread. Besides, I need to know the pid of the user space process, so I am using pid_task(find_vpid(pid), PIDTYPE_PID) function.

This is my module where I am facing the problem :

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/siginfo.h>    //siginfo
#include <linux/rcupdate.h>    //rcu_read_lock
#include <linux/sched/signal.h>    //find_task_by_pid_type
#include <linux/debugfs.h>
#include <linux/uaccess.h>
#include<linux/slab.h>
#include <linux/input.h>
#include <linux/device.h>
#include <linux/fs.h> 
#include <linux/random.h> 
#include <linux/kthread.h> 

#define SIG_TEST 44    // we choose 44 as our signal number (real-time signals are in the range of 33 to 64)
#define BTN_FILE_PATH "/dev/input/event0"


char *str = BTN_FILE_PATH;
int file;

struct file *f;   // keyboard driver

// prototypage des fonctions read_in_thread & read_pid
int read_in_thread(void *data);
static ssize_t read_pid(struct file *pfile, char __user *buffer, size_t length, loff_t *offset);


static ssize_t write_pid(struct file *pfile, const char __user *buffer,
                                size_t length, loff_t *offset)
{
   return 0;
}



struct read_args {
    struct file *pfile;
    const char __user *buffer;
    size_t length;
    loff_t *offset;
};


static ssize_t read_pid(struct file *pfile, char __user *buffer, size_t length, loff_t *offset)
{
  // création de la structure des arguments
    struct read_args args ;
    args.pfile = pfile;
    args.buffer = buffer;
    args.length = length;
    args.offset = offset;

struct task_struct *thread1;
char our_thread[20];
unsigned int rand;

get_random_bytes(&rand, sizeof(rand));
rand = rand % 250;
sprintf(our_thread, "thread%u", rand);

if(thread1==NULL)
{
thread1 = kthread_create(read_in_thread,&args,our_thread);
    if((thread1))
        {
            printk(KERN_INFO "Thread is created\n");
        printk("thread name %s\n", our_thread);
// lancement du thread
            wake_up_process(thread1);
        printk(KERN_INFO "Thread is awake\n");
        }
}

else 
printk("\nTHREAD1 IS NOT NULL!!! CAN NOT CREATE THREAD!!!\n"); 

return 0;                   
}



int read_in_thread(void *data) {

/************************** récupération des arguments *******************/

    struct read_args *const args = data;

/***************************   corps de la fonction ***********************/


// init des variables 

    char mybuf[10];
    enum { MAX_BUF_SIZE = 4096 };
    size_t buf_size = 0;
    char *buf = NULL;
    ssize_t total = 0;
    ssize_t rc = 0;
    struct task_struct *t;
    struct input_event ev[64];
    int yalv;

    int ret;
    struct siginfo info;
    int pid =0; 
    size_t amount = sizeof(ev);    


// récupération de l'ID du processus appelant

/* read the value from user space */
    if(args->length > 10)
        return -EINVAL;
    copy_from_user(mybuf, args->buffer, args->length);
    sscanf(mybuf, "%d", &pid);
    printk("pid = %d\n", pid);

    // the signal 
    memset(&info, 0, sizeof(struct siginfo));
    info.si_signo = SIG_TEST;
    info.si_code = SI_QUEUE;    // 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_int = 260;          //real time signals may have 32 bits of data.

    rcu_read_lock();
    t = pid_task(find_vpid(pid), PIDTYPE_PID);  //find the task_struct associated with this pid
    if(t == NULL){
        printk("no such pid\n");
        rcu_read_unlock();
        return -ENODEV;
    }
    rcu_read_unlock();


// lecture blocquante

    rc = kernel_read(f, ev, amount, &f->f_pos);

// récupération de l'événement

    if (rc > 0) {
            for (yalv = 0; yalv < (int) (rc / sizeof(struct input_event)); yalv++) {
            if (ev[yalv].type == EV_KEY) {
                if (ev[yalv].value == 0)
                     //eval_keycode(ev[yalv].code);
                     info.si_int = ev[yalv].code;  

// envoie du signal vers le processus appelant avec les événements lu

                                         ret = send_sig_info(SIG_TEST, &info, t);    //send the signal
                         printk("signal was send\n");
                     if (ret < 0) {
                            printk("error sending signal\n");
                        kfree(buf);
                            return ret;
                         }              
            }
        }

                if (rc < amount) {
                    /* Didn't read the full amount, so terminate early. */
                    rc = 0;
                }

    } 

    /* Free temporary buffer. */
        kfree(buf);

return 0;
}


static const struct file_operations my_fops = {
    .owner = THIS_MODULE,
    .write = write_pid,
    .read = read_pid,
    //.open = open_pid,
};



static int __init signalexample_module_init(void)
{
    printk(KERN_INFO "Initializing LKM");
    register_chrdev(240, "mod", &my_fops);
    file = debugfs_create_file("signalconfpid", 0200, NULL, NULL, &my_fops);
    f = filp_open(str, O_RDONLY , 0);

    return 0;
}



static void __exit signalexample_module_exit(void)
{
    unregister_chrdev(240, "mod");
    debugfs_remove(file);

}

module_init(signalexample_module_init);
module_exit(signalexample_module_exit);
MODULE_LICENSE("GPL");

When I run my user-space program after inserting this module, it seems for the first time to work without a problem : it prints on the console :

Thread is created 
thread name thread91
Thread is awake
pid = 323

But after I exit and when I try to re-execute my user space code again it shows to me :

pid = 0 
No such pid

I want to know why it's not working in the right way when I execute my application for multiple times ? what's wrong here ? I need some help please. Thank you.


Solution

  • For anyone who is looking for a solution for this problem, after some researches I found that using copy_from_user function must be used out of the thread function. So, I move it inside read_pid function in my code and declared the variables which it used as global variables and I am able now to usually receive the correct PID of my user space application.