xref: /openbsd-src/regress/sys/kern/pledge/generic/main.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: main.c,v 1.8 2015/10/30 07:24:20 semarie Exp $ */
2 /*
3  * Copyright (c) 2015 Sebastien Marie <semarie@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/mman.h>
19 #include <sys/resource.h>
20 #include <sys/socket.h>
21 #include <sys/stat.h>
22 #include <sys/time.h>
23 #include <sys/types.h>
24 #include <sys/wait.h>
25 
26 #include <err.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <limits.h>
30 #include <signal.h>
31 #include <stdarg.h>
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <time.h>
36 #include <unistd.h>
37 
38 #include "manager.h"
39 
40 void test_request_stdio(void);
41 void test_request_tty(void);
42 
43 static void
44 test_nop()
45 {
46 	/* nop */
47 }
48 
49 static void
50 test_inet()
51 {
52 	int fd = socket(AF_INET, SOCK_STREAM, 0);
53 	int saved_errno = errno;
54 	close(fd);
55 	errno = saved_errno ? saved_errno : errno;
56 }
57 
58 static void
59 test_kill()
60 {
61 	kill(0, SIGINT);
62 }
63 
64 static void
65 open_close(const char *filename)
66 {
67 	int fd;
68 	int saved_errno;
69 
70 	errno = 0;
71 	printf("\n open_close(\"%s\")", filename);
72 	fd = open(filename, O_RDONLY);
73 	saved_errno = errno;
74 	printf(" fd=%d errno=%d", fd, errno);
75 	if (fd != -1)
76 		close(fd);
77 	errno = saved_errno;
78 }
79 
80 static void
81 test_wpaths()
82 {
83 	/* absolute file */
84 	open_close("/etc/passwd");
85 
86 	/* relative */
87 	open_close("generic");
88 
89 	/* relative */
90 	open_close("../../../../../../../../../../../../../../../etc/passwd");
91 
92 	/* ENOENT */
93 	open_close("/nonexistent");
94 
95 	/* calling exit to flush stdout */
96 	printf("\n");
97 	exit(EXIT_SUCCESS);
98 }
99 
100 static void
101 test_pledge()
102 {
103 	const char *wpaths[] = { "/sbin", NULL };
104 
105 	if (pledge("stdio rpath", wpaths) != 0)
106 		_exit(errno);
107 }
108 
109 static void
110 do_stat(const char *path)
111 {
112 	char resolved[PATH_MAX];
113 	struct stat sb;
114 
115 	printf("\n stat(\"%s\"):", path);
116 
117 	/* call realpath(3) */
118 	errno = 0;
119 	if (realpath(path, resolved) != NULL)
120 		printf(" realpath=\"%s\"", resolved);
121 	else
122 		printf(" realpath=failed(%d)", errno);
123 
124 	/* call stat(2) */
125 	errno = 0;
126 	if (stat(path, &sb) == 0)
127 		printf(" uid=%d gid=%d mode=%04o", sb.st_uid, sb.st_gid,
128 		    sb.st_mode);
129 	else
130 		printf(" errno=%d", errno);
131 }
132 
133 static void
134 test_stat()
135 {
136 	/* in whitelisted path */
137 	do_stat("/usr/share/man/man8/afterboot.8");
138 	do_stat("/usr/share/man/man8/");
139 	do_stat("/usr/share/man");
140 
141 	/* parent of whitelisted path */
142 	do_stat("/usr/share");
143 	do_stat("/usr");
144 	do_stat("/");
145 
146 	/* outside whitelisted path */
147 	do_stat("/usr/bin/gzip");
148 
149 	/* calling exit to flush stdout */
150 	printf("\n");
151 	exit(EXIT_SUCCESS);
152 }
153 
154 static void
155 test_mmap()
156 {
157 	int fd;
158 	void * data;
159 
160 	if ((fd = open("/dev/zero", O_RDONLY, 0)) == -1)
161 		_exit(errno);
162 
163 	data = mmap(NULL, 4096, PROT_READ|PROT_WRITE|PROT_EXEC,
164 	    MAP_FILE|MAP_SHARED, fd, 0);
165 
166 	if (data == MAP_FAILED)
167 		_exit(errno);
168 
169 	munmap(data, 4096);
170 	close(fd);
171 }
172 
173 static void
174 test_rpath()
175 {
176 	int fd;
177 	char data[512];
178 
179 	if ((fd = open("/dev/zero", O_RDONLY, 0)) == -1)
180 		_exit(errno);
181 
182 	if (read(fd, data, sizeof(data)) == -1)
183 		_exit(errno);
184 
185 	close(fd);
186 }
187 
188 static void
189 test_wpath()
190 {
191 	int fd;
192 	char data[] = { 0x01, 0x02, 0x03, 0x04, 0x05 };
193 
194 	if ((fd = open("/dev/null", O_WRONLY, 0)) == -1)
195 		_exit(errno);
196 
197 	if (write(fd, data, sizeof(data)) == -1)
198 		_exit(errno);
199 
200 	close(fd);
201 }
202 
203 static void
204 test_cpath()
205 {
206 	const char filename[] = "/tmp/generic-test-cpath";
207 
208 	if (mkdir(filename, S_IRWXU) == -1)
209 		_exit(errno);
210 
211 	if (rmdir(filename) == -1)
212 		_exit(errno);
213 }
214 
215 int
216 main(int argc, char *argv[])
217 {
218 	int ret = EXIT_SUCCESS;
219 
220 	if (argc != 1)
221 		errx(1, "usage: %s", argv[0]);
222 
223 	/*
224 	 * testsuite
225 	 */
226 
227 	/* _exit is always allowed, and nothing else under flags=0 */
228 	start_test(&ret, "", NULL, test_nop);
229 	start_test(&ret, "", NULL, test_inet);
230 
231 	/* test coredump */
232 	start_test(&ret, "abort", NULL, test_inet);
233 
234 	/* inet under inet is ok (stdio is needed of close(2)) */
235 	start_test(&ret, "stdio", NULL, test_inet);
236 	start_test(&ret, "inet", NULL, test_inet);
237 	start_test(&ret, "stdio inet", NULL, test_inet);
238 
239 	/* kill under fattr is forbidden */
240 	start_test(&ret, "fattr", NULL, test_kill);
241 
242 	/* kill under stdio is allowed */
243 	start_test(&ret, "stdio", NULL, test_kill);
244 
245 	/* stdio for open(2) */
246 	start_test(&ret, "stdio rpath", NULL, test_rpath);
247 	start_test(&ret, "stdio wpath", NULL, test_wpath);
248 	start_test(&ret, "cpath", NULL, test_cpath);
249 
250 	/*
251 	 * test whitelist path
252 	 */
253 	start_test(&ret, "stdio rpath", NULL, test_wpaths);
254 	start_test1(&ret, "stdio rpath", NULL, test_wpaths);
255 	start_test1(&ret, "stdio rpath", "/", test_wpaths);
256 	start_test1(&ret, "stdio rpath", "/etc", test_wpaths);
257 	start_test1(&ret, "stdio rpath", "/etc/", test_wpaths);
258 	start_test1(&ret, "stdio rpath", "/etc/passwd", test_wpaths);
259 	// XXX start_test1(&ret, "stdio rpath", "/etc/passwd/", test_wpaths);
260 	start_test1(&ret, "stdio rpath", "/bin", test_wpaths);
261 	start_test1(&ret, "stdio rpath", "generic", test_wpaths);
262 	start_test1(&ret, "stdio rpath", "", test_wpaths);
263 	start_test1(&ret, "stdio rpath", ".", test_wpaths);
264 
265 	/*
266 	 * test pledge(2) arguments
267 	 */
268 	/* same request */
269 	start_test(&ret, "stdio rpath", NULL, test_pledge);
270 	/* reduce request */
271 	start_test(&ret, "stdio rpath wpath", NULL, test_pledge);
272 	/* reduce request (with same/other wpaths) */
273 	start_test1(&ret, "stdio rpath wpath", "/sbin", test_pledge);
274 	start_test1(&ret, "stdio rpath wpath", "/", test_pledge);
275 	/* add request */
276 	start_test(&ret, "stdio", NULL, test_pledge);
277 	/* change request */
278 	start_test(&ret, "stdio unix", NULL, test_pledge);
279 
280 	/* test stat(2) */
281 	start_test1(&ret, "stdio rpath", "/usr/share/man", test_stat);
282 
283 	/* mmap */
284 	start_test1(&ret, "stdio rpath prot_exec", "/dev/zero", test_mmap);
285 	start_test1(&ret, "stdio rpath", "/dev/zero", test_mmap);
286 
287 	/* stdio */
288 	start_test(&ret, NULL, NULL, test_request_stdio);
289 
290 	/* tty */
291 	start_test(&ret, NULL, NULL, test_request_tty);
292 
293 	return (ret);
294 }
295