linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 0/2] proc,fcntl: introduce F_SET_DESCRIPTION
@ 2020-08-14  3:54 Pascal Bouchareine
  2020-08-14  3:54 ` [PATCH v4 1/2] mm: add GFP mask param to strndup_user Pascal Bouchareine
  2020-08-14  3:54 ` [PATCH v4 2/2] fcntl: introduce F_SET_DESCRIPTION Pascal Bouchareine
  0 siblings, 2 replies; 5+ messages in thread
From: Pascal Bouchareine @ 2020-08-14  3:54 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-fsdevel, linux-api, Andrew Morton, Alexey Dobriyan,
	Al Viro, Jeff Layton, J. Bruce Fields, Pascal Bouchareine

This is a first attempt at taking Alexey's comments into account

This goes against v5.8

tl;dr in commit 2/2 but motivation is also described a bit in
https://lore.kernel.org/linux-api/CAGbU3_nVvuzMn2wo4_ZKufWcGfmGsopVujzTWw-Bbeky=xS+GA@mail.gmail.com/



^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v4 1/2] mm: add GFP mask param to strndup_user
  2020-08-14  3:54 [PATCH v4 0/2] proc,fcntl: introduce F_SET_DESCRIPTION Pascal Bouchareine
@ 2020-08-14  3:54 ` Pascal Bouchareine
  2020-08-14  3:54 ` [PATCH v4 2/2] fcntl: introduce F_SET_DESCRIPTION Pascal Bouchareine
  1 sibling, 0 replies; 5+ messages in thread
From: Pascal Bouchareine @ 2020-08-14  3:54 UTC (permalink / raw)
  To: linux-kernel
  Cc: Pascal Bouchareine, linux-fsdevel, linux-api, Andrew Morton,
	Alexey Dobriyan, Al Viro, Jeff Layton, J. Bruce Fields

Let caller specify allocation.
Keep the existing calls with GFP_USER, and enforce the existing
defense against log spam from userspace with __GFP_NOWARN.

Signed-off-by: Pascal Bouchareine <kalou@tfz.net>
---
 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..1d61dcee510d 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


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH v4 2/2] fcntl: introduce F_SET_DESCRIPTION
  2020-08-14  3:54 [PATCH v4 0/2] proc,fcntl: introduce F_SET_DESCRIPTION Pascal Bouchareine
  2020-08-14  3:54 ` [PATCH v4 1/2] mm: add GFP mask param to strndup_user Pascal Bouchareine
@ 2020-08-14  3:54 ` Pascal Bouchareine
  2020-08-14  5:28   ` Christoph Hellwig
  1 sibling, 1 reply; 5+ messages in thread
From: Pascal Bouchareine @ 2020-08-14  3:54 UTC (permalink / raw)
  To: linux-kernel
  Cc: Pascal Bouchareine, linux-fsdevel, linux-api, Andrew Morton,
	Alexey Dobriyan, Al Viro, Jeff Layton, J. Bruce Fields

This command attaches a description to a file descriptor for
troubleshooting purposes. The free string is displayed in the
process fdinfo file for that fd /proc/pid/fdinfo/fd.

One intended usage is to allow processes to self-document sockets
for netstat and friends to report

Signed-off-by: Pascal Bouchareine <kalou@tfz.net>
---
 fs/fcntl.c                 | 21 +++++++++++++++++++++
 fs/file_table.c            |  2 ++
 fs/proc/fd.c               |  5 +++++
 include/linux/fs.h         |  3 +++
 include/uapi/linux/fcntl.h |  5 +++++
 5 files changed, 36 insertions(+)

diff --git a/fs/fcntl.c b/fs/fcntl.c
index 2e4c0fa2074b..9fbeaaf02802 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -319,6 +319,24 @@ static long fcntl_rw_hint(struct file *file, unsigned int cmd,
 	}
 }
 
+static long fcntl_set_description(struct file *file, char __user *desc)
+{
+	char *d, *old;
+
+	d = strndup_user(desc, MAX_FILE_DESC_SIZE, GFP_KERNEL_ACCOUNT);
+	if (IS_ERR(d))
+		return PTR_ERR(d);
+
+	spin_lock(&file->f_lock);
+	old = file->f_description;
+	file->f_description = d;
+	spin_unlock(&file->f_lock);
+
+	kfree(old);
+
+	return 0;
+}
+
 static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
 		struct file *filp)
 {
@@ -426,6 +444,9 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
 	case F_SET_FILE_RW_HINT:
 		err = fcntl_rw_hint(filp, cmd, arg);
 		break;
+	case F_SET_DESCRIPTION:
+		err = fcntl_set_description(filp, argp);
+		break;
 	default:
 		break;
 	}
diff --git a/fs/file_table.c b/fs/file_table.c
index 656647f9575a..6673a48d2ea1 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -272,6 +272,8 @@ static void __fput(struct file *file)
 	eventpoll_release(file);
 	locks_remove_file(file);
 
+	kfree(file->f_description);
+
 	ima_file_free(file);
 	if (unlikely(file->f_flags & FASYNC)) {
 		if (file->f_op->fasync)
diff --git a/fs/proc/fd.c b/fs/proc/fd.c
index 81882a13212d..60b3ff971b2b 100644
--- a/fs/proc/fd.c
+++ b/fs/proc/fd.c
@@ -57,6 +57,11 @@ static int seq_show(struct seq_file *m, void *v)
 		   (long long)file->f_pos, f_flags,
 		   real_mount(file->f_path.mnt)->mnt_id);
 
+	spin_lock(&file->f_lock);
+	if (file->f_description)
+		seq_printf(m, "desc:\t%s\n", file->f_description);
+	spin_unlock(&file->f_lock);
+
 	show_fd_locks(m, file, files);
 	if (seq_has_overflowed(m))
 		goto out;
diff --git a/include/linux/fs.h b/include/linux/fs.h
index f5abba86107d..a2a683d603b6 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -980,6 +980,9 @@ struct file {
 	struct address_space	*f_mapping;
 	errseq_t		f_wb_err;
 	errseq_t		f_sb_err; /* for syncfs */
+
+#define MAX_FILE_DESC_SIZE 256
+	char			*f_description;
 } __randomize_layout
   __attribute__((aligned(4)));	/* lest something weird decides that 2 is OK */
 
diff --git a/include/uapi/linux/fcntl.h b/include/uapi/linux/fcntl.h
index 2f86b2ad6d7e..465385e52f49 100644
--- a/include/uapi/linux/fcntl.h
+++ b/include/uapi/linux/fcntl.h
@@ -55,6 +55,11 @@
 #define F_GET_FILE_RW_HINT	(F_LINUX_SPECIFIC_BASE + 13)
 #define F_SET_FILE_RW_HINT	(F_LINUX_SPECIFIC_BASE + 14)
 
+/*
+ * Set file description
+ */
+#define F_SET_DESCRIPTION      (F_LINUX_SPECIFIC_BASE + 15)
+
 /*
  * Valid hint values for F_{GET,SET}_RW_HINT. 0 is "not set", or can be
  * used to clear any hints previously set.
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH v4 2/2] fcntl: introduce F_SET_DESCRIPTION
  2020-08-14  3:54 ` [PATCH v4 2/2] fcntl: introduce F_SET_DESCRIPTION Pascal Bouchareine
@ 2020-08-14  5:28   ` Christoph Hellwig
  2020-08-14  5:48     ` Pascal Bouchareine
  0 siblings, 1 reply; 5+ messages in thread
From: Christoph Hellwig @ 2020-08-14  5:28 UTC (permalink / raw)
  To: Pascal Bouchareine
  Cc: linux-kernel, linux-fsdevel, linux-api, Andrew Morton,
	Alexey Dobriyan, Al Viro, Jeff Layton, J. Bruce Fields

On Thu, Aug 13, 2020 at 08:54:53PM -0700, Pascal Bouchareine wrote:
> This command attaches a description to a file descriptor for
> troubleshooting purposes. The free string is displayed in the
> process fdinfo file for that fd /proc/pid/fdinfo/fd.
> 
> One intended usage is to allow processes to self-document sockets
> for netstat and friends to report

NAK.  There is no way we're going to bloat a criticial structure like
struct file for some vanity information like this.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v4 2/2] fcntl: introduce F_SET_DESCRIPTION
  2020-08-14  5:28   ` Christoph Hellwig
@ 2020-08-14  5:48     ` Pascal Bouchareine
  0 siblings, 0 replies; 5+ messages in thread
From: Pascal Bouchareine @ 2020-08-14  5:48 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: linux-kernel, linux-fsdevel, linux-api, Andrew Morton,
	Alexey Dobriyan, Al Viro, Jeff Layton, J. Bruce Fields

On Thu, Aug 13, 2020 at 10:28 PM Christoph Hellwig <hch@infradead.org> wrote:
> > One intended usage is to allow processes to self-document sockets
> > for netstat and friends to report
>
> NAK.  There is no way we're going to bloat a criticial structure like
> struct file for some vanity information like this.

The useful case is for sockets - Is there a more suited place to do that?
Do you think adding a setsockopt and sk_description to struct sock
would work, or would be considered the same?

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2020-08-14  5:49 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-08-14  3:54 [PATCH v4 0/2] proc,fcntl: introduce F_SET_DESCRIPTION Pascal Bouchareine
2020-08-14  3:54 ` [PATCH v4 1/2] mm: add GFP mask param to strndup_user Pascal Bouchareine
2020-08-14  3:54 ` [PATCH v4 2/2] fcntl: introduce F_SET_DESCRIPTION Pascal Bouchareine
2020-08-14  5:28   ` Christoph Hellwig
2020-08-14  5:48     ` Pascal Bouchareine

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).