Linux kernel 如何使用copy\u to\u user将内核中的字符串(char*)传输到用户进程中

Linux kernel 如何使用copy\u to\u user将内核中的字符串(char*)传输到用户进程中,linux-kernel,kernel,system-calls,Linux Kernel,Kernel,System Calls,我正在编写代码,使用systemcall将内核中的字符串传输到用户模式,并将\u复制到\u用户 这是我的代码 内核 #包括 #包括 #包括 #包括 #包括 ASMLINKING int sys\u getProcTagSysCall(pid\u t pid,字符**标记){ printk(“getProcTag系统调用\n\n”); struct task_struct*task=(struct task_struct*)kmalloc(sizeof(struct task_struct),GF

我正在编写代码,使用systemcall将内核中的字符串传输到用户模式,并将\u复制到\u用户 这是我的代码
内核

#包括
#包括
#包括
#包括
#包括
ASMLINKING int sys\u getProcTagSysCall(pid\u t pid,字符**标记){
printk(“getProcTag系统调用\n\n”);
struct task_struct*task=(struct task_struct*)kmalloc(sizeof(struct task_struct),GFP_内核);
读取锁定(&任务列表锁定);
task=通过vpid(pid)查找_task_;
如果(任务==NULL)
{
printk(“相应的pid任务不存在\n”);
读取\u解锁(&任务列表\u锁定);
返回-默认值;
}
读取\u解锁(&任务列表\u锁定);
printk(“存在相应的pid任务\n”);
printk(“标记是%s\n”,任务->标记);
/*
任务->标记:字符串存储在任务->标记中(例如:“abcde”)
这部分做得很好
*/
如果(复制到用户(*标记,任务->标记,大小(字符)*任务->标记长度)!=0)
;
返回1;
}
这是用户
#包括
#包括
int main()
{
char*ret=NULL;
int-pid=0;
printf(“PID:”);
scanf(“%4d”和&pid);
if(syscall(339,pid和ret)!=1)//syscall 339是getProcTagSysCall
printf(“pid%d不存在\n”,pid);
其他的
printf(“对应的pid标记是%s\n”,ret);//我的输出是%s=null
返回0;
}
事实上,我不太了解复制用户。但我认为copy_to_user(*tag,task->tag,sizeof(char)*task->tag_length)的操作与此代码类似 所以我使用上面提到的复制用户

#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;
}
#包括
int-re();
void main(){
char*b=NULL;
如果(re&b))
printf(“成功”);
printf(“%s”,b);
}
int-re(字符**str){
char*temp=“Gdg”;
*str=温度;
返回1;
}

我通过在用户界面中创建malloc解决了我的问题

我变了

char *b = NULL;

我不知道这为什么能正常工作。但正如我猜想的那样,copy_to_用户将字节数作为第三个参数,所以我应该在赋值之前使用malloc


我不知道。任何知道为什么添加malloc可以正常工作的人都告诉我,从您修复它的方式来看,这是非常明显的
copy_to_user()
将只在两个内存区域之间复制数据-一个仅可由内核访问,另一个也可由用户访问。但是,它不会处理任何内存分配。必须已经分配了用户空间缓冲区,您应该将该缓冲区的地址传递给内核

您可以更改的另一件事是将syscall更改为使用普通的指向char的指针,而不是无用的指向指针的指针


还要注意的是,内核代码中正在泄漏内存。您可以使用
kmalloc
task\u struct
分配内存,然后在调用
find\u task\u by_vpid()
时重写指向该内存的唯一指针,并且该内存永远不会被释放
find_task\u by_vpid()
将返回指向内存中已存在的任务结构的指针,因此无需为此分配任何缓冲区。

这是某种大学作业吗

   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);
通过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);   
。。。换句话说,当您执行任务->标记时,任务可能已经消失。访问->标记本身有什么要求

    if(copy_to_user(*tag, task->tag, sizeof(char) * task->tag_length) !=0) 
        ;
这是怎么回事?sizeof(char)保证为1

我真的被这整件事搞糊涂了

当您有一个将数据复制到用户空间的系统调用,而在调用之前数据量未知时,该系统调用接受缓冲区及其大小。然后,如果您试图复制的内容不适合,您可以返回相应的错误

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

    printk("Corresponding pid task exist \n");  
    printk("tag is %s\n" , task->tag);   
    if(copy_to_user(*tag, task->tag, sizeof(char) * task->tag_length) !=0) 
        ;