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
server(struct sockaddr_un * addr)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
non_priv_send(struct sockaddr_un * addr,int uid)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
main(int argc,char ** argv)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