1 /*
2  * Copyright (C) 2012 Linux Test Project, Inc.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of version 2 of the GNU General Public
6  * License as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it would be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11  *
12  * Further, this software is distributed without any warranty that it
13  * is free of the rightful claim of any third person regarding
14  * infringement or the like.  Any license provided herein, whether
15  * implied or otherwise, applies only to this software file.  Patent
16  * licenses, if any, provided herein do not apply to combinations of
17  * this program with other software, or any other product whatsoever.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22  * 02110-1301, USA.
23  */
24 /*
25  * Test Name: mremap05
26  *
27  * Test Description:
28  *  Verify that MREMAP_FIXED fails without MREMAP_MAYMOVE.
29  *  Verify that MREMAP_FIXED|MREMAP_MAYMOVE fails if target address
30  *    is not page aligned.
31  *  Verify that MREMAP_FIXED|MREMAP_MAYMOVE fails if old range
32  *    overlaps with new range.
33  *  Verify that MREMAP_FIXED|MREMAP_MAYMOVE can move mapping to new address.
34  *  Verify that MREMAP_FIXED|MREMAP_MAYMOVE unmaps previous mapping
35  *    at the address range specified by new_address and new_size.
36  */
37 
38 #define _GNU_SOURCE
39 #include "config.h"
40 #include <sys/mman.h>
41 #include <errno.h>
42 #include <unistd.h>
43 #include "test.h"
44 #include "safe_macros.h"
45 
46 char *TCID = "mremap05";
47 
48 #ifdef HAVE_MREMAP_FIXED
49 
50 struct test_case_t {
51 	char *old_address;
52 	char *new_address;
53 	size_t old_size;	/* in pages */
54 	size_t new_size;	/* in pages */
55 	int flags;
56 	const const char *msg;
57 	void *exp_ret;
58 	int exp_errno;
59 	char *ret;
60 	void (*setup) (struct test_case_t *);
61 	void (*cleanup) (struct test_case_t *);
62 };
63 
64 static void setup(void);
65 static void cleanup(void);
66 static void setup0(struct test_case_t *);
67 static void setup1(struct test_case_t *);
68 static void setup2(struct test_case_t *);
69 static void setup3(struct test_case_t *);
70 static void setup4(struct test_case_t *);
71 static void cleanup0(struct test_case_t *);
72 static void cleanup1(struct test_case_t *);
73 
74 struct test_case_t tdat[] = {
75 	{
76 	 .old_size = 1,
77 	 .new_size = 1,
78 	 .flags = MREMAP_FIXED,
79 	 .msg = "MREMAP_FIXED requires MREMAP_MAYMOVE",
80 	 .exp_ret = MAP_FAILED,
81 	 .exp_errno = EINVAL,
82 	 .setup = setup0,
83 	 .cleanup = cleanup0},
84 	{
85 	 .old_size = 1,
86 	 .new_size = 1,
87 	 .flags = MREMAP_FIXED | MREMAP_MAYMOVE,
88 	 .msg = "new_addr has to be page aligned",
89 	 .exp_ret = MAP_FAILED,
90 	 .exp_errno = EINVAL,
91 	 .setup = setup1,
92 	 .cleanup = cleanup0},
93 	{
94 	 .old_size = 2,
95 	 .new_size = 1,
96 	 .flags = MREMAP_FIXED | MREMAP_MAYMOVE,
97 	 .msg = "old/new area must not overlap",
98 	 .exp_ret = MAP_FAILED,
99 	 .exp_errno = EINVAL,
100 	 .setup = setup2,
101 	 .cleanup = cleanup0},
102 	{
103 	 .old_size = 1,
104 	 .new_size = 1,
105 	 .flags = MREMAP_FIXED | MREMAP_MAYMOVE,
106 	 .msg = "mremap #1",
107 	 .setup = setup3,
108 	 .cleanup = cleanup0},
109 	{
110 	 .old_size = 1,
111 	 .new_size = 1,
112 	 .flags = MREMAP_FIXED | MREMAP_MAYMOVE,
113 	 .msg = "mremap #2",
114 	 .setup = setup4,
115 	 .cleanup = cleanup1},
116 };
117 
118 static int pagesize;
119 static int TST_TOTAL = sizeof(tdat) / sizeof(tdat[0]);
120 
free_test_area(void * p,int size)121 static void free_test_area(void *p, int size)
122 {
123 	SAFE_MUNMAP(cleanup, p, size);
124 }
125 
get_test_area(int size,int free_area)126 static void *get_test_area(int size, int free_area)
127 {
128 	void *p;
129 	p = mmap(NULL, size, PROT_READ | PROT_WRITE,
130 		 MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
131 	if (p == MAP_FAILED)
132 		tst_brkm(TBROK | TERRNO, cleanup, "get_test_area mmap");
133 	if (free_area)
134 		free_test_area(p, size);
135 	return p;
136 }
137 
test_mremap(struct test_case_t * t)138 static void test_mremap(struct test_case_t *t)
139 {
140 	t->ret = mremap(t->old_address, t->old_size, t->new_size, t->flags,
141 			t->new_address);
142 
143 	if (t->ret == t->exp_ret) {
144 		if (t->ret != MAP_FAILED) {
145 			tst_resm(TPASS, "%s", t->msg);
146 			if (*(t->ret) == 0x1)
147 				tst_resm(TPASS, "%s value OK", t->msg);
148 			else
149 				tst_resm(TPASS, "%s value failed", t->msg);
150 		} else {
151 			if (errno == t->exp_errno)
152 				tst_resm(TPASS, "%s", t->msg);
153 			else
154 				tst_resm(TFAIL | TERRNO, "%s", t->msg);
155 		}
156 	} else {
157 		tst_resm(TFAIL, "%s ret: %p, expected: %p", t->msg,
158 			 t->ret, t->exp_ret);
159 	}
160 }
161 
setup0(struct test_case_t * t)162 static void setup0(struct test_case_t *t)
163 {
164 	t->old_address = get_test_area(t->old_size * pagesize, 0);
165 	t->new_address = get_test_area(t->new_size * pagesize, 1);
166 }
167 
setup1(struct test_case_t * t)168 static void setup1(struct test_case_t *t)
169 {
170 	t->old_address = get_test_area(t->old_size * pagesize, 0);
171 	t->new_address = get_test_area((t->new_size + 1) * pagesize, 1) + 1;
172 }
173 
setup2(struct test_case_t * t)174 static void setup2(struct test_case_t *t)
175 {
176 	t->old_address = get_test_area(t->old_size * pagesize, 0);
177 	t->new_address = t->old_address;
178 }
179 
setup3(struct test_case_t * t)180 static void setup3(struct test_case_t *t)
181 {
182 	t->old_address = get_test_area(t->old_size * pagesize, 0);
183 	t->new_address = get_test_area(t->new_size * pagesize, 1);
184 	t->exp_ret = t->new_address;
185 	*(t->old_address) = 0x1;
186 }
187 
setup4(struct test_case_t * t)188 static void setup4(struct test_case_t *t)
189 {
190 	t->old_address = get_test_area(t->old_size * pagesize, 0);
191 	t->new_address = get_test_area(t->new_size * pagesize, 0);
192 	t->exp_ret = t->new_address;
193 	*(t->old_address) = 0x1;
194 	*(t->new_address) = 0x2;
195 }
196 
cleanup0(struct test_case_t * t)197 static void cleanup0(struct test_case_t *t)
198 {
199 	if (t->ret == MAP_FAILED)
200 		free_test_area(t->old_address, t->old_size * pagesize);
201 	else
202 		free_test_area(t->ret, t->new_size * pagesize);
203 }
204 
cleanup1(struct test_case_t * t)205 static void cleanup1(struct test_case_t *t)
206 {
207 	if (t->ret == MAP_FAILED) {
208 		free_test_area(t->old_address, t->old_size * pagesize);
209 		free_test_area(t->new_address, t->new_size * pagesize);
210 	} else {
211 		free_test_area(t->ret, t->new_size * pagesize);
212 	}
213 }
214 
main(int ac,char ** av)215 int main(int ac, char **av)
216 {
217 	int lc, testno;
218 
219 	tst_parse_opts(ac, av, NULL, NULL);
220 
221 	setup();
222 	for (lc = 0; TEST_LOOPING(lc); lc++) {
223 		tst_count = 0;
224 		for (testno = 0; testno < TST_TOTAL; testno++) {
225 			tdat[testno].setup(&tdat[testno]);
226 			test_mremap(&tdat[testno]);
227 			tdat[testno].cleanup(&tdat[testno]);
228 		}
229 	}
230 	cleanup();
231 	tst_exit();
232 }
233 
setup(void)234 static void setup(void)
235 {
236 	pagesize = getpagesize();
237 }
238 
cleanup(void)239 static void cleanup(void)
240 {
241 }
242 
243 #else
244 
main(void)245 int main(void)
246 {
247 	tst_brkm(TCONF, NULL, "MREMAP_FIXED not present in <sys/mman.h>");
248 }
249 
250 #endif /* HAVE_MREMAP_FIXED */
251