From 6c2c97a24f096e3239bc54029b808c6bcba4f358 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 7 Jan 2018 13:00:27 -0500 Subject: memdup_user(): switch to GFP_USER Signed-off-by: Al Viro --- mm/util.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'mm') diff --git a/mm/util.c b/mm/util.c index 34e57fae..4b93ffa 100644 --- a/mm/util.c +++ b/mm/util.c @@ -156,12 +156,7 @@ void *memdup_user(const void __user *src, size_t len) { void *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, GFP_KERNEL); + p = kmalloc_track_caller(len, GFP_USER); if (!p) return ERR_PTR(-ENOMEM); -- cgit v1.1 From 50fd2f298bef9d1f69ac755f1fdf70cd98746be2 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 7 Jan 2018 13:06:15 -0500 Subject: new primitive: vmemdup_user() similar to memdup_user(), but does *not* guarantee that result will be physically contiguous; use only in cases where that's not a requirement and free it with kvfree(). Signed-off-by: Al Viro --- mm/util.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) (limited to 'mm') diff --git a/mm/util.c b/mm/util.c index 4b93ffa..c125050 100644 --- a/mm/util.c +++ b/mm/util.c @@ -150,7 +150,8 @@ EXPORT_SYMBOL(kmemdup_nul); * @src: source address in user space * @len: number of bytes to copy * - * Returns an ERR_PTR() on failure. + * Returns an ERR_PTR() on failure. Result is physically + * contiguous, to be freed by kfree(). */ void *memdup_user(const void __user *src, size_t len) { @@ -169,6 +170,32 @@ void *memdup_user(const void __user *src, size_t len) } EXPORT_SYMBOL(memdup_user); +/** + * vmemdup_user - duplicate memory region from user space + * + * @src: source address in user space + * @len: number of bytes to copy + * + * Returns an ERR_PTR() on failure. Result may be not + * physically contiguous. Use kvfree() to free. + */ +void *vmemdup_user(const void __user *src, size_t len) +{ + void *p; + + p = kvmalloc(len, GFP_USER); + if (!p) + return ERR_PTR(-ENOMEM); + + if (copy_from_user(p, src, len)) { + kvfree(p); + return ERR_PTR(-EFAULT); + } + + return p; +} +EXPORT_SYMBOL(vmemdup_user); + /* * strndup_user - duplicate an existing string from user space * @s: The string to duplicate -- cgit v1.1