Re: [PATCH v4 17/20] mm/vma: only permit MAP_PRIVATE /dev/zero to be mapped anonymous

"David Hildenbrand (Arm)" <[email protected]>
Newsgroups org.freedesktop.lists.amd-gfx,org.freedesktop.lists.dri-devel,org.freedesktop.lists.intel-xe,org.kernel.vger.kvm,org.kernel.vger.linux-fsdevel,org.kernel.vger.linux-kernel,org.kernel.vger.linux-kselftest,org.kernel.vger.linux-perf-users,org.kernel.vger.linux-s390,org.kernel.vger.linux-trace-kernel,org.kvack.linux-mm
Message-ID <[email protected]>
>>
>> My brain is a bit slow after digging through this series.
>>
>> We identify shmem, for example, through shmem_vm_ops/shmem_anon_vm_ops.
>>
>> So naturally I am wondering: couldn't we do something similar to identify that?
>> Like, checking for zero_fops?
> 
> We don't assign vm_ops for a MAP_PRIVATE-/dev/zero mapping. So that won't work.
> 
> We could expose zero->f_ops but then it's literally in drivers/char/ and that's
> just weird to expose in mm.h or whatever.

Thinking out loud: could we use a dummy (empty) vm_ops?

We'd place it in mm.h (zero_vm_ops) and just use it in drivers/char/.

See below.

> 
> I'm giving a really minimal possible thing to export, which is the DEVZERO_MINOR
> number which avoids all kinds of weirdness like that. No driver stuff exported,
> just a number :) MEM_MAJOR is already available.
> 
> So I think it's the least bad choice in this one, very very specific scenario.

I'd hope we find something cleaner than the DEVZERO_MINOR thingy.

Something slightly cleaned up chloppedi-schlop on top of mm-unstable.

vma tests seems to still work, but I haven't boot-tested this.


From 3cdc1d205a8e10dedd99b21a5f4f3f570ba24469 Mon Sep 17 00:00:00 2001
From: "David Hildenbrand (Arm)" <[email protected]>
Date: Wed, 12 Aug 2026 19:13:32 +0200
Subject: [PATCH] tmp

Signed-off-by: David Hildenbrand (Arm) <[email protected]>
---
 drivers/char/mem.c              |  5 +++--
 include/linux/mm.h              |  4 +---
 mm/init-mm.c                    |  1 +
 mm/vma.c                        | 10 +--------
 mm/vma_internal.h               |  1 -
 tools/testing/vma/include/dup.h | 38 +--------------------------------
 tools/testing/vma/shared.c      |  1 +
 tools/testing/vma/tests/mmap.c  | 10 +++------
 8 files changed, 11 insertions(+), 59 deletions(-)

diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index dcfd896b733d8..147568c65c1be 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -506,7 +506,8 @@ static int mmap_zero_prepare(struct vm_area_desc *desc)
 	if (vma_desc_test(desc, VMA_SHARED_BIT))
 		return shmem_zero_setup_desc(desc);
 
-	/* MAP_PRIVATE semantics are taken care for us by core mm. */
+	/* Indicate MAP_PRIVATE mappings, so core mm can do the right thing. */
+	desc->vm_ops = &zero_vm_ops;
 	return 0;
 }
 
@@ -694,7 +695,7 @@ static const struct memdev {
 #ifdef CONFIG_DEVPORT
 	[4] = { "port", &port_fops, 0, 0 },
 #endif
-	[DEVZERO_MINOR] = { "zero", &zero_fops, FMODE_NOWAIT, 0666 },
+	[5] = { "zero", &zero_fops, FMODE_NOWAIT, 0666 },
 	[7] = { "full", &full_fops, 0, 0666 },
 	[8] = { "random", &random_fops, FMODE_NOWAIT, 0666 },
 	[9] = { "urandom", &urandom_fops, FMODE_NOWAIT, 0666 },
diff --git a/include/linux/mm.h b/include/linux/mm.h
index f940d20551d53..29f13cc6b52a2 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -740,9 +740,6 @@ static inline bool fault_flag_allow_retry_first(enum fault_flag flags)
 	{ FAULT_FLAG_INTERRUPTIBLE,	"INTERRUPTIBLE" }, \
 	{ FAULT_FLAG_VMA_LOCK,		"VMA_LOCK" }
 
-/* /dev/zero minor device number. Special due to MAP_PRIVATE semantics. */
-#define DEVZERO_MINOR	5
-
 /*
  * vm_fault is filled by the pagefault handler and passed to the vma's
  * ->fault function. The vma's ->fault is responsible for returning a bitmask
@@ -990,6 +987,7 @@ static inline void mm_flags_clear_all(struct mm_struct *mm)
 }
 
 extern const struct vm_operations_struct vma_dummy_vm_ops;
+extern const struct vm_operations_struct zero_vm_ops;
 
 static inline void vma_init(struct vm_area_struct *vma, struct mm_struct *mm)
 {
diff --git a/mm/init-mm.c b/mm/init-mm.c
index 3e792aad76261..2030f8e47a98a 100644
--- a/mm/init-mm.c
+++ b/mm/init-mm.c
@@ -18,6 +18,7 @@
 #endif
 
 const struct vm_operations_struct vma_dummy_vm_ops;
+const struct vm_operations_struct zero_vm_ops;
 
 /*
  * For dynamically allocated mm_structs, there is a dynamically sized cpumask
diff --git a/mm/vma.c b/mm/vma.c
index e7c8b6cb8347e..4f9b78791daf9 100644
--- a/mm/vma.c
+++ b/mm/vma.c
@@ -2623,15 +2623,7 @@ static int __mmap_new_file_vma(struct mmap_state *map,
 
 static bool map_is_dev_zero(const struct mmap_state *map)
 {
-	const struct file *file = map->file;
-	struct inode *inode;
-
-	if (!file)
-		return false;
-	inode = file_inode(file);
-	if (!S_ISCHR(inode->i_mode))
-		return false;
-	return imajor(inode) == MEM_MAJOR && iminor(inode) == DEVZERO_MINOR;
+	return map->vm_ops == &zero_vm_ops;
 }
 
 static void map_set_anon(struct mmap_state *map)
diff --git a/mm/vma_internal.h b/mm/vma_internal.h
index 385c0ab137774..4d300e7bbaf4c 100644
--- a/mm/vma_internal.h
+++ b/mm/vma_internal.h
@@ -23,7 +23,6 @@
 #include <linux/ksm.h>
 #include <linux/khugepaged.h>
 #include <linux/list.h>
-#include <linux/major.h>
 #include <linux/maple_tree.h>
 #include <linux/mempolicy.h>
 #include <linux/mm.h>
diff --git a/tools/testing/vma/include/dup.h b/tools/testing/vma/include/dup.h
index 41203b1c2323d..8457fabf53452 100644
--- a/tools/testing/vma/include/dup.h
+++ b/tools/testing/vma/include/dup.h
@@ -7,6 +7,7 @@ struct vm_area_struct;
 static inline void vma_start_write(struct vm_area_struct *vma);
 
 extern const struct vm_operations_struct vma_dummy_vm_ops;
+extern const struct vm_operations_struct zero_vm_ops;
 extern unsigned long stack_guard_gap;
 extern const struct vm_operations_struct vma_dummy_vm_ops;
 extern unsigned long rlimit(unsigned int limit);
@@ -15,21 +16,6 @@ struct task_struct *get_current(void);
 #define MMF_HAS_MDWE	28
 #define current get_current()
 
-#define MINORBITS	20
-#define MINORMASK	((1U << MINORBITS) - 1)
-
-#define MAJOR(dev)	((unsigned int) ((dev) >> MINORBITS))
-#define MINOR(dev)	((unsigned int) ((dev) & MINORMASK))
-#define MKDEV(ma, mi)	(((ma) << MINORBITS) | (mi))
-
-#define S_IFMT  00170000
-#define S_IFCHR  0020000
-
-#define S_ISCHR(m)	(((m) & S_IFMT) == S_IFCHR)
-
-#define MEM_MAJOR		1
-#define DEVZERO_MINOR	5
-
 /*
  * Define the task command name length as enum, then it can be visible to
  * BPF programs.
@@ -38,8 +24,6 @@ enum {
 	TASK_COMM_LEN = 16,
 };
 
-typedef unsigned short		umode_t;
-
 /* PARTIALLY implemented types. */
 struct mm_struct {
 	struct maple_tree mm_mt;
@@ -62,10 +46,6 @@ struct address_space {
 	unsigned long		flags;
 	atomic_t		i_mmap_writable;
 };
-struct inode {
-	umode_t			i_mode;
-	dev_t			i_rdev;
-};
 struct file_operations {
 	int (*mmap)(struct file *, struct vm_area_struct *);
 	int (*mmap_prepare)(struct vm_area_desc *);
@@ -73,7 +53,6 @@ struct file_operations {
 struct file {
 	struct address_space	*f_mapping;
 	const struct file_operations	*f_op;
-	struct inode			*f_inode;
 };
 struct anon_vma_chain {
 	struct anon_vma *anon_vma;
@@ -1665,18 +1644,3 @@ static inline pgoff_t linear_anon_page_index(const struct vm_area_struct *vma,
 
 	return pgoff;
 }
-
-static inline struct inode *file_inode(const struct file *f)
-{
-	return f->f_inode;
-}
-
-static inline unsigned iminor(const struct inode *inode)
-{
-	return MINOR(inode->i_rdev);
-}
-
-static inline unsigned imajor(const struct inode *inode)
-{
-	return MAJOR(inode->i_rdev);
-}
diff --git a/tools/testing/vma/shared.c b/tools/testing/vma/shared.c
index 4a39c9d504896..46d8d2e96bd71 100644
--- a/tools/testing/vma/shared.c
+++ b/tools/testing/vma/shared.c
@@ -9,6 +9,7 @@ unsigned long dac_mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR;
 unsigned long stack_guard_gap = 256UL<<PAGE_SHIFT;
 
 const struct vm_operations_struct vma_dummy_vm_ops;
+const struct vm_operations_struct zero_vm_ops;
 struct anon_vma dummy_anon_vma;
 struct task_struct __current;
 
diff --git a/tools/testing/vma/tests/mmap.c b/tools/testing/vma/tests/mmap.c
index ebe01362e530c..a63069d34a5a8 100644
--- a/tools/testing/vma/tests/mmap.c
+++ b/tools/testing/vma/tests/mmap.c
@@ -45,8 +45,9 @@ static bool test_mmap_region_basic(void)
 	return true;
 }
 
-static int dummy_mmap_prepare(struct vm_area_desc *desc)
+static int zero_mmap_prepare(struct vm_area_desc *desc)
 {
+	desc->vm_ops = &zero_vm_ops;
 	return 0;
 }
 
@@ -55,14 +56,9 @@ static bool test_pure_anon_dev_zero(void)
 	const vma_flags_t vma_flags = mk_vma_flags(VMA_READ_BIT, VMA_WRITE_BIT,
 			VMA_MAYREAD_BIT, VMA_MAYWRITE_BIT);
 	const struct file_operations f_op = {
-		.mmap_prepare = dummy_mmap_prepare,
-	};
-	struct inode inode = {
-		.i_mode = S_IFCHR,
-		.i_rdev = MKDEV(MEM_MAJOR, DEVZERO_MINOR),
+		.mmap_prepare = zero_mmap_prepare,
 	};
 	struct file file = {
-		.f_inode = &inode,
 		.f_op = &f_op,
 	};
 	struct mm_struct mm = {};
-- 
2.43.0



-- 
Cheers,

David
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.