I’m trying to allocate some memory for a char* as follows.
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’ is declared in a header file as
char *data;
When I call the write function, the ‘kmalloc fail’ line isn’t reached, which leads me to believe the kmalloc succeeded, however the data isn’t displayed when I try to read from the ‘data’ variable again.
More confusingly, if I get rid of the kmalloc bit altogether, the data can be read from the driver. Although the problem then is it is followed by a load of other data because i don’t have the opportunity to memset() it.
Am I using kmalloc correctly? Presumably not. How should I be doing this?
Additionally, my read function is as follows.
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;
}
Thanks.
You should be using
strlen_user()on the userspace pointer, instead ofstrlen()– and you should only call it once, and keep the result around (otherwise, you have a potential kernel exploit, because a second userspace thread could change the buffer while you’re working on it).Alternatively, you could use
strncpy_from_user().Apart from that, the
kmalloclooks OK.(But really, as ephemient says, you should rethink your whole approach and use the
countargument instead of treating the input as a string).Since you can’t rely on the data written to a file being nul-terminated strings, you’ll need to keep a
data_lenlength parameter around alongside thedata. Then yourread/writeimplementations would be along these lines: