如何使用 copy_to_user 将内核中的字符串(char*)传输到用户进程

how to transfer string(char*) in kernel into user process using copy_to_user

我正在编写代码,使用系统调用和 copy_to_user 将内核中的字符串传输到用户模式 这是我的代码
内核

     #include<linux/kernel.h>
        #include<linux/syscalls.h>
        #include<linux/sched.h>
        #include<linux/slab.h>
        #include<linux/errno.h>


    asmlinkage int sys_getProcTagSysCall(pid_t pid, char  **tag){


        printk("getProcTag system call \n\n");
         struct task_struct *task= (struct  task_struct*) kmalloc(sizeof(struct task_struct),GFP_KERNEL);

            read_lock(&tasklist_lock);
            task = find_task_by_vpid(pid);

            if(task == NULL )
            {
                    printk("corresponding pid task does not exist\n");
                    read_unlock(&tasklist_lock);
                    return -EFAULT;
            }

            read_unlock(&tasklist_lock);

        printk("Corresponding pid task exist \n");  
        printk("tag is %s\n" , task->tag);   
/*
 task -> tag : string is stored in task->tag (ex : "abcde")
          this part is well worked
*/

        if(copy_to_user(*tag, task->tag, sizeof(char) * task->tag_length) !=0) 
            ;

        return 1;
    }


and this is user 

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


    int main()
    {
        char *ret=NULL;
        int pid = 0;
        printf("PID : ");
        scanf("%4d", &pid);

           if(syscall(339, pid, &ret)!=1)  // syscall 339 is getProcTagSysCall
            printf("pid %d does not exist\n", pid); 
        else
            printf("Corresponding pid tag is %s \n",ret);  //my output is %s = null

        return 0; 
    }

其实我不太了解copy_to_user。但我认为 copy_to_user(*tag, task->tag, sizeof(char) * task->tag_length) 像这段代码一样操作 所以我像上面那样使用copy_to_user

#include<stdio.h>

int re();

void main(){


    char *b = NULL;



    if (re(&b))
        printf("success");

    printf("%s", b);
}


int re(char **str){

    char *temp = "Gdg";
    *str = temp;

    return 1;
}

我通过在用户

中创建 malloc 解决了我的问题

我变了

char *b = NULL;

char *b = (char*)malloc(sizeof(char) * 100) 

我不知道为什么这能正常工作。但我猜 copy_to_user 将字节数作为第三个参数,所以我应该在分配值之前进行 malloc

我不知道。任何知道为什么添加 malloc 可以正常工作的人告诉我

从您修复它的方式来看很明显。 copy_to_user() 只会在两个内存区域之间复制数据 - 一个只能由内核访问,另一个也可以由用户访问。但是,它不会处理任何内存分配。用户空间缓冲区必须已经分配,​​您应该将此缓冲区的地址传递给内核。

您可以更改的另一件事是更改您的系统调用以使用指向 char 的普通指针而不是指向无用的指针的指针。

另请注意,您的内核代码正在泄漏内存。您使用 kmalloctask_struct 分配内存,然后在调用 find_task_by_vpid() 时重写指向此内存的唯一指针,并且此内存永远不会被释放。 find_task_by_vpid() 将 return 指向内存中已存在的 task_struct 的指针,因此无需为此分配任何缓冲区。

这是某种大学作业吗?

   asmlinkage int sys_getProcTagSysCall(pid_t pid, char  **tag){

这是什么,Linux 2.6?用 ** 代替 * 是怎么回事?

    printk("getProcTag system call \n\n");

有点不好。所有字符串都应该有前缀。

     struct task_struct *task= (struct  task_struct*) kmalloc(sizeof(struct task_struct),GFP_KERNEL);

这是怎么回事?铸造 malloc 没有任何意义,如果你 malloc 你应该使用 sizeof(*task) 而不是,但你不应该首先使用 malloc。你想找到一个任务,实际上你只是在几行之后覆盖了这个指针的值。

        read_lock(&tasklist_lock);
        task = find_task_by_vpid(pid);

find_task_by_vpid 需要 RCU。如果您启用了调试,内核会告诉您。

        if(task == NULL )
        {
                printk("corresponding pid task does not exist\n");
                read_unlock(&tasklist_lock);
                return -EFAULT;
        }

        read_unlock(&tasklist_lock);

所以...您解锁...但您没有获得任何类型的任务参考。

    printk("Corresponding pid task exist \n");  
    printk("tag is %s\n" , task->tag);   

... 换句话说,当您执行任务-> 标记时,任务可能已经消失了。访问 ->tag 本身有什么要求?

    if(copy_to_user(*tag, task->tag, sizeof(char) * task->tag_length) !=0) 
        ;

这是怎么回事? sizeof(char) 保证为 1.

我真的对这整件事感到困惑。

当你有一个将数据复制到用户空间的系统调用时,在调用之前不知道数据量,系统调用接受缓冲区及其大小。然后,如果您尝试复制的东西不适合,您可以 return 适当的错误。

但是,首先使用系统调用看起来是不正确的。在 linux 中,每个任务数据暴露给 /proc/pid/ 中的用户空间。弄清楚如何将文件添加到 proc 很容易,留作 reader.

的练习。