xref: /illumos-gate/usr/src/test/os-tests/tests/sockfs/drop_priv.c (revision 20a7641f9918de8574b8b3b47dbe35c4bfc78df1)
1 /*
2  * Copyright 2016 Jeremy Allison
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20  * DEALINGS IN THE SOFTWARE.
21  */
22 
23 /*
24  * This is a regression test for a (former) problem in illumos
25  * where a program that tries to send on a "connected" AF_UNIX
26  * _datagram_ socket fails if: (a) the file system path used for
27  * the socket requires privileges to access, and (b) a process
28  * with privileges to access that path does a connect() to that
29  * address and then drops privileges.  In that case, a sendmsg()
30  * call where the "to" address is left blank should succeed.
31  * Before the fix for illumos 7590 that would fail.
32  *
33  * This program must be run as root.  The expected output is:
34  *
35  *	non_priv_send - sendmsg fail (expected) Permission denied
36  *	CLIENT:TEST0
37  *	SERVER:TEST0
38  *	CLIENT:TEST1
39  *	SERVER:TEST1
40  *	CLIENT:TEST2
41  *	SERVER:TEST2
42  *	CLIENT:TEST3
43  *	SERVER:TEST3
44  *	CLIENT:TEST4
45  *	SERVER:TEST4
46  *
47  * Without the fix for 7590, one would see:
48  *	non_priv_send - sendmsg fail (expected) Permission denied
49  *	CLIENT:TEST0
50  *	./sendtest - sendmsg fail Permission denied
51  */
52 
53 #include <sys/param.h>
54 #include <sys/types.h>
55 #include <sys/stat.h>
56 #include <sys/socket.h>
57 #include <sys/un.h>
58 #include <stdio.h>
59 #include <unistd.h>
60 #include <string.h>
61 #include <errno.h>
62 #include <stdint.h>
63 #include <stdlib.h>
64 
65 static int
66 server(struct sockaddr_un *addr)
67 {
68 	int ret;
69 	pid_t pid;
70 	int sock;
71 	unsigned int i;
72 
73 	pid = fork();
74 	if (pid == (pid_t)-1) {
75 		fprintf(stderr, "server - fork fail %s\n", strerror(errno));
76 		return (-1);
77 	}
78 
79 	if (pid != 0) {
80 		/* Parent. */
81 		return (0);
82 	}
83 
84 	/* Child. */
85 	sock = socket(AF_UNIX, SOCK_DGRAM, 0);
86 	if (sock == -1) {
87 		fprintf(stderr, "server - socket fail %s\n", strerror(errno));
88 		exit(1);
89 	}
90 
91 	ret = bind(sock, (struct sockaddr *)addr, sizeof (*addr));
92 
93 	if (ret == -1) {
94 		fprintf(stderr, "server - bind fail %s\n", strerror(errno));
95 		exit(1);
96 	}
97 
98 	for (i = 0; i < 5; i++) {
99 		struct iovec iov;
100 		struct msghdr msg;
101 		uint8_t buf[4096];
102 
103 		iov = (struct iovec) {
104 			.iov_base = buf,
105 			.iov_len = sizeof (buf)
106 		};
107 
108 		msg = (struct msghdr) {
109 			.msg_iov = &iov,
110 			.msg_iovlen = 1,
111 		};
112 
113 		ret = recvmsg(sock, &msg, 0);
114 		if (ret == -1) {
115 			fprintf(stderr, "server - recvmsg fail %s\n",
116 			    strerror(errno));
117 			exit(1);
118 		}
119 
120 		printf("SERVER:%s\n", (char *)msg.msg_iov->iov_base);
121 		fflush(stdout);
122 	}
123 
124 	exit(0);
125 }
126 
127 static void
128 non_priv_send(struct sockaddr_un *addr, int uid)
129 {
130 	pid_t pid;
131 	int sock;
132 	int ret;
133 	struct iovec iov;
134 	struct msghdr msg;
135 	uint8_t buf[4096];
136 
137 	pid = fork();
138 	if (pid == (pid_t)-1) {
139 		fprintf(stderr, "non_priv_send - fork fail %s\n",
140 		    strerror(errno));
141 		return;
142 	}
143 
144 	if (pid != 0) {
145 		/* Parent. */
146 		return;
147 	}
148 
149 	/* Child. */
150 	memcpy(buf, "TEST1\n", sizeof ("TEST1\n"));
151 
152 	iov = (struct iovec) {
153 		.iov_base = buf,
154 		.iov_len = sizeof (buf),
155 	};
156 
157 	msg = (struct msghdr) {
158 		.msg_name = addr,
159 		.msg_namelen = sizeof (*addr),
160 		.msg_iov = &iov,
161 		.msg_iovlen = 1,
162 	};
163 
164 	sock = socket(AF_UNIX, SOCK_DGRAM, 0);
165 	if (sock == -1) {
166 		fprintf(stderr, "non_priv_send - socket fail %s\n",
167 		    strerror(errno));
168 		exit(1);
169 	}
170 
171 	ret = setreuid(uid, uid);
172 	if (ret == -1) {
173 		fprintf(stderr, "non_priv_send - setresuid fail %s\n",
174 		    strerror(errno));
175 		exit(1);
176 	}
177 
178 	ret = sendmsg(sock, &msg, 0);
179 
180 	if (ret == -1) {
181 		printf("non_priv_send - sendmsg fail (expected) %s\n",
182 		    strerror(errno));
183 		exit(0);
184 	}
185 
186 	fprintf(stderr, "non_priv_send - UNEXPECTED sendmsg OK\n");
187 	exit(1);
188 }
189 
190 /*
191  * This should be a place only root is allowed to write.
192  * The test will create and destroy this directory.
193  */
194 char testdir[100] = "/var/run/os-tests-sockfs";
195 struct sockaddr_un addr;
196 int test_uid = UID_NOBODY;
197 
198 int
199 main(int argc, char **argv)
200 {
201 	int ret;
202 	int sock;
203 	unsigned int i;
204 	uid_t us = geteuid();
205 
206 	/* Ensure we're root. */
207 	if (us != 0) {
208 		fprintf(stderr, "%s: need to be root\n", argv[0]);
209 		exit(1);
210 	}
211 
212 	if (argc > 1) {
213 		ret = strlcpy(testdir, argv[1], sizeof (testdir));
214 		if (ret >= sizeof (testdir)) {
215 			fprintf(stderr, "%s: too long\n", argv[1]);
216 			exit(1);
217 		}
218 	}
219 
220 	addr.sun_family = AF_UNIX;
221 	(void) sprintf(addr.sun_path, "%s/s", testdir);
222 
223 	if (mkdir(testdir, 0700) != 0) {
224 		switch (errno) {
225 		case EEXIST:
226 		case EISDIR:
227 			break;
228 		default:
229 			perror(testdir);
230 			exit(1);
231 		}
232 	}
233 	(void) unlink(addr.sun_path);
234 
235 	/* Set up the server. */
236 	ret = server(&addr);
237 	if (ret == -1) {
238 		fprintf(stderr, "%s - server fork fail %s\n",
239 		    argv[0], strerror(errno));
240 		exit(1);
241 	}
242 
243 	sleep(1);
244 
245 	/* Chec non-priv client - should fail. */
246 	non_priv_send(&addr, test_uid);
247 
248 	sleep(1);
249 
250 	/* Create and connect the socket endpoint. */
251 
252 	sock = socket(AF_UNIX, SOCK_DGRAM, 0);
253 	if (sock == -1) {
254 		fprintf(stderr, "%s - socket fail %s\n",
255 		    argv[0], strerror(errno));
256 		exit(1);
257 	}
258 
259 	ret = connect(sock, (struct sockaddr *)&addr, sizeof (addr));
260 	if (ret == -1) {
261 		fprintf(stderr, "%s - connect fail %s\n",
262 		    argv[0], strerror(errno));
263 		exit(1);
264 	}
265 
266 	/*
267 	 * Now lose all privilages.
268 	 * The sendmsg() should still succeed as
269 	 * 'sock' has been connected to the endpoint,
270 	 * even though we don't have permissions as
271 	 * the non privileged user to access the
272 	 * UNIX domain socket.
273 	 */
274 
275 	ret = setreuid(test_uid, test_uid);
276 	if (ret == -1) {
277 		printf("%s - setresuid fail %s\n",
278 		    argv[0], strerror(errno));
279 		exit(1);
280 	}
281 
282 	for (i = 0; i < 5; i++) {
283 		struct iovec iov;
284 		struct msghdr msg;
285 		uint8_t buf[4096];
286 
287 		memcpy(buf, "TEST0", sizeof ("TEST0"));
288 		buf[4] = '0' + i;
289 
290 		printf("CLIENT:%s\n", buf);
291 
292 		iov = (struct iovec) {
293 			.iov_base = buf,
294 			.iov_len = sizeof (buf),
295 		};
296 
297 		msg = (struct msghdr) {
298 			/*
299 			 * If not for the dropped privileges that are
300 			 * the essential feature of this test, a more
301 			 * common practice would be to fill in the
302 			 * .msg_name, .msg_namelen fields here.
303 			 * However, when we've dropped privileges,
304 			 * and when we do specify the "to" address,
305 			 * the kernel does permission checks and the
306 			 * sendmsg fails with permission denied.
307 			 * So long as we do _not_ fill in the "to"
308 			 * address, send on a connected dgram socket
309 			 * is supposed to work.  Before the fix for
310 			 * illumos 7590, that would fail.
311 			 */
312 			.msg_iov = &iov,
313 			.msg_iovlen = 1,
314 		};
315 
316 		ret = sendmsg(sock, &msg, 0);
317 
318 		if (ret == -1) {
319 			fprintf(stderr, "%s - sendmsg fail %s\n",
320 			    argv[0], strerror(errno));
321 			exit(1);
322 		}
323 
324 		fflush(stdout);
325 		sleep(1);
326 	}
327 
328 	close(sock);
329 	return (0);
330 }
331