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