]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_guarded.c
xnu-3247.10.11.tar.gz
[apple/xnu.git] / bsd / kern / kern_guarded.c
1 /*
2 * Copyright (c) 2015 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 <sys/vnode_internal.h>
39 #include <sys/uio_internal.h>
40 #include <sys/ubc_internal.h>
41 #include <vfs/vfs_support.h>
42 #include <security/audit/audit.h>
43 #include <sys/syscall.h>
44 #include <sys/kauth.h>
45 #include <sys/kdebug.h>
46 #include <stdbool.h>
47 #include <vm/vm_protos.h>
48 #if CONFIG_PROTECT
49 #include <sys/cprotect.h>
50 #endif
51
52
53 #define f_flag f_fglob->fg_flag
54 #define f_type f_fglob->fg_ops->fo_type
55 extern int dofilewrite(vfs_context_t ctx, struct fileproc *fp,
56 user_addr_t bufp, user_size_t nbyte, off_t offset,
57 int flags, user_ssize_t *retval );
58 extern int wr_uio(struct proc *p, struct fileproc *fp, uio_t uio, user_ssize_t *retval);
59
60 /*
61 * Experimental guarded file descriptor support.
62 */
63
64 kern_return_t task_exception_notify(exception_type_t exception,
65 mach_exception_data_type_t code, mach_exception_data_type_t subcode);
66
67 /*
68 * Most fd's have an underlying fileproc struct; but some may be
69 * guarded_fileproc structs which implement guarded fds. The latter
70 * struct (below) embeds the former.
71 *
72 * The two types should be distinguished by the "type" portion of f_flags.
73 * There's also a magic number to help catch misuse and bugs.
74 *
75 * This is a bit unpleasant, but results from the desire to allow
76 * alternate file behaviours for a few file descriptors without
77 * growing the fileproc data structure.
78 */
79
80 struct guarded_fileproc {
81 struct fileproc gf_fileproc;
82 u_int gf_magic;
83 u_int gf_attrs;
84 thread_t gf_thread;
85 guardid_t gf_guard;
86 int gf_exc_fd;
87 u_int gf_exc_code;
88 };
89
90 const size_t sizeof_guarded_fileproc = sizeof (struct guarded_fileproc);
91
92 #define FP_TO_GFP(fp) ((struct guarded_fileproc *)(fp))
93 #define GFP_TO_FP(gfp) (&(gfp)->gf_fileproc)
94
95 #define GUARDED_FILEPROC_MAGIC 0x29083
96
97 struct gfp_crarg {
98 guardid_t gca_guard;
99 u_int gca_attrs;
100 };
101
102 static struct fileproc *
103 guarded_fileproc_alloc_init(void *crarg)
104 {
105 struct gfp_crarg *aarg = crarg;
106 struct guarded_fileproc *gfp;
107
108 if ((gfp = kalloc(sizeof (*gfp))) == NULL)
109 return (NULL);
110
111 bzero(gfp, sizeof (*gfp));
112 gfp->gf_fileproc.f_flags = FTYPE_GUARDED;
113 gfp->gf_magic = GUARDED_FILEPROC_MAGIC;
114 gfp->gf_guard = aarg->gca_guard;
115 gfp->gf_attrs = aarg->gca_attrs;
116
117 return (GFP_TO_FP(gfp));
118 }
119
120 void
121 guarded_fileproc_free(struct fileproc *fp)
122 {
123 struct guarded_fileproc *gfp = FP_TO_GFP(fp);
124
125 if (FILEPROC_TYPE(fp) != FTYPE_GUARDED ||
126 GUARDED_FILEPROC_MAGIC != gfp->gf_magic)
127 panic("%s: corrupt fp %p flags %x", __func__, fp, fp->f_flags);
128
129 kfree(gfp, sizeof (*gfp));
130 }
131
132 static int
133 fp_lookup_guarded(proc_t p, int fd, guardid_t guard,
134 struct guarded_fileproc **gfpp, int locked)
135 {
136 struct fileproc *fp;
137 int error;
138
139 if ((error = fp_lookup(p, fd, &fp, locked)) != 0)
140 return (error);
141 if (FILEPROC_TYPE(fp) != FTYPE_GUARDED) {
142 (void) fp_drop(p, fd, fp, locked);
143 return (EINVAL);
144 }
145 struct guarded_fileproc *gfp = FP_TO_GFP(fp);
146
147 if (GUARDED_FILEPROC_MAGIC != gfp->gf_magic)
148 panic("%s: corrupt fp %p", __func__, fp);
149
150 if (guard != gfp->gf_guard) {
151 (void) fp_drop(p, fd, fp, locked);
152 return (EPERM); /* *not* a mismatch exception */
153 }
154 if (gfpp)
155 *gfpp = gfp;
156 return (0);
157 }
158
159 /*
160 * Expected use pattern:
161 *
162 * if (FP_ISGUARDED(fp, GUARD_CLOSE)) {
163 * error = fp_guard_exception(p, fd, fp, kGUARD_EXC_CLOSE);
164 * proc_fdunlock(p);
165 * return (error);
166 * }
167 */
168
169 int
170 fp_isguarded(struct fileproc *fp, u_int attrs)
171 {
172 if (FILEPROC_TYPE(fp) == FTYPE_GUARDED) {
173 struct guarded_fileproc *gfp = FP_TO_GFP(fp);
174
175 if (GUARDED_FILEPROC_MAGIC != gfp->gf_magic)
176 panic("%s: corrupt gfp %p flags %x",
177 __func__, gfp, fp->f_flags);
178 return ((attrs & gfp->gf_attrs) == attrs);
179 }
180 return (0);
181 }
182
183 extern char *proc_name_address(void *p);
184
185 int
186 fp_guard_exception(proc_t p, int fd, struct fileproc *fp, u_int code)
187 {
188 if (FILEPROC_TYPE(fp) != FTYPE_GUARDED)
189 panic("%s corrupt fp %p flags %x", __func__, fp, fp->f_flags);
190
191 struct guarded_fileproc *gfp = FP_TO_GFP(fp);
192
193 /* all gfd fields protected via proc_fdlock() */
194 proc_fdlock_assert(p, LCK_MTX_ASSERT_OWNED);
195
196 if (NULL == gfp->gf_thread) {
197 thread_t t = current_thread();
198 gfp->gf_thread = t;
199 gfp->gf_exc_fd = fd;
200 gfp->gf_exc_code = code;
201
202 /*
203 * This thread was the first to attempt the
204 * operation that violated the guard on this fd;
205 * generate an exception.
206 */
207 printf("%s: guarded fd exception: "
208 "fd %d code 0x%x guard 0x%llx\n",
209 proc_name_address(p), gfp->gf_exc_fd,
210 gfp->gf_exc_code, gfp->gf_guard);
211
212 thread_guard_violation(t, GUARD_TYPE_FD);
213 } else {
214 /*
215 * We already recorded a violation on this fd for a
216 * different thread, so posting an exception is
217 * already in progress. We could pause for a bit
218 * and check again, or we could panic (though that seems
219 * heavy handed), or we could just press on with the
220 * error return alone. For now, resort to printf.
221 */
222 printf("%s: guarded fd exception+: "
223 "fd %d code 0x%x guard 0x%llx\n",
224 proc_name_address(p), gfp->gf_exc_fd,
225 gfp->gf_exc_code, gfp->gf_guard);
226 }
227
228 return (EPERM);
229 }
230
231 /*
232 * (Invoked before returning to userland from the syscall handler.)
233 */
234 void
235 fd_guard_ast(thread_t t)
236 {
237 proc_t p = current_proc();
238 struct filedesc *fdp = p->p_fd;
239 int i;
240
241 proc_fdlock(p);
242 for (i = fdp->fd_lastfile; i >= 0; i--) {
243 struct fileproc *fp = fdp->fd_ofiles[i];
244
245 if (fp == NULL ||
246 FILEPROC_TYPE(fp) != FTYPE_GUARDED)
247 continue;
248
249 struct guarded_fileproc *gfp = FP_TO_GFP(fp);
250
251 if (GUARDED_FILEPROC_MAGIC != gfp->gf_magic)
252 panic("%s: corrupt gfp %p flags %x",
253 __func__, gfp, fp->f_flags);
254
255 if (gfp->gf_thread == t) {
256 mach_exception_data_type_t code, subcode;
257
258 gfp->gf_thread = NULL;
259
260 /*
261 * EXC_GUARD exception code namespace.
262 *
263 * code:
264 * +-------------------------------------------------+
265 * | [63:61] guard type | [60:0] guard-specific data |
266 * +-------------------------------------------------+
267 *
268 * subcode:
269 * +-------------------------------------------------+
270 * | [63:0] guard-specific data |
271 * +-------------------------------------------------+
272 *
273 * At the moment, we have just one guard type: file
274 * descriptor guards.
275 *
276 * File descriptor guards use the exception codes like
277 * so:
278 *
279 * code:
280 * +--------------------------------------------------+
281 * |[63:61] GUARD_TYPE_FD | [60:32] flavor | [31:0] fd|
282 * +--------------------------------------------------+
283 *
284 * subcode:
285 * +--------------------------------------------------+
286 * | [63:0] guard value |
287 * +--------------------------------------------------+
288 */
289 code = (((uint64_t)GUARD_TYPE_FD) << 61) |
290 (((uint64_t)gfp->gf_exc_code) << 32) |
291 ((uint64_t)gfp->gf_exc_fd);
292 subcode = gfp->gf_guard;
293 proc_fdunlock(p);
294
295 (void) task_exception_notify(EXC_GUARD, code, subcode);
296 psignal(p, SIGKILL);
297
298 return;
299 }
300 }
301 proc_fdunlock(p);
302 }
303
304 /*
305 * Experimental guarded file descriptor SPIs
306 */
307
308 /*
309 * int guarded_open_np(const char *pathname, int flags,
310 * const guardid_t *guard, u_int guardflags, ...);
311 *
312 * In this initial implementation, GUARD_DUP must be specified.
313 * GUARD_CLOSE, GUARD_SOCKET_IPC and GUARD_FILEPORT are optional.
314 *
315 * If GUARD_DUP wasn't specified, then we'd have to do the (extra) work
316 * to allow dup-ing a descriptor to inherit the guard onto the new
317 * descriptor. (Perhaps GUARD_DUP behaviours should just always be true
318 * for a guarded fd? Or, more sanely, all the dup operations should
319 * just always propagate the guard?)
320 *
321 * Guarded descriptors are always close-on-exec, and GUARD_CLOSE
322 * requires close-on-fork; O_CLOEXEC must be set in flags.
323 * This setting is immutable; attempts to clear the flag will
324 * cause a guard exception.
325 *
326 * XXX It's somewhat broken that change_fdguard_np() can completely
327 * remove the guard and thus revoke down the immutability
328 * promises above. Ick.
329 */
330 int
331 guarded_open_np(proc_t p, struct guarded_open_np_args *uap, int32_t *retval)
332 {
333 if ((uap->flags & O_CLOEXEC) == 0)
334 return (EINVAL);
335
336 #define GUARD_REQUIRED (GUARD_DUP)
337 #define GUARD_ALL (GUARD_REQUIRED | \
338 (GUARD_CLOSE | GUARD_SOCKET_IPC | GUARD_FILEPORT | GUARD_WRITE))
339
340 if (((uap->guardflags & GUARD_REQUIRED) != GUARD_REQUIRED) ||
341 ((uap->guardflags & ~GUARD_ALL) != 0))
342 return (EINVAL);
343
344 int error;
345 struct gfp_crarg crarg = {
346 .gca_attrs = uap->guardflags
347 };
348
349 if ((error = copyin(uap->guard,
350 &(crarg.gca_guard), sizeof (crarg.gca_guard))) != 0)
351 return (error);
352
353 /*
354 * Disallow certain guard values -- is zero enough?
355 */
356 if (crarg.gca_guard == 0)
357 return (EINVAL);
358
359 struct filedesc *fdp = p->p_fd;
360 struct vnode_attr va;
361 struct nameidata nd;
362 vfs_context_t ctx = vfs_context_current();
363 int cmode;
364
365 VATTR_INIT(&va);
366 cmode = ((uap->mode & ~fdp->fd_cmask) & ALLPERMS) & ~S_ISTXT;
367 VATTR_SET(&va, va_mode, cmode & ACCESSPERMS);
368
369 NDINIT(&nd, LOOKUP, OP_OPEN, FOLLOW | AUDITVNPATH1, UIO_USERSPACE,
370 uap->path, ctx);
371
372 return (open1(ctx, &nd, uap->flags | O_CLOFORK, &va,
373 guarded_fileproc_alloc_init, &crarg, retval));
374 }
375
376 /*
377 * int guarded_open_dprotected_np(const char *pathname, int flags,
378 * const guardid_t *guard, u_int guardflags, int dpclass, int dpflags, ...);
379 *
380 * This SPI is extension of guarded_open_np() to include dataprotection class on creation
381 * in "dpclass" and dataprotection flags 'dpflags'. Otherwise behaviors are same as in
382 * guarded_open_np()
383 */
384 int
385 guarded_open_dprotected_np(proc_t p, struct guarded_open_dprotected_np_args *uap, int32_t *retval)
386 {
387 if ((uap->flags & O_CLOEXEC) == 0)
388 return (EINVAL);
389
390 if (((uap->guardflags & GUARD_REQUIRED) != GUARD_REQUIRED) ||
391 ((uap->guardflags & ~GUARD_ALL) != 0))
392 return (EINVAL);
393
394 int error;
395 struct gfp_crarg crarg = {
396 .gca_attrs = uap->guardflags
397 };
398
399 if ((error = copyin(uap->guard,
400 &(crarg.gca_guard), sizeof (crarg.gca_guard))) != 0)
401 return (error);
402
403 /*
404 * Disallow certain guard values -- is zero enough?
405 */
406 if (crarg.gca_guard == 0)
407 return (EINVAL);
408
409 struct filedesc *fdp = p->p_fd;
410 struct vnode_attr va;
411 struct nameidata nd;
412 vfs_context_t ctx = vfs_context_current();
413 int cmode;
414
415 VATTR_INIT(&va);
416 cmode = ((uap->mode & ~fdp->fd_cmask) & ALLPERMS) & ~S_ISTXT;
417 VATTR_SET(&va, va_mode, cmode & ACCESSPERMS);
418
419 NDINIT(&nd, LOOKUP, OP_OPEN, FOLLOW | AUDITVNPATH1, UIO_USERSPACE,
420 uap->path, ctx);
421
422 /*
423 * Initialize the extra fields in vnode_attr to pass down dataprotection
424 * extra fields.
425 * 1. target cprotect class.
426 * 2. set a flag to mark it as requiring open-raw-encrypted semantics.
427 */
428 if (uap->flags & O_CREAT) {
429 VATTR_SET(&va, va_dataprotect_class, uap->dpclass);
430 }
431
432 if (uap->dpflags & (O_DP_GETRAWENCRYPTED|O_DP_GETRAWUNENCRYPTED)) {
433 if ( uap->flags & (O_RDWR | O_WRONLY)) {
434 /* Not allowed to write raw encrypted bytes */
435 return EINVAL;
436 }
437 if (uap->dpflags & O_DP_GETRAWENCRYPTED) {
438 VATTR_SET(&va, va_dataprotect_flags, VA_DP_RAWENCRYPTED);
439 }
440 if (uap->dpflags & O_DP_GETRAWUNENCRYPTED) {
441 VATTR_SET(&va, va_dataprotect_flags, VA_DP_RAWUNENCRYPTED);
442 }
443 }
444
445 return (open1(ctx, &nd, uap->flags | O_CLOFORK, &va,
446 guarded_fileproc_alloc_init, &crarg, retval));
447 }
448
449 /*
450 * int guarded_kqueue_np(const guardid_t *guard, u_int guardflags);
451 *
452 * Create a guarded kqueue descriptor with guardid and guardflags.
453 *
454 * Same restrictions on guardflags as for guarded_open_np().
455 * All kqueues are -always- close-on-exec and close-on-fork by themselves
456 * and are not sendable.
457 */
458 int
459 guarded_kqueue_np(proc_t p, struct guarded_kqueue_np_args *uap, int32_t *retval)
460 {
461 if (((uap->guardflags & GUARD_REQUIRED) != GUARD_REQUIRED) ||
462 ((uap->guardflags & ~GUARD_ALL) != 0))
463 return (EINVAL);
464
465 int error;
466 struct gfp_crarg crarg = {
467 .gca_attrs = uap->guardflags
468 };
469
470 if ((error = copyin(uap->guard,
471 &(crarg.gca_guard), sizeof (crarg.gca_guard))) != 0)
472 return (error);
473
474 if (crarg.gca_guard == 0)
475 return (EINVAL);
476
477 return (kqueue_body(p, guarded_fileproc_alloc_init, &crarg, retval));
478 }
479
480 /*
481 * int guarded_close_np(int fd, const guardid_t *guard);
482 */
483 int
484 guarded_close_np(proc_t p, struct guarded_close_np_args *uap,
485 __unused int32_t *retval)
486 {
487 struct guarded_fileproc *gfp;
488 int fd = uap->fd;
489 int error;
490 guardid_t uguard;
491
492 AUDIT_SYSCLOSE(p, fd);
493
494 if ((error = copyin(uap->guard, &uguard, sizeof (uguard))) != 0)
495 return (error);
496
497 proc_fdlock(p);
498 if ((error = fp_lookup_guarded(p, fd, uguard, &gfp, 1)) != 0) {
499 proc_fdunlock(p);
500 return (error);
501 }
502 error = close_internal_locked(p, fd, GFP_TO_FP(gfp), 0);
503 proc_fdunlock(p);
504 return (error);
505 }
506
507 /*
508 * int
509 * change_fdguard_np(int fd, const guardid_t *guard, u_int guardflags,
510 * const guardid_t *nguard, u_int nguardflags, int *fdflagsp);
511 *
512 * Given a file descriptor, atomically exchange <guard, guardflags> for
513 * a new guard <nguard, nguardflags>, returning the previous fd
514 * flags (see fcntl:F_SETFD) in *fdflagsp.
515 *
516 * This syscall can be used to either (a) add a new guard to an existing
517 * unguarded file descriptor (b) remove the old guard from an existing
518 * guarded file descriptor or (c) change the guard (guardid and/or
519 * guardflags) on a guarded file descriptor.
520 *
521 * If 'guard' is NULL, fd must be unguarded at entry. If the call completes
522 * successfully the fd will be guarded with <nguard, nguardflags>.
523 *
524 * Guarding a file descriptor has some side-effects on the "fdflags"
525 * associated with the descriptor - in particular FD_CLOEXEC is
526 * forced ON unconditionally, and FD_CLOFORK is forced ON by GUARD_CLOSE.
527 * Callers who wish to subsequently restore the state of the fd should save
528 * the value of *fdflagsp after a successful invocation.
529 *
530 * If 'nguard' is NULL, fd must be guarded at entry, <guard, guardflags>
531 * must match with what's already guarding the descriptor, and the
532 * result will be to completely remove the guard. Note also that the
533 * fdflags are copied to the descriptor from the incoming *fdflagsp argument.
534 *
535 * If the descriptor is guarded, and neither 'guard' nor 'nguard' is NULL
536 * and <guard, guardflags> matches what's already guarding the descriptor,
537 * then <nguard, nguardflags> becomes the new guard. In this case, even if
538 * the GUARD_CLOSE flag is being cleared, it is still possible to continue
539 * to keep FD_CLOFORK on the descriptor by passing FD_CLOFORK via fdflagsp.
540 *
541 * (File descriptors whose underlying fileglobs are marked FG_CONFINED are
542 * still close-on-fork, regardless of the setting of FD_CLOFORK.)
543 *
544 * Example 1: Guard an unguarded descriptor during a set of operations,
545 * then restore the original state of the descriptor.
546 *
547 * int sav_flags = 0;
548 * change_fdguard_np(fd, NULL, 0, &myguard, GUARD_CLOSE, &sav_flags);
549 * // do things with now guarded 'fd'
550 * change_fdguard_np(fd, &myguard, GUARD_CLOSE, NULL, 0, &sav_flags);
551 * // fd now unguarded.
552 *
553 * Example 2: Change the guard of a guarded descriptor during a set of
554 * operations, then restore the original state of the descriptor.
555 *
556 * int sav_flags = (gdflags & GUARD_CLOSE) ? FD_CLOFORK : 0;
557 * change_fdguard_np(fd, &gd, gdflags, &myguard, GUARD_CLOSE, &sav_flags);
558 * // do things with 'fd' with a different guard
559 * change_fdguard_np(fd, &myg, GUARD_CLOSE, &gd, gdflags, &sav_flags);
560 * // back to original guarded state
561 *
562 * XXX This SPI is too much of a chainsaw and should be revised.
563 */
564
565 int
566 change_fdguard_np(proc_t p, struct change_fdguard_np_args *uap,
567 __unused int32_t *retval)
568 {
569 struct fileproc *fp;
570 int fd = uap->fd;
571 int error;
572 guardid_t oldg = 0, newg = 0;
573 int nfdflags = 0;
574
575 if (0 != uap->guard &&
576 0 != (error = copyin(uap->guard, &oldg, sizeof (oldg))))
577 return (error); /* can't copyin current guard */
578
579 if (0 != uap->nguard &&
580 0 != (error = copyin(uap->nguard, &newg, sizeof (newg))))
581 return (error); /* can't copyin new guard */
582
583 if (0 != uap->fdflagsp &&
584 0 != (error = copyin(uap->fdflagsp, &nfdflags, sizeof (nfdflags))))
585 return (error); /* can't copyin new fdflags */
586
587 proc_fdlock(p);
588 restart:
589 if ((error = fp_lookup(p, fd, &fp, 1)) != 0) {
590 proc_fdunlock(p);
591 return (error);
592 }
593
594 if (0 != uap->fdflagsp) {
595 int ofdflags = FDFLAGS_GET(p, fd);
596 int ofl = ((ofdflags & UF_EXCLOSE) ? FD_CLOEXEC : 0) |
597 ((ofdflags & UF_FORKCLOSE) ? FD_CLOFORK : 0);
598 proc_fdunlock(p);
599 if (0 != (error = copyout(&ofl, uap->fdflagsp, sizeof (ofl)))) {
600 proc_fdlock(p);
601 goto dropout; /* can't copyout old fdflags */
602 }
603 proc_fdlock(p);
604 }
605
606 if (FILEPROC_TYPE(fp) == FTYPE_GUARDED) {
607 if (0 == uap->guard || 0 == uap->guardflags)
608 error = EINVAL; /* missing guard! */
609 else if (0 == oldg)
610 error = EPERM; /* guardids cannot be zero */
611 } else {
612 if (0 != uap->guard || 0 != uap->guardflags)
613 error = EINVAL; /* guard provided, but none needed! */
614 }
615
616 if (0 != error)
617 goto dropout;
618
619 if (0 != uap->nguard) {
620 /*
621 * There's a new guard in town.
622 */
623 if (0 == newg)
624 error = EINVAL; /* guards cannot contain zero */
625 else if (((uap->nguardflags & GUARD_REQUIRED) != GUARD_REQUIRED) ||
626 ((uap->nguardflags & ~GUARD_ALL) != 0))
627 error = EINVAL; /* must have valid attributes too */
628 if (0 != error)
629 goto dropout;
630
631 if (FILEPROC_TYPE(fp) == FTYPE_GUARDED) {
632 /*
633 * Replace old guard with new guard
634 */
635 struct guarded_fileproc *gfp = FP_TO_GFP(fp);
636
637 if (GUARDED_FILEPROC_MAGIC != gfp->gf_magic)
638 panic("%s: corrupt gfp %p flags %x",
639 __func__, gfp, fp->f_flags);
640
641 if (oldg == gfp->gf_guard &&
642 uap->guardflags == gfp->gf_attrs) {
643 /*
644 * Must match existing guard + attributes
645 * before we'll swap them to new ones, managing
646 * fdflags "side-effects" as we go. Note that
647 * userland can request FD_CLOFORK semantics.
648 */
649 if (gfp->gf_attrs & GUARD_CLOSE)
650 FDFLAGS_CLR(p, fd, UF_FORKCLOSE);
651 gfp->gf_guard = newg;
652 gfp->gf_attrs = uap->nguardflags;
653 if (gfp->gf_attrs & GUARD_CLOSE)
654 FDFLAGS_SET(p, fd, UF_FORKCLOSE);
655 FDFLAGS_SET(p, fd,
656 (nfdflags & FD_CLOFORK) ? UF_FORKCLOSE : 0);
657 /* FG_CONFINED enforced regardless */
658 } else {
659 error = EPERM;
660 }
661 goto dropout;
662 } else {
663 /*
664 * Add a guard to a previously unguarded descriptor
665 */
666 switch (FILEGLOB_DTYPE(fp->f_fglob)) {
667 case DTYPE_VNODE:
668 case DTYPE_PIPE:
669 case DTYPE_SOCKET:
670 case DTYPE_KQUEUE:
671 break;
672 default:
673 error = ENOTSUP;
674 goto dropout;
675 }
676
677 proc_fdunlock(p);
678
679 struct gfp_crarg crarg = {
680 .gca_guard = newg,
681 .gca_attrs = uap->nguardflags
682 };
683 struct fileproc *nfp =
684 guarded_fileproc_alloc_init(&crarg);
685 struct guarded_fileproc *gfp;
686
687 proc_fdlock(p);
688
689 switch (error = fp_tryswap(p, fd, nfp)) {
690 case 0: /* guarded-ness comes with side-effects */
691 gfp = FP_TO_GFP(nfp);
692 if (gfp->gf_attrs & GUARD_CLOSE)
693 FDFLAGS_SET(p, fd, UF_FORKCLOSE);
694 FDFLAGS_SET(p, fd, UF_EXCLOSE);
695 (void) fp_drop(p, fd, nfp, 1);
696 fileproc_free(fp);
697 break;
698 case EKEEPLOOKING: /* f_iocount indicates a collision */
699 (void) fp_drop(p, fd, fp, 1);
700 fileproc_free(nfp);
701 goto restart;
702 default:
703 (void) fp_drop(p, fd, fp, 1);
704 fileproc_free(nfp);
705 break;
706 }
707 proc_fdunlock(p);
708 return (error);
709 }
710 } else {
711 /*
712 * No new guard.
713 */
714 if (FILEPROC_TYPE(fp) == FTYPE_GUARDED) {
715 /*
716 * Remove the guard altogether.
717 */
718 struct guarded_fileproc *gfp = FP_TO_GFP(fp);
719
720 if (0 != uap->nguardflags) {
721 error = EINVAL;
722 goto dropout;
723 }
724
725 if (GUARDED_FILEPROC_MAGIC != gfp->gf_magic)
726 panic("%s: corrupt gfp %p flags %x",
727 __func__, gfp, fp->f_flags);
728
729 if (oldg != gfp->gf_guard ||
730 uap->guardflags != gfp->gf_attrs) {
731 error = EPERM;
732 goto dropout;
733 }
734
735 proc_fdunlock(p);
736 struct fileproc *nfp = fileproc_alloc_init(NULL);
737 proc_fdlock(p);
738
739 switch (error = fp_tryswap(p, fd, nfp)) {
740 case 0: /* undo side-effects of guarded-ness */
741 FDFLAGS_CLR(p, fd, UF_FORKCLOSE | UF_EXCLOSE);
742 FDFLAGS_SET(p, fd,
743 (nfdflags & FD_CLOFORK) ? UF_FORKCLOSE : 0);
744 /* FG_CONFINED enforced regardless */
745 FDFLAGS_SET(p, fd,
746 (nfdflags & FD_CLOEXEC) ? UF_EXCLOSE : 0);
747 (void) fp_drop(p, fd, nfp, 1);
748 fileproc_free(fp);
749 break;
750 case EKEEPLOOKING: /* f_iocount indicates collision */
751 (void) fp_drop(p, fd, fp, 1);
752 fileproc_free(nfp);
753 goto restart;
754 default:
755 (void) fp_drop(p, fd, fp, 1);
756 fileproc_free(nfp);
757 break;
758 }
759 proc_fdunlock(p);
760 return (error);
761 } else {
762 /*
763 * Not already guarded, and no new guard?
764 */
765 error = EINVAL;
766 }
767 }
768
769 dropout:
770 (void) fp_drop(p, fd, fp, 1);
771 proc_fdunlock(p);
772 return (error);
773 }
774
775 /*
776 * user_ssize_t guarded_write_np(int fd, const guardid_t *guard,
777 * user_addr_t cbuf, user_ssize_t nbyte);
778 *
779 * Initial implementation of guarded writes.
780 */
781 int
782 guarded_write_np(struct proc *p, struct guarded_write_np_args *uap, user_ssize_t *retval)
783 {
784 int error;
785 int fd = uap->fd;
786 guardid_t uguard;
787 struct fileproc *fp;
788 struct guarded_fileproc *gfp;
789 bool wrote_some = false;
790
791 AUDIT_ARG(fd, fd);
792
793 if ((error = copyin(uap->guard, &uguard, sizeof (uguard))) != 0)
794 return (error);
795
796 error = fp_lookup_guarded(p, fd, uguard, &gfp, 0);
797 if (error)
798 return(error);
799
800 fp = GFP_TO_FP(gfp);
801 if ((fp->f_flag & FWRITE) == 0) {
802 error = EBADF;
803 } else {
804
805 struct vfs_context context = *(vfs_context_current());
806 context.vc_ucred = fp->f_fglob->fg_cred;
807
808 error = dofilewrite(&context, fp, uap->cbuf, uap->nbyte,
809 (off_t)-1, 0, retval);
810 wrote_some = *retval > 0;
811 }
812 if (wrote_some)
813 fp_drop_written(p, fd, fp);
814 else
815 fp_drop(p, fd, fp, 0);
816 return(error);
817 }
818
819 /*
820 * user_ssize_t guarded_pwrite_np(int fd, const guardid_t *guard,
821 * user_addr_t buf, user_size_t nbyte, off_t offset);
822 *
823 * Initial implementation of guarded pwrites.
824 */
825 int
826 guarded_pwrite_np(struct proc *p, struct guarded_pwrite_np_args *uap, user_ssize_t *retval)
827 {
828 struct fileproc *fp;
829 int error;
830 int fd = uap->fd;
831 vnode_t vp = (vnode_t)0;
832 guardid_t uguard;
833 struct guarded_fileproc *gfp;
834 bool wrote_some = false;
835
836 AUDIT_ARG(fd, fd);
837
838 if ((error = copyin(uap->guard, &uguard, sizeof (uguard))) != 0)
839 return (error);
840
841 error = fp_lookup_guarded(p, fd, uguard, &gfp, 0);
842 if (error)
843 return(error);
844
845 fp = GFP_TO_FP(gfp);
846 if ((fp->f_flag & FWRITE) == 0) {
847 error = EBADF;
848 } else {
849 struct vfs_context context = *vfs_context_current();
850 context.vc_ucred = fp->f_fglob->fg_cred;
851
852 if (fp->f_type != DTYPE_VNODE) {
853 error = ESPIPE;
854 goto errout;
855 }
856 vp = (vnode_t)fp->f_fglob->fg_data;
857 if (vnode_isfifo(vp)) {
858 error = ESPIPE;
859 goto errout;
860 }
861 if ((vp->v_flag & VISTTY)) {
862 error = ENXIO;
863 goto errout;
864 }
865 if (uap->offset == (off_t)-1) {
866 error = EINVAL;
867 goto errout;
868 }
869
870 error = dofilewrite(&context, fp, uap->buf, uap->nbyte,
871 uap->offset, FOF_OFFSET, retval);
872 wrote_some = *retval > 0;
873 }
874 errout:
875 if (wrote_some)
876 fp_drop_written(p, fd, fp);
877 else
878 fp_drop(p, fd, fp, 0);
879
880 KERNEL_DEBUG_CONSTANT((BSDDBG_CODE(DBG_BSD_SC_EXTENDED_INFO, SYS_guarded_pwrite_np) | DBG_FUNC_NONE),
881 uap->fd, uap->nbyte, (unsigned int)((uap->offset >> 32)), (unsigned int)(uap->offset), 0);
882
883 return(error);
884 }
885
886 /*
887 * user_ssize_t guarded_writev_np(int fd, const guardid_t *guard,
888 * struct iovec *iovp, u_int iovcnt);
889 *
890 * Initial implementation of guarded writev.
891 *
892 */
893 int
894 guarded_writev_np(struct proc *p, struct guarded_writev_np_args *uap, user_ssize_t *retval)
895 {
896 uio_t auio = NULL;
897 int error;
898 struct fileproc *fp;
899 struct user_iovec *iovp;
900 guardid_t uguard;
901 struct guarded_fileproc *gfp;
902 bool wrote_some = false;
903
904 AUDIT_ARG(fd, uap->fd);
905
906 /* Verify range bedfore calling uio_create() */
907 if (uap->iovcnt <= 0 || uap->iovcnt > UIO_MAXIOV)
908 return (EINVAL);
909
910 /* allocate a uio large enough to hold the number of iovecs passed */
911 auio = uio_create(uap->iovcnt, 0,
912 (IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32),
913 UIO_WRITE);
914
915 /* get location of iovecs within the uio. then copyin the iovecs from
916 * user space.
917 */
918 iovp = uio_iovsaddr(auio);
919 if (iovp == NULL) {
920 error = ENOMEM;
921 goto ExitThisRoutine;
922 }
923 error = copyin_user_iovec_array(uap->iovp,
924 IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32,
925 uap->iovcnt, iovp);
926 if (error) {
927 goto ExitThisRoutine;
928 }
929
930 /* finalize uio_t for use and do the IO
931 */
932 error = uio_calculateresid(auio);
933 if (error) {
934 goto ExitThisRoutine;
935 }
936
937 if ((error = copyin(uap->guard, &uguard, sizeof (uguard))) != 0)
938 goto ExitThisRoutine;
939
940 error = fp_lookup_guarded(p, uap->fd, uguard, &gfp, 0);
941 if (error)
942 goto ExitThisRoutine;
943
944 fp = GFP_TO_FP(gfp);
945 if ((fp->f_flag & FWRITE) == 0) {
946 error = EBADF;
947 } else {
948 error = wr_uio(p, fp, auio, retval);
949 wrote_some = *retval > 0;
950 }
951
952 if (wrote_some)
953 fp_drop_written(p, uap->fd, fp);
954 else
955 fp_drop(p, uap->fd, fp, 0);
956 ExitThisRoutine:
957 if (auio != NULL) {
958 uio_free(auio);
959 }
960 return (error);
961 }