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