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