我正在尝试为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; }
‘data’在头文件中声明为
char *data;
当我调用write函数时,未达到’kmalloc fail’行,这使我相信kmalloc成功,但是当我尝试再次从’data’变量读取时,数据不会显示.
更令人困惑的是,如果我完全摆脱kmalloc位,可以从驱动程序中读取数据.虽然问题在于它之后是其他数据的加载,因为我没有机会memset()它.
我正确使用kmalloc吗?大概不是.我该怎么做?
另外,我的阅读功能如下.
static ssize_t memo_read(struct file *f,char __user *buf,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; }
谢谢.
解决方法
您应该在用户空间指针上使用strlen_user()而不是strlen() – 并且您应该只调用一次,并保持结果(否则,您有潜在的内核漏洞,因为第二个用户空间线程可能会更改缓冲区当你正在努力的时候).
或者,您可以使用strncpy_from_user().
除此之外,kmalloc看起来还不错.
(但实际上,正如ephemient所说,你应该重新考虑整个方法并使用count参数而不是将输入视为字符串).
由于您不能依赖写入以nul结尾的字符串的文件的数据,因此您需要在数据旁边保留data_len长度参数.那么你的读/写实现将沿着这些方向:
static char *data = NULL; static size_t data_len; static DEFINE_MUTEX(data_mutex); static ssize_t memo_read(struct file *f,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,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,count)) { kfree(data); retval = -EFAULT; goto out; } *f_pos = count; retval = count; data_len = count; out: mutex_unlock(&data_mutex); return retval; }