diff options
Diffstat (limited to 'mm/util.c')
| -rw-r--r-- | mm/util.c | 31 | 
1 files changed, 31 insertions, 0 deletions
| diff --git a/mm/util.c b/mm/util.c index 9af1c12b310c..2d28f7930043 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)  { | 
