0

実験として新しい syscall を実装しようとしていますが、常に segfault が発生します。問題は、ユーザー空間にない 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 のようになっています。

誰が何が悪いのか考えていますか?

4

2 に答える 2

1

コピーの宛先はユーザー空間ポインターである必要がありますが、ポインターretはカーネル空間にあります。宛先ポインターを引数としてユーザーから提供する必要があります。例を参照してください。

于 2014-11-22T13:28:57.037 に答える