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