From: Al Viro Date: Thu, 24 Dec 2015 05:06:05 +0000 (-0500) Subject: new helper: memdup_user_nul() X-Git-Tag: v5.15~14438^2~39^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e9d408e107db9a554b36c3a79f67b37dd3e16da0;p=platform%2Fkernel%2Flinux-starfive.git 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: Al Viro --- diff --git a/include/linux/string.h b/include/linux/string.h index 9ef7795..9eebc66 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -10,6 +10,7 @@ extern char *strndup_user(const char __user *, long); extern void *memdup_user(const void __user *, size_t); +extern void *memdup_user_nul(const void __user *, size_t); /* * Include machine specific inline routines diff --git a/mm/util.c b/mm/util.c index 9af1c12..2d28f79 100644 --- a/mm/util.c +++ b/mm/util.c @@ -176,6 +176,37 @@ char *strndup_user(const char __user *s, long n) } 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, struct vm_area_struct *prev, struct rb_node *rb_parent) {