我正在尝试实施一个新的syscall作为实验,但是我总是遇到段错误。我认为问题是我试图返回一个指向不在用户空间中的char数组的指针。
我尝试通过使用GFP_USER作为kmalloc的标志在用户空间中分配内存,但是问题仍然相同。

这就是我调用syscall的方式,目前无法更改它(通常将分配内存以供返回,并将其作为参数提供):

#include <errno.h>
#include <linux/unistd.h>
#include <linux/mysyscall.h>

main() {
  printf("Returned: %s\n", mycall("user string arg"));

}


syscall函数的定义如下所示:

#include <linux/mysyscall.h>
#include <linux/kernel.h>
#include <linux/unistd.h>
#include <linux/slab.h>
#include <asm/uaccess.h>

asmlinkage char* sys_mycall (char * str_in) {
    int size = 0;

    printk(KERN_INFO "Starting mycall.\n");
    size = strnlen_user(str_in, 255);
    printk(KERN_INFO "size = %d\n", size);
    char str[size];
    char *ret;
    ret = kmalloc(size, GFP_ATOMIC | GFP_USER);

    if(str != NULL){
        copy_from_user(str, str_in, size);
        printk(KERN_INFO "Copied string.\n");
    }else{
        printk(KERN_ERR "str is NULL!!!\n");
        return -EFAULT;
    }

    // Doing operations on str

    int acc = access_ok(VERIFY_WRITE, ret, size);
    if(acc){
        printk(KERN_ERR "Not accessible!\n");
        return -EFAULT;
    }

    int len = copy_to_user(ret, str, size);
    if(len){
        printk(KERN_ERR "Could not copy! len = %d\n", len);
        return -EFAULT;
    }

    return ret;
}


我已经对其进行了大量测试,并且确定可以正确调用syscall,但是copy_to_user存在问题。
copy_to_user始终返回正值(等于大小,因此根本不会复制)。
顺便说一下,ret的地址就像f74ce400和str_in 080484ac。

有人知道出什么事了吗?

最佳答案

副本的目的地应该是用户空间指针,而指针ret则位于内核空间中。您应该从用户那里提供目标指针作为参数。参见例如:


Source code example from "Linux kernel programming"

10-07 19:26
查看更多