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