• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017  Red Hat, Inc.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of
7  * the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it would be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  */
15 
16 /*
17  *  Based on Linux/tools/testing/selftests/memfd/memfd_test.c
18  *  by David Herrmann <dh.herrmann@gmail.com>
19  *
20  *  24/02/2017   Port to LTP    <jracek@redhat.com>
21  */
22 
23 #define _GNU_SOURCE
24 
25 #include <errno.h>
26 #include "tst_test.h"
27 #include "memfd_create_common.h"
28 
29 /*
30  * Do few basic sealing tests to see whether setting/retrieving seals works.
31  */
test_basic(int fd)32 static void test_basic(int fd)
33 {
34 	/* add basic seals */
35 	CHECK_MFD_HAS_SEALS(fd, 0);
36 	CHECK_MFD_ADD_SEALS(fd, F_SEAL_SHRINK | F_SEAL_WRITE);
37 	CHECK_MFD_HAS_SEALS(fd, F_SEAL_SHRINK | F_SEAL_WRITE);
38 
39 	/* add them again */
40 	CHECK_MFD_ADD_SEALS(fd, F_SEAL_SHRINK | F_SEAL_WRITE);
41 	CHECK_MFD_HAS_SEALS(fd, F_SEAL_SHRINK | F_SEAL_WRITE);
42 
43 	/* add more seals and seal against sealing */
44 	CHECK_MFD_ADD_SEALS(fd, F_SEAL_GROW | F_SEAL_SEAL);
45 	CHECK_MFD_HAS_SEALS(fd, F_SEAL_SHRINK | F_SEAL_GROW |
46 			F_SEAL_WRITE | F_SEAL_SEAL);
47 
48 	/* verify that sealing no longer works */
49 	CHECK_MFD_FAIL_ADD_SEALS(fd, F_SEAL_GROW);
50 	CHECK_MFD_FAIL_ADD_SEALS(fd, 0);
51 }
52 
53 /*
54  * Verify that no sealing is possible when memfd is created without
55  * MFD_ALLOW_SEALING flag.
56  */
test_no_sealing_without_flag(int fd)57 static void test_no_sealing_without_flag(int fd)
58 {
59 	CHECK_MFD_HAS_SEALS(fd, F_SEAL_SEAL);
60 	CHECK_MFD_FAIL_ADD_SEALS(fd,
61 		F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE);
62 	CHECK_MFD_HAS_SEALS(fd, F_SEAL_SEAL);
63 }
64 
65 /*
66  * Test SEAL_WRITE
67  * Test whether SEAL_WRITE actually prevents modifications.
68  */
test_seal_write(int fd)69 static void test_seal_write(int fd)
70 {
71 	CHECK_MFD_HAS_SEALS(fd, 0);
72 	CHECK_MFD_ADD_SEALS(fd, F_SEAL_WRITE);
73 	CHECK_MFD_HAS_SEALS(fd, F_SEAL_WRITE);
74 
75 	CHECK_MFD_READABLE(fd);
76 	CHECK_MFD_NON_WRITEABLE(fd);
77 	CHECK_MFD_SHRINKABLE(fd);
78 	CHECK_MFD_GROWABLE(fd);
79 	CHECK_MFD_NON_GROWABLE_BY_WRITE(fd);
80 }
81 
82 /*
83  * Test SEAL_SHRINK
84  * Test whether SEAL_SHRINK actually prevents shrinking
85  */
test_seal_shrink(int fd)86 static void test_seal_shrink(int fd)
87 {
88 	CHECK_MFD_HAS_SEALS(fd, 0);
89 	CHECK_MFD_ADD_SEALS(fd, F_SEAL_SHRINK);
90 	CHECK_MFD_HAS_SEALS(fd, F_SEAL_SHRINK);
91 
92 	CHECK_MFD_READABLE(fd);
93 	CHECK_MFD_WRITEABLE(fd);
94 	CHECK_MFD_NON_SHRINKABLE(fd);
95 	CHECK_MFD_GROWABLE(fd);
96 	CHECK_MFD_GROWABLE_BY_WRITE(fd);
97 }
98 
99 /*
100  * Test SEAL_GROW
101  * Test whether SEAL_GROW actually prevents growing
102  */
test_seal_grow(int fd)103 static void test_seal_grow(int fd)
104 {
105 	CHECK_MFD_HAS_SEALS(fd, 0);
106 	CHECK_MFD_ADD_SEALS(fd, F_SEAL_GROW);
107 	CHECK_MFD_HAS_SEALS(fd, F_SEAL_GROW);
108 
109 	CHECK_MFD_READABLE(fd);
110 	CHECK_MFD_WRITEABLE(fd);
111 	CHECK_MFD_SHRINKABLE(fd);
112 	CHECK_MFD_NON_GROWABLE(fd);
113 	CHECK_MFD_NON_GROWABLE_BY_WRITE(fd);
114 }
115 
116 /*
117  * Test SEAL_SHRINK | SEAL_GROW
118  * Test whether SEAL_SHRINK | SEAL_GROW actually prevents resizing
119  */
test_seal_resize(int fd)120 static void test_seal_resize(int fd)
121 {
122 	CHECK_MFD_HAS_SEALS(fd, 0);
123 	CHECK_MFD_ADD_SEALS(fd, F_SEAL_SHRINK | F_SEAL_GROW);
124 	CHECK_MFD_HAS_SEALS(fd, F_SEAL_SHRINK | F_SEAL_GROW);
125 
126 	CHECK_MFD_READABLE(fd);
127 	CHECK_MFD_WRITEABLE(fd);
128 	CHECK_MFD_NON_SHRINKABLE(fd);
129 	CHECK_MFD_NON_GROWABLE(fd);
130 	CHECK_MFD_NON_GROWABLE_BY_WRITE(fd);
131 }
132 
133 /*
134  * Test sharing via dup()
135  * Test that seals are shared between dupped FDs and they're all equal.
136  */
test_share_dup(int fd)137 static void test_share_dup(int fd)
138 {
139 	int fd2;
140 
141 	CHECK_MFD_HAS_SEALS(fd, 0);
142 
143 	fd2 = SAFE_DUP(fd);
144 	CHECK_MFD_HAS_SEALS(fd2, 0);
145 
146 	CHECK_MFD_ADD_SEALS(fd, F_SEAL_WRITE);
147 	CHECK_MFD_HAS_SEALS(fd, F_SEAL_WRITE);
148 	CHECK_MFD_HAS_SEALS(fd2, F_SEAL_WRITE);
149 
150 	CHECK_MFD_ADD_SEALS(fd2, F_SEAL_SHRINK);
151 	CHECK_MFD_HAS_SEALS(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
152 	CHECK_MFD_HAS_SEALS(fd2, F_SEAL_WRITE | F_SEAL_SHRINK);
153 
154 	CHECK_MFD_ADD_SEALS(fd, F_SEAL_SEAL);
155 	CHECK_MFD_HAS_SEALS(fd, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
156 	CHECK_MFD_HAS_SEALS(fd2, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
157 
158 	CHECK_MFD_FAIL_ADD_SEALS(fd, F_SEAL_GROW);
159 	CHECK_MFD_FAIL_ADD_SEALS(fd2, F_SEAL_GROW);
160 	CHECK_MFD_FAIL_ADD_SEALS(fd, F_SEAL_SEAL);
161 	CHECK_MFD_FAIL_ADD_SEALS(fd2, F_SEAL_SEAL);
162 
163 	SAFE_CLOSE(fd2);
164 
165 	CHECK_MFD_FAIL_ADD_SEALS(fd, F_SEAL_GROW);
166 }
167 
168 /*
169  * Test sealing with active mmap()s
170  * Modifying seals is only allowed if no other mmap() refs exist.
171  */
test_share_mmap(int fd)172 static void test_share_mmap(int fd)
173 {
174 	void *p;
175 
176 	CHECK_MFD_HAS_SEALS(fd, 0);
177 
178 	/* shared/writable ref prevents sealing WRITE, but allows others */
179 	p = SAFE_MMAP(NULL, MFD_DEF_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
180 		fd, 0);
181 
182 	CHECK_MFD_FAIL_ADD_SEALS(fd, F_SEAL_WRITE);
183 	CHECK_MFD_HAS_SEALS(fd, 0);
184 	CHECK_MFD_ADD_SEALS(fd, F_SEAL_SHRINK);
185 	CHECK_MFD_HAS_SEALS(fd, F_SEAL_SHRINK);
186 	SAFE_MUNMAP(p, MFD_DEF_SIZE);
187 
188 	/* readable ref allows sealing */
189 	p = SAFE_MMAP(NULL, MFD_DEF_SIZE, PROT_READ, MAP_PRIVATE, fd, 0);
190 	CHECK_MFD_ADD_SEALS(fd, F_SEAL_WRITE);
191 	CHECK_MFD_HAS_SEALS(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
192 	SAFE_MUNMAP(p, MFD_DEF_SIZE);
193 }
194 
195 /*
196  * Test sealing with open(/proc/self/fd/%d)
197  * Via /proc we can get access to a separate file-context for the same memfd.
198  * This is *not* like dup(), but like a real separate open(). Make sure the
199  * semantics are as expected and we correctly check for RDONLY / WRONLY / RDWR.
200  */
test_share_open(int fd)201 static void test_share_open(int fd)
202 {
203 	int fd2;
204 
205 	CHECK_MFD_HAS_SEALS(fd, 0);
206 
207 	fd2 = CHECK_MFD_OPEN(fd, O_RDWR, 0);
208 	CHECK_MFD_ADD_SEALS(fd, F_SEAL_WRITE);
209 	CHECK_MFD_HAS_SEALS(fd, F_SEAL_WRITE);
210 	CHECK_MFD_HAS_SEALS(fd2, F_SEAL_WRITE);
211 
212 	CHECK_MFD_ADD_SEALS(fd2, F_SEAL_SHRINK);
213 	CHECK_MFD_HAS_SEALS(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
214 	CHECK_MFD_HAS_SEALS(fd2, F_SEAL_WRITE | F_SEAL_SHRINK);
215 
216 	SAFE_CLOSE(fd);
217 	fd = CHECK_MFD_OPEN(fd2, O_RDONLY, 0);
218 
219 	CHECK_MFD_FAIL_ADD_SEALS(fd, F_SEAL_SEAL);
220 	CHECK_MFD_HAS_SEALS(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
221 	CHECK_MFD_HAS_SEALS(fd2, F_SEAL_WRITE | F_SEAL_SHRINK);
222 
223 	SAFE_CLOSE(fd2);
224 }
225 
226 
227 static const struct tcase {
228 	int flags;
229 	void (*func)(int fd);
230 	const char *desc;
231 } tcases[] = {
232 	{MFD_ALLOW_SEALING, &test_basic, "Basic tests + set/get seals"},
233 	{0,                 &test_no_sealing_without_flag, "Disabled sealing"},
234 
235 	{MFD_ALLOW_SEALING, &test_seal_write, "Write seal"},
236 	{MFD_ALLOW_SEALING, &test_seal_shrink, "Shrink seal"},
237 	{MFD_ALLOW_SEALING, &test_seal_grow, "Grow seal"},
238 	{MFD_ALLOW_SEALING, &test_seal_resize, "Resize seal"},
239 
240 	{MFD_ALLOW_SEALING, &test_share_dup, "Seals shared for dup"},
241 	{MFD_ALLOW_SEALING, &test_share_mmap, "Seals shared for mmap"},
242 	{MFD_ALLOW_SEALING, &test_share_open, "Seals shared for open"},
243 };
244 
verify_memfd_create(unsigned int n)245 static void verify_memfd_create(unsigned int n)
246 {
247 	int fd;
248 	const struct tcase *tc;
249 
250 	tc = &tcases[n];
251 
252 	tst_res(TINFO, "%s", tc->desc);
253 
254 	fd = CHECK_MFD_NEW(TCID, MFD_DEF_SIZE, tc->flags);
255 
256 	tc->func(fd);
257 
258 	SAFE_CLOSE(fd);
259 }
260 
setup(void)261 static void setup(void)
262 {
263 	/*
264 	 * For now, all tests in this file require MFD_ALLOW_SEALING flag
265 	 * to be implemented, even though that flag isn't always set when
266 	 * memfd is created. So don't check anything else and TCONF right away
267 	 * is this flag is missing.
268 	 */
269 	if (!MFD_FLAGS_AVAILABLE(MFD_ALLOW_SEALING)) {
270 		tst_brk(TCONF | TTERRNO,
271 			"memfd_create(%u) not implemented", MFD_ALLOW_SEALING);
272 	}
273 }
274 
275 static struct tst_test test = {
276 	.test = verify_memfd_create,
277 	.tcnt = ARRAY_SIZE(tcases),
278 	.setup = setup,
279 };
280