2 * SPDX-License-Identifier: BSD-3-Clause
4 * Copyright (c) 1999-2009 Apple Inc.
5 * Copyright (c) 2005, 2016-2017 Robert N. M. Watson
8 * Portions of this software were developed by BAE Systems, the University of
9 * Cambridge Computer Laboratory, and Memorial University under DARPA/AFRL
10 * contract FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent
11 * Computing (TC) research program.
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of Apple Inc. ("Apple") nor the names of
22 * its contributors may be used to endorse or promote products derived
23 * from this software without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
29 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
33 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
34 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD$");
41 #include <sys/param.h>
42 #include <sys/capsicum.h>
43 #include <sys/fcntl.h>
44 #include <sys/filedesc.h>
45 #include <sys/libkern.h>
46 #include <sys/malloc.h>
47 #include <sys/mount.h>
49 #include <sys/rwlock.h>
53 #include <sys/syscall.h>
54 #include <sys/sysctl.h>
55 #include <sys/sysent.h>
56 #include <sys/vnode.h>
58 #include <bsm/audit.h>
59 #include <bsm/audit_kevents.h>
60 #include <security/audit/audit.h>
61 #include <security/audit/audit_private.h>
63 struct aue_open_event {
68 static const struct aue_open_event aue_open[] = {
69 { O_RDONLY, AUE_OPEN_R },
70 { (O_RDONLY | O_CREAT), AUE_OPEN_RC },
71 { (O_RDONLY | O_CREAT | O_TRUNC), AUE_OPEN_RTC },
72 { (O_RDONLY | O_TRUNC), AUE_OPEN_RT },
73 { O_RDWR, AUE_OPEN_RW },
74 { (O_RDWR | O_CREAT), AUE_OPEN_RWC },
75 { (O_RDWR | O_CREAT | O_TRUNC), AUE_OPEN_RWTC },
76 { (O_RDWR | O_TRUNC), AUE_OPEN_RWT },
77 { O_WRONLY, AUE_OPEN_W },
78 { (O_WRONLY | O_CREAT), AUE_OPEN_WC },
79 { (O_WRONLY | O_CREAT | O_TRUNC), AUE_OPEN_WTC },
80 { (O_WRONLY | O_TRUNC), AUE_OPEN_WT },
83 static const struct aue_open_event aue_openat[] = {
84 { O_RDONLY, AUE_OPENAT_R },
85 { (O_RDONLY | O_CREAT), AUE_OPENAT_RC },
86 { (O_RDONLY | O_CREAT | O_TRUNC), AUE_OPENAT_RTC },
87 { (O_RDONLY | O_TRUNC), AUE_OPENAT_RT },
88 { O_RDWR, AUE_OPENAT_RW },
89 { (O_RDWR | O_CREAT), AUE_OPENAT_RWC },
90 { (O_RDWR | O_CREAT | O_TRUNC), AUE_OPENAT_RWTC },
91 { (O_RDWR | O_TRUNC), AUE_OPENAT_RWT },
92 { O_WRONLY, AUE_OPENAT_W },
93 { (O_WRONLY | O_CREAT), AUE_OPENAT_WC },
94 { (O_WRONLY | O_CREAT | O_TRUNC), AUE_OPENAT_WTC },
95 { (O_WRONLY | O_TRUNC), AUE_OPENAT_WT },
98 static const int aue_msgsys[] = {
104 static const int aue_msgsys_count = sizeof(aue_msgsys) / sizeof(int);
106 static const int aue_semsys[] = {
111 static const int aue_semsys_count = sizeof(aue_semsys) / sizeof(int);
113 static const int aue_shmsys[] = {
119 static const int aue_shmsys_count = sizeof(aue_shmsys) / sizeof(int);
122 * Check whether an event is aditable by comparing the mask of classes this
123 * event is part of against the given mask.
126 au_preselect(au_event_t event, au_class_t class, au_mask_t *mask_p, int sorf)
128 au_class_t effmask = 0;
134 * Perform the actual check of the masks against the event.
136 if (sorf & AU_PRS_SUCCESS)
137 effmask |= (mask_p->am_success & class);
139 if (sorf & AU_PRS_FAILURE)
140 effmask |= (mask_p->am_failure & class);
149 * Convert sysctl names and present arguments to events.
152 audit_ctlname_to_sysctlevent(int name[], uint64_t valid_arg)
155 /* can't parse it - so return the worst case */
156 if ((valid_arg & (ARG_CTLNAME | ARG_LEN)) != (ARG_CTLNAME | ARG_LEN))
160 /* non-admin "lookups" treat them special */
170 case KERN_JOB_CONTROL:
174 return (AUE_SYSCTL_NONADMIN);
176 /* only treat the changeable controls as admin */
180 case KERN_MAXPROCPERUID:
181 case KERN_MAXFILESPERPROC:
189 case KERN_NISDOMAINNAME:
190 case KERN_UPDATEINTERVAL:
195 case KERN_PS_STRINGS:
197 case KERN_LOGSIGEXIT:
199 return ((valid_arg & ARG_VALUE) ?
200 AUE_SYSCTL : AUE_SYSCTL_NONADMIN);
209 * Convert an open flags specifier into a specific type of open event for
213 audit_flags_and_error_to_openevent(int oflags, int error)
218 * Need to check only those flags we care about.
220 oflags = oflags & (O_RDONLY | O_CREAT | O_TRUNC | O_RDWR | O_WRONLY);
221 for (i = 0; i < nitems(aue_open); i++) {
222 if (aue_open[i].aoe_flags == oflags)
223 return (aue_open[i].aoe_event);
229 audit_flags_and_error_to_openatevent(int oflags, int error)
234 * Need to check only those flags we care about.
236 oflags = oflags & (O_RDONLY | O_CREAT | O_TRUNC | O_RDWR | O_WRONLY);
237 for (i = 0; i < nitems(aue_openat); i++) {
238 if (aue_openat[i].aoe_flags == oflags)
239 return (aue_openat[i].aoe_event);
245 * Convert a MSGCTL command to a specific event.
248 audit_msgctl_to_event(int cmd)
253 return (AUE_MSGCTL_RMID);
256 return (AUE_MSGCTL_SET);
259 return (AUE_MSGCTL_STAT);
262 /* We will audit a bad command. */
268 * Convert a SEMCTL command to a specific event.
271 audit_semctl_to_event(int cmd)
276 return (AUE_SEMCTL_GETALL);
279 return (AUE_SEMCTL_GETNCNT);
282 return (AUE_SEMCTL_GETPID);
285 return (AUE_SEMCTL_GETVAL);
288 return (AUE_SEMCTL_GETZCNT);
291 return (AUE_SEMCTL_RMID);
294 return (AUE_SEMCTL_SET);
297 return (AUE_SEMCTL_SETALL);
300 return (AUE_SEMCTL_SETVAL);
303 return (AUE_SEMCTL_STAT);
306 /* We will audit a bad command. */
312 * Convert msgsys(2), semsys(2), and shmsys(2) system-call variations into
313 * audit events, if possible.
316 audit_msgsys_to_event(int which)
319 if ((which >= 0) && (which < aue_msgsys_count))
320 return (aue_msgsys[which]);
322 /* Audit a bad command. */
327 audit_semsys_to_event(int which)
330 if ((which >= 0) && (which < aue_semsys_count))
331 return (aue_semsys[which]);
333 /* Audit a bad command. */
338 audit_shmsys_to_event(int which)
341 if ((which >= 0) && (which < aue_shmsys_count))
342 return (aue_shmsys[which]);
344 /* Audit a bad command. */
349 * Convert a command for the auditon() system call to a audit event.
352 auditon_command_event(int cmd)
357 return (AUE_AUDITON_GPOLICY);
360 return (AUE_AUDITON_SPOLICY);
363 return (AUE_AUDITON_GETKMASK);
366 return (AUE_AUDITON_SETKMASK);
369 return (AUE_AUDITON_GQCTRL);
372 return (AUE_AUDITON_SQCTRL);
375 return (AUE_AUDITON_GETCWD);
378 return (AUE_AUDITON_GETCAR);
381 return (AUE_AUDITON_GETSTAT);
384 return (AUE_AUDITON_SETSTAT);
387 return (AUE_AUDITON_SETUMASK);
390 return (AUE_AUDITON_SETSMASK);
393 return (AUE_AUDITON_GETCOND);
396 return (AUE_AUDITON_SETCOND);
399 return (AUE_AUDITON_GETCLASS);
402 return (AUE_AUDITON_SETCLASS);
408 case A_GETPINFO_ADDR:
412 return (AUE_AUDITON); /* No special record */
417 * Create a canonical path from given path by prefixing either the root
418 * directory, or the current working directory. If the process working
419 * directory is NULL, we could use 'rootvnode' to obtain the root directory,
420 * but this results in a volfs name written to the audit log. So we will
421 * leave the filename starting with '/' in the audit log in this case.
424 audit_canon_path(struct thread *td, int dirfd, char *path, char *cpath)
426 struct vnode *cvnp, *rvnp;
427 char *rbuf, *fbuf, *copy;
428 struct filedesc *fdp;
431 int error, needslash;
433 WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "%s: at %s:%d",
434 __func__, __FILE__, __LINE__);
438 fdp = td->td_proc->p_fd;
441 * Make sure that we handle the chroot(2) case. If there is an
442 * alternate root directory, prepend it to the audited pathname.
444 if (fdp->fd_rdir != NULL && fdp->fd_rdir != rootvnode) {
449 * If the supplied path is relative, make sure we capture the current
450 * working directory so we can prepend it to the supplied relative
454 if (dirfd == AT_FDCWD) {
458 /* XXX: fgetvp() that vhold()s vnode instead of vref()ing it would be better */
459 error = fgetvp(td, dirfd, cap_rights_init(&rights), &cvnp);
461 FILEDESC_SUNLOCK(fdp);
470 needslash = (fdp->fd_rdir != cvnp);
474 FILEDESC_SUNLOCK(fdp);
476 * NB: We require that the supplied array be at least MAXPATHLEN bytes
477 * long. If this is not the case, then we can run into serious trouble.
479 (void) sbuf_new(&sbf, cpath, MAXPATHLEN, SBUF_FIXEDLEN);
481 * Strip leading forward slashes.
486 * Make sure we handle chroot(2) and prepend the global path to these
489 * NB: vn_fullpath(9) on FreeBSD is less reliable than vn_getpath(9)
490 * on Darwin. As a result, this may need some additional attention
494 error = vn_fullpath_global(td, rvnp, &rbuf, &fbuf);
502 (void) sbuf_cat(&sbf, rbuf);
506 error = vn_fullpath(td, cvnp, &rbuf, &fbuf);
512 (void) sbuf_cat(&sbf, rbuf);
516 (void) sbuf_putc(&sbf, '/');
518 * Now that we have processed any alternate root and relative path
519 * names, add the supplied pathname.
521 (void) sbuf_cat(&sbf, copy);
523 * One or more of the previous sbuf operations could have resulted in
524 * the supplied buffer being overflowed. Check to see if this is the
527 if (sbuf_error(&sbf) != 0) {