Commit e9d408e1 authored by Al Viro's avatar Al Viro

new helper: memdup_user_nul()

Similar to memdup_user(), except that allocated buffer is one byte
longer and '\0' is stored after the copied data.
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 74bf8efb
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
extern char *strndup_user(const char __user *, long); extern char *strndup_user(const char __user *, long);
extern void *memdup_user(const void __user *, size_t); extern void *memdup_user(const void __user *, size_t);
extern void *memdup_user_nul(const void __user *, size_t);
/* /*
* Include machine specific inline routines * Include machine specific inline routines
......
...@@ -176,6 +176,37 @@ char *strndup_user(const char __user *s, long n) ...@@ -176,6 +176,37 @@ char *strndup_user(const char __user *s, long n)
} }
EXPORT_SYMBOL(strndup_user); EXPORT_SYMBOL(strndup_user);
/**
* memdup_user_nul - duplicate memory region from user space and NUL-terminate
*
* @src: source address in user space
* @len: number of bytes to copy
*
* Returns an ERR_PTR() on failure.
*/
void *memdup_user_nul(const void __user *src, size_t len)
{
char *p;
/*
* Always use GFP_KERNEL, since copy_from_user() can sleep and
* cause pagefault, which makes it pointless to use GFP_NOFS
* or GFP_ATOMIC.
*/
p = kmalloc_track_caller(len + 1, GFP_KERNEL);
if (!p)
return ERR_PTR(-ENOMEM);
if (copy_from_user(p, src, len)) {
kfree(p);
return ERR_PTR(-EFAULT);
}
p[len] = '\0';
return p;
}
EXPORT_SYMBOL(memdup_user_nul);
void __vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma, void __vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma,
struct vm_area_struct *prev, struct rb_node *rb_parent) struct vm_area_struct *prev, struct rb_node *rb_parent)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment