xref: /linux/tools/testing/vma/tests/mmap.c (revision c32fddc0a01da9627789cd5cb3add00b75081da6)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 static bool test_mmap_region_basic(void)
4 {
5 	const vma_flags_t vma_flags = mk_vma_flags(VMA_READ_BIT, VMA_WRITE_BIT,
6 			VMA_MAYREAD_BIT, VMA_MAYWRITE_BIT);
7 	struct mm_struct mm = {};
8 	unsigned long addr;
9 	struct vm_area_struct *vma;
10 	VMA_ITERATOR(vmi, &mm, 0);
11 
12 	current->mm = &mm;
13 
14 	/* Map at 0x300000, length 0x3000. */
15 	addr = __mmap_region(NULL, 0x300000, 0x3000, vma_flags, 0x300, NULL);
16 	ASSERT_EQ(addr, 0x300000);
17 
18 	/* Map at 0x250000, length 0x3000. */
19 	addr = __mmap_region(NULL, 0x250000, 0x3000, vma_flags, 0x250, NULL);
20 	ASSERT_EQ(addr, 0x250000);
21 
22 	/* Map at 0x303000, merging to 0x300000 of length 0x6000. */
23 	addr = __mmap_region(NULL, 0x303000, 0x3000, vma_flags, 0x303, NULL);
24 	ASSERT_EQ(addr, 0x303000);
25 
26 	/* Map at 0x24d000, merging to 0x250000 of length 0x6000. */
27 	addr = __mmap_region(NULL, 0x24d000, 0x3000, vma_flags, 0x24d, NULL);
28 	ASSERT_EQ(addr, 0x24d000);
29 
30 	ASSERT_EQ(mm.map_count, 2);
31 
32 	for_each_vma(vmi, vma) {
33 		if (vma->vm_start == 0x300000) {
34 			ASSERT_EQ(vma->vm_end, 0x306000);
35 			ASSERT_EQ(vma->vm_pgoff, 0x300);
36 		} else if (vma->vm_start == 0x24d000) {
37 			ASSERT_EQ(vma->vm_end, 0x253000);
38 			ASSERT_EQ(vma->vm_pgoff, 0x24d);
39 		} else {
40 			ASSERT_FALSE(true);
41 		}
42 	}
43 
44 	cleanup_mm(&mm, &vmi);
45 	return true;
46 }
47 
48 static bool mmap_region_fill_hole(bool merge)
49 {
50 	const vma_flags_t vma_flags = mk_vma_flags(VMA_READ_BIT, VMA_WRITE_BIT,
51 			VMA_MAYREAD_BIT, VMA_MAYWRITE_BIT, VMA_MAYEXEC_BIT);
52 	vma_flags_t middle_flags = vma_flags;
53 	struct mm_struct mm = {};
54 	struct vm_area_struct *vma;
55 	unsigned long addr;
56 	int count = 0;
57 	VMA_ITERATOR(vmi, &mm, 0);
58 
59 	current->mm = &mm;
60 	if (!merge)
61 		vma_flags_set(&middle_flags, VMA_EXEC_BIT);
62 
63 	/* Map at 0x300000, length 0x3000. */
64 	addr = __mmap_region(NULL, 0x300000, 0x3000, vma_flags, 0x300, NULL);
65 	ASSERT_EQ(addr, 0x300000);
66 
67 	/* Map at 0x306000, length 0x3000, leaving a hole. */
68 	addr = __mmap_region(NULL, 0x306000, 0x3000, vma_flags, 0x306, NULL);
69 	ASSERT_EQ(addr, 0x306000);
70 	ASSERT_EQ(mm.map_count, 2);
71 
72 	/* Map at 0x303000, length 0x3000, filling the hole. */
73 	addr = __mmap_region(NULL, 0x303000, 0x3000, middle_flags, 0x303, NULL);
74 	ASSERT_EQ(addr, 0x303000);
75 	ASSERT_EQ(mm.map_count, merge ? 1 : 3);
76 
77 	vma_iter_set(&vmi, 0);
78 	for_each_vma(vmi, vma) {
79 		const unsigned long start = 0x300000 + count * 0x3000;
80 		const unsigned long end = merge ? 0x309000 : start + 0x3000;
81 		/* Only the middle VMA in the non-merge case has VMA_EXEC. */
82 		const bool is_middle_vma = count == 1;
83 		const bool expect_exec_vma = is_middle_vma && !merge;
84 
85 		ASSERT_EQ(vma->vm_start, start);
86 		ASSERT_EQ(vma->vm_end, end);
87 		ASSERT_EQ(vma_start_pgoff(vma), start >> PAGE_SHIFT);
88 		ASSERT_EQ(vma_start_anon_pgoff(vma), start >> PAGE_SHIFT);
89 
90 		ASSERT_TRUE(vma_test_all(vma, VMA_READ_BIT, VMA_WRITE_BIT,
91 					 VMA_MAYREAD_BIT, VMA_MAYWRITE_BIT,
92 					 VMA_MAYEXEC_BIT));
93 		ASSERT_EQ(vma_test(vma, VMA_EXEC_BIT), expect_exec_vma);
94 
95 		count++;
96 	}
97 
98 	ASSERT_EQ(count, mm.map_count);
99 
100 	ASSERT_EQ(cleanup_mm(&mm, &vmi), count);
101 	return true;
102 }
103 
104 static bool test_mmap_region_fill_hole_merge(void)
105 {
106 	return mmap_region_fill_hole(true);
107 }
108 
109 static bool test_mmap_region_fill_hole_flags_mismatch(void)
110 {
111 	return mmap_region_fill_hole(false);
112 }
113 
114 static bool test_pure_anon_dev_zero(void)
115 {
116 	const vma_flags_t vma_flags = mk_vma_flags(VMA_READ_BIT, VMA_WRITE_BIT,
117 			VMA_MAYREAD_BIT, VMA_MAYWRITE_BIT);
118 	struct file file = {
119 		.f_op = &zero_fops,
120 	};
121 	struct mm_struct mm = {};
122 	struct vm_area_struct *vma;
123 	unsigned long addr;
124 	VMA_ITERATOR(vmi, &mm, 0);
125 
126 	current->mm = &mm;
127 
128 	/*
129 	 * Map a MAP_PRIVATE-/dev/zero mapping at address 0x300000 with a page
130 	 * offset of 0x10, which we expect to be reset to the anonymous page
131 	 * offset.
132 	 */
133 	addr = __mmap_region(&file, 0x300000, 0x3000, vma_flags, 0x10, NULL);
134 	ASSERT_EQ(addr, 0x300000);
135 
136 	/* Assert that it truly is an anonymous mapping. */
137 	vma = vma_lookup(&mm, addr);
138 	ASSERT_NE(vma, NULL);
139 	ASSERT_TRUE(vma_is_anonymous(vma));
140 	ASSERT_EQ(vma->vm_file, NULL);
141 	ASSERT_EQ(vma->vm_private_data, NULL);
142 	/* Expect anonymous page offsets. */
143 	ASSERT_EQ(vma->vm_pgoff, 0x300);
144 	ASSERT_EQ(vma_start_anon_pgoff(vma), 0x300);
145 
146 	cleanup_mm(&mm, &vmi);
147 	return true;
148 }
149 
150 static void run_mmap_tests(int *num_tests, int *num_fail)
151 {
152 	TEST(mmap_region_basic);
153 	TEST(mmap_region_fill_hole_merge);
154 	TEST(mmap_region_fill_hole_flags_mismatch);
155 	TEST(pure_anon_dev_zero);
156 }
157