1 /*- 2 * Copyright (c) 2012 The FreeBSD Foundation 3 * 4 * This software was developed by Pawel Jakub Dawidek under sponsorship from 5 * the FreeBSD Foundation. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/param.h> 30 #include <sys/capsicum.h> 31 #include <sys/ioctl.h> 32 #include <sys/procdesc.h> 33 #include <sys/socket.h> 34 #include <sys/wait.h> 35 36 #include <err.h> 37 #include <errno.h> 38 #include <limits.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <unistd.h> 42 43 #include "misc.h" 44 45 static void 46 ioctl_tests_0(int fd) 47 { 48 unsigned long cmds[2]; 49 50 CHECK(cap_ioctls_get(fd, NULL, 0) == CAP_IOCTLS_ALL); 51 52 CHECK(fcntl(fd, F_GETFD) == 0); 53 CHECK(ioctl(fd, FIOCLEX) == 0); 54 CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC); 55 CHECK(ioctl(fd, FIONCLEX) == 0); 56 CHECK(fcntl(fd, F_GETFD) == 0); 57 58 cmds[0] = FIOCLEX; 59 cmds[1] = FIONCLEX; 60 CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == 0); 61 cmds[0] = cmds[1] = 0; 62 CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == nitems(cmds)); 63 CHECK((cmds[0] == FIOCLEX && cmds[1] == FIONCLEX) || 64 (cmds[0] == FIONCLEX && cmds[1] == FIOCLEX)); 65 cmds[0] = FIOCLEX; 66 cmds[1] = FIONCLEX; 67 CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == 0); 68 cmds[0] = cmds[1] = 0; 69 CHECK(cap_ioctls_get(fd, cmds, 1) == nitems(cmds)); 70 CHECK(cmds[0] == FIOCLEX || cmds[0] == FIONCLEX); 71 CHECK(cmds[1] == 0); 72 73 CHECK(fcntl(fd, F_GETFD) == 0); 74 CHECK(ioctl(fd, FIOCLEX) == 0); 75 CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC); 76 CHECK(ioctl(fd, FIONCLEX) == 0); 77 CHECK(fcntl(fd, F_GETFD) == 0); 78 79 cmds[0] = FIOCLEX; 80 CHECK(cap_ioctls_limit(fd, cmds, 1) == 0); 81 cmds[0] = cmds[1] = 0; 82 CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 1); 83 CHECK(cmds[0] == FIOCLEX); 84 cmds[0] = FIOCLEX; 85 cmds[1] = FIONCLEX; 86 errno = 0; 87 CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == -1); 88 CHECK(errno == ENOTCAPABLE); 89 cmds[0] = cmds[1] = 0; 90 CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 1); 91 CHECK(cmds[0] == FIOCLEX); 92 93 CHECK(fcntl(fd, F_GETFD) == 0); 94 CHECK(ioctl(fd, FIOCLEX) == 0); 95 CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC); 96 errno = 0; 97 CHECK(ioctl(fd, FIONCLEX) == -1); 98 CHECK(errno == ENOTCAPABLE); 99 CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC); 100 CHECK(fcntl(fd, F_SETFD, 0) == 0); 101 CHECK(fcntl(fd, F_GETFD) == 0); 102 103 CHECK(cap_ioctls_limit(fd, NULL, 0) == 0); 104 CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0); 105 cmds[0] = FIOCLEX; 106 errno = 0; 107 CHECK(cap_ioctls_limit(fd, cmds, 1) == -1); 108 CHECK(errno == ENOTCAPABLE); 109 CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0); 110 111 CHECK(fcntl(fd, F_GETFD) == 0); 112 errno = 0; 113 CHECK(ioctl(fd, FIOCLEX) == -1); 114 CHECK(errno == ENOTCAPABLE); 115 CHECK(fcntl(fd, F_GETFD) == 0); 116 CHECK(fcntl(fd, F_SETFD, FD_CLOEXEC) == 0); 117 CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC); 118 errno = 0; 119 CHECK(ioctl(fd, FIONCLEX) == -1); 120 CHECK(errno == ENOTCAPABLE); 121 CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC); 122 CHECK(fcntl(fd, F_SETFD, 0) == 0); 123 CHECK(fcntl(fd, F_GETFD) == 0); 124 } 125 126 static void 127 ioctl_tests_1(int fd) 128 { 129 unsigned long cmds[2]; 130 cap_rights_t rights; 131 132 cmds[0] = FIOCLEX; 133 CHECK(cap_ioctls_limit(fd, cmds, 1) == 0); 134 cmds[0] = cmds[1] = 0; 135 CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 1); 136 CHECK(cmds[0] == FIOCLEX); 137 CHECK(cmds[1] == 0); 138 139 CAP_ALL(&rights); 140 cap_rights_clear(&rights, CAP_IOCTL); 141 142 CHECK(cap_rights_limit(fd, &rights) == 0); 143 CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0); 144 145 cmds[0] = FIOCLEX; 146 cmds[1] = FIONCLEX; 147 errno = 0; 148 CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == -1); 149 CHECK(errno == ENOTCAPABLE); 150 CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0); 151 cmds[0] = FIOCLEX; 152 errno = 0; 153 CHECK(cap_ioctls_limit(fd, cmds, 1) == -1); 154 CHECK(errno == ENOTCAPABLE); 155 CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0); 156 157 CHECK(fcntl(fd, F_GETFD) == 0); 158 errno = 0; 159 CHECK(ioctl(fd, FIOCLEX) == -1); 160 CHECK(errno == ENOTCAPABLE); 161 CHECK(fcntl(fd, F_GETFD) == 0); 162 CHECK(fcntl(fd, F_SETFD, FD_CLOEXEC) == 0); 163 CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC); 164 errno = 0; 165 CHECK(ioctl(fd, FIONCLEX) == -1); 166 CHECK(errno == ENOTCAPABLE); 167 CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC); 168 CHECK(fcntl(fd, F_SETFD, 0) == 0); 169 CHECK(fcntl(fd, F_GETFD) == 0); 170 } 171 172 static void 173 ioctl_tests_2(int fd) 174 { 175 unsigned long cmds[2]; 176 cap_rights_t rights; 177 178 CAP_ALL(&rights); 179 cap_rights_clear(&rights, CAP_IOCTL); 180 181 CHECK(cap_rights_limit(fd, &rights) == 0); 182 CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0); 183 184 cmds[0] = FIOCLEX; 185 cmds[1] = FIONCLEX; 186 errno = 0; 187 CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == -1); 188 CHECK(errno == ENOTCAPABLE); 189 CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0); 190 cmds[0] = FIOCLEX; 191 errno = 0; 192 CHECK(cap_ioctls_limit(fd, cmds, 1) == -1); 193 CHECK(errno == ENOTCAPABLE); 194 CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0); 195 196 CHECK(fcntl(fd, F_GETFD) == 0); 197 errno = 0; 198 CHECK(ioctl(fd, FIOCLEX) == -1); 199 CHECK(errno == ENOTCAPABLE); 200 CHECK(fcntl(fd, F_GETFD) == 0); 201 CHECK(fcntl(fd, F_SETFD, FD_CLOEXEC) == 0); 202 CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC); 203 errno = 0; 204 CHECK(ioctl(fd, FIONCLEX) == -1); 205 CHECK(errno == ENOTCAPABLE); 206 CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC); 207 CHECK(fcntl(fd, F_SETFD, 0) == 0); 208 CHECK(fcntl(fd, F_GETFD) == 0); 209 } 210 211 static void 212 ioctl_tests_send_0(int sock) 213 { 214 unsigned long cmds[2]; 215 int fd; 216 217 CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0); 218 CHECK(descriptor_send(sock, fd) == 0); 219 CHECK(close(fd) == 0); 220 221 CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0); 222 cmds[0] = FIOCLEX; 223 cmds[1] = FIONCLEX; 224 CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == 0); 225 CHECK(descriptor_send(sock, fd) == 0); 226 CHECK(close(fd) == 0); 227 228 CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0); 229 cmds[0] = FIOCLEX; 230 CHECK(cap_ioctls_limit(fd, cmds, 1) == 0); 231 CHECK(descriptor_send(sock, fd) == 0); 232 CHECK(close(fd) == 0); 233 234 CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0); 235 CHECK(cap_ioctls_limit(fd, NULL, 0) == 0); 236 CHECK(descriptor_send(sock, fd) == 0); 237 CHECK(close(fd) == 0); 238 } 239 240 static void 241 ioctl_tests_recv_0(int sock) 242 { 243 unsigned long cmds[2]; 244 int fd; 245 246 CHECK(descriptor_recv(sock, &fd) == 0); 247 248 CHECK(cap_ioctls_get(fd, NULL, 0) == CAP_IOCTLS_ALL); 249 250 CHECK(fcntl(fd, F_GETFD) == 0); 251 CHECK(ioctl(fd, FIOCLEX) == 0); 252 CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC); 253 CHECK(ioctl(fd, FIONCLEX) == 0); 254 CHECK(fcntl(fd, F_GETFD) == 0); 255 256 CHECK(close(fd) == 0); 257 258 CHECK(descriptor_recv(sock, &fd) == 0); 259 260 cmds[0] = cmds[1] = 0; 261 CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == nitems(cmds)); 262 CHECK((cmds[0] == FIOCLEX && cmds[1] == FIONCLEX) || 263 (cmds[0] == FIONCLEX && cmds[1] == FIOCLEX)); 264 265 CHECK(fcntl(fd, F_GETFD) == 0); 266 CHECK(ioctl(fd, FIOCLEX) == 0); 267 CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC); 268 CHECK(ioctl(fd, FIONCLEX) == 0); 269 CHECK(fcntl(fd, F_GETFD) == 0); 270 271 CHECK(close(fd) == 0); 272 273 CHECK(descriptor_recv(sock, &fd) == 0); 274 275 cmds[0] = cmds[1] = 0; 276 CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 1); 277 CHECK(cmds[0] == FIOCLEX); 278 279 CHECK(fcntl(fd, F_GETFD) == 0); 280 CHECK(ioctl(fd, FIOCLEX) == 0); 281 CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC); 282 errno = 0; 283 CHECK(ioctl(fd, FIONCLEX) == -1); 284 CHECK(errno == ENOTCAPABLE); 285 CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC); 286 CHECK(fcntl(fd, F_SETFD, 0) == 0); 287 CHECK(fcntl(fd, F_GETFD) == 0); 288 289 CHECK(close(fd) == 0); 290 291 CHECK(descriptor_recv(sock, &fd) == 0); 292 293 CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0); 294 295 CHECK(fcntl(fd, F_GETFD) == 0); 296 errno = 0; 297 CHECK(ioctl(fd, FIOCLEX) == -1); 298 CHECK(errno == ENOTCAPABLE); 299 CHECK(fcntl(fd, F_GETFD) == 0); 300 CHECK(fcntl(fd, F_SETFD, FD_CLOEXEC) == 0); 301 CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC); 302 errno = 0; 303 CHECK(ioctl(fd, FIONCLEX) == -1); 304 CHECK(errno == ENOTCAPABLE); 305 CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC); 306 CHECK(fcntl(fd, F_SETFD, 0) == 0); 307 CHECK(fcntl(fd, F_GETFD) == 0); 308 309 CHECK(close(fd) == 0); 310 } 311 312 int 313 main(void) 314 { 315 int fd, pfd, sp[2]; 316 pid_t pid; 317 318 printf("1..607\n"); 319 320 CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0); 321 ioctl_tests_0(fd); 322 CHECK(close(fd) == 0); 323 324 CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0); 325 ioctl_tests_1(fd); 326 CHECK(close(fd) == 0); 327 328 CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0); 329 ioctl_tests_2(fd); 330 CHECK(close(fd) == 0); 331 332 /* Child inherits descriptor and operates on it first. */ 333 CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0); 334 pid = fork(); 335 switch (pid) { 336 case -1: 337 err(1, "fork() failed"); 338 case 0: 339 ioctl_tests_0(fd); 340 CHECK(close(fd) == 0); 341 exit(0); 342 default: 343 if (waitpid(pid, NULL, 0) == -1) 344 err(1, "waitpid() failed"); 345 ioctl_tests_0(fd); 346 } 347 CHECK(close(fd) == 0); 348 349 /* Child inherits descriptor, but operates on it after parent. */ 350 CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0); 351 pid = fork(); 352 switch (pid) { 353 case -1: 354 err(1, "fork() failed"); 355 case 0: 356 sleep(1); 357 ioctl_tests_0(fd); 358 CHECK(close(fd) == 0); 359 exit(0); 360 default: 361 ioctl_tests_0(fd); 362 if (waitpid(pid, NULL, 0) == -1) 363 err(1, "waitpid() failed"); 364 } 365 CHECK(close(fd) == 0); 366 367 /* Child inherits descriptor and operates on it first. */ 368 CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0); 369 pid = pdfork(&pfd, 0); 370 switch (pid) { 371 case -1: 372 err(1, "pdfork() failed"); 373 case 0: 374 ioctl_tests_1(fd); 375 exit(0); 376 default: 377 if (pdwait(pfd) == -1) 378 err(1, "pdwait() failed"); 379 close(pfd); 380 ioctl_tests_1(fd); 381 } 382 CHECK(close(fd) == 0); 383 384 /* Child inherits descriptor, but operates on it after parent. */ 385 CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0); 386 pid = pdfork(&pfd, 0); 387 switch (pid) { 388 case -1: 389 err(1, "pdfork() failed"); 390 case 0: 391 sleep(1); 392 ioctl_tests_1(fd); 393 exit(0); 394 default: 395 ioctl_tests_1(fd); 396 if (pdwait(pfd) == -1) 397 err(1, "pdwait() failed"); 398 close(pfd); 399 } 400 CHECK(close(fd) == 0); 401 402 /* Child inherits descriptor and operates on it first. */ 403 CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0); 404 pid = fork(); 405 switch (pid) { 406 case -1: 407 err(1, "fork() failed"); 408 case 0: 409 ioctl_tests_2(fd); 410 exit(0); 411 default: 412 if (waitpid(pid, NULL, 0) == -1) 413 err(1, "waitpid() failed"); 414 ioctl_tests_2(fd); 415 } 416 CHECK(close(fd) == 0); 417 418 /* Child inherits descriptor, but operates on it after parent. */ 419 CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0); 420 pid = fork(); 421 switch (pid) { 422 case -1: 423 err(1, "fork() failed"); 424 case 0: 425 sleep(1); 426 ioctl_tests_2(fd); 427 exit(0); 428 default: 429 ioctl_tests_2(fd); 430 if (waitpid(pid, NULL, 0) == -1) 431 err(1, "waitpid() failed"); 432 } 433 CHECK(close(fd) == 0); 434 435 /* Send descriptors from parent to child. */ 436 CHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, sp) == 0); 437 CHECK((pid = fork()) >= 0); 438 if (pid == 0) { 439 CHECK(close(sp[0]) == 0); 440 ioctl_tests_recv_0(sp[1]); 441 CHECK(close(sp[1]) == 0); 442 exit(0); 443 } else { 444 CHECK(close(sp[1]) == 0); 445 ioctl_tests_send_0(sp[0]); 446 CHECK(waitpid(pid, NULL, 0) == pid); 447 CHECK(close(sp[0]) == 0); 448 } 449 450 /* Send descriptors from child to parent. */ 451 CHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, sp) == 0); 452 CHECK((pid = fork()) >= 0); 453 if (pid == 0) { 454 CHECK(close(sp[0]) == 0); 455 ioctl_tests_send_0(sp[1]); 456 CHECK(close(sp[1]) == 0); 457 exit(0); 458 } else { 459 CHECK(close(sp[1]) == 0); 460 ioctl_tests_recv_0(sp[0]); 461 CHECK(waitpid(pid, NULL, 0) == pid); 462 CHECK(close(sp[0]) == 0); 463 } 464 465 exit(0); 466 } 467