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/param.h> 31 #include <sys/capsicum.h> 32 #include <sys/ioctl.h> 33 #include <sys/procdesc.h> 34 #include <sys/socket.h> 35 #include <sys/wait.h> 36 37 #include <err.h> 38 #include <errno.h> 39 #include <limits.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <unistd.h> 43 44 #include "misc.h" 45 46 static void 47 ioctl_tests_0(int fd) 48 { 49 unsigned long cmds[2]; 50 51 CHECK(cap_ioctls_get(fd, NULL, 0) == CAP_IOCTLS_ALL); 52 53 CHECK(fcntl(fd, F_GETFD) == 0); 54 CHECK(ioctl(fd, FIOCLEX) == 0); 55 CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC); 56 CHECK(ioctl(fd, FIONCLEX) == 0); 57 CHECK(fcntl(fd, F_GETFD) == 0); 58 59 cmds[0] = FIOCLEX; 60 cmds[1] = FIONCLEX; 61 CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == 0); 62 cmds[0] = cmds[1] = 0; 63 CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == nitems(cmds)); 64 CHECK((cmds[0] == FIOCLEX && cmds[1] == FIONCLEX) || 65 (cmds[0] == FIONCLEX && cmds[1] == FIOCLEX)); 66 cmds[0] = FIOCLEX; 67 cmds[1] = FIONCLEX; 68 CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == 0); 69 cmds[0] = cmds[1] = 0; 70 CHECK(cap_ioctls_get(fd, cmds, 1) == nitems(cmds)); 71 CHECK(cmds[0] == FIOCLEX || cmds[0] == FIONCLEX); 72 CHECK(cmds[1] == 0); 73 74 CHECK(fcntl(fd, F_GETFD) == 0); 75 CHECK(ioctl(fd, FIOCLEX) == 0); 76 CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC); 77 CHECK(ioctl(fd, FIONCLEX) == 0); 78 CHECK(fcntl(fd, F_GETFD) == 0); 79 80 cmds[0] = FIOCLEX; 81 CHECK(cap_ioctls_limit(fd, cmds, 1) == 0); 82 cmds[0] = cmds[1] = 0; 83 CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 1); 84 CHECK(cmds[0] == FIOCLEX); 85 cmds[0] = FIOCLEX; 86 cmds[1] = FIONCLEX; 87 errno = 0; 88 CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == -1); 89 CHECK(errno == ENOTCAPABLE); 90 cmds[0] = cmds[1] = 0; 91 CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 1); 92 CHECK(cmds[0] == FIOCLEX); 93 94 CHECK(fcntl(fd, F_GETFD) == 0); 95 CHECK(ioctl(fd, FIOCLEX) == 0); 96 CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC); 97 errno = 0; 98 CHECK(ioctl(fd, FIONCLEX) == -1); 99 CHECK(errno == ENOTCAPABLE); 100 CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC); 101 CHECK(fcntl(fd, F_SETFD, 0) == 0); 102 CHECK(fcntl(fd, F_GETFD) == 0); 103 104 CHECK(cap_ioctls_limit(fd, NULL, 0) == 0); 105 CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0); 106 cmds[0] = FIOCLEX; 107 errno = 0; 108 CHECK(cap_ioctls_limit(fd, cmds, 1) == -1); 109 CHECK(errno == ENOTCAPABLE); 110 CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0); 111 112 CHECK(fcntl(fd, F_GETFD) == 0); 113 errno = 0; 114 CHECK(ioctl(fd, FIOCLEX) == -1); 115 CHECK(errno == ENOTCAPABLE); 116 CHECK(fcntl(fd, F_GETFD) == 0); 117 CHECK(fcntl(fd, F_SETFD, FD_CLOEXEC) == 0); 118 CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC); 119 errno = 0; 120 CHECK(ioctl(fd, FIONCLEX) == -1); 121 CHECK(errno == ENOTCAPABLE); 122 CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC); 123 CHECK(fcntl(fd, F_SETFD, 0) == 0); 124 CHECK(fcntl(fd, F_GETFD) == 0); 125 } 126 127 static void 128 ioctl_tests_1(int fd) 129 { 130 unsigned long cmds[2]; 131 cap_rights_t rights; 132 133 cmds[0] = FIOCLEX; 134 CHECK(cap_ioctls_limit(fd, cmds, 1) == 0); 135 cmds[0] = cmds[1] = 0; 136 CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 1); 137 CHECK(cmds[0] == FIOCLEX); 138 CHECK(cmds[1] == 0); 139 140 CAP_ALL(&rights); 141 cap_rights_clear(&rights, CAP_IOCTL); 142 143 CHECK(cap_rights_limit(fd, &rights) == 0); 144 CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0); 145 146 cmds[0] = FIOCLEX; 147 cmds[1] = FIONCLEX; 148 errno = 0; 149 CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == -1); 150 CHECK(errno == ENOTCAPABLE); 151 CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0); 152 cmds[0] = FIOCLEX; 153 errno = 0; 154 CHECK(cap_ioctls_limit(fd, cmds, 1) == -1); 155 CHECK(errno == ENOTCAPABLE); 156 CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0); 157 158 CHECK(fcntl(fd, F_GETFD) == 0); 159 errno = 0; 160 CHECK(ioctl(fd, FIOCLEX) == -1); 161 CHECK(errno == ENOTCAPABLE); 162 CHECK(fcntl(fd, F_GETFD) == 0); 163 CHECK(fcntl(fd, F_SETFD, FD_CLOEXEC) == 0); 164 CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC); 165 errno = 0; 166 CHECK(ioctl(fd, FIONCLEX) == -1); 167 CHECK(errno == ENOTCAPABLE); 168 CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC); 169 CHECK(fcntl(fd, F_SETFD, 0) == 0); 170 CHECK(fcntl(fd, F_GETFD) == 0); 171 } 172 173 static void 174 ioctl_tests_2(int fd) 175 { 176 unsigned long cmds[2]; 177 cap_rights_t rights; 178 179 CAP_ALL(&rights); 180 cap_rights_clear(&rights, CAP_IOCTL); 181 182 CHECK(cap_rights_limit(fd, &rights) == 0); 183 CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0); 184 185 cmds[0] = FIOCLEX; 186 cmds[1] = FIONCLEX; 187 errno = 0; 188 CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == -1); 189 CHECK(errno == ENOTCAPABLE); 190 CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0); 191 cmds[0] = FIOCLEX; 192 errno = 0; 193 CHECK(cap_ioctls_limit(fd, cmds, 1) == -1); 194 CHECK(errno == ENOTCAPABLE); 195 CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0); 196 197 CHECK(fcntl(fd, F_GETFD) == 0); 198 errno = 0; 199 CHECK(ioctl(fd, FIOCLEX) == -1); 200 CHECK(errno == ENOTCAPABLE); 201 CHECK(fcntl(fd, F_GETFD) == 0); 202 CHECK(fcntl(fd, F_SETFD, FD_CLOEXEC) == 0); 203 CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC); 204 errno = 0; 205 CHECK(ioctl(fd, FIONCLEX) == -1); 206 CHECK(errno == ENOTCAPABLE); 207 CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC); 208 CHECK(fcntl(fd, F_SETFD, 0) == 0); 209 CHECK(fcntl(fd, F_GETFD) == 0); 210 } 211 212 static void 213 ioctl_tests_send_0(int sock) 214 { 215 unsigned long cmds[2]; 216 int fd; 217 218 CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0); 219 CHECK(descriptor_send(sock, fd) == 0); 220 CHECK(close(fd) == 0); 221 222 CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0); 223 cmds[0] = FIOCLEX; 224 cmds[1] = FIONCLEX; 225 CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == 0); 226 CHECK(descriptor_send(sock, fd) == 0); 227 CHECK(close(fd) == 0); 228 229 CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0); 230 cmds[0] = FIOCLEX; 231 CHECK(cap_ioctls_limit(fd, cmds, 1) == 0); 232 CHECK(descriptor_send(sock, fd) == 0); 233 CHECK(close(fd) == 0); 234 235 CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0); 236 CHECK(cap_ioctls_limit(fd, NULL, 0) == 0); 237 CHECK(descriptor_send(sock, fd) == 0); 238 CHECK(close(fd) == 0); 239 } 240 241 static void 242 ioctl_tests_recv_0(int sock) 243 { 244 unsigned long cmds[2]; 245 int fd; 246 247 CHECK(descriptor_recv(sock, &fd) == 0); 248 249 CHECK(cap_ioctls_get(fd, NULL, 0) == CAP_IOCTLS_ALL); 250 251 CHECK(fcntl(fd, F_GETFD) == 0); 252 CHECK(ioctl(fd, FIOCLEX) == 0); 253 CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC); 254 CHECK(ioctl(fd, FIONCLEX) == 0); 255 CHECK(fcntl(fd, F_GETFD) == 0); 256 257 CHECK(close(fd) == 0); 258 259 CHECK(descriptor_recv(sock, &fd) == 0); 260 261 cmds[0] = cmds[1] = 0; 262 CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == nitems(cmds)); 263 CHECK((cmds[0] == FIOCLEX && cmds[1] == FIONCLEX) || 264 (cmds[0] == FIONCLEX && cmds[1] == FIOCLEX)); 265 266 CHECK(fcntl(fd, F_GETFD) == 0); 267 CHECK(ioctl(fd, FIOCLEX) == 0); 268 CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC); 269 CHECK(ioctl(fd, FIONCLEX) == 0); 270 CHECK(fcntl(fd, F_GETFD) == 0); 271 272 CHECK(close(fd) == 0); 273 274 CHECK(descriptor_recv(sock, &fd) == 0); 275 276 cmds[0] = cmds[1] = 0; 277 CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 1); 278 CHECK(cmds[0] == FIOCLEX); 279 280 CHECK(fcntl(fd, F_GETFD) == 0); 281 CHECK(ioctl(fd, FIOCLEX) == 0); 282 CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC); 283 errno = 0; 284 CHECK(ioctl(fd, FIONCLEX) == -1); 285 CHECK(errno == ENOTCAPABLE); 286 CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC); 287 CHECK(fcntl(fd, F_SETFD, 0) == 0); 288 CHECK(fcntl(fd, F_GETFD) == 0); 289 290 CHECK(close(fd) == 0); 291 292 CHECK(descriptor_recv(sock, &fd) == 0); 293 294 CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0); 295 296 CHECK(fcntl(fd, F_GETFD) == 0); 297 errno = 0; 298 CHECK(ioctl(fd, FIOCLEX) == -1); 299 CHECK(errno == ENOTCAPABLE); 300 CHECK(fcntl(fd, F_GETFD) == 0); 301 CHECK(fcntl(fd, F_SETFD, FD_CLOEXEC) == 0); 302 CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC); 303 errno = 0; 304 CHECK(ioctl(fd, FIONCLEX) == -1); 305 CHECK(errno == ENOTCAPABLE); 306 CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC); 307 CHECK(fcntl(fd, F_SETFD, 0) == 0); 308 CHECK(fcntl(fd, F_GETFD) == 0); 309 310 CHECK(close(fd) == 0); 311 } 312 313 int 314 main(void) 315 { 316 int fd, pfd, sp[2]; 317 pid_t pid; 318 319 printf("1..607\n"); 320 321 CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0); 322 ioctl_tests_0(fd); 323 CHECK(close(fd) == 0); 324 325 CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0); 326 ioctl_tests_1(fd); 327 CHECK(close(fd) == 0); 328 329 CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0); 330 ioctl_tests_2(fd); 331 CHECK(close(fd) == 0); 332 333 /* Child inherits descriptor and operates on it first. */ 334 CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0); 335 pid = fork(); 336 switch (pid) { 337 case -1: 338 err(1, "fork() failed"); 339 case 0: 340 ioctl_tests_0(fd); 341 CHECK(close(fd) == 0); 342 exit(0); 343 default: 344 if (waitpid(pid, NULL, 0) == -1) 345 err(1, "waitpid() failed"); 346 ioctl_tests_0(fd); 347 } 348 CHECK(close(fd) == 0); 349 350 /* Child inherits descriptor, but operates on it after parent. */ 351 CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0); 352 pid = fork(); 353 switch (pid) { 354 case -1: 355 err(1, "fork() failed"); 356 case 0: 357 sleep(1); 358 ioctl_tests_0(fd); 359 CHECK(close(fd) == 0); 360 exit(0); 361 default: 362 ioctl_tests_0(fd); 363 if (waitpid(pid, NULL, 0) == -1) 364 err(1, "waitpid() failed"); 365 } 366 CHECK(close(fd) == 0); 367 368 /* Child inherits descriptor and operates on it first. */ 369 CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0); 370 pid = pdfork(&pfd, 0); 371 switch (pid) { 372 case -1: 373 err(1, "pdfork() failed"); 374 case 0: 375 ioctl_tests_1(fd); 376 exit(0); 377 default: 378 if (pdwait(pfd) == -1) 379 err(1, "pdwait() failed"); 380 close(pfd); 381 ioctl_tests_1(fd); 382 } 383 CHECK(close(fd) == 0); 384 385 /* Child inherits descriptor, but operates on it after parent. */ 386 CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0); 387 pid = pdfork(&pfd, 0); 388 switch (pid) { 389 case -1: 390 err(1, "pdfork() failed"); 391 case 0: 392 sleep(1); 393 ioctl_tests_1(fd); 394 exit(0); 395 default: 396 ioctl_tests_1(fd); 397 if (pdwait(pfd) == -1) 398 err(1, "pdwait() failed"); 399 close(pfd); 400 } 401 CHECK(close(fd) == 0); 402 403 /* Child inherits descriptor and operates on it first. */ 404 CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0); 405 pid = fork(); 406 switch (pid) { 407 case -1: 408 err(1, "fork() failed"); 409 case 0: 410 ioctl_tests_2(fd); 411 exit(0); 412 default: 413 if (waitpid(pid, NULL, 0) == -1) 414 err(1, "waitpid() failed"); 415 ioctl_tests_2(fd); 416 } 417 CHECK(close(fd) == 0); 418 419 /* Child inherits descriptor, but operates on it after parent. */ 420 CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0); 421 pid = fork(); 422 switch (pid) { 423 case -1: 424 err(1, "fork() failed"); 425 case 0: 426 sleep(1); 427 ioctl_tests_2(fd); 428 exit(0); 429 default: 430 ioctl_tests_2(fd); 431 if (waitpid(pid, NULL, 0) == -1) 432 err(1, "waitpid() failed"); 433 } 434 CHECK(close(fd) == 0); 435 436 /* Send descriptors from parent to child. */ 437 CHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, sp) == 0); 438 CHECK((pid = fork()) >= 0); 439 if (pid == 0) { 440 CHECK(close(sp[0]) == 0); 441 ioctl_tests_recv_0(sp[1]); 442 CHECK(close(sp[1]) == 0); 443 exit(0); 444 } else { 445 CHECK(close(sp[1]) == 0); 446 ioctl_tests_send_0(sp[0]); 447 CHECK(waitpid(pid, NULL, 0) == pid); 448 CHECK(close(sp[0]) == 0); 449 } 450 451 /* Send descriptors from child to parent. */ 452 CHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, sp) == 0); 453 CHECK((pid = fork()) >= 0); 454 if (pid == 0) { 455 CHECK(close(sp[0]) == 0); 456 ioctl_tests_send_0(sp[1]); 457 CHECK(close(sp[1]) == 0); 458 exit(0); 459 } else { 460 CHECK(close(sp[1]) == 0); 461 ioctl_tests_recv_0(sp[0]); 462 CHECK(waitpid(pid, NULL, 0) == pid); 463 CHECK(close(sp[0]) == 0); 464 } 465 466 exit(0); 467 } 468