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

时间:2015-05-01 07:33:24

标签: linux-kernel kernel system-calls

我正在使用systemcall和copy_to_user创建代码以将内核中的字符串传输到usermode 这是我的代码
内核

     #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-&gt; tag,sizeof(char)* task-&gt; 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;
}

3 个答案:

答案 0 :(得分:0)

我通过在用户

中创建malloc解决了我的问题

我改变了

char *b = NULL;

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

我不知道为什么这项工作正常。但是我猜copy_to_user获取字节数作为第三个参数所以我应该在分配值之前使用malloc

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

答案 1 :(得分:0)

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

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

另请注意,您在内核代码中泄漏了内存。您使用task_structkmalloc分配内存,然后在调用find_task_by_vpid()时覆盖您对此内存的唯一指针,并且永远不会释放此内存。 find_task_by_vpid()将返回一个指向已存在于内存中的task_struct的指针,因此不需要为此分配任何缓冲区。

答案 2 :(得分:0)

这是某种大学作业吗?

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

...换句话说,当你执行任务 - >标签时,任务可能已经消失。有什么要求可以访问 - &gt;标记本身?

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

这是什么? sizeof(char)保证为1。

我对这整个事业感到很困惑。

当你有一个系统调用将数据复制到用户空间时,在调用之前未知数据量,teh syscall接受缓冲区和它的大小。如果您要复制的东西不适合,则可以返回相应的错误。

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