any example of copy_from_user() ? kernel and userspace

17,520

Look into code you have given, it seems that you want to handle SIGIO signal

Here is my attempt to solve your problem,

signal_kernel.c file :

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/siginfo.h>
#include <linux/rcupdate.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <linux/signal.h>
#include <linux/debugfs.h>
#include <linux/pid.h>

#define MAX 10

MODULE_LICENSE("GPL");

struct dentry *file;

static ssize_t write_conf_pid(struct file *file, const char *buf,
            size_t count, loff_t *position)
{
    char temp_str[MAX];
    int ret;
    int pid = 0;
    struct siginfo sinfo;
    struct task_struct *task;

    /* NEVER TRUST USER INPUT */
    if (count > MAX)
        return -EINVAL;

    if (copy_from_user(temp_str, buf, MAX) != 0)
        return -EFAULT;

    ret = sscanf(temp_str, "%d", &pid);
    if (ret != 1) {
        pr_info("Error in reading PID value from user");
        return -EINVAL;
    }

    pr_info("User entered pid %d\n", pid);
    memset(&sinfo, 0, sizeof(struct siginfo));
    sinfo.si_signo = SIGIO;
    sinfo.si_code = SI_USER;
    task = pid_task(find_vpid(pid), PIDTYPE_PID);
    if (task == NULL) {
        pr_info("Cannot find PID from user program\r\n");
        return -ENODEV;
    }
    ret = send_sig_info(SIGIO, &sinfo, task);
    if (ret < 0)
        pr_info("Error sending signal\n");
    return count;
}

static const struct file_operations my_fops = {
    .write = write_conf_pid,
};

int init_module()
{
    /* Only root can write to this file */
    file = debugfs_create_file("pidconf", 0200, NULL, NULL, &my_fops);
    return 0;
}

void cleanup_module()
{
    pr_info("\nGoodBye World\n\n");
}

signal_user.c file :

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>

void signal_handler(int signum)
{
    if (signum == SIGIO)
        printf("SIGIO\r\n");
    return;
}

int main()
{
    int i = 1;
    signal(SIGIO, signal_handler);
    printf("My PID is %d.\n", getpid());
    while (i);
    return 0;
}

After compiling and running both user space and kernel space program, use debugfs interface to send PID value to Kernel space,

$ insmod signal_kernel.ko
$ ./signal_user 
My PID is 17633.

... # Process will run in loop due to while(1)

From another terminal, provide PID to debugfs interface,

$ echo 17633 > /sys/kernel/debug/pidconf

There are various ways (sysfs, misc_char_device, char device etc.) to this task, but this will give you brief idea about using copy_from_user() and copy_to_user()

Please note that there is little error handling done in signal_user.c and signal_kernel.c.

Share:
17,520
Raheel
Author by

Raheel

Updated on June 04, 2022

Comments

  • Raheel
    Raheel almost 2 years

    I am looking for copying PID value from User space to Kernel space, here is my code snaps.

    Kernel Module:

    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/init.h>
    #include <asm/siginfo.h>
    #include <linux/rcupdate.h>
    #include <linux/sched.h>
    #include <linux/uaccess.h>
    #include <linux/signal.h>
    
    MODULE_LICENSE ("GPL");
    
    struct siginfo sinfo;
    pid_t pid;
    struct task_struct *task;
    
    int init_module() 
    {
        memset(&sinfo, 0, sizeof(struct siginfo));
        sinfo.si_signo = SIGIO;
        sinfo.si_code = SI_USER;
        pid = 5218; // Everytime a new PID 
        // task = find_task_by_vpid(pid); I am also working on new and old version of UBUNTU so thats why this is here
        task = pid_task(find_vpid(pid), PIDTYPE_PID); 
        printk("%d .\n", task);
    
        if(task == NULL) {
            printk("Cannot find PID from user program\r\n");
            return 0;
        }
    
        send_sig_info(SIGIO, &sinfo, task);
        return 0;
    }
    void cleanup_module () 
    {
        printk(KERN_ALERT"\nGoodBye World\n\n");
    }
    

    Userspace Code:

    #include <stdio.h>
    #include <stdlib.h>
    #include <signal.h>
    #include <string.h>
    
    void signal_handler(int signum)
    {
        if (signum == SIGIO) printf("SIGIO\r\n"); return;
    }
    
    int main()
    {
        int i = 1;
        signal(SIGIO, signal_handler);
        printf("My PID is %d.\n", getpid());
        
        while (i);
        return 0;
    }
    

    Now, here I am always running user space program to get PID and then I always have to edit the pid variable in Kernel module.

    I found one way to access information from user space into Kernel space and vice-versa (i.e., using copy_from/to_user() )

    But I am unable to understand either of them for getting a PID from user space, I have to make file in /dev directory and should apply all the required functions for just getting PID?

    Is there any other way? if not, then can anyone please help me to do this? I am new in c programming and playing with kernel module directly so its hard for me.