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