]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_guarded.c
5c175c7bb103a8825232534382b834afcf5381b1
[apple/xnu.git] / bsd / kern / kern_guarded.c
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
45 kern_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
61 struct 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
71 const 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
78 struct gfp_crarg {
79 guardid_t gca_guard;
80 u_int gca_attrs;
81 };
82
83 static struct fileproc *
84 guarded_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
101 void
102 guarded_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
113 static int
114 fp_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
150 int
151 fp_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
164 extern char *proc_name_address(void *p);
165
166 int
167 fp_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 */
215 void
216 fd_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 */
307 int
308 guarded_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 */
364 int
365 guarded_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 */
389 int
390 guarded_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
472 int
473 change_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);
495 restart:
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
678 dropout:
679 (void) fp_drop(p, fd, fp, 1);
680 proc_fdunlock(p);
681 return (error);
682 }
683