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 */
32static 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 */
57static 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 */
69static 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 */
86static 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 */
103static 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 */
120static 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 */
137static 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 */
172static 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 */
201static 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
227static 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
245static 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
261static 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
275static struct tst_test test = {
276	.test = verify_memfd_create,
277	.tcnt = ARRAY_SIZE(tcases),
278	.setup = setup,
279};
280