如何使用 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 的普通指针而不是指向无用的指针的指针。
另请注意,您的内核代码正在泄漏内存。您使用 kmalloc
为 task_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.
的练习。
我正在编写代码,使用系统调用和 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 的普通指针而不是指向无用的指针的指针。
另请注意,您的内核代码正在泄漏内存。您使用 kmalloc
为 task_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.
的练习。