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