xref: /freebsd/tools/regression/priv/priv_vfs_read_write.c (revision f0a75d274af375d15b97b830966b99a02b7db911)
1 /*-
2  * Copyright (c) 2006 nCircle Network Security, Inc.
3  * All rights reserved.
4  *
5  * This software was developed by Robert N. M. Watson for the TrustedBSD
6  * Project under contract to nCircle Network Security, Inc.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR, NCIRCLE NETWORK SECURITY,
21  * INC., OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
23  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31 
32 /*
33  * This is a joint test of both the read and write privileges with respect to
34  * discretionary file system access control (permissions).  Only permissions,
35  * not ACL semantics, and only privilege-related checks are performed.
36  */
37 
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 
41 #include <err.h>
42 #include <errno.h>
43 #include <fcntl.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47 
48 #include "main.h"
49 
50 struct test_arguments {
51 	int	open_flags;
52 	uid_t	proc_uid;
53 	gid_t	proc_gid;
54 	uid_t	file_uid;
55 	gid_t	file_gid;
56 };
57 
58 /*
59  * Rather special-purpose, don't reuse.  Will need updating if anything other
60  * than O_RDONLY and O_WRONLY are to be used in tests.
61  */
62 static const char *
63 flags_to_string(int flags)
64 {
65 
66 	switch (flags) {
67 	case O_RDONLY:
68 		return ("O_RDONLY");
69 
70 	case O_WRONLY:
71 		return ("O_WRONLY");
72 
73 	default:
74 		return ("unknown");
75 	}
76 }
77 
78 static void
79 test_perm(struct test_arguments ta, mode_t file_mode, int expected)
80 {
81 	uid_t proc_uid, file_uid;
82 	gid_t proc_gid, file_gid;
83 	int fd, open_flags;
84 	char fpath[1024];
85 
86 	proc_uid = ta.proc_uid;
87 	proc_gid = ta.proc_gid;
88 	file_uid = ta.file_uid;
89 	file_gid = ta.file_gid;
90 	open_flags = ta.open_flags;
91 
92 	setup_file(fpath, file_uid, file_gid, file_mode);
93 	set_creds(proc_uid, proc_gid);
94 
95 	fd = open(fpath, open_flags);
96 
97 	if (expected == 0) {
98 		if (fd <= 0) {
99 			warn("test_perm(%s, %d, %d, %d, %d, %04o, %d) "
100 			    "returned %d instead of %d",
101 			    flags_to_string(open_flags), proc_uid, proc_gid,
102 			    file_uid, file_gid, file_mode, expected,
103 			    errno, expected);
104 			restore_creds();
105 			(void)unlink(fpath);
106 			exit(-1);
107 		}
108 		close(fd);
109 	} else {
110 		if (fd >= 0) {
111 			warnx("test_perm(%s, %d, %d, %d, %d, %04o, %d)"
112 			    " returned 0 instead of %d",
113 			    flags_to_string(open_flags), proc_uid, proc_gid,
114 			    file_uid, file_gid, file_mode, expected,
115 			    expected);
116 			close(fd);
117 			restore_creds();
118 			(void)unlink(fpath);
119 			exit(-1);
120 		} else if (errno != expected) {
121 			warn("test_perm(%s, %d, %d, %d, %d, %04o, %d)"
122 			    " returned %d instead of %d",
123 			    flags_to_string(open_flags), proc_uid, proc_gid,
124 			    file_uid, file_gid, file_mode, expected,
125 			    errno, expected);
126 			restore_creds();
127 			(void)unlink(fpath);
128 			exit(-1);
129 		}
130 	}
131 
132 	restore_creds();
133 	(void)unlink(fpath);
134 }
135 
136 static const gid_t gidset[] = { GID_WHEEL };
137 
138 static void
139 preamble(void)
140 {
141 
142 	if (getuid() != UID_ROOT)
143 		errx(-1, "must be run as root");
144 	if (setgroups(1, gidset) < 0)
145 		err(-1, "setgroups(1, {%d})", GID_WHEEL);
146 }
147 
148 void
149 priv_vfs_read(void)
150 {
151 	struct test_arguments ta;
152 
153 	preamble();
154 
155 	ta.open_flags = O_RDONLY;
156 
157 	/*
158 	 * Privileged user and file owner.  All tests should pass.
159 	 */
160 	ta.proc_uid = UID_ROOT;
161 	ta.proc_gid = GID_WHEEL;
162 	ta.file_uid = UID_ROOT;
163 	ta.file_gid = GID_WHEEL;
164 
165 	test_perm(ta, 0000, 0);
166 	test_perm(ta, 0100, 0);
167 	test_perm(ta, 0200, 0);
168 	test_perm(ta, 0300, 0);
169 	test_perm(ta, 0400, 0);
170 	test_perm(ta, 0500, 0);
171 	test_perm(ta, 0600, 0);
172 	test_perm(ta, 0700, 0);
173 
174 	/*
175 	 * Privileged user and file group.  All tests should pass.
176 	 */
177 	ta.proc_uid = UID_ROOT;
178 	ta.proc_gid = GID_WHEEL;
179 	ta.file_uid = UID_OWNER;
180 	ta.file_gid = GID_WHEEL;
181 
182 	test_perm(ta, 0000, 0);
183 	test_perm(ta, 0010, 0);
184 	test_perm(ta, 0020, 0);
185 	test_perm(ta, 0030, 0);
186 	test_perm(ta, 0040, 0);
187 	test_perm(ta, 0050, 0);
188 	test_perm(ta, 0060, 0);
189 	test_perm(ta, 0070, 0);
190 
191 	/*
192 	 * Privileged user and file other.  All tests should pass.
193 	 */
194 	ta.proc_uid = UID_ROOT;
195 	ta.proc_gid = GID_WHEEL;
196 	ta.file_uid = UID_OWNER;
197 	ta.file_gid = GID_OWNER;
198 
199 	test_perm(ta, 0000, 0);
200 	test_perm(ta, 0001, 0);
201 	test_perm(ta, 0002, 0);
202 	test_perm(ta, 0003, 0);
203 	test_perm(ta, 0004, 0);
204 	test_perm(ta, 0005, 0);
205 	test_perm(ta, 0006, 0);
206 	test_perm(ta, 0007, 0);
207 
208 	/*
209 	 * Unprivileged user and file owner.  Various DAC failures.
210 	 */
211 	ta.proc_uid = UID_OWNER;
212 	ta.proc_gid = GID_OWNER;
213 	ta.file_uid = UID_OWNER;
214 	ta.file_gid = GID_OWNER;
215 
216 	test_perm(ta, 0000, EACCES);
217 	test_perm(ta, 0100, EACCES);
218 	test_perm(ta, 0200, EACCES);
219 	test_perm(ta, 0300, EACCES);
220 	test_perm(ta, 0400, 0);
221 	test_perm(ta, 0500, 0);
222 	test_perm(ta, 0600, 0);
223 	test_perm(ta, 0700, 0);
224 
225 	/*
226 	 * Unprivileged user and file group.  Various DAC failures.
227 	 */
228 	ta.proc_uid = UID_OTHER;
229 	ta.proc_gid = GID_OWNER;
230 	ta.file_uid = UID_OWNER;
231 	ta.file_gid = GID_OWNER;
232 
233 	test_perm(ta, 0000, EACCES);
234 	test_perm(ta, 0010, EACCES);
235 	test_perm(ta, 0020, EACCES);
236 	test_perm(ta, 0030, EACCES);
237 	test_perm(ta, 0040, 0);
238 	test_perm(ta, 0050, 0);
239 	test_perm(ta, 0060, 0);
240 	test_perm(ta, 0070, 0);
241 
242 	/*
243 	 * Unprivileged user and file other.  Various DAC failures.
244 	 */
245 	ta.proc_uid = UID_OTHER;
246 	ta.proc_gid = GID_OTHER;
247 	ta.file_uid = UID_OWNER;
248 	ta.file_gid = GID_OWNER;
249 
250 	test_perm(ta, 0000, EACCES);
251 	test_perm(ta, 0001, EACCES);
252 	test_perm(ta, 0002, EACCES);
253 	test_perm(ta, 0003, EACCES);
254 	test_perm(ta, 0004, 0);
255 	test_perm(ta, 0005, 0);
256 	test_perm(ta, 0006, 0);
257 	test_perm(ta, 0007, 0);
258 }
259 
260 void
261 priv_vfs_write(void)
262 {
263 	struct test_arguments ta;
264 
265 	preamble();
266 
267 	ta.open_flags = O_WRONLY;
268 
269 	/*
270 	 * Privileged user and file owner.  All tests should pass.
271 	 */
272 	ta.proc_uid = UID_ROOT;
273 	ta.proc_gid = GID_WHEEL;
274 	ta.file_uid = UID_ROOT;
275 	ta.file_gid = GID_WHEEL;
276 
277 	test_perm(ta, 0000, 0);
278 	test_perm(ta, 0100, 0);
279 	test_perm(ta, 0200, 0);
280 	test_perm(ta, 0300, 0);
281 	test_perm(ta, 0400, 0);
282 	test_perm(ta, 0500, 0);
283 	test_perm(ta, 0600, 0);
284 	test_perm(ta, 0700, 0);
285 
286 	/*
287 	 * Privileged user and file group.  All tests should pass.
288 	 */
289 	ta.proc_uid = UID_ROOT;
290 	ta.proc_gid = GID_WHEEL;
291 	ta.file_uid = UID_OWNER;
292 	ta.file_gid = GID_WHEEL;
293 
294 	test_perm(ta, 0000, 0);
295 	test_perm(ta, 0010, 0);
296 	test_perm(ta, 0020, 0);
297 	test_perm(ta, 0030, 0);
298 	test_perm(ta, 0040, 0);
299 	test_perm(ta, 0050, 0);
300 	test_perm(ta, 0060, 0);
301 	test_perm(ta, 0070, 0);
302 
303 	/*
304 	 * Privileged user and file other.  All tests should pass.
305 	 */
306 	ta.proc_uid = UID_ROOT;
307 	ta.proc_gid = GID_WHEEL;
308 	ta.file_uid = UID_OWNER;
309 	ta.file_gid = GID_OWNER;
310 
311 	test_perm(ta, 0000, 0);
312 	test_perm(ta, 0001, 0);
313 	test_perm(ta, 0002, 0);
314 	test_perm(ta, 0003, 0);
315 	test_perm(ta, 0004, 0);
316 	test_perm(ta, 0005, 0);
317 	test_perm(ta, 0006, 0);
318 	test_perm(ta, 0007, 0);
319 
320 	/*
321 	 * Unprivileged user and file owner.  Various DAC failures.
322 	 */
323 	ta.proc_uid = UID_OWNER;
324 	ta.proc_gid = GID_OWNER;
325 	ta.file_uid = UID_OWNER;
326 	ta.file_gid = GID_OWNER;
327 
328 	test_perm(ta, 0000, EACCES);
329 	test_perm(ta, 0100, EACCES);
330 	test_perm(ta, 0200, 0);
331 	test_perm(ta, 0300, 0);
332 	test_perm(ta, 0400, EACCES);
333 	test_perm(ta, 0500, EACCES);
334 	test_perm(ta, 0600, 0);
335 	test_perm(ta, 0700, 0);
336 
337 	/*
338 	 * Unprivileged user and file group.  Various DAC failures.
339 	 */
340 	ta.proc_uid = UID_OTHER;
341 	ta.proc_gid = GID_OWNER;
342 	ta.file_uid = UID_OWNER;
343 	ta.file_gid = GID_OWNER;
344 
345 	test_perm(ta, 0000, EACCES);
346 	test_perm(ta, 0010, EACCES);
347 	test_perm(ta, 0020, 0);
348 	test_perm(ta, 0030, 0);
349 	test_perm(ta, 0040, EACCES);
350 	test_perm(ta, 0050, EACCES);
351 	test_perm(ta, 0060, 0);
352 	test_perm(ta, 0070, 0);
353 
354 	/*
355 	 * Unprivileged user and file other.  Various DAC failures.
356 	 */
357 	ta.proc_uid = UID_OTHER;
358 	ta.proc_gid = GID_OTHER;
359 	ta.file_uid = UID_OWNER;
360 	ta.file_gid = GID_OWNER;
361 
362 	test_perm(ta, 0000, EACCES);
363 	test_perm(ta, 0001, EACCES);
364 	test_perm(ta, 0002, 0);
365 	test_perm(ta, 0003, 0);
366 	test_perm(ta, 0004, EACCES);
367 	test_perm(ta, 0005, EACCES);
368 	test_perm(ta, 0006, 0);
369 	test_perm(ta, 0007, 0);
370 }
371