2010-01-20 96 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