]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_guarded.c
xnu-4903.270.47.tar.gz
[apple/xnu.git] / bsd / kern / kern_guarded.c
1 /*
2 * Copyright (c) 2018 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 <kern/exc_guard.h>
35 #include <sys/guarded.h>
36 #include <kern/kalloc.h>
37 #include <sys/sysproto.h>
38 #include <sys/vnode.h>
39 #include <sys/vnode_internal.h>
40 #include <sys/uio_internal.h>
41 #include <sys/ubc_internal.h>
42 #include <vfs/vfs_support.h>
43 #include <security/audit/audit.h>
44 #include <sys/syscall.h>
45 #include <sys/kauth.h>
46 #include <sys/kdebug.h>
47 #include <stdbool.h>
48 #include <vm/vm_protos.h>
49 #include <libkern/section_keywords.h>
50 #if CONFIG_MACF && CONFIG_VNGUARD
51 #include <security/mac.h>
52 #include <security/mac_framework.h>
53 #include <security/mac_policy.h>
54 #include <pexpert/pexpert.h>
55 #include <sys/sysctl.h>
56 #include <sys/reason.h>
57 #endif
58
59
60 #define f_flag f_fglob->fg_flag
61 #define f_type f_fglob->fg_ops->fo_type
62 extern int dofilewrite(vfs_context_t ctx, struct fileproc *fp,
63 user_addr_t bufp, user_size_t nbyte, off_t offset,
64 int flags, user_ssize_t *retval );
65 extern int wr_uio(struct proc *p, struct fileproc *fp, uio_t uio, user_ssize_t *retval);
66
67 /*
68 * Experimental guarded file descriptor support.
69 */
70
71 kern_return_t task_exception_notify(exception_type_t exception,
72 mach_exception_data_type_t code, mach_exception_data_type_t subcode);
73 kern_return_t task_violated_guard(mach_exception_code_t, mach_exception_subcode_t, void *);
74
75 /*
76 * Most fd's have an underlying fileproc struct; but some may be
77 * guarded_fileproc structs which implement guarded fds. The latter
78 * struct (below) embeds the former.
79 *
80 * The two types should be distinguished by the "type" portion of f_flags.
81 * There's also a magic number to help catch misuse and bugs.
82 *
83 * This is a bit unpleasant, but results from the desire to allow
84 * alternate file behaviours for a few file descriptors without
85 * growing the fileproc data structure.
86 */
87
88 struct guarded_fileproc {
89 struct fileproc gf_fileproc;
90 u_int gf_magic;
91 u_int gf_attrs;
92 guardid_t gf_guard;
93 };
94
95 const size_t sizeof_guarded_fileproc = sizeof(struct guarded_fileproc);
96
97 #define FP_TO_GFP(fp) ((struct guarded_fileproc *)(fp))
98 #define GFP_TO_FP(gfp) (&(gfp)->gf_fileproc)
99
100 #define GUARDED_FILEPROC_MAGIC 0x29083
101
102 struct gfp_crarg {
103 guardid_t gca_guard;
104 u_int gca_attrs;
105 };
106
107 static struct fileproc *
108 guarded_fileproc_alloc_init(void *crarg)
109 {
110 struct gfp_crarg *aarg = crarg;
111 struct guarded_fileproc *gfp;
112
113 if ((gfp = kalloc(sizeof(*gfp))) == NULL) {
114 return NULL;
115 }
116
117 bzero(gfp, sizeof(*gfp));
118 gfp->gf_fileproc.f_flags = FTYPE_GUARDED;
119 gfp->gf_magic = GUARDED_FILEPROC_MAGIC;
120 gfp->gf_guard = aarg->gca_guard;
121 gfp->gf_attrs = aarg->gca_attrs;
122
123 return GFP_TO_FP(gfp);
124 }
125
126 void
127 guarded_fileproc_free(struct fileproc *fp)
128 {
129 struct guarded_fileproc *gfp = FP_TO_GFP(fp);
130
131 if (FILEPROC_TYPE(fp) != FTYPE_GUARDED ||
132 GUARDED_FILEPROC_MAGIC != gfp->gf_magic) {
133 panic("%s: corrupt fp %p flags %x", __func__, fp, fp->f_flags);
134 }
135
136 kfree(gfp, sizeof(*gfp));
137 }
138
139 static int
140 fp_lookup_guarded(proc_t p, int fd, guardid_t guard,
141 struct guarded_fileproc **gfpp, int locked)
142 {
143 struct fileproc *fp;
144 int error;
145
146 if ((error = fp_lookup(p, fd, &fp, locked)) != 0) {
147 return error;
148 }
149 if (FILEPROC_TYPE(fp) != FTYPE_GUARDED) {
150 (void) fp_drop(p, fd, fp, locked);
151 return EINVAL;
152 }
153 struct guarded_fileproc *gfp = FP_TO_GFP(fp);
154
155 if (GUARDED_FILEPROC_MAGIC != gfp->gf_magic) {
156 panic("%s: corrupt fp %p", __func__, fp);
157 }
158
159 if (guard != gfp->gf_guard) {
160 (void) fp_drop(p, fd, fp, locked);
161 return EPERM; /* *not* a mismatch exception */
162 }
163 if (gfpp) {
164 *gfpp = gfp;
165 }
166 return 0;
167 }
168
169 /*
170 * Expected use pattern:
171 *
172 * if (FP_ISGUARDED(fp, GUARD_CLOSE)) {
173 * error = fp_guard_exception(p, fd, fp, kGUARD_EXC_CLOSE);
174 * proc_fdunlock(p);
175 * return (error);
176 * }
177 */
178
179 int
180 fp_isguarded(struct fileproc *fp, u_int attrs)
181 {
182 if (FILEPROC_TYPE(fp) == FTYPE_GUARDED) {
183 struct guarded_fileproc *gfp = FP_TO_GFP(fp);
184
185 if (GUARDED_FILEPROC_MAGIC != gfp->gf_magic) {
186 panic("%s: corrupt gfp %p flags %x",
187 __func__, gfp, fp->f_flags);
188 }
189 return (attrs & gfp->gf_attrs) == attrs;
190 }
191 return 0;
192 }
193
194 extern char *proc_name_address(void *p);
195
196 int
197 fp_guard_exception(proc_t p, int fd, struct fileproc *fp, u_int flavor)
198 {
199 if (FILEPROC_TYPE(fp) != FTYPE_GUARDED) {
200 panic("%s corrupt fp %p flags %x", __func__, fp, fp->f_flags);
201 }
202
203 struct guarded_fileproc *gfp = FP_TO_GFP(fp);
204 /* all gfd fields protected via proc_fdlock() */
205 proc_fdlock_assert(p, LCK_MTX_ASSERT_OWNED);
206
207 mach_exception_code_t code = 0;
208 EXC_GUARD_ENCODE_TYPE(code, GUARD_TYPE_FD);
209 EXC_GUARD_ENCODE_FLAVOR(code, flavor);
210 EXC_GUARD_ENCODE_TARGET(code, fd);
211 mach_exception_subcode_t subcode = gfp->gf_guard;
212
213 thread_t t = current_thread();
214 thread_guard_violation(t, code, subcode);
215 return EPERM;
216 }
217
218 /*
219 * (Invoked before returning to userland from the syscall handler.)
220 */
221 void
222 fd_guard_ast(
223 thread_t __unused t,
224 mach_exception_code_t code,
225 mach_exception_subcode_t subcode)
226 {
227 task_exception_notify(EXC_GUARD, code, subcode);
228 proc_t p = current_proc();
229 psignal(p, SIGKILL);
230 }
231
232 /*
233 * Experimental guarded file descriptor SPIs
234 */
235
236 /*
237 * int guarded_open_np(const char *pathname, int flags,
238 * const guardid_t *guard, u_int guardflags, ...);
239 *
240 * In this initial implementation, GUARD_DUP must be specified.
241 * GUARD_CLOSE, GUARD_SOCKET_IPC and GUARD_FILEPORT are optional.
242 *
243 * If GUARD_DUP wasn't specified, then we'd have to do the (extra) work
244 * to allow dup-ing a descriptor to inherit the guard onto the new
245 * descriptor. (Perhaps GUARD_DUP behaviours should just always be true
246 * for a guarded fd? Or, more sanely, all the dup operations should
247 * just always propagate the guard?)
248 *
249 * Guarded descriptors are always close-on-exec, and GUARD_CLOSE
250 * requires close-on-fork; O_CLOEXEC must be set in flags.
251 * This setting is immutable; attempts to clear the flag will
252 * cause a guard exception.
253 *
254 * XXX It's somewhat broken that change_fdguard_np() can completely
255 * remove the guard and thus revoke down the immutability
256 * promises above. Ick.
257 */
258 int
259 guarded_open_np(proc_t p, struct guarded_open_np_args *uap, int32_t *retval)
260 {
261 if ((uap->flags & O_CLOEXEC) == 0) {
262 return EINVAL;
263 }
264
265 #define GUARD_REQUIRED (GUARD_DUP)
266 #define GUARD_ALL (GUARD_REQUIRED | \
267 (GUARD_CLOSE | GUARD_SOCKET_IPC | GUARD_FILEPORT | GUARD_WRITE))
268
269 if (((uap->guardflags & GUARD_REQUIRED) != GUARD_REQUIRED) ||
270 ((uap->guardflags & ~GUARD_ALL) != 0)) {
271 return EINVAL;
272 }
273
274 int error;
275 struct gfp_crarg crarg = {
276 .gca_attrs = uap->guardflags
277 };
278
279 if ((error = copyin(uap->guard,
280 &(crarg.gca_guard), sizeof(crarg.gca_guard))) != 0) {
281 return error;
282 }
283
284 /*
285 * Disallow certain guard values -- is zero enough?
286 */
287 if (crarg.gca_guard == 0) {
288 return EINVAL;
289 }
290
291 struct filedesc *fdp = p->p_fd;
292 struct vnode_attr va;
293 struct nameidata nd;
294 vfs_context_t ctx = vfs_context_current();
295 int cmode;
296
297 VATTR_INIT(&va);
298 cmode = ((uap->mode & ~fdp->fd_cmask) & ALLPERMS) & ~S_ISTXT;
299 VATTR_SET(&va, va_mode, cmode & ACCESSPERMS);
300
301 NDINIT(&nd, LOOKUP, OP_OPEN, FOLLOW | AUDITVNPATH1, UIO_USERSPACE,
302 uap->path, ctx);
303
304 return open1(ctx, &nd, uap->flags | O_CLOFORK, &va,
305 guarded_fileproc_alloc_init, &crarg, retval);
306 }
307
308 /*
309 * int guarded_open_dprotected_np(const char *pathname, int flags,
310 * const guardid_t *guard, u_int guardflags, int dpclass, int dpflags, ...);
311 *
312 * This SPI is extension of guarded_open_np() to include dataprotection class on creation
313 * in "dpclass" and dataprotection flags 'dpflags'. Otherwise behaviors are same as in
314 * guarded_open_np()
315 */
316 int
317 guarded_open_dprotected_np(proc_t p, struct guarded_open_dprotected_np_args *uap, int32_t *retval)
318 {
319 if ((uap->flags & O_CLOEXEC) == 0) {
320 return EINVAL;
321 }
322
323 if (((uap->guardflags & GUARD_REQUIRED) != GUARD_REQUIRED) ||
324 ((uap->guardflags & ~GUARD_ALL) != 0)) {
325 return EINVAL;
326 }
327
328 int error;
329 struct gfp_crarg crarg = {
330 .gca_attrs = uap->guardflags
331 };
332
333 if ((error = copyin(uap->guard,
334 &(crarg.gca_guard), sizeof(crarg.gca_guard))) != 0) {
335 return error;
336 }
337
338 /*
339 * Disallow certain guard values -- is zero enough?
340 */
341 if (crarg.gca_guard == 0) {
342 return EINVAL;
343 }
344
345 struct filedesc *fdp = p->p_fd;
346 struct vnode_attr va;
347 struct nameidata nd;
348 vfs_context_t ctx = vfs_context_current();
349 int cmode;
350
351 VATTR_INIT(&va);
352 cmode = ((uap->mode & ~fdp->fd_cmask) & ALLPERMS) & ~S_ISTXT;
353 VATTR_SET(&va, va_mode, cmode & ACCESSPERMS);
354
355 NDINIT(&nd, LOOKUP, OP_OPEN, FOLLOW | AUDITVNPATH1, UIO_USERSPACE,
356 uap->path, ctx);
357
358 /*
359 * Initialize the extra fields in vnode_attr to pass down dataprotection
360 * extra fields.
361 * 1. target cprotect class.
362 * 2. set a flag to mark it as requiring open-raw-encrypted semantics.
363 */
364 if (uap->flags & O_CREAT) {
365 VATTR_SET(&va, va_dataprotect_class, uap->dpclass);
366 }
367
368 if (uap->dpflags & (O_DP_GETRAWENCRYPTED | O_DP_GETRAWUNENCRYPTED)) {
369 if (uap->flags & (O_RDWR | O_WRONLY)) {
370 /* Not allowed to write raw encrypted bytes */
371 return EINVAL;
372 }
373 if (uap->dpflags & O_DP_GETRAWENCRYPTED) {
374 VATTR_SET(&va, va_dataprotect_flags, VA_DP_RAWENCRYPTED);
375 }
376 if (uap->dpflags & O_DP_GETRAWUNENCRYPTED) {
377 VATTR_SET(&va, va_dataprotect_flags, VA_DP_RAWUNENCRYPTED);
378 }
379 }
380
381 return open1(ctx, &nd, uap->flags | O_CLOFORK, &va,
382 guarded_fileproc_alloc_init, &crarg, retval);
383 }
384
385 /*
386 * int guarded_kqueue_np(const guardid_t *guard, u_int guardflags);
387 *
388 * Create a guarded kqueue descriptor with guardid and guardflags.
389 *
390 * Same restrictions on guardflags as for guarded_open_np().
391 * All kqueues are -always- close-on-exec and close-on-fork by themselves
392 * and are not sendable.
393 */
394 int
395 guarded_kqueue_np(proc_t p, struct guarded_kqueue_np_args *uap, int32_t *retval)
396 {
397 if (((uap->guardflags & GUARD_REQUIRED) != GUARD_REQUIRED) ||
398 ((uap->guardflags & ~GUARD_ALL) != 0)) {
399 return EINVAL;
400 }
401
402 int error;
403 struct gfp_crarg crarg = {
404 .gca_attrs = uap->guardflags
405 };
406
407 if ((error = copyin(uap->guard,
408 &(crarg.gca_guard), sizeof(crarg.gca_guard))) != 0) {
409 return error;
410 }
411
412 if (crarg.gca_guard == 0) {
413 return EINVAL;
414 }
415
416 return kqueue_body(p, guarded_fileproc_alloc_init, &crarg, retval);
417 }
418
419 /*
420 * int guarded_close_np(int fd, const guardid_t *guard);
421 */
422 int
423 guarded_close_np(proc_t p, struct guarded_close_np_args *uap,
424 __unused int32_t *retval)
425 {
426 struct guarded_fileproc *gfp;
427 int fd = uap->fd;
428 int error;
429 guardid_t uguard;
430
431 AUDIT_SYSCLOSE(p, fd);
432
433 if ((error = copyin(uap->guard, &uguard, sizeof(uguard))) != 0) {
434 return error;
435 }
436
437 proc_fdlock(p);
438 if ((error = fp_lookup_guarded(p, fd, uguard, &gfp, 1)) != 0) {
439 proc_fdunlock(p);
440 return error;
441 }
442 error = close_internal_locked(p, fd, GFP_TO_FP(gfp), 0);
443 proc_fdunlock(p);
444 return error;
445 }
446
447 /*
448 * int
449 * change_fdguard_np(int fd, const guardid_t *guard, u_int guardflags,
450 * const guardid_t *nguard, u_int nguardflags, int *fdflagsp);
451 *
452 * Given a file descriptor, atomically exchange <guard, guardflags> for
453 * a new guard <nguard, nguardflags>, returning the previous fd
454 * flags (see fcntl:F_SETFD) in *fdflagsp.
455 *
456 * This syscall can be used to either (a) add a new guard to an existing
457 * unguarded file descriptor (b) remove the old guard from an existing
458 * guarded file descriptor or (c) change the guard (guardid and/or
459 * guardflags) on a guarded file descriptor.
460 *
461 * If 'guard' is NULL, fd must be unguarded at entry. If the call completes
462 * successfully the fd will be guarded with <nguard, nguardflags>.
463 *
464 * Guarding a file descriptor has some side-effects on the "fdflags"
465 * associated with the descriptor - in particular FD_CLOEXEC is
466 * forced ON unconditionally, and FD_CLOFORK is forced ON by GUARD_CLOSE.
467 * Callers who wish to subsequently restore the state of the fd should save
468 * the value of *fdflagsp after a successful invocation.
469 *
470 * If 'nguard' is NULL, fd must be guarded at entry, <guard, guardflags>
471 * must match with what's already guarding the descriptor, and the
472 * result will be to completely remove the guard. Note also that the
473 * fdflags are copied to the descriptor from the incoming *fdflagsp argument.
474 *
475 * If the descriptor is guarded, and neither 'guard' nor 'nguard' is NULL
476 * and <guard, guardflags> matches what's already guarding the descriptor,
477 * then <nguard, nguardflags> becomes the new guard. In this case, even if
478 * the GUARD_CLOSE flag is being cleared, it is still possible to continue
479 * to keep FD_CLOFORK on the descriptor by passing FD_CLOFORK via fdflagsp.
480 *
481 * (File descriptors whose underlying fileglobs are marked FG_CONFINED are
482 * still close-on-fork, regardless of the setting of FD_CLOFORK.)
483 *
484 * Example 1: Guard an unguarded descriptor during a set of operations,
485 * then restore the original state of the descriptor.
486 *
487 * int sav_flags = 0;
488 * change_fdguard_np(fd, NULL, 0, &myguard, GUARD_CLOSE, &sav_flags);
489 * // do things with now guarded 'fd'
490 * change_fdguard_np(fd, &myguard, GUARD_CLOSE, NULL, 0, &sav_flags);
491 * // fd now unguarded.
492 *
493 * Example 2: Change the guard of a guarded descriptor during a set of
494 * operations, then restore the original state of the descriptor.
495 *
496 * int sav_flags = (gdflags & GUARD_CLOSE) ? FD_CLOFORK : 0;
497 * change_fdguard_np(fd, &gd, gdflags, &myguard, GUARD_CLOSE, &sav_flags);
498 * // do things with 'fd' with a different guard
499 * change_fdguard_np(fd, &myg, GUARD_CLOSE, &gd, gdflags, &sav_flags);
500 * // back to original guarded state
501 *
502 * XXX This SPI is too much of a chainsaw and should be revised.
503 */
504
505 int
506 change_fdguard_np(proc_t p, struct change_fdguard_np_args *uap,
507 __unused int32_t *retval)
508 {
509 struct fileproc *fp;
510 int fd = uap->fd;
511 int error;
512 guardid_t oldg = 0, newg = 0;
513 int nfdflags = 0;
514
515 if (0 != uap->guard &&
516 0 != (error = copyin(uap->guard, &oldg, sizeof(oldg)))) {
517 return error; /* can't copyin current guard */
518 }
519 if (0 != uap->nguard &&
520 0 != (error = copyin(uap->nguard, &newg, sizeof(newg)))) {
521 return error; /* can't copyin new guard */
522 }
523 if (0 != uap->fdflagsp &&
524 0 != (error = copyin(uap->fdflagsp, &nfdflags, sizeof(nfdflags)))) {
525 return error; /* can't copyin new fdflags */
526 }
527 proc_fdlock(p);
528 restart:
529 if ((error = fp_lookup(p, fd, &fp, 1)) != 0) {
530 proc_fdunlock(p);
531 return error;
532 }
533
534 if (0 != uap->fdflagsp) {
535 int ofdflags = FDFLAGS_GET(p, fd);
536 int ofl = ((ofdflags & UF_EXCLOSE) ? FD_CLOEXEC : 0) |
537 ((ofdflags & UF_FORKCLOSE) ? FD_CLOFORK : 0);
538 proc_fdunlock(p);
539 if (0 != (error = copyout(&ofl, uap->fdflagsp, sizeof(ofl)))) {
540 proc_fdlock(p);
541 goto dropout; /* can't copyout old fdflags */
542 }
543 proc_fdlock(p);
544 }
545
546 if (FILEPROC_TYPE(fp) == FTYPE_GUARDED) {
547 if (0 == uap->guard || 0 == uap->guardflags) {
548 error = EINVAL; /* missing guard! */
549 } else if (0 == oldg) {
550 error = EPERM; /* guardids cannot be zero */
551 }
552 } else {
553 if (0 != uap->guard || 0 != uap->guardflags) {
554 error = EINVAL; /* guard provided, but none needed! */
555 }
556 }
557
558 if (0 != error) {
559 goto dropout;
560 }
561
562 if (0 != uap->nguard) {
563 /*
564 * There's a new guard in town.
565 */
566 if (0 == newg) {
567 error = EINVAL; /* guards cannot contain zero */
568 } else if (((uap->nguardflags & GUARD_REQUIRED) != GUARD_REQUIRED) ||
569 ((uap->nguardflags & ~GUARD_ALL) != 0)) {
570 error = EINVAL; /* must have valid attributes too */
571 }
572 if (0 != error) {
573 goto dropout;
574 }
575
576 if (FILEPROC_TYPE(fp) == FTYPE_GUARDED) {
577 /*
578 * Replace old guard with new guard
579 */
580 struct guarded_fileproc *gfp = FP_TO_GFP(fp);
581
582 if (GUARDED_FILEPROC_MAGIC != gfp->gf_magic) {
583 panic("%s: corrupt gfp %p flags %x",
584 __func__, gfp, fp->f_flags);
585 }
586
587 if (oldg == gfp->gf_guard &&
588 uap->guardflags == gfp->gf_attrs) {
589 /*
590 * Must match existing guard + attributes
591 * before we'll swap them to new ones, managing
592 * fdflags "side-effects" as we go. Note that
593 * userland can request FD_CLOFORK semantics.
594 */
595 if (gfp->gf_attrs & GUARD_CLOSE) {
596 FDFLAGS_CLR(p, fd, UF_FORKCLOSE);
597 }
598 gfp->gf_guard = newg;
599 gfp->gf_attrs = uap->nguardflags;
600 if (gfp->gf_attrs & GUARD_CLOSE) {
601 FDFLAGS_SET(p, fd, UF_FORKCLOSE);
602 }
603 FDFLAGS_SET(p, fd,
604 (nfdflags & FD_CLOFORK) ? UF_FORKCLOSE : 0);
605 /* FG_CONFINED enforced regardless */
606 } else {
607 error = EPERM;
608 }
609 goto dropout;
610 } else {
611 /*
612 * Add a guard to a previously unguarded descriptor
613 */
614 switch (FILEGLOB_DTYPE(fp->f_fglob)) {
615 case DTYPE_VNODE:
616 case DTYPE_PIPE:
617 case DTYPE_SOCKET:
618 case DTYPE_KQUEUE:
619 case DTYPE_NETPOLICY:
620 break;
621 default:
622 error = ENOTSUP;
623 goto dropout;
624 }
625
626 proc_fdunlock(p);
627
628 struct gfp_crarg crarg = {
629 .gca_guard = newg,
630 .gca_attrs = uap->nguardflags
631 };
632 struct fileproc *nfp =
633 guarded_fileproc_alloc_init(&crarg);
634 struct guarded_fileproc *gfp;
635
636 proc_fdlock(p);
637
638 switch (error = fp_tryswap(p, fd, nfp)) {
639 case 0: /* guarded-ness comes with side-effects */
640 gfp = FP_TO_GFP(nfp);
641 if (gfp->gf_attrs & GUARD_CLOSE) {
642 FDFLAGS_SET(p, fd, UF_FORKCLOSE);
643 }
644 FDFLAGS_SET(p, fd, UF_EXCLOSE);
645 (void) fp_drop(p, fd, nfp, 1);
646 fileproc_free(fp);
647 break;
648 case EKEEPLOOKING: /* f_iocount indicates a collision */
649 (void) fp_drop(p, fd, fp, 1);
650 fileproc_free(nfp);
651 goto restart;
652 default:
653 (void) fp_drop(p, fd, fp, 1);
654 fileproc_free(nfp);
655 break;
656 }
657 proc_fdunlock(p);
658 return error;
659 }
660 } else {
661 /*
662 * No new guard.
663 */
664 if (FILEPROC_TYPE(fp) == FTYPE_GUARDED) {
665 /*
666 * Remove the guard altogether.
667 */
668 struct guarded_fileproc *gfp = FP_TO_GFP(fp);
669
670 if (0 != uap->nguardflags) {
671 error = EINVAL;
672 goto dropout;
673 }
674
675 if (GUARDED_FILEPROC_MAGIC != gfp->gf_magic) {
676 panic("%s: corrupt gfp %p flags %x",
677 __func__, gfp, fp->f_flags);
678 }
679
680 if (oldg != gfp->gf_guard ||
681 uap->guardflags != gfp->gf_attrs) {
682 error = EPERM;
683 goto dropout;
684 }
685
686 proc_fdunlock(p);
687 struct fileproc *nfp = fileproc_alloc_init(NULL);
688 proc_fdlock(p);
689
690 switch (error = fp_tryswap(p, fd, nfp)) {
691 case 0: /* undo side-effects of guarded-ness */
692 FDFLAGS_CLR(p, fd, UF_FORKCLOSE | UF_EXCLOSE);
693 FDFLAGS_SET(p, fd,
694 (nfdflags & FD_CLOFORK) ? UF_FORKCLOSE : 0);
695 /* FG_CONFINED enforced regardless */
696 FDFLAGS_SET(p, fd,
697 (nfdflags & FD_CLOEXEC) ? UF_EXCLOSE : 0);
698 (void) fp_drop(p, fd, nfp, 1);
699 fileproc_free(fp);
700 break;
701 case EKEEPLOOKING: /* f_iocount indicates collision */
702 (void) fp_drop(p, fd, fp, 1);
703 fileproc_free(nfp);
704 goto restart;
705 default:
706 (void) fp_drop(p, fd, fp, 1);
707 fileproc_free(nfp);
708 break;
709 }
710 proc_fdunlock(p);
711 return error;
712 } else {
713 /*
714 * Not already guarded, and no new guard?
715 */
716 error = EINVAL;
717 }
718 }
719
720 dropout:
721 (void) fp_drop(p, fd, fp, 1);
722 proc_fdunlock(p);
723 return error;
724 }
725
726 /*
727 * user_ssize_t guarded_write_np(int fd, const guardid_t *guard,
728 * user_addr_t cbuf, user_ssize_t nbyte);
729 *
730 * Initial implementation of guarded writes.
731 */
732 int
733 guarded_write_np(struct proc *p, struct guarded_write_np_args *uap, user_ssize_t *retval)
734 {
735 int error;
736 int fd = uap->fd;
737 guardid_t uguard;
738 struct fileproc *fp;
739 struct guarded_fileproc *gfp;
740 bool wrote_some = false;
741
742 AUDIT_ARG(fd, fd);
743
744 if ((error = copyin(uap->guard, &uguard, sizeof(uguard))) != 0) {
745 return error;
746 }
747
748 error = fp_lookup_guarded(p, fd, uguard, &gfp, 0);
749 if (error) {
750 return error;
751 }
752
753 fp = GFP_TO_FP(gfp);
754 if ((fp->f_flag & FWRITE) == 0) {
755 error = EBADF;
756 } else {
757 struct vfs_context context = *(vfs_context_current());
758 context.vc_ucred = fp->f_fglob->fg_cred;
759
760 error = dofilewrite(&context, fp, uap->cbuf, uap->nbyte,
761 (off_t)-1, 0, retval);
762 wrote_some = *retval > 0;
763 }
764 if (wrote_some) {
765 fp_drop_written(p, fd, fp);
766 } else {
767 fp_drop(p, fd, fp, 0);
768 }
769 return error;
770 }
771
772 /*
773 * user_ssize_t guarded_pwrite_np(int fd, const guardid_t *guard,
774 * user_addr_t buf, user_size_t nbyte, off_t offset);
775 *
776 * Initial implementation of guarded pwrites.
777 */
778 int
779 guarded_pwrite_np(struct proc *p, struct guarded_pwrite_np_args *uap, user_ssize_t *retval)
780 {
781 struct fileproc *fp;
782 int error;
783 int fd = uap->fd;
784 vnode_t vp = (vnode_t)0;
785 guardid_t uguard;
786 struct guarded_fileproc *gfp;
787 bool wrote_some = false;
788
789 AUDIT_ARG(fd, fd);
790
791 if ((error = copyin(uap->guard, &uguard, sizeof(uguard))) != 0) {
792 return error;
793 }
794
795 error = fp_lookup_guarded(p, fd, uguard, &gfp, 0);
796 if (error) {
797 return error;
798 }
799
800 fp = GFP_TO_FP(gfp);
801 if ((fp->f_flag & FWRITE) == 0) {
802 error = EBADF;
803 } else {
804 struct vfs_context context = *vfs_context_current();
805 context.vc_ucred = fp->f_fglob->fg_cred;
806
807 if (fp->f_type != DTYPE_VNODE) {
808 error = ESPIPE;
809 goto errout;
810 }
811 vp = (vnode_t)fp->f_fglob->fg_data;
812 if (vnode_isfifo(vp)) {
813 error = ESPIPE;
814 goto errout;
815 }
816 if ((vp->v_flag & VISTTY)) {
817 error = ENXIO;
818 goto errout;
819 }
820 if (uap->offset == (off_t)-1) {
821 error = EINVAL;
822 goto errout;
823 }
824
825 error = dofilewrite(&context, fp, uap->buf, uap->nbyte,
826 uap->offset, FOF_OFFSET, retval);
827 wrote_some = *retval > 0;
828 }
829 errout:
830 if (wrote_some) {
831 fp_drop_written(p, fd, fp);
832 } else {
833 fp_drop(p, fd, fp, 0);
834 }
835
836 KERNEL_DEBUG_CONSTANT((BSDDBG_CODE(DBG_BSD_SC_EXTENDED_INFO, SYS_guarded_pwrite_np) | DBG_FUNC_NONE),
837 uap->fd, uap->nbyte, (unsigned int)((uap->offset >> 32)), (unsigned int)(uap->offset), 0);
838
839 return error;
840 }
841
842 /*
843 * user_ssize_t guarded_writev_np(int fd, const guardid_t *guard,
844 * struct iovec *iovp, u_int iovcnt);
845 *
846 * Initial implementation of guarded writev.
847 *
848 */
849 int
850 guarded_writev_np(struct proc *p, struct guarded_writev_np_args *uap, user_ssize_t *retval)
851 {
852 uio_t auio = NULL;
853 int error;
854 struct fileproc *fp;
855 struct user_iovec *iovp;
856 guardid_t uguard;
857 struct guarded_fileproc *gfp;
858 bool wrote_some = false;
859
860 AUDIT_ARG(fd, uap->fd);
861
862 /* Verify range bedfore calling uio_create() */
863 if (uap->iovcnt <= 0 || uap->iovcnt > UIO_MAXIOV) {
864 return EINVAL;
865 }
866
867 /* allocate a uio large enough to hold the number of iovecs passed */
868 auio = uio_create(uap->iovcnt, 0,
869 (IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32),
870 UIO_WRITE);
871
872 /* get location of iovecs within the uio. then copyin the iovecs from
873 * user space.
874 */
875 iovp = uio_iovsaddr(auio);
876 if (iovp == NULL) {
877 error = ENOMEM;
878 goto ExitThisRoutine;
879 }
880 error = copyin_user_iovec_array(uap->iovp,
881 IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32,
882 uap->iovcnt, iovp);
883 if (error) {
884 goto ExitThisRoutine;
885 }
886
887 /* finalize uio_t for use and do the IO
888 */
889 error = uio_calculateresid(auio);
890 if (error) {
891 goto ExitThisRoutine;
892 }
893
894 if ((error = copyin(uap->guard, &uguard, sizeof(uguard))) != 0) {
895 goto ExitThisRoutine;
896 }
897
898 error = fp_lookup_guarded(p, uap->fd, uguard, &gfp, 0);
899 if (error) {
900 goto ExitThisRoutine;
901 }
902
903 fp = GFP_TO_FP(gfp);
904 if ((fp->f_flag & FWRITE) == 0) {
905 error = EBADF;
906 } else {
907 error = wr_uio(p, fp, auio, retval);
908 wrote_some = *retval > 0;
909 }
910
911 if (wrote_some) {
912 fp_drop_written(p, uap->fd, fp);
913 } else {
914 fp_drop(p, uap->fd, fp, 0);
915 }
916 ExitThisRoutine:
917 if (auio != NULL) {
918 uio_free(auio);
919 }
920 return error;
921 }
922
923 /*
924 * int falloc_guarded(struct proc *p, struct fileproc **fp, int *fd,
925 * vfs_context_t ctx, const guardid_t *guard, u_int attrs);
926 *
927 * This SPI is the guarded variant of falloc(). It borrows the same
928 * restrictions as those used by the rest of the guarded_* routines.
929 */
930 int
931 falloc_guarded(struct proc *p, struct fileproc **fp, int *fd,
932 vfs_context_t ctx, const guardid_t *guard, u_int attrs)
933 {
934 struct gfp_crarg crarg;
935
936 if (((attrs & GUARD_REQUIRED) != GUARD_REQUIRED) ||
937 ((attrs & ~GUARD_ALL) != 0) || (*guard == 0)) {
938 return EINVAL;
939 }
940
941 bzero(&crarg, sizeof(crarg));
942 crarg.gca_guard = *guard;
943 crarg.gca_attrs = attrs;
944
945 return falloc_withalloc(p, fp, fd, ctx, guarded_fileproc_alloc_init,
946 &crarg);
947 }
948
949 #if CONFIG_MACF && CONFIG_VNGUARD
950
951 /*
952 * Guarded vnodes
953 *
954 * Uses MAC hooks to guard operations on vnodes in the system. Given an fd,
955 * add data to the label on the fileglob and the vnode it points at.
956 * The data contains a pointer to the fileglob, the set of attributes to
957 * guard, a guard value for uniquification, and the pid of the process
958 * who set the guard up in the first place.
959 *
960 * The fd must have been opened read/write, and the underlying
961 * fileglob is FG_CONFINED so that there's no ambiguity about the
962 * owning process.
963 *
964 * When there's a callback for a vnode operation of interest (rename, unlink,
965 * etc.) check to see if the guard permits that operation, and if not
966 * take an action e.g. log a message or generate a crash report.
967 *
968 * The label is removed from the vnode and the fileglob when the fileglob
969 * is closed.
970 *
971 * The initial action to be taken can be specified by a boot arg (vnguard=0x42)
972 * and change via the "kern.vnguard.flags" sysctl.
973 */
974
975 struct vng_owner;
976
977 struct vng_info { /* lives on the vnode label */
978 guardid_t vgi_guard;
979 unsigned vgi_attrs;
980 TAILQ_HEAD(, vng_owner) vgi_owners;
981 };
982
983 struct vng_owner { /* lives on the fileglob label */
984 proc_t vgo_p;
985 struct fileglob *vgo_fg;
986 struct vng_info *vgo_vgi;
987 TAILQ_ENTRY(vng_owner) vgo_link;
988 };
989
990 static struct vng_info *
991 new_vgi(unsigned attrs, guardid_t guard)
992 {
993 struct vng_info *vgi = kalloc(sizeof(*vgi));
994 vgi->vgi_guard = guard;
995 vgi->vgi_attrs = attrs;
996 TAILQ_INIT(&vgi->vgi_owners);
997 return vgi;
998 }
999
1000 static struct vng_owner *
1001 new_vgo(proc_t p, struct fileglob *fg)
1002 {
1003 struct vng_owner *vgo = kalloc(sizeof(*vgo));
1004 memset(vgo, 0, sizeof(*vgo));
1005 vgo->vgo_p = p;
1006 vgo->vgo_fg = fg;
1007 return vgo;
1008 }
1009
1010 static void
1011 vgi_add_vgo(struct vng_info *vgi, struct vng_owner *vgo)
1012 {
1013 vgo->vgo_vgi = vgi;
1014 TAILQ_INSERT_HEAD(&vgi->vgi_owners, vgo, vgo_link);
1015 }
1016
1017 static boolean_t
1018 vgi_remove_vgo(struct vng_info *vgi, struct vng_owner *vgo)
1019 {
1020 TAILQ_REMOVE(&vgi->vgi_owners, vgo, vgo_link);
1021 vgo->vgo_vgi = NULL;
1022 return TAILQ_EMPTY(&vgi->vgi_owners);
1023 }
1024
1025 static void
1026 free_vgi(struct vng_info *vgi)
1027 {
1028 assert(TAILQ_EMPTY(&vgi->vgi_owners));
1029 #if DEVELOP || DEBUG
1030 memset(vgi, 0xbeadfade, sizeof(*vgi));
1031 #endif
1032 kfree(vgi, sizeof(*vgi));
1033 }
1034
1035 static void
1036 free_vgo(struct vng_owner *vgo)
1037 {
1038 #if DEVELOP || DEBUG
1039 memset(vgo, 0x2bedf1d0, sizeof(*vgo));
1040 #endif
1041 kfree(vgo, sizeof(*vgo));
1042 }
1043
1044 static int label_slot;
1045 static lck_rw_t llock;
1046 static lck_grp_t *llock_grp;
1047
1048 static __inline void *
1049 vng_lbl_get(struct label *label)
1050 {
1051 lck_rw_assert(&llock, LCK_RW_ASSERT_HELD);
1052 void *data;
1053 if (NULL == label) {
1054 data = NULL;
1055 } else {
1056 data = (void *)mac_label_get(label, label_slot);
1057 }
1058 return data;
1059 }
1060
1061 static __inline struct vng_info *
1062 vng_lbl_get_withattr(struct label *label, unsigned attrmask)
1063 {
1064 struct vng_info *vgi = vng_lbl_get(label);
1065 assert(NULL == vgi || (vgi->vgi_attrs & ~VNG_ALL) == 0);
1066 if (NULL != vgi && 0 == (vgi->vgi_attrs & attrmask)) {
1067 vgi = NULL;
1068 }
1069 return vgi;
1070 }
1071
1072 static __inline void
1073 vng_lbl_set(struct label *label, void *data)
1074 {
1075 assert(NULL != label);
1076 lck_rw_assert(&llock, LCK_RW_ASSERT_EXCLUSIVE);
1077 mac_label_set(label, label_slot, (intptr_t)data);
1078 }
1079
1080 static int
1081 vnguard_sysc_setguard(proc_t p, const struct vnguard_set *vns)
1082 {
1083 const int fd = vns->vns_fd;
1084
1085 if ((vns->vns_attrs & ~VNG_ALL) != 0 ||
1086 0 == vns->vns_attrs || 0 == vns->vns_guard) {
1087 return EINVAL;
1088 }
1089
1090 int error;
1091 struct fileproc *fp;
1092 if (0 != (error = fp_lookup(p, fd, &fp, 0))) {
1093 return error;
1094 }
1095 do {
1096 /*
1097 * To avoid trivial DoS, insist that the caller
1098 * has read/write access to the file.
1099 */
1100 if ((FREAD | FWRITE) != (fp->f_flag & (FREAD | FWRITE))) {
1101 error = EBADF;
1102 break;
1103 }
1104 struct fileglob *fg = fp->f_fglob;
1105 if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
1106 error = EBADF;
1107 break;
1108 }
1109 /*
1110 * Confinement means there's only one fd pointing at
1111 * this fileglob, and will always be associated with
1112 * this pid.
1113 */
1114 if (0 == (FG_CONFINED & fg->fg_lflags)) {
1115 error = EBADF;
1116 break;
1117 }
1118 struct vnode *vp = fg->fg_data;
1119 if (!vnode_isreg(vp) || NULL == vp->v_mount) {
1120 error = EBADF;
1121 break;
1122 }
1123 error = vnode_getwithref(vp);
1124 if (0 != error) {
1125 fp_drop(p, fd, fp, 0);
1126 break;
1127 }
1128 /* Ensure the target vnode -has- a label */
1129 struct vfs_context *ctx = vfs_context_current();
1130 mac_vnode_label_update(ctx, vp, NULL);
1131
1132 struct vng_info *nvgi = new_vgi(vns->vns_attrs, vns->vns_guard);
1133 struct vng_owner *nvgo = new_vgo(p, fg);
1134
1135 lck_rw_lock_exclusive(&llock);
1136
1137 do {
1138 /*
1139 * A vnode guard is associated with one or more
1140 * fileglobs in one or more processes.
1141 */
1142 struct vng_info *vgi = vng_lbl_get(vp->v_label);
1143 struct vng_owner *vgo = vng_lbl_get(fg->fg_label);
1144
1145 if (NULL == vgi) {
1146 /* vnode unguarded, add the first guard */
1147 if (NULL != vgo) {
1148 panic("vnguard label on fileglob "
1149 "but not vnode");
1150 }
1151 /* add a kusecount so we can unlabel later */
1152 error = vnode_ref_ext(vp, O_EVTONLY, 0);
1153 if (0 == error) {
1154 /* add the guard */
1155 vgi_add_vgo(nvgi, nvgo);
1156 vng_lbl_set(vp->v_label, nvgi);
1157 vng_lbl_set(fg->fg_label, nvgo);
1158 } else {
1159 free_vgo(nvgo);
1160 free_vgi(nvgi);
1161 }
1162 } else {
1163 /* vnode already guarded */
1164 free_vgi(nvgi);
1165 if (vgi->vgi_guard != vns->vns_guard) {
1166 error = EPERM; /* guard mismatch */
1167 } else if (vgi->vgi_attrs != vns->vns_attrs) {
1168 error = EACCES; /* attr mismatch */
1169 }
1170 if (0 != error || NULL != vgo) {
1171 free_vgo(nvgo);
1172 break;
1173 }
1174 /* record shared ownership */
1175 vgi_add_vgo(vgi, nvgo);
1176 vng_lbl_set(fg->fg_label, nvgo);
1177 }
1178 } while (0);
1179
1180 lck_rw_unlock_exclusive(&llock);
1181 vnode_put(vp);
1182 } while (0);
1183
1184 fp_drop(p, fd, fp, 0);
1185 return error;
1186 }
1187
1188 static int
1189 vng_policy_syscall(proc_t p, int cmd, user_addr_t arg)
1190 {
1191 int error = EINVAL;
1192
1193 switch (cmd) {
1194 case VNG_SYSC_PING:
1195 if (0 == arg) {
1196 error = 0;
1197 }
1198 break;
1199 case VNG_SYSC_SET_GUARD: {
1200 struct vnguard_set vns;
1201 error = copyin(arg, (void *)&vns, sizeof(vns));
1202 if (error) {
1203 break;
1204 }
1205 error = vnguard_sysc_setguard(p, &vns);
1206 break;
1207 }
1208 default:
1209 break;
1210 }
1211 return error;
1212 }
1213
1214 /*
1215 * This is called just before the fileglob disappears in fg_free().
1216 * Take the exclusive lock: no other thread can add or remove
1217 * a vng_info to any vnode in the system.
1218 */
1219 static void
1220 vng_file_label_destroy(struct label *label)
1221 {
1222 lck_rw_lock_exclusive(&llock);
1223 struct vng_owner *lvgo = vng_lbl_get(label);
1224 if (lvgo) {
1225 vng_lbl_set(label, 0);
1226 struct vng_info *vgi = lvgo->vgo_vgi;
1227 assert(vgi);
1228 if (vgi_remove_vgo(vgi, lvgo)) {
1229 /* that was the last reference */
1230 vgi->vgi_attrs = 0;
1231 struct fileglob *fg = lvgo->vgo_fg;
1232 assert(fg);
1233 if (DTYPE_VNODE == FILEGLOB_DTYPE(fg)) {
1234 struct vnode *vp = fg->fg_data;
1235 int error = vnode_getwithref(vp);
1236 if (0 == error) {
1237 vng_lbl_set(vp->v_label, 0);
1238 lck_rw_unlock_exclusive(&llock);
1239 /* may trigger VNOP_INACTIVE */
1240 vnode_rele_ext(vp, O_EVTONLY, 0);
1241 vnode_put(vp);
1242 free_vgi(vgi);
1243 free_vgo(lvgo);
1244 return;
1245 }
1246 }
1247 }
1248 free_vgo(lvgo);
1249 }
1250 lck_rw_unlock_exclusive(&llock);
1251 }
1252
1253 static os_reason_t
1254 vng_reason_from_pathname(const char *path, uint32_t pathlen)
1255 {
1256 os_reason_t r = os_reason_create(OS_REASON_GUARD, GUARD_REASON_VNODE);
1257 if (NULL == r) {
1258 return r;
1259 }
1260 /*
1261 * If the pathname is very long, just keep the trailing part
1262 */
1263 const uint32_t pathmax = 3 * EXIT_REASON_USER_DESC_MAX_LEN / 4;
1264 if (pathlen > pathmax) {
1265 path += (pathlen - pathmax);
1266 pathlen = pathmax;
1267 }
1268 uint32_t rsize = kcdata_estimate_required_buffer_size(1, pathlen);
1269 if (0 == os_reason_alloc_buffer(r, rsize)) {
1270 struct kcdata_descriptor *kcd = &r->osr_kcd_descriptor;
1271 mach_vm_address_t addr;
1272 if (kcdata_get_memory_addr(kcd,
1273 EXIT_REASON_USER_DESC, pathlen, &addr) == KERN_SUCCESS) {
1274 kcdata_memcpy(kcd, addr, path, pathlen);
1275 return r;
1276 }
1277 }
1278 os_reason_free(r);
1279 return OS_REASON_NULL;
1280 }
1281
1282 static int vng_policy_flags;
1283
1284 static int
1285 vng_guard_violation(const struct vng_info *vgi,
1286 unsigned opval, vnode_t vp)
1287 {
1288 int retval = 0;
1289
1290 if (vng_policy_flags & kVNG_POLICY_EPERM) {
1291 /* deny the operation */
1292 retval = EPERM;
1293 }
1294
1295 if (vng_policy_flags & (kVNG_POLICY_LOGMSG | kVNG_POLICY_UPRINTMSG)) {
1296 /* log a message */
1297 const char *op;
1298 switch (opval) {
1299 case VNG_RENAME_FROM:
1300 op = "rename-from";
1301 break;
1302 case VNG_RENAME_TO:
1303 op = "rename-to";
1304 break;
1305 case VNG_UNLINK:
1306 op = "unlink";
1307 break;
1308 case VNG_LINK:
1309 op = "link";
1310 break;
1311 case VNG_EXCHDATA:
1312 op = "exchdata";
1313 break;
1314 case VNG_WRITE_OTHER:
1315 op = "write";
1316 break;
1317 case VNG_TRUNC_OTHER:
1318 op = "truncate";
1319 break;
1320 default:
1321 op = "(unknown)";
1322 break;
1323 }
1324
1325 const char *nm = vnode_getname(vp);
1326 proc_t p = current_proc();
1327 const struct vng_owner *vgo;
1328 TAILQ_FOREACH(vgo, &vgi->vgi_owners, vgo_link) {
1329 const char fmt[] =
1330 "%s[%d]: %s%s: '%s' guarded by %s[%d] (0x%llx)\n";
1331
1332 if (vng_policy_flags & kVNG_POLICY_LOGMSG) {
1333 printf(fmt,
1334 proc_name_address(p), proc_pid(p), op,
1335 0 != retval ? " denied" : "",
1336 NULL != nm ? nm : "(unknown)",
1337 proc_name_address(vgo->vgo_p),
1338 proc_pid(vgo->vgo_p), vgi->vgi_guard);
1339 }
1340 if (vng_policy_flags & kVNG_POLICY_UPRINTMSG) {
1341 uprintf(fmt,
1342 proc_name_address(p), proc_pid(p), op,
1343 0 != retval ? " denied" : "",
1344 NULL != nm ? nm : "(unknown)",
1345 proc_name_address(vgo->vgo_p),
1346 proc_pid(vgo->vgo_p), vgi->vgi_guard);
1347 }
1348 }
1349 if (NULL != nm) {
1350 vnode_putname(nm);
1351 }
1352 }
1353
1354 if (vng_policy_flags & (kVNG_POLICY_EXC | kVNG_POLICY_EXC_CORPSE)) {
1355 /* EXC_GUARD exception */
1356 const struct vng_owner *vgo = TAILQ_FIRST(&vgi->vgi_owners);
1357 pid_t pid = vgo ? proc_pid(vgo->vgo_p) : 0;
1358 mach_exception_code_t code;
1359 mach_exception_subcode_t subcode;
1360
1361 code = 0;
1362 EXC_GUARD_ENCODE_TYPE(code, GUARD_TYPE_VN);
1363 EXC_GUARD_ENCODE_FLAVOR(code, opval);
1364 EXC_GUARD_ENCODE_TARGET(code, pid);
1365 subcode = vgi->vgi_guard;
1366
1367 if (vng_policy_flags & kVNG_POLICY_EXC_CORPSE) {
1368 char *path;
1369 int len = MAXPATHLEN;
1370 MALLOC(path, char *, len, M_TEMP, M_WAITOK);
1371 os_reason_t r = NULL;
1372 if (NULL != path) {
1373 vn_getpath(vp, path, &len);
1374 if (*path && len) {
1375 r = vng_reason_from_pathname(path, len);
1376 }
1377 }
1378 task_violated_guard(code, subcode, r); /* not fatal */
1379 if (NULL != r) {
1380 os_reason_free(r);
1381 }
1382 if (NULL != path) {
1383 FREE(path, M_TEMP);
1384 }
1385 } else {
1386 thread_t t = current_thread();
1387 thread_guard_violation(t, code, subcode);
1388 }
1389 } else if (vng_policy_flags & kVNG_POLICY_SIGKILL) {
1390 proc_t p = current_proc();
1391 psignal(p, SIGKILL);
1392 }
1393
1394 return retval;
1395 }
1396
1397 /*
1398 * A fatal vnode guard was tripped on this thread.
1399 *
1400 * (Invoked before returning to userland from the syscall handler.)
1401 */
1402 void
1403 vn_guard_ast(thread_t __unused t,
1404 mach_exception_data_type_t code, mach_exception_data_type_t subcode)
1405 {
1406 task_exception_notify(EXC_GUARD, code, subcode);
1407 proc_t p = current_proc();
1408 psignal(p, SIGKILL);
1409 }
1410
1411 /*
1412 * vnode callbacks
1413 */
1414
1415 static int
1416 vng_vnode_check_rename(kauth_cred_t __unused cred,
1417 struct vnode *__unused dvp, struct label *__unused dlabel,
1418 struct vnode *vp, struct label *label,
1419 struct componentname *__unused cnp,
1420 struct vnode *__unused tdvp, struct label *__unused tdlabel,
1421 struct vnode *tvp, struct label *tlabel,
1422 struct componentname *__unused tcnp)
1423 {
1424 int error = 0;
1425 if (NULL != label || NULL != tlabel) {
1426 lck_rw_lock_shared(&llock);
1427 const struct vng_info *vgi =
1428 vng_lbl_get_withattr(label, VNG_RENAME_FROM);
1429 if (NULL != vgi) {
1430 error = vng_guard_violation(vgi, VNG_RENAME_FROM, vp);
1431 }
1432 if (0 == error) {
1433 vgi = vng_lbl_get_withattr(tlabel, VNG_RENAME_TO);
1434 if (NULL != vgi) {
1435 error = vng_guard_violation(vgi,
1436 VNG_RENAME_TO, tvp);
1437 }
1438 }
1439 lck_rw_unlock_shared(&llock);
1440 }
1441 return error;
1442 }
1443
1444 static int
1445 vng_vnode_check_link(kauth_cred_t __unused cred,
1446 struct vnode *__unused dvp, struct label *__unused dlabel,
1447 struct vnode *vp, struct label *label, struct componentname *__unused cnp)
1448 {
1449 int error = 0;
1450 if (NULL != label) {
1451 lck_rw_lock_shared(&llock);
1452 const struct vng_info *vgi =
1453 vng_lbl_get_withattr(label, VNG_LINK);
1454 if (vgi) {
1455 error = vng_guard_violation(vgi, VNG_LINK, vp);
1456 }
1457 lck_rw_unlock_shared(&llock);
1458 }
1459 return error;
1460 }
1461
1462 static int
1463 vng_vnode_check_unlink(kauth_cred_t __unused cred,
1464 struct vnode *__unused dvp, struct label *__unused dlabel,
1465 struct vnode *vp, struct label *label, struct componentname *__unused cnp)
1466 {
1467 int error = 0;
1468 if (NULL != label) {
1469 lck_rw_lock_shared(&llock);
1470 const struct vng_info *vgi =
1471 vng_lbl_get_withattr(label, VNG_UNLINK);
1472 if (vgi) {
1473 error = vng_guard_violation(vgi, VNG_UNLINK, vp);
1474 }
1475 lck_rw_unlock_shared(&llock);
1476 }
1477 return error;
1478 }
1479
1480 /*
1481 * Only check violations for writes performed by "other processes"
1482 */
1483 static int
1484 vng_vnode_check_write(kauth_cred_t __unused actv_cred,
1485 kauth_cred_t __unused file_cred, struct vnode *vp, struct label *label)
1486 {
1487 int error = 0;
1488 if (NULL != label) {
1489 lck_rw_lock_shared(&llock);
1490 const struct vng_info *vgi =
1491 vng_lbl_get_withattr(label, VNG_WRITE_OTHER);
1492 if (vgi) {
1493 proc_t p = current_proc();
1494 const struct vng_owner *vgo;
1495 TAILQ_FOREACH(vgo, &vgi->vgi_owners, vgo_link) {
1496 if (vgo->vgo_p == p) {
1497 goto done;
1498 }
1499 }
1500 error = vng_guard_violation(vgi, VNG_WRITE_OTHER, vp);
1501 }
1502 done:
1503 lck_rw_unlock_shared(&llock);
1504 }
1505 return error;
1506 }
1507
1508 /*
1509 * Only check violations for truncates performed by "other processes"
1510 */
1511 static int
1512 vng_vnode_check_truncate(kauth_cred_t __unused actv_cred,
1513 kauth_cred_t __unused file_cred, struct vnode *vp,
1514 struct label *label)
1515 {
1516 int error = 0;
1517 if (NULL != label) {
1518 lck_rw_lock_shared(&llock);
1519 const struct vng_info *vgi =
1520 vng_lbl_get_withattr(label, VNG_TRUNC_OTHER);
1521 if (vgi) {
1522 proc_t p = current_proc();
1523 const struct vng_owner *vgo;
1524 TAILQ_FOREACH(vgo, &vgi->vgi_owners, vgo_link) {
1525 if (vgo->vgo_p == p) {
1526 goto done;
1527 }
1528 }
1529 error = vng_guard_violation(vgi, VNG_TRUNC_OTHER, vp);
1530 }
1531 done:
1532 lck_rw_unlock_shared(&llock);
1533 }
1534 return error;
1535 }
1536
1537 static int
1538 vng_vnode_check_exchangedata(kauth_cred_t __unused cred,
1539 struct vnode *fvp, struct label *flabel,
1540 struct vnode *svp, struct label *slabel)
1541 {
1542 int error = 0;
1543 if (NULL != flabel || NULL != slabel) {
1544 lck_rw_lock_shared(&llock);
1545 const struct vng_info *vgi =
1546 vng_lbl_get_withattr(flabel, VNG_EXCHDATA);
1547 if (NULL != vgi) {
1548 error = vng_guard_violation(vgi, VNG_EXCHDATA, fvp);
1549 }
1550 if (0 == error) {
1551 vgi = vng_lbl_get_withattr(slabel, VNG_EXCHDATA);
1552 if (NULL != vgi) {
1553 error = vng_guard_violation(vgi,
1554 VNG_EXCHDATA, svp);
1555 }
1556 }
1557 lck_rw_unlock_shared(&llock);
1558 }
1559 return error;
1560 }
1561
1562 /* Intercept open-time truncations (by "other") of a guarded vnode */
1563
1564 static int
1565 vng_vnode_check_open(kauth_cred_t cred,
1566 struct vnode *vp, struct label *label, int acc_mode)
1567 {
1568 if (0 == (acc_mode & O_TRUNC)) {
1569 return 0;
1570 }
1571 return vng_vnode_check_truncate(cred, NULL, vp, label);
1572 }
1573
1574 /*
1575 * Configuration gorp
1576 */
1577
1578 static void
1579 vng_init(struct mac_policy_conf *mpc)
1580 {
1581 llock_grp = lck_grp_alloc_init(mpc->mpc_name, LCK_GRP_ATTR_NULL);
1582 lck_rw_init(&llock, llock_grp, LCK_ATTR_NULL);
1583 }
1584
1585 SECURITY_READ_ONLY_EARLY(static struct mac_policy_ops) vng_policy_ops = {
1586 .mpo_file_label_destroy = vng_file_label_destroy,
1587
1588 .mpo_vnode_check_link = vng_vnode_check_link,
1589 .mpo_vnode_check_unlink = vng_vnode_check_unlink,
1590 .mpo_vnode_check_rename = vng_vnode_check_rename,
1591 .mpo_vnode_check_write = vng_vnode_check_write,
1592 .mpo_vnode_check_truncate = vng_vnode_check_truncate,
1593 .mpo_vnode_check_exchangedata = vng_vnode_check_exchangedata,
1594 .mpo_vnode_check_open = vng_vnode_check_open,
1595
1596 .mpo_policy_syscall = vng_policy_syscall,
1597 .mpo_policy_init = vng_init,
1598 };
1599
1600 static const char *vng_labelnames[] = {
1601 "vnguard",
1602 };
1603
1604 #define ACOUNT(arr) ((unsigned)(sizeof (arr) / sizeof (arr[0])))
1605
1606 SECURITY_READ_ONLY_LATE(static struct mac_policy_conf) vng_policy_conf = {
1607 .mpc_name = VNG_POLICY_NAME,
1608 .mpc_fullname = "Guarded vnode policy",
1609 .mpc_field_off = &label_slot,
1610 .mpc_labelnames = vng_labelnames,
1611 .mpc_labelname_count = ACOUNT(vng_labelnames),
1612 .mpc_ops = &vng_policy_ops,
1613 .mpc_loadtime_flags = 0,
1614 .mpc_runtime_flags = 0
1615 };
1616
1617 static mac_policy_handle_t vng_policy_handle;
1618
1619 void
1620 vnguard_policy_init(void)
1621 {
1622 if (0 == PE_i_can_has_debugger(NULL)) {
1623 return;
1624 }
1625 vng_policy_flags = kVNG_POLICY_LOGMSG |
1626 kVNG_POLICY_EXC_CORPSE | kVNG_POLICY_UPRINTMSG;
1627 PE_parse_boot_argn("vnguard", &vng_policy_flags, sizeof(vng_policy_flags));
1628 if (vng_policy_flags) {
1629 mac_policy_register(&vng_policy_conf, &vng_policy_handle, NULL);
1630 }
1631 }
1632
1633 #if DEBUG || DEVELOPMENT
1634 #include <sys/sysctl.h>
1635
1636 SYSCTL_DECL(_kern_vnguard);
1637 SYSCTL_NODE(_kern, OID_AUTO, vnguard, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "vnguard");
1638 SYSCTL_INT(_kern_vnguard, OID_AUTO, flags, CTLFLAG_RW | CTLFLAG_LOCKED,
1639 &vng_policy_flags, 0, "vnguard policy flags");
1640 #endif
1641
1642 #endif /* CONFIG_MACF && CONFIG_VNGUARD */