2010-01-20 48 views
6

我想为char *分配一些内存,如下所示。如何在Linux内核中为char *类型的字符串分配内存?

static ssize_t memo_write(struct file *filp, const char __user *buf, 
    size_t count, loff_t *f_pos){ 
    ssize_t retval = -ENOMEM; 
    printk("write function\n"); 

    if((data = kmalloc(strlen(buf), GFP_KERNEL)) == NULL) 
     printk("kmalloc fail\n"); 

    if(copy_from_user(data, buf, strlen(buf))){ 
     retval = -EFAULT; 
     goto out; 
    } 
    *f_pos += strlen(buf); 
    retval = strlen(buf); 

    out: 
     return retval; 
} 

“数据”被宣布在头文件作为

char *data; 

当我调用write功能,“kmalloc的失败,”没有达到线,这使我相信,成功的kmalloc ,但是当我尝试再次读取'data'变量时,数据不会显示。

更令人困惑的是,如果我完全摆脱了kmalloc位,可以从驱动程序读取数据。虽然问题在于后面是其他数据的加载,因为我没有机会memset()它。

我是否正确使用kmalloc?大概不会。我应该怎么做?

此外,我的阅读功能如下。

static ssize_t memo_read(struct file *f, char __user *buf, 
    size_t count, loff_t *f_pos){ 
    ssize_t retval = 0; 

    printk("read function\n"); 
    printk("data = %s\n", data); 

    if(*f_pos >= strlen(data)){ 
     printk("EOF\n"); 
     goto out; 
    } 

    if(copy_to_user(buf, data, strlen(data))){ 
     retval = -EFAULT; 
     goto out; 
    } 
    printk("copy_to_user success\n"); 
    *f_pos += strlen(data); 
    retval = strlen(data); 
    out: 
     return retval; 
} 

谢谢。

+0

既感谢这些伟大的答案,这是真的有很大的帮助!如果可以的话,我会把它们都标记为所选的答案,但我会选择咖啡因为他/她包括锁定并且声誉较低:p 再次感谢! – cheesysam 2010-01-20 12:33:36

回答

9

你应该在用户空间指针使用strlen_user(),而不是strlen() - 你应该只调用一次,并保持结果左右(否则,你有一个潜在的内核漏洞,因为第二个用户空间线程可能更改缓冲区而你正在努力)。

或者,您可以使用strncpy_from_user()

除此之外,kmalloc看起来没问题。


(不过说真的,作为ephemient说,你应该重新考虑你的整个方法,并使用count参数而不是将输入的字符串)。


既然你不能依靠写入一个文件是空终止字符串数据,你需要保持周围一个data_len长度参数旁边的data。然后你read/write实现将沿着这些路线:

static char *data = NULL; 
static size_t data_len; 
static DEFINE_MUTEX(data_mutex); 

static ssize_t memo_read(struct file *f, char __user *buf, size_t count, loff_t *f_pos 
{ 
    ssize_t retval = 0; 
    char *start; 

    mutex_lock(&data_mutex); 

    if (!data) 
    { 
     retval = -EINVAL; /* Or whatever you want to do here... */ 
     goto out; 
    } 

    if (*f_pos >= data_len) 
     goto out; /* EOF */ 

    start = data + *f_pos; 
    retval = data_len - *f_pos; 

    if (retval > count) 
     retval = count; 

    if (copy_to_user(buf, start, retval)) 
    { 
     retval = -EFAULT; 
     goto out; 
    } 

    *f_pos += retval; 

out: 
    mutex_unlock(&data_mutex); 
    return retval; 
} 

static ssize_t memo_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) 
{ 
    ssize_t retval = -ENOMEM; 

    mutex_lock(&data_mutex); 

    if (data) 
     kfree(data); 

    data = kmalloc(count, GFP_KERNEL); 

    if (!data) 
     goto out; 

    if (copy_from_user(data, buf, count)) 
    { 
     kfree(data); 
     retval = -EFAULT; 
     goto out; 
    } 

    *f_pos = count; 
    retval = count; 
    data_len = count; 

out: 
    mutex_unlock(&data_mutex); 
    return retval; 
} 
+0

我想到了这一点,但大概这是在'写入'处理程序...所以为什么不使用'count'参数?不应该保证'buf'是NUL终止的。 – ephemient 2010-01-20 04:54:32

+1

非常真实 - 我已经更新了答案以表示同意(但未删除答案,因为我认为我添加的其他信息是独立有用的)。 – caf 2010-01-20 04:59:20

+0

现在你已经提到过了,使用count参数更有意义。 – cheesysam 2010-01-20 05:00:25

4

不要忘了在你的错误情况kfree(data) ...

在任何情况下,buf是一个指向用户内存,所以不要打电话strlen(buf)。您首先必须copy_from_user。为什么不是

data = kmalloc(count); 
copy_from_user(data, buf, count); 


你读的处理程序假定data是一个NULL结尾的字符串。当你使用一个数组时,这可能是错误的,但你永远不会在写处理程序中确保这一点。我的猜测是copy_to_user失败。

下面是我写了刚才用kmalloc一个“备忘录”模块的工作示例:

#include <linux/fs.h> 
#include <linux/miscdevice.h> 
#include <linux/module.h> 
#include <linux/types.h> 
#include <linux/uaccess.h> 

static char *data; 
static size_t len; 

static ssize_t 
memo_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) 
{ 
     ssize_t copy_len = min(len - min(len, *ppos), count); 
     ssize_t retval; 

     if (copy_to_user(buf, data + *ppos, copy_len)) { 
       retval = -EFAULT; 
       goto out; 
     } 

     *ppos += copy_len; 
     retval = copy_len; 

out: 
     return retval; 
} 

static ssize_t 
memo_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) 
{ 
     ssize_t retval; 
     char *newdata; 

     newdata = kmalloc(count, GFP_KERNEL); 
     if (!newdata) { 
       retval = -ENOMEM; 
       goto out; 
     } 

     if (copy_from_user(newdata, buf, count)) { 
       retval = -EFAULT; 
       goto out; 
     } 

     kfree(data); 
     data = newdata; 
     newdata = NULL; 
     retval = len = count; 

out: 
     kfree(newdata); 
     return retval; 
} 

static const struct file_operations memo_fops = { 
     .owner = THIS_MODULE, 
     .llseek = no_llseek, 
     .read = memo_read, 
     .write = memo_write, 
}; 

static struct miscdevice memo_misc = { MISC_DYNAMIC_MINOR, "memo", &memo_fops }; 

static int __init memo_init(void) 
{ 
     int result; 

     result = misc_register(&memo_misc); 
     if (result < 0) 
       return -ENODEV; 

     return 0; 
} 

static void __exit memo_exit(void) 
{ 
     misc_deregister(&memo_misc); 
     kfree(data); 
     return; 
} 

module_init(memo_init); 
module_exit(memo_exit); 
MODULE_AUTHOR("ephemient"); 
MODULE_LICENSE("GPL"); 

当然,这是缺少锁等安全防范措施,但我希望这会有所帮助。

+0

我试过这个,但是我遇到同样的问题。当我使用'cat/dev/myDriver'来查看有什么时,我写入我的驱动程序的任何内容都不会反映出来。即使它完全摆脱了kmalloc的东西。 – cheesysam 2010-01-20 05:01:28

+0

您的阅读代码中可能还存在一个错误,它只是偶然工作 - 您也可以使用您的阅读实现更新您的问题。 – caf 2010-01-20 05:04:44

+0

好吧,谢谢,你去了:) – cheesysam 2010-01-20 05:08:58

相关问题