[PATCH RFC 24/27] alloc_tag: let procfs copy the ioctl arguments of /proc/allocinfo

From: Christian Brauner

Date: Mon Nov 02 2026 - 11:41:23 EST


Implement ->proc_ioctl_buf() so procfs copies the arguments in before
it pins the entry and back out after unpinning it. The commands encode
their arguments. procfs converts the pointers of 32-bit tasks, so
allocinfo_compat_ioctl() goes away.

Signed-off-by: Christian Brauner (Amutable) <brauner@xxxxxxxxxx>
---
mm/alloc_tag.c | 47 +++++++++++++++++------------------------------
1 file changed, 17 insertions(+), 30 deletions(-)

diff --git a/mm/alloc_tag.c b/mm/alloc_tag.c
index 788c9d7f7151..1734705e2990 100644
--- a/mm/alloc_tag.c
+++ b/mm/alloc_tag.c
@@ -6,7 +6,6 @@
#include <linux/kallsyms.h>
#include <linux/module.h>
#include <linux/mutex.h>
-#include <linux/compat.h>
#include <linux/page_ext.h>
#include <linux/pgalloc_tag.h>
#include <linux/proc_fs.h>
@@ -235,16 +234,14 @@ static void allocinfo_to_params(struct codetag *ct,
* Retrieves the unique content ID representing the current allocation tag module
* layout, allowing userspace to detect if modules were loaded / unloaded.
*/
-static int allocinfo_ioctl_get_content_id(struct seq_file *m, void __user *arg)
+static int allocinfo_ioctl_get_content_id(struct seq_file *m, void *arg)
{
struct allocinfo_content_id params;

codetag_lock_module_list(alloc_tag_cttype);
params.id = codetag_get_content_id(alloc_tag_cttype);
codetag_unlock_module_list(alloc_tag_cttype);
- if (copy_to_user(arg, &params, sizeof(params)))
- return -EFAULT;
-
+ memcpy(arg, &params, sizeof(params));
return 0;
}

@@ -309,7 +306,7 @@ static bool matches_filter(struct codetag *ct, struct allocinfo_filter *filter,
* Seeks the ioctl iterator to the specified 0-indexed tag position, reads its
* profiling data and returns it to userspace.
*/
-static int allocinfo_ioctl_get_at(struct seq_file *m, void __user *arg)
+static int allocinfo_ioctl_get_at(struct seq_file *m, void *arg)
{
struct allocinfo_private *priv;
struct codetag *ct;
@@ -318,8 +315,7 @@ static int allocinfo_ioctl_get_at(struct seq_file *m, void __user *arg)
struct alloc_tag_counters counters;
bool fetched_counters;

- if (copy_from_user(&params, arg, sizeof(params)))
- return -EFAULT;
+ memcpy(&params, arg, sizeof(params));

if (params.filter.mask & ~ALLOCINFO_FILTER_MASKS)
return -EINVAL;
@@ -374,9 +370,7 @@ static int allocinfo_ioctl_get_at(struct seq_file *m, void __user *arg)
if (!ct)
return -ENOENT;

- if (copy_to_user(arg, &params, sizeof(params)))
- return -EFAULT;
-
+ memcpy(arg, &params, sizeof(params));
return 0;
}

@@ -384,7 +378,7 @@ static int allocinfo_ioctl_get_at(struct seq_file *m, void __user *arg)
* Advances the ioctl iterator to the next allocation tag in the sequence and
* returns its profiling data to userspace.
*/
-static int allocinfo_ioctl_get_next(struct seq_file *m, void __user *arg)
+static int allocinfo_ioctl_get_next(struct seq_file *m, void *arg)
{
struct allocinfo_private *priv;
struct codetag *ct;
@@ -424,10 +418,8 @@ static int allocinfo_ioctl_get_next(struct seq_file *m, void __user *arg)
codetag_unlock_module_list(alloc_tag_cttype);
mutex_unlock(&priv->ioctl_lock);

- if (ret == 0) {
- if (copy_to_user(arg, &params, sizeof(params)))
- return -EFAULT;
- }
+ if (ret == 0)
+ memcpy(arg, &params, sizeof(params));
return ret;
}

@@ -435,10 +427,8 @@ static int allocinfo_ioctl_get_next(struct seq_file *m, void __user *arg)
* Entry point ioctl function for /proc/allocinfo routing requests to fetch the
* layout content ID, seek to a specific tag, or read sequential tags.
*/
-static long allocinfo_ioctl(struct file *file, unsigned int cmd,
- unsigned long __arg)
+static long allocinfo_ioctl(struct file *file, unsigned int cmd, void *arg)
{
- void __user *arg = (void __user *)__arg;
int ret;

switch (cmd) {
@@ -459,23 +449,20 @@ static long allocinfo_ioctl(struct file *file, unsigned int cmd,
return ret;
}

-#ifdef CONFIG_COMPAT
-static long allocinfo_compat_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- return allocinfo_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
-}
-#endif
+static const struct proc_ioctl_arg allocinfo_ioctl_args[] = {
+ PROC_IOCTL_IOC(ALLOCINFO_IOC_CONTENT_ID),
+ PROC_IOCTL_IOC(ALLOCINFO_IOC_GET_AT),
+ PROC_IOCTL_IOC(ALLOCINFO_IOC_GET_NEXT),
+};

static const struct proc_ops allocinfo_proc_ops = {
.proc_seq_ops = &allocinfo_seq_op,
.proc_state_size = sizeof(struct allocinfo_private),
.proc_open = allocinfo_open,
.proc_release = allocinfo_release,
- .proc_ioctl = allocinfo_ioctl,
-#ifdef CONFIG_COMPAT
- .proc_compat_ioctl = allocinfo_compat_ioctl,
-#endif
+ .proc_ioctl_buf = allocinfo_ioctl,
+ .proc_ioctl_args = allocinfo_ioctl_args,
+ .proc_nr_ioctl_args = ARRAY_SIZE(allocinfo_ioctl_args),
};

size_t alloc_tag_top_users(struct codetag_bytes *tags, size_t count, bool can_sleep)

--
2.53.0