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