1/* 2 * Copyright (c) 2012 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 29#include <sys/param.h> 30#include <sys/systm.h> 31#include <sys/filedesc.h> 32#include <sys/kernel.h> 33#include <sys/file_internal.h> 34#include <sys/guarded.h> 35#include <kern/kalloc.h> 36#include <sys/sysproto.h> 37#include <sys/vnode.h> 38#include <vfs/vfs_support.h> 39#include <security/audit/audit.h> 40 41/* 42 * Experimental guarded file descriptor support. 43 */ 44 45kern_return_t task_exception_notify(exception_type_t exception, 46 mach_exception_data_type_t code, mach_exception_data_type_t subcode); 47 48/* 49 * Most fd's have an underlying fileproc struct; but some may be 50 * guarded_fileproc structs which implement guarded fds. The latter 51 * struct (below) embeds the former. 52 * 53 * The two types should be distinguished by the "type" portion of f_flags. 54 * There's also a magic number to help catch misuse and bugs. 55 * 56 * This is a bit unpleasant, but results from the desire to allow 57 * alternate file behaviours for a few file descriptors without 58 * growing the fileproc data structure. 59 */ 60 61struct guarded_fileproc { 62 struct fileproc gf_fileproc; 63 u_int gf_magic; 64 u_int gf_attrs; 65 thread_t gf_thread; 66 guardid_t gf_guard; 67 int gf_exc_fd; 68 u_int gf_exc_code; 69}; 70 71const size_t sizeof_guarded_fileproc = sizeof (struct guarded_fileproc); 72 73#define FP_TO_GFP(fp) ((struct guarded_fileproc *)(fp)) 74#define GFP_TO_FP(gfp) (&(gfp)->gf_fileproc) 75 76#define GUARDED_FILEPROC_MAGIC 0x29083 77 78struct gfp_crarg { 79 guardid_t gca_guard; 80 u_int gca_attrs; 81}; 82 83static struct fileproc * 84guarded_fileproc_alloc_init(void *crarg) 85{ 86 struct gfp_crarg *aarg = crarg; 87 struct guarded_fileproc *gfp; 88 89 if ((gfp = kalloc(sizeof (*gfp))) == NULL) 90 return (NULL); 91 92 bzero(gfp, sizeof (*gfp)); 93 gfp->gf_fileproc.f_flags = FTYPE_GUARDED; 94 gfp->gf_magic = GUARDED_FILEPROC_MAGIC; 95 gfp->gf_guard = aarg->gca_guard; 96 gfp->gf_attrs = aarg->gca_attrs; 97 98 return (GFP_TO_FP(gfp)); 99} 100 101void 102guarded_fileproc_free(struct fileproc *fp) 103{ 104 struct guarded_fileproc *gfp = FP_TO_GFP(fp); 105 106 if (FILEPROC_TYPE(fp) != FTYPE_GUARDED || 107 GUARDED_FILEPROC_MAGIC != gfp->gf_magic) 108 panic("%s: corrupt fp %p flags %x", __func__, fp, fp->f_flags); 109 110 kfree(gfp, sizeof (*gfp)); 111} 112 113static int 114fp_lookup_guarded(proc_t p, int fd, guardid_t guard, 115 struct guarded_fileproc **gfpp) 116{ 117 struct fileproc *fp; 118 int error; 119 120 if ((error = fp_lookup(p, fd, &fp, 1)) != 0) 121 return (error); 122 if (FILEPROC_TYPE(fp) != FTYPE_GUARDED) { 123 (void) fp_drop(p, fd, fp, 1); 124 return (EINVAL); 125 } 126 struct guarded_fileproc *gfp = FP_TO_GFP(fp); 127 128 if (GUARDED_FILEPROC_MAGIC != gfp->gf_magic) 129 panic("%s: corrupt fp %p", __func__, fp); 130 131 if (guard != gfp->gf_guard) { 132 (void) fp_drop(p, fd, fp, 1); 133 return (EPERM); /* *not* a mismatch exception */ 134 } 135 if (gfpp) 136 *gfpp = gfp; 137 return (0); 138} 139 140/* 141 * Expected use pattern: 142 * 143 * if (FP_ISGUARDED(fp, GUARD_CLOSE)) { 144 * error = fp_guard_exception(p, fd, fp, kGUARD_EXC_CLOSE); 145 * proc_fdunlock(p); 146 * return (error); 147 * } 148 */ 149 150int 151fp_isguarded(struct fileproc *fp, u_int attrs) 152{ 153 if (FILEPROC_TYPE(fp) == FTYPE_GUARDED) { 154 struct guarded_fileproc *gfp = FP_TO_GFP(fp); 155 156 if (GUARDED_FILEPROC_MAGIC != gfp->gf_magic) 157 panic("%s: corrupt gfp %p flags %x", 158 __func__, gfp, fp->f_flags); 159 return ((attrs & gfp->gf_attrs) ? 1 : 0); 160 } 161 return (0); 162} 163 164extern char *proc_name_address(void *p); 165 166int 167fp_guard_exception(proc_t p, int fd, struct fileproc *fp, u_int code) 168{ 169 if (FILEPROC_TYPE(fp) != FTYPE_GUARDED) 170 panic("%s corrupt fp %p flags %x", __func__, fp, fp->f_flags); 171 172 struct guarded_fileproc *gfp = FP_TO_GFP(fp); 173 174 /* all gfd fields protected via proc_fdlock() */ 175 proc_fdlock_assert(p, LCK_MTX_ASSERT_OWNED); 176 177 if (NULL == gfp->gf_thread) { 178 thread_t t = current_thread(); 179 gfp->gf_thread = t; 180 gfp->gf_exc_fd = fd; 181 gfp->gf_exc_code = code; 182 183 /* 184 * This thread was the first to attempt the 185 * operation that violated the guard on this fd; 186 * generate an exception. 187 */ 188 printf("%s: guarded fd exception: " 189 "fd %d code 0x%x guard 0x%llx\n", 190 proc_name_address(p), gfp->gf_exc_fd, 191 gfp->gf_exc_code, gfp->gf_guard); 192 193 thread_guard_violation(t, GUARD_TYPE_FD); 194 } else { 195 /* 196 * We already recorded a violation on this fd for a 197 * different thread, so posting an exception is 198 * already in progress. We could pause for a bit 199 * and check again, or we could panic (though that seems 200 * heavy handed), or we could just press on with the 201 * error return alone. For now, resort to printf. 202 */ 203 printf("%s: guarded fd exception+: " 204 "fd %d code 0x%x guard 0x%llx\n", 205 proc_name_address(p), gfp->gf_exc_fd, 206 gfp->gf_exc_code, gfp->gf_guard); 207 } 208 209 return (EPERM); 210} 211 212/* 213 * (Invoked before returning to userland from the syscall handler.) 214 */ 215void 216fd_guard_ast(thread_t t) 217{ 218 proc_t p = current_proc(); 219 struct filedesc *fdp = p->p_fd; 220 int i; 221 222 proc_fdlock(p); 223 for (i = fdp->fd_lastfile; i >= 0; i--) { 224 struct fileproc *fp = fdp->fd_ofiles[i]; 225 226 if (fp == NULL || 227 FILEPROC_TYPE(fp) != FTYPE_GUARDED) 228 continue; 229 230 struct guarded_fileproc *gfp = FP_TO_GFP(fp); 231 232 if (GUARDED_FILEPROC_MAGIC != gfp->gf_magic) 233 panic("%s: corrupt gfp %p flags %x", 234 __func__, gfp, fp->f_flags); 235 236 if (gfp->gf_thread == t) { 237 mach_exception_data_type_t code, subcode; 238 239 gfp->gf_thread = NULL; 240 241 /* 242 * EXC_GUARD exception code namespace. 243 * 244 * code: 245 * +-------------------------------------------------+ 246 * | [63:61] guard type | [60:0] guard-specific data | 247 * +-------------------------------------------------+ 248 * 249 * subcode: 250 * +-------------------------------------------------+ 251 * | [63:0] guard-specific data | 252 * +-------------------------------------------------+ 253 * 254 * At the moment, we have just one guard type: file 255 * descriptor guards. 256 * 257 * File descriptor guards use the exception codes like 258 * so: 259 * 260 * code: 261 * +--------------------------------------------------+ 262 * |[63:61] GUARD_TYPE_FD | [60:32] flavor | [31:0] fd| 263 * +--------------------------------------------------+ 264 * 265 * subcode: 266 * +--------------------------------------------------+ 267 * | [63:0] guard value | 268 * +--------------------------------------------------+ 269 */ 270 code = (((uint64_t)GUARD_TYPE_FD) << 61) | 271 (((uint64_t)gfp->gf_exc_code) << 32) | 272 ((uint64_t)gfp->gf_exc_fd); 273 subcode = gfp->gf_guard; 274 proc_fdunlock(p); 275 276 (void) task_exception_notify(EXC_GUARD, code, subcode); 277 psignal(p, SIGKILL); 278 279 return; 280 } 281 } 282 proc_fdunlock(p); 283} 284 285/* 286 * Experimental guarded file descriptor SPIs 287 */ 288 289/* 290 * int guarded_open_np(const char *pathname, int flags, 291 * const guardid_t *guard, u_int guardflags, ...); 292 * 293 * In this initial implementation, GUARD_DUP must be specified. 294 * GUARD_CLOSE, GUARD_SOCKET_IPC and GUARD_FILEPORT are optional. 295 * 296 * If GUARD_DUP wasn't specified, then we'd have to do the (extra) work 297 * to allow dup-ing a descriptor to inherit the guard onto the new 298 * descriptor. (Perhaps GUARD_DUP behaviours should just always be true 299 * for a guarded fd? Or, more sanely, all the dup operations should 300 * just always propagate the guard?) 301 * 302 * Guarded descriptors are always close-on-exec, and GUARD_CLOSE 303 * requires close-on-fork; O_CLOEXEC must be set in flags. 304 * This setting is immutable; attempts to clear the flag will 305 * cause a guard exception. 306 */ 307int 308guarded_open_np(proc_t p, struct guarded_open_np_args *uap, int32_t *retval) 309{ 310 if ((uap->flags & O_CLOEXEC) == 0) 311 return (EINVAL); 312 313#define GUARD_REQUIRED (GUARD_DUP) 314#define GUARD_ALL (GUARD_REQUIRED | \ 315 (GUARD_CLOSE | GUARD_SOCKET_IPC | GUARD_FILEPORT)) 316 317 if (((uap->guardflags & GUARD_REQUIRED) != GUARD_REQUIRED) || 318 ((uap->guardflags & ~GUARD_ALL) != 0)) 319 return (EINVAL); 320 321 int error; 322 struct gfp_crarg crarg = { 323 .gca_attrs = uap->guardflags 324 }; 325 326 if ((error = copyin(uap->guard, 327 &(crarg.gca_guard), sizeof (crarg.gca_guard))) != 0) 328 return (error); 329 330 /* 331 * Disallow certain guard values -- is zero enough? 332 */ 333 if (crarg.gca_guard == 0) 334 return (EINVAL); 335 336 struct filedesc *fdp = p->p_fd; 337 struct vnode_attr va; 338 struct nameidata nd; 339 vfs_context_t ctx = vfs_context_current(); 340 int cmode; 341 342 VATTR_INIT(&va); 343 cmode = ((uap->mode & ~fdp->fd_cmask) & ALLPERMS) & ~S_ISTXT; 344 VATTR_SET(&va, va_mode, cmode & ACCESSPERMS); 345 346 NDINIT(&nd, LOOKUP, OP_OPEN, FOLLOW | AUDITVNPATH1, UIO_USERSPACE, 347 uap->path, ctx); 348 349 return (open1(ctx, &nd, uap->flags | O_CLOFORK, &va, 350 guarded_fileproc_alloc_init, &crarg, retval)); 351} 352 353/* 354 * int guarded_kqueue_np(const guardid_t *guard, u_int guardflags); 355 * 356 * Create a guarded kqueue descriptor with guardid and guardflags. 357 * 358 * Same restrictions on guardflags as for guarded_open_np(). 359 * All kqueues are -always- close-on-exec and close-on-fork by themselves. 360 * 361 * XXX Is it ever sensible to allow a kqueue fd (guarded or not) to 362 * be sent to another process via a fileport or socket? 363 */ 364int 365guarded_kqueue_np(proc_t p, struct guarded_kqueue_np_args *uap, int32_t *retval) 366{ 367 if (((uap->guardflags & GUARD_REQUIRED) != GUARD_REQUIRED) || 368 ((uap->guardflags & ~GUARD_ALL) != 0)) 369 return (EINVAL); 370 371 int error; 372 struct gfp_crarg crarg = { 373 .gca_attrs = uap->guardflags 374 }; 375 376 if ((error = copyin(uap->guard, 377 &(crarg.gca_guard), sizeof (crarg.gca_guard))) != 0) 378 return (error); 379 380 if (crarg.gca_guard == 0) 381 return (EINVAL); 382 383 return (kqueue_body(p, guarded_fileproc_alloc_init, &crarg, retval)); 384} 385 386/* 387 * int guarded_close_np(int fd, const guardid_t *guard); 388 */ 389int 390guarded_close_np(proc_t p, struct guarded_close_np_args *uap, 391 __unused int32_t *retval) 392{ 393 struct guarded_fileproc *gfp; 394 int fd = uap->fd; 395 int error; 396 guardid_t uguard; 397 398 AUDIT_SYSCLOSE(p, fd); 399 400 if ((error = copyin(uap->guard, &uguard, sizeof (uguard))) != 0) 401 return (error); 402 403 proc_fdlock(p); 404 if ((error = fp_lookup_guarded(p, fd, uguard, &gfp)) != 0) { 405 proc_fdunlock(p); 406 return (error); 407 } 408 error = close_internal_locked(p, fd, GFP_TO_FP(gfp), 0); 409 proc_fdunlock(p); 410 return (error); 411} 412 413/* 414 * int 415 * change_fdguard_np(int fd, const guardid_t *guard, u_int guardflags, 416 * const guardid_t *nguard, u_int nguardflags, int *fdflagsp); 417 * 418 * Given a file descriptor, atomically exchange <guard, guardflags> for 419 * a new guard <nguard, nguardflags>, returning the previous fd 420 * flags (see fcntl:F_SETFD) in *fdflagsp. 421 * 422 * This syscall can be used to either (a) add a new guard to an existing 423 * unguarded file descriptor (b) remove the old guard from an existing 424 * guarded file descriptor or (c) change the guard (guardid and/or 425 * guardflags) on a guarded file descriptor. 426 * 427 * If 'guard' is NULL, fd must be unguarded at entry. If the call completes 428 * successfully the fd will be guarded with <nguard, nguardflags>. 429 * 430 * Guarding a file descriptor has some side-effects on the "fdflags" 431 * associated with the descriptor - in particular FD_CLOEXEC is 432 * forced ON unconditionally, and FD_CLOFORK is forced ON by GUARD_CLOSE. 433 * Callers who wish to subsequently restore the state of the fd should save 434 * the value of *fdflagsp after a successful invocation. 435 * 436 * If 'nguard' is NULL, fd must be guarded at entry, <guard, guardflags> 437 * must match with what's already guarding the descriptor, and the 438 * result will be to completely remove the guard. Note also that the 439 * fdflags are copied to the descriptor from the incoming *fdflagsp argument. 440 * 441 * If the descriptor is guarded, and neither 'guard' nor 'nguard' is NULL 442 * and <guard, guardflags> matches what's already guarding the descriptor, 443 * then <nguard, nguardflags> becomes the new guard. In this case, even if 444 * the GUARD_CLOSE flag is being cleared, it is still possible to continue 445 * to keep FD_CLOFORK on the descriptor by passing FD_CLOFORK via fdflagsp. 446 * 447 * Example 1: Guard an unguarded descriptor during a set of operations, 448 * then restore the original state of the descriptor. 449 * 450 * int sav_flags = 0; 451 * change_fdguard_np(fd, NULL, 0, &myguard, GUARD_CLOSE, &sav_flags); 452 * // do things with now guarded 'fd' 453 * change_fdguard_np(fd, &myguard, GUARD_CLOSE, NULL, 0, &sav_flags); 454 * // fd now unguarded. 455 * 456 * Example 2: Change the guard of a guarded descriptor during a set of 457 * operations, then restore the original state of the descriptor. 458 * 459 * int sav_flags = (gdflags & GUARD_CLOSE) ? FD_CLOFORK : 0; 460 * change_fdguard_np(fd, &gd, gdflags, &myguard, GUARD_CLOSE, &sav_flags); 461 * // do things with 'fd' with a different guard 462 * change_fdguard_np(fd, &myg, GUARD_CLOSE, &gd, gdflags, &sav_flags); 463 * // back to original guarded state 464 */ 465 466#define FDFLAGS_GET(p, fd) (*fdflags(p, fd) & (UF_EXCLOSE|UF_FORKCLOSE)) 467#define FDFLAGS_SET(p, fd, bits) \ 468 (*fdflags(p, fd) |= ((bits) & (UF_EXCLOSE|UF_FORKCLOSE))) 469#define FDFLAGS_CLR(p, fd, bits) \ 470 (*fdflags(p, fd) &= ~((bits) & (UF_EXCLOSE|UF_FORKCLOSE))) 471 472int 473change_fdguard_np(proc_t p, struct change_fdguard_np_args *uap, 474 __unused int32_t *retval) 475{ 476 struct fileproc *fp; 477 int fd = uap->fd; 478 int error; 479 guardid_t oldg = 0, newg = 0; 480 int nfdflags = 0; 481 482 if (0 != uap->guard && 483 0 != (error = copyin(uap->guard, &oldg, sizeof (oldg)))) 484 return (error); /* can't copyin current guard */ 485 486 if (0 != uap->nguard && 487 0 != (error = copyin(uap->nguard, &newg, sizeof (newg)))) 488 return (error); /* can't copyin new guard */ 489 490 if (0 != uap->fdflagsp && 491 0 != (error = copyin(uap->fdflagsp, &nfdflags, sizeof (nfdflags)))) 492 return (error); /* can't copyin new fdflags */ 493 494 proc_fdlock(p); 495restart: 496 if ((error = fp_lookup(p, fd, &fp, 1)) != 0) { 497 proc_fdunlock(p); 498 return (error); 499 } 500 501 if (0 != uap->fdflagsp) { 502 int ofdflags = FDFLAGS_GET(p, fd); 503 int ofl = ((ofdflags & UF_EXCLOSE) ? FD_CLOEXEC : 0) | 504 ((ofdflags & UF_FORKCLOSE) ? FD_CLOFORK : 0); 505 proc_fdunlock(p); 506 if (0 != (error = copyout(&ofl, uap->fdflagsp, sizeof (ofl)))) { 507 proc_fdlock(p); 508 goto dropout; /* can't copyout old fdflags */ 509 } 510 proc_fdlock(p); 511 } 512 513 if (FILEPROC_TYPE(fp) == FTYPE_GUARDED) { 514 if (0 == uap->guard || 0 == uap->guardflags) 515 error = EINVAL; /* missing guard! */ 516 else if (0 == oldg) 517 error = EPERM; /* guardids cannot be zero */ 518 } else { 519 if (0 != uap->guard || 0 != uap->guardflags) 520 error = EINVAL; /* guard provided, but none needed! */ 521 } 522 523 if (0 != error) 524 goto dropout; 525 526 if (0 != uap->nguard) { 527 /* 528 * There's a new guard in town. 529 */ 530 if (0 == newg) 531 error = EINVAL; /* guards cannot contain zero */ 532 else if (0 == uap->nguardflags) 533 error = EINVAL; /* attributes cannot be zero */ 534 else if (((uap->nguardflags & GUARD_REQUIRED) != GUARD_REQUIRED) || 535 ((uap->guardflags & ~GUARD_ALL) != 0)) 536 error = EINVAL; /* must have valid attributes too */ 537 538 if (0 != error) 539 goto dropout; 540 541 if (FILEPROC_TYPE(fp) == FTYPE_GUARDED) { 542 /* 543 * Replace old guard with new guard 544 */ 545 struct guarded_fileproc *gfp = FP_TO_GFP(fp); 546 547 if (GUARDED_FILEPROC_MAGIC != gfp->gf_magic) 548 panic("%s: corrupt gfp %p flags %x", 549 __func__, gfp, fp->f_flags); 550 551 if (oldg == gfp->gf_guard && 552 uap->guardflags == gfp->gf_attrs) { 553 /* 554 * Must match existing guard + attributes 555 * before we'll swap them to new ones, managing 556 * fdflags "side-effects" as we go. Note that 557 * userland can request FD_CLOFORK semantics. 558 */ 559 if (gfp->gf_attrs & GUARD_CLOSE) 560 FDFLAGS_CLR(p, fd, UF_FORKCLOSE); 561 gfp->gf_guard = newg; 562 gfp->gf_attrs = uap->nguardflags; 563 if (gfp->gf_attrs & GUARD_CLOSE) 564 FDFLAGS_SET(p, fd, UF_FORKCLOSE); 565 FDFLAGS_SET(p, fd, 566 (nfdflags & FD_CLOFORK) ? UF_FORKCLOSE : 0); 567 } else { 568 error = EPERM; 569 } 570 goto dropout; 571 } else { 572 /* 573 * Add a guard to a previously unguarded descriptor 574 */ 575 switch (FILEGLOB_DTYPE(fp->f_fglob)) { 576 case DTYPE_VNODE: 577 case DTYPE_PIPE: 578 case DTYPE_SOCKET: 579 case DTYPE_KQUEUE: 580 break; 581 default: 582 error = ENOTSUP; 583 goto dropout; 584 } 585 586 proc_fdunlock(p); 587 588 struct gfp_crarg crarg = { 589 .gca_guard = newg, 590 .gca_attrs = uap->nguardflags 591 }; 592 struct fileproc *nfp = 593 guarded_fileproc_alloc_init(&crarg); 594 595 proc_fdlock(p); 596 597 switch (error = fp_tryswap(p, fd, nfp)) { 598 struct guarded_fileproc *gfp; 599 600 case 0: /* guarded-ness comes with side-effects */ 601 gfp = FP_TO_GFP(nfp); 602 if (gfp->gf_attrs & GUARD_CLOSE) 603 FDFLAGS_SET(p, fd, UF_FORKCLOSE); 604 FDFLAGS_SET(p, fd, UF_EXCLOSE); 605 (void) fp_drop(p, fd, nfp, 1); 606 fileproc_free(fp); 607 break; 608 case EKEEPLOOKING: /* f_iocount indicates a collision */ 609 (void) fp_drop(p, fd, fp, 1); 610 fileproc_free(nfp); 611 goto restart; 612 default: 613 (void) fp_drop(p, fd, fp, 1); 614 fileproc_free(nfp); 615 break; 616 } 617 proc_fdunlock(p); 618 return (error); 619 } 620 } else { 621 /* 622 * No new guard. 623 */ 624 if (FILEPROC_TYPE(fp) == FTYPE_GUARDED) { 625 /* 626 * Remove the guard altogether. 627 */ 628 struct guarded_fileproc *gfp = FP_TO_GFP(fp); 629 630 if (0 != uap->nguardflags) { 631 error = EINVAL; 632 goto dropout; 633 } 634 635 if (GUARDED_FILEPROC_MAGIC != gfp->gf_magic) 636 panic("%s: corrupt gfp %p flags %x", 637 __func__, gfp, fp->f_flags); 638 639 if (oldg != gfp->gf_guard || 640 uap->guardflags != gfp->gf_attrs) { 641 error = EPERM; 642 goto dropout; 643 } 644 645 proc_fdunlock(p); 646 struct fileproc *nfp = fileproc_alloc_init(NULL); 647 proc_fdlock(p); 648 649 switch (error = fp_tryswap(p, fd, nfp)) { 650 case 0: /* undo side-effects of guarded-ness */ 651 FDFLAGS_CLR(p, fd, UF_FORKCLOSE | UF_EXCLOSE); 652 FDFLAGS_SET(p, fd, 653 (nfdflags & FD_CLOFORK) ? UF_FORKCLOSE : 0); 654 FDFLAGS_SET(p, fd, 655 (nfdflags & FD_CLOEXEC) ? UF_EXCLOSE : 0); 656 (void) fp_drop(p, fd, nfp, 1); 657 fileproc_free(fp); 658 break; 659 case EKEEPLOOKING: /* f_iocount indicates collision */ 660 (void) fp_drop(p, fd, fp, 1); 661 fileproc_free(nfp); 662 goto restart; 663 default: 664 (void) fp_drop(p, fd, fp, 1); 665 fileproc_free(nfp); 666 break; 667 } 668 proc_fdunlock(p); 669 return (error); 670 } else { 671 /* 672 * Not already guarded, and no new guard? 673 */ 674 error = EINVAL; 675 } 676 } 677 678dropout: 679 (void) fp_drop(p, fd, fp, 1); 680 proc_fdunlock(p); 681 return (error); 682} 683 684