Thread (22 messages) 22 messages, 7 authors, 2020-08-23

[PATCH 1/2] mm: add GFP mask param to strndup_user

From: Pascal Bouchareine <hidden>
Date: 2020-08-15 22:02:11
Also in: linux-api, lkml
Subsystem: dma buffer sharing framework, drm drivers, drm drivers and misc gpu patches, drm drivers for vc4, f2fs file system, filesystems (vfs and infrastructure), generic string library, input (keyboard, mouse, joystick, touchscreen) drivers, intel drm i915 driver (meteor lake, dg2 and older excluding poulsbo, moorestown and derivative), keys/keyrings, memory management, memory management - core, networking [general], nfs, sunrpc, and lockd clients, performance events subsystem, s390 architecture, security subsystem, the rest, tracing, vfio driver, xfs filesystem · Maintainers: Sumit Semwal, Christian König, David Airlie, Simona Vetter, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Dave Stevenson, Jaegeuk Kim, Chao Yu, Alexander Viro, Christian Brauner, Kees Cook, Dmitry Torokhov, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, David Howells, Jarkko Sakkinen, Andrew Morton, David Hildenbrand, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Trond Myklebust, Anna Schumaker, Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo, Namhyung Kim, Heiko Carstens, Vasily Gorbik, Alexander Gordeev, Paul Moore, James Morris, "Serge E. Hallyn", Linus Torvalds, Steven Rostedt, Masami Hiramatsu, Alex Williamson, Carlos Maiolino

Let caller specify allocation.
Preserve existing calls with GFP_USER.

Signed-off-by: Pascal Bouchareine <redacted>
---
 drivers/dma-buf/dma-buf.c                  |  2 +-
 drivers/gpu/drm/i915/i915_debugfs_params.c |  2 +-
 drivers/gpu/drm/vc4/vc4_bo.c               |  3 +-
 drivers/input/misc/uinput.c                |  2 +-
 drivers/s390/char/keyboard.c               |  3 +-
 drivers/vfio/vfio.c                        |  3 +-
 drivers/virt/fsl_hypervisor.c              |  4 +--
 fs/f2fs/file.c                             |  3 +-
 fs/fsopen.c                                |  6 ++--
 fs/namespace.c                             |  2 +-
 fs/nfs/fs_context.c                        |  8 +++--
 fs/xfs/xfs_ioctl.c                         |  2 +-
 include/linux/string.h                     |  2 +-
 kernel/events/core.c                       |  2 +-
 kernel/module.c                            |  2 +-
 kernel/trace/trace_event_perf.c            |  2 +-
 mm/util.c                                  | 34 +++++++++++++---------
 net/core/pktgen.c                          |  2 +-
 security/keys/dh.c                         |  3 +-
 security/keys/keyctl.c                     | 17 +++++++----
 security/keys/keyctl_pkey.c                |  2 +-
 21 files changed, 63 insertions(+), 43 deletions(-)
diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
index 1ca609f66fdf..3d94ba811f4b 100644
--- a/drivers/dma-buf/dma-buf.c
+++ b/drivers/dma-buf/dma-buf.c
@@ -326,7 +326,7 @@ static __poll_t dma_buf_poll(struct file *file, poll_table *poll)
  */
 static long dma_buf_set_name(struct dma_buf *dmabuf, const char __user *buf)
 {
-	char *name = strndup_user(buf, DMA_BUF_NAME_LEN);
+	char *name = strndup_user(buf, DMA_BUF_NAME_LEN, GFP_USER);
 	long ret = 0;
 
 	if (IS_ERR(name))
diff --git a/drivers/gpu/drm/i915/i915_debugfs_params.c b/drivers/gpu/drm/i915/i915_debugfs_params.c
index 62b2c5f0495d..4c0a77e15c09 100644
--- a/drivers/gpu/drm/i915/i915_debugfs_params.c
+++ b/drivers/gpu/drm/i915/i915_debugfs_params.c
@@ -142,7 +142,7 @@ static ssize_t i915_param_charp_write(struct file *file,
 	kernel_param_lock(THIS_MODULE);
 
 	old = *s;
-	new = strndup_user(ubuf, PAGE_SIZE);
+	new = strndup_user(ubuf, PAGE_SIZE, GFP_USER);
 	if (IS_ERR(new)) {
 		len = PTR_ERR(new);
 		goto out;
diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c
index 72d30d90b856..deb2c4957a6f 100644
--- a/drivers/gpu/drm/vc4/vc4_bo.c
+++ b/drivers/gpu/drm/vc4/vc4_bo.c
@@ -1072,7 +1072,8 @@ int vc4_label_bo_ioctl(struct drm_device *dev, void *data,
 	if (!args->len)
 		return -EINVAL;
 
-	name = strndup_user(u64_to_user_ptr(args->name), args->len + 1);
+	name = strndup_user(u64_to_user_ptr(args->name), args->len + 1,
+				GFP_USER);
 	if (IS_ERR(name))
 		return PTR_ERR(name);
 
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index f2593133e524..11627a4b4d87 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -926,7 +926,7 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
 			goto out;
 		}
 
-		phys = strndup_user(p, 1024);
+		phys = strndup_user(p, 1024, GFP_USER);
 		if (IS_ERR(phys)) {
 			retval = PTR_ERR(phys);
 			goto out;
diff --git a/drivers/s390/char/keyboard.c b/drivers/s390/char/keyboard.c
index 567aedc03c76..8e58921d5db4 100644
--- a/drivers/s390/char/keyboard.c
+++ b/drivers/s390/char/keyboard.c
@@ -464,7 +464,8 @@ do_kdgkb_ioctl(struct kbd_data *kbd, struct kbsentry __user *u_kbs,
 	case KDSKBSENT:
 		if (!perm)
 			return -EPERM;
-		p = strndup_user(u_kbs->kb_string, sizeof(u_kbs->kb_string));
+		p = strndup_user(u_kbs->kb_string,
+			sizeof(u_kbs->kb_string), GFP_USER);
 		if (IS_ERR(p))
 			return PTR_ERR(p);
 		kfree(kbd->func_table[kb_func]);
diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c
index 580099afeaff..d55aae6661eb 100644
--- a/drivers/vfio/vfio.c
+++ b/drivers/vfio/vfio.c
@@ -1547,7 +1547,8 @@ static long vfio_group_fops_unl_ioctl(struct file *filep,
 	{
 		char *buf;
 
-		buf = strndup_user((const char __user *)arg, PAGE_SIZE);
+		buf = strndup_user((const char __user *)arg, PAGE_SIZE,
+					GFP_USER);
 		if (IS_ERR(buf))
 			return PTR_ERR(buf);
 
diff --git a/drivers/virt/fsl_hypervisor.c b/drivers/virt/fsl_hypervisor.c
index 1b0b11b55d2a..142c74aab2b0 100644
--- a/drivers/virt/fsl_hypervisor.c
+++ b/drivers/virt/fsl_hypervisor.c
@@ -346,11 +346,11 @@ static long ioctl_dtprop(struct fsl_hv_ioctl_prop __user *p, int set)
 	upropname = (char __user *)(uintptr_t)param.propname;
 	upropval = (void __user *)(uintptr_t)param.propval;
 
-	path = strndup_user(upath, FH_DTPROP_MAX_PATHLEN);
+	path = strndup_user(upath, FH_DTPROP_MAX_PATHLEN, GFP_USER);
 	if (IS_ERR(path))
 		return PTR_ERR(path);
 
-	propname = strndup_user(upropname, FH_DTPROP_MAX_PATHLEN);
+	propname = strndup_user(upropname, FH_DTPROP_MAX_PATHLEN, GFP_USER);
 	if (IS_ERR(propname)) {
 		ret = PTR_ERR(propname);
 		goto err_free_path;
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 3268f8dd59bb..ce37a97fbca7 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -3395,7 +3395,8 @@ static int f2fs_set_volume_name(struct file *filp, unsigned long arg)
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
-	vbuf = strndup_user((const char __user *)arg, FSLABEL_MAX);
+	vbuf = strndup_user((const char __user *)arg, FSLABEL_MAX,
+				GFP_USER);
 	if (IS_ERR(vbuf))
 		return PTR_ERR(vbuf);
 
diff --git a/fs/fsopen.c b/fs/fsopen.c
index 2fa3f241b762..c17ef9ee455c 100644
--- a/fs/fsopen.c
+++ b/fs/fsopen.c
@@ -125,7 +125,7 @@ SYSCALL_DEFINE2(fsopen, const char __user *, _fs_name, unsigned int, flags)
 	if (flags & ~FSOPEN_CLOEXEC)
 		return -EINVAL;
 
-	fs_name = strndup_user(_fs_name, PAGE_SIZE);
+	fs_name = strndup_user(_fs_name, PAGE_SIZE, GFP_USER);
 	if (IS_ERR(fs_name))
 		return PTR_ERR(fs_name);
 
@@ -381,7 +381,7 @@ SYSCALL_DEFINE5(fsconfig,
 	}
 
 	if (_key) {
-		param.key = strndup_user(_key, 256);
+		param.key = strndup_user(_key, 256, GFP_USER);
 		if (IS_ERR(param.key)) {
 			ret = PTR_ERR(param.key);
 			goto out_f;
@@ -394,7 +394,7 @@ SYSCALL_DEFINE5(fsconfig,
 		break;
 	case FSCONFIG_SET_STRING:
 		param.type = fs_value_is_string;
-		param.string = strndup_user(_value, 256);
+		param.string = strndup_user(_value, 256, GFP_USER);
 		if (IS_ERR(param.string)) {
 			ret = PTR_ERR(param.string);
 			goto out_key;
diff --git a/fs/namespace.c b/fs/namespace.c
index 4a0f600a3328..1d9da91fbd2e 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -3099,7 +3099,7 @@ void *copy_mount_options(const void __user * data)
 
 char *copy_mount_string(const void __user *data)
 {
-	return data ? strndup_user(data, PATH_MAX) : NULL;
+	return data ? strndup_user(data, PATH_MAX, GFP_USER) : NULL;
 }
 
 /*
diff --git a/fs/nfs/fs_context.c b/fs/nfs/fs_context.c
index ccc88be88d6a..fcdaeca51ca9 100644
--- a/fs/nfs/fs_context.c
+++ b/fs/nfs/fs_context.c
@@ -1077,18 +1077,20 @@ static int nfs4_parse_monolithic(struct fs_context *fc,
 		} else
 			ctx->selected_flavor = RPC_AUTH_UNIX;
 
-		c = strndup_user(data->hostname.data, NFS4_MAXNAMLEN);
+		c = strndup_user(data->hostname.data, NFS4_MAXNAMLEN,
+					GFP_USER);
 		if (IS_ERR(c))
 			return PTR_ERR(c);
 		ctx->nfs_server.hostname = c;
 
-		c = strndup_user(data->mnt_path.data, NFS4_MAXPATHLEN);
+		c = strndup_user(data->mnt_path.data, NFS4_MAXPATHLEN,
+					GFP_USER);
 		if (IS_ERR(c))
 			return PTR_ERR(c);
 		ctx->nfs_server.export_path = c;
 		dfprintk(MOUNT, "NFS: MNTPATH: '%s'\n", c);
 
-		c = strndup_user(data->client_addr.data, 16);
+		c = strndup_user(data->client_addr.data, 16, GFP_USER);
 		if (IS_ERR(c))
 			return PTR_ERR(c);
 		ctx->client_address = c;
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index a190212ca85d..216ab920c6b3 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -546,7 +546,7 @@ xfs_ioc_attrmulti_one(
 	if ((flags & XFS_IOC_ATTR_ROOT) && (flags & XFS_IOC_ATTR_SECURE))
 		return -EINVAL;
 
-	name = strndup_user(uname, MAXNAMELEN);
+	name = strndup_user(uname, MAXNAMELEN, GFP_USER);
 	if (IS_ERR(name))
 		return PTR_ERR(name);
 
diff --git a/include/linux/string.h b/include/linux/string.h
index 9b7a0632e87a..3eb69aee484d 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -9,7 +9,7 @@
 #include <stdarg.h>
 #include <uapi/linux/string.h>
 
-extern char *strndup_user(const char __user *, long);
+extern char *strndup_user(const char __user *, long, gfp_t);
 extern void *memdup_user(const void __user *, size_t);
 extern void *vmemdup_user(const void __user *, size_t);
 extern void *memdup_user_nul(const void __user *, size_t);
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 856d98c36f56..3b0621563d7f 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -10072,7 +10072,7 @@ static int perf_event_set_filter(struct perf_event *event, void __user *arg)
 	int ret = -EINVAL;
 	char *filter_str;
 
-	filter_str = strndup_user(arg, PAGE_SIZE);
+	filter_str = strndup_user(arg, PAGE_SIZE, GFP_USER);
 	if (IS_ERR(filter_str))
 		return PTR_ERR(filter_str);
 
diff --git a/kernel/module.c b/kernel/module.c
index aa183c9ac0a2..566c9ddb86d3 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -3872,7 +3872,7 @@ static int load_module(struct load_info *info, const char __user *uargs,
 	flush_module_icache(mod);
 
 	/* Now copy in args */
-	mod->args = strndup_user(uargs, ~0UL >> 1);
+	mod->args = strndup_user(uargs, ~0UL >> 1, GFP_USER);
 	if (IS_ERR(mod->args)) {
 		err = PTR_ERR(mod->args);
 		goto free_arch_cleanup;
diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c
index 643e0b19920d..48569b39d1f2 100644
--- a/kernel/trace/trace_event_perf.c
+++ b/kernel/trace/trace_event_perf.c
@@ -310,7 +310,7 @@ int perf_uprobe_init(struct perf_event *p_event,
 		return -EINVAL;
 
 	path = strndup_user(u64_to_user_ptr(p_event->attr.uprobe_path),
-			    PATH_MAX);
+			    PATH_MAX, GFP_USER);
 	if (IS_ERR(path)) {
 		ret = PTR_ERR(path);
 		return (ret == -EINVAL) ? -E2BIG : ret;
diff --git a/mm/util.c b/mm/util.c
index c63c8e47be57..cec32cc6d434 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -156,20 +156,13 @@ char *kmemdup_nul(const char *s, size_t len, gfp_t gfp)
 }
 EXPORT_SYMBOL(kmemdup_nul);
 
-/**
- * memdup_user - duplicate memory region from user space
- *
- * @src: source address in user space
- * @len: number of bytes to copy
- *
- * Return: an ERR_PTR() on failure.  Result is physically
- * contiguous, to be freed by kfree().
- */
-void *memdup_user(const void __user *src, size_t len)
+static inline void *__memdup_user_flags(const void __user *src, size_t len,
+	gfp_t gfp)
 {
 	void *p;
 
-	p = kmalloc_track_caller(len, GFP_USER | __GFP_NOWARN);
+	/* Don't let users spam with big allocs and use GFP_NOWARN */
+	p = kmalloc_track_caller(len, __GFP_NOWARN | gfp);
 	if (!p)
 		return ERR_PTR(-ENOMEM);
 
@@ -180,6 +173,20 @@ void *memdup_user(const void __user *src, size_t len)
 
 	return p;
 }
+
+/**
+ * memdup_user - duplicate memory region from user space
+ *
+ * @src: source address in user space
+ * @len: number of bytes to copy
+ *
+ * Return: an ERR_PTR() on failure.  Result is physically
+ * contiguous, to be freed by kfree().
+ */
+void *memdup_user(const void __user *src, size_t len)
+{
+	return __memdup_user_flags(src, len, GFP_USER);
+}
 EXPORT_SYMBOL(memdup_user);
 
 /**
@@ -212,10 +219,11 @@ EXPORT_SYMBOL(vmemdup_user);
  * strndup_user - duplicate an existing string from user space
  * @s: The string to duplicate
  * @n: Maximum number of bytes to copy, including the trailing NUL.
+ * @gfp: the GFP mask used in the kmalloc() call when allocating memory
  *
  * Return: newly allocated copy of @s or an ERR_PTR() in case of error
  */
-char *strndup_user(const char __user *s, long n)
+char *strndup_user(const char __user *s, long n, gfp_t gfp)
 {
 	char *p;
 	long length;
@@ -228,7 +236,7 @@ char *strndup_user(const char __user *s, long n)
 	if (length > n)
 		return ERR_PTR(-EINVAL);
 
-	p = memdup_user(s, length);
+	p = __memdup_user_flags(s, length, gfp);
 
 	if (IS_ERR(p))
 		return p;
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index b53b6d38c4df..ed12433e194a 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -901,7 +901,7 @@ static ssize_t pktgen_if_write(struct file *file,
 
 	if (debug) {
 		size_t copy = min_t(size_t, count + 1, 1024);
-		char *tp = strndup_user(user_buffer, copy);
+		char *tp = strndup_user(user_buffer, copy, GFP_USER);
 
 		if (IS_ERR(tp))
 			return PTR_ERR(tp);
diff --git a/security/keys/dh.c b/security/keys/dh.c
index c4c629bb1c03..fada6015b25b 100644
--- a/security/keys/dh.c
+++ b/security/keys/dh.c
@@ -266,7 +266,8 @@ long __keyctl_dh_compute(struct keyctl_dh_params __user *params,
 		}
 
 		/* get KDF name string */
-		hashname = strndup_user(kdfcopy->hashname, CRYPTO_MAX_ALG_NAME);
+		hashname = strndup_user(kdfcopy->hashname,
+				CRYPTO_MAX_ALG_NAME, GFP_USER);
 		if (IS_ERR(hashname)) {
 			ret = PTR_ERR(hashname);
 			goto out1;
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 9febd37a168f..0f74097cdcd1 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -93,7 +93,8 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
 
 	description = NULL;
 	if (_description) {
-		description = strndup_user(_description, KEY_MAX_DESC_SIZE);
+		description = strndup_user(_description,
+				KEY_MAX_DESC_SIZE, GFP_USER);
 		if (IS_ERR(description)) {
 			ret = PTR_ERR(description);
 			goto error;
@@ -182,7 +183,8 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type,
 		goto error;
 
 	/* pull the description into kernel space */
-	description = strndup_user(_description, KEY_MAX_DESC_SIZE);
+	description = strndup_user(_description, KEY_MAX_DESC_SIZE,
+				GFP_USER);
 	if (IS_ERR(description)) {
 		ret = PTR_ERR(description);
 		goto error;
@@ -192,7 +194,8 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type,
 	callout_info = NULL;
 	callout_len = 0;
 	if (_callout_info) {
-		callout_info = strndup_user(_callout_info, PAGE_SIZE);
+		callout_info = strndup_user(_callout_info, PAGE_SIZE,
+					GFP_USER);
 		if (IS_ERR(callout_info)) {
 			ret = PTR_ERR(callout_info);
 			goto error2;
@@ -293,7 +296,7 @@ long keyctl_join_session_keyring(const char __user *_name)
 	/* fetch the name from userspace */
 	name = NULL;
 	if (_name) {
-		name = strndup_user(_name, KEY_MAX_DESC_SIZE);
+		name = strndup_user(_name, KEY_MAX_DESC_SIZE, GFP_USER);
 		if (IS_ERR(name)) {
 			ret = PTR_ERR(name);
 			goto error;
@@ -728,7 +731,8 @@ long keyctl_keyring_search(key_serial_t ringid,
 	if (ret < 0)
 		goto error;
 
-	description = strndup_user(_description, KEY_MAX_DESC_SIZE);
+	description = strndup_user(_description, KEY_MAX_DESC_SIZE,
+			GFP_USER);
 	if (IS_ERR(description)) {
 		ret = PTR_ERR(description);
 		goto error;
@@ -1742,7 +1746,8 @@ long keyctl_restrict_keyring(key_serial_t id, const char __user *_type,
 		if (ret < 0)
 			goto error;
 
-		restriction = strndup_user(_restriction, PAGE_SIZE);
+		restriction = strndup_user(_restriction, PAGE_SIZE,
+				GFP_USER);
 		if (IS_ERR(restriction)) {
 			ret = PTR_ERR(restriction);
 			goto error;
diff --git a/security/keys/keyctl_pkey.c b/security/keys/keyctl_pkey.c
index 931d8dfb4a7f..903792123a85 100644
--- a/security/keys/keyctl_pkey.c
+++ b/security/keys/keyctl_pkey.c
@@ -86,7 +86,7 @@ static int keyctl_pkey_params_get(key_serial_t id,
 	memset(params, 0, sizeof(*params));
 	params->encoding = "raw";
 
-	p = strndup_user(_info, PAGE_SIZE);
+	p = strndup_user(_info, PAGE_SIZE, GFP_USER);
 	if (IS_ERR(p))
 		return PTR_ERR(p);
 	params->info = p;
-- 
2.25.1
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help