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