2 * Copyright (c) 1999-2009 Apple Inc.
3 * Copyright (c) 2005 Robert N. M. Watson
6 * @APPLE_BSD_LICENSE_HEADER_START@
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of Apple Inc. ("Apple") nor the names of
17 * its contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
24 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
32 * @APPLE_BSD_LICENSE_HEADER_END@
35 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
36 * support for mandatory and extensible security protections. This notice
37 * is included in support of clause 2.2 (b) of the Apple Public License,
41 #include <sys/systm.h>
42 #include <sys/sysent.h>
43 #include <sys/types.h>
44 #include <sys/proc_internal.h>
45 #include <sys/vnode_internal.h>
46 #include <sys/fcntl.h>
47 #include <sys/filedesc.h>
49 #include <sys/syscall.h>
51 #include <bsm/audit.h>
52 #include <bsm/audit_kevents.h>
53 #include <security/audit/audit.h>
54 #include <security/audit/audit_bsd.h>
55 #include <security/audit/audit_private.h>
56 #include <IOKit/IOBSD.h>
60 * Hash table functions for the audit event number to event class mask
63 #define EVCLASSMAP_HASH_TABLE_SIZE 251
67 LIST_ENTRY(evclass_elem
) entry
;
70 LIST_HEAD(, evclass_elem
) head
;
73 static MALLOC_DEFINE(M_AUDITEVCLASS
, "audit_evclass", "Audit event class");
74 static struct rwlock evclass_lock
;
75 static struct evclass_list evclass_hash
[EVCLASSMAP_HASH_TABLE_SIZE
];
77 #define EVCLASS_LOCK_INIT() rw_init(&evclass_lock, "evclass_lock")
78 #define EVCLASS_RLOCK() rw_rlock(&evclass_lock)
79 #define EVCLASS_RUNLOCK() rw_runlock(&evclass_lock)
80 #define EVCLASS_WLOCK() rw_wlock(&evclass_lock)
81 #define EVCLASS_WUNLOCK() rw_wunlock(&evclass_lock)
84 * Look up the class for an audit event in the class mapping table.
87 au_event_class(au_event_t event
)
89 struct evclass_list
*evcl
;
90 struct evclass_elem
*evc
;
94 evcl
= &evclass_hash
[event
% EVCLASSMAP_HASH_TABLE_SIZE
];
96 LIST_FOREACH(evc
, &evcl
->head
, entry
) {
97 if (evc
->event
== event
) {
108 * Return a new class mask that allows changing the reserved class bit
109 * only if the current task is entitled to do so or if this is being done
110 * from the kernel task. If the current task is not allowed to make the
111 * change, the reserved bit is reverted to its previous state and the rest
112 * of the mask is left intact.
115 au_class_protect(au_class_t old_class
, au_class_t new_class
)
117 au_class_t result
= new_class
;
119 /* Check if the reserved class bit has been flipped */
120 if ((old_class
& AU_CLASS_MASK_RESERVED
) !=
121 (new_class
& AU_CLASS_MASK_RESERVED
)) {
122 task_t task
= current_task();
123 if (task
!= kernel_task
&&
124 !IOTaskHasEntitlement(task
, AU_CLASS_RESERVED_ENTITLEMENT
)) {
126 * If the caller isn't entitled, revert the class bit:
127 * - First remove the reserved bit from the new_class mask
128 * - Next get the state of the old_class mask's reserved bit
129 * - Finally, OR the result from the first two operations
131 result
= (new_class
& ~AU_CLASS_MASK_RESERVED
) |
132 (old_class
& AU_CLASS_MASK_RESERVED
);
140 * Insert a event to class mapping. If the event already exists in the
141 * mapping, then replace the mapping with the new one.
143 * IMPORTANT: This function should only be called from the kernel during
144 * initialization (e.g. during au_evclassmap_init). Calling afterwards can
145 * have adverse effects on other system components that rely on event/class
148 * XXX There is currently no constraints placed on the number of mappings.
149 * May want to either limit to a number, or in terms of memory usage.
152 au_evclassmap_insert(au_event_t event
, au_class_t
class)
154 struct evclass_list
*evcl
;
155 struct evclass_elem
*evc
, *evc_new
;
158 * If this event requires auditing a system call then add it to our
159 * audit kernel event mask. We use audit_kevent_mask to check to see
160 * if the audit syscalls flag needs to be set when preselection masks
163 if (AUE_IS_A_KEVENT(event
)) {
164 audit_kevent_mask
|= class;
168 * Pessimistically, always allocate storage before acquiring mutex.
169 * Free if there is already a mapping for this event.
171 evc_new
= malloc(sizeof(*evc
), M_AUDITEVCLASS
, M_WAITOK
);
174 evcl
= &evclass_hash
[event
% EVCLASSMAP_HASH_TABLE_SIZE
];
175 LIST_FOREACH(evc
, &evcl
->head
, entry
) {
176 if (evc
->event
== event
) {
177 evc
->class = au_class_protect(evc
->class, class);
179 free(evc_new
, M_AUDITEVCLASS
);
186 * Mappings that require a new element must use 0 as the "old_class" since
187 * there is no previous state.
189 evc
->class = au_class_protect(0, class);
190 LIST_INSERT_HEAD(&evcl
->head
, evc
, entry
);
195 au_evclassmap_init(void)
200 for (i
= 0; i
< EVCLASSMAP_HASH_TABLE_SIZE
; i
++) {
201 LIST_INIT(&evclass_hash
[i
].head
);
205 * Set up the initial event to class mapping for system calls.
207 for (i
= 0; i
< nsysent
; i
++) {
208 if (sys_au_event
[i
] != AUE_NULL
) {
209 au_evclassmap_insert(sys_au_event
[i
], 0);
214 * Add the Mach system call events. These are not in sys_au_event[].
216 au_evclassmap_insert(AUE_TASKFORPID
, 0);
217 au_evclassmap_insert(AUE_PIDFORTASK
, 0);
218 au_evclassmap_insert(AUE_SWAPON
, 0);
219 au_evclassmap_insert(AUE_SWAPOFF
, 0);
220 au_evclassmap_insert(AUE_MAPFD
, 0);
221 au_evclassmap_insert(AUE_INITPROCESS
, 0);
225 * Check whether an event is aditable by comparing the mask of classes this
226 * event is part of against the given mask.
229 au_preselect(__unused au_event_t event
, au_class_t
class, au_mask_t
*mask_p
,
232 au_class_t effmask
= 0;
234 if (mask_p
== NULL
) {
239 * Perform the actual check of the masks against the event.
241 if (sorf
& AU_PRS_SUCCESS
) {
242 effmask
|= (mask_p
->am_success
& class);
245 if (sorf
& AU_PRS_FAILURE
) {
246 effmask
|= (mask_p
->am_failure
& class);
257 * Convert sysctl names and present arguments to events.
260 audit_ctlname_to_sysctlevent(int name
[], uint64_t valid_arg
)
262 /* can't parse it - so return the worst case */
263 if ((valid_arg
& (ARG_CTLNAME
| ARG_LEN
)) != (ARG_CTLNAME
| ARG_LEN
)) {
268 /* non-admin "lookups" treat them special */
278 case KERN_JOB_CONTROL
:
283 case KERN_SHREG_PRIVATIZABLE
:
285 return AUE_SYSCTL_NONADMIN
;
287 /* only treat the changeable controls as admin */
291 case KERN_MAXPROCPERUID
:
292 case KERN_MAXFILESPERPROC
:
295 case KERN_AIOPROCMAX
:
296 case KERN_AIOTHREADS
:
298 case KERN_SUGID_COREDUMP
:
299 case KERN_NX_PROTECTION
:
300 return (valid_arg
& ARG_VALUE32
) ?
301 AUE_SYSCTL
: AUE_SYSCTL_NONADMIN
;
310 * Convert an open flags specifier into a specific type of open event for
314 audit_flags_and_error_to_openevent(int oflags
, int error
)
319 * Need to check only those flags we care about.
321 oflags
= oflags
& (O_RDONLY
| O_CREAT
| O_TRUNC
| O_RDWR
| O_WRONLY
);
324 * These checks determine what flags are on with the condition that
325 * ONLY that combination is on, and no other flags are on.
332 case (O_RDONLY
| O_CREAT
):
333 aevent
= AUE_OPEN_RC
;
336 case (O_RDONLY
| O_CREAT
| O_TRUNC
):
337 aevent
= AUE_OPEN_RTC
;
340 case (O_RDONLY
| O_TRUNC
):
341 aevent
= AUE_OPEN_RT
;
345 aevent
= AUE_OPEN_RW
;
348 case (O_RDWR
| O_CREAT
):
349 aevent
= AUE_OPEN_RWC
;
352 case (O_RDWR
| O_CREAT
| O_TRUNC
):
353 aevent
= AUE_OPEN_RWTC
;
356 case (O_RDWR
| O_TRUNC
):
357 aevent
= AUE_OPEN_RWT
;
364 case (O_WRONLY
| O_CREAT
):
365 aevent
= AUE_OPEN_WC
;
368 case (O_WRONLY
| O_CREAT
| O_TRUNC
):
369 aevent
= AUE_OPEN_WTC
;
372 case (O_WRONLY
| O_TRUNC
):
373 aevent
= AUE_OPEN_WT
;
382 * Convert chatty errors to better matching events. Failures to
383 * find a file are really just attribute events -- so recast them as
386 * XXXAUDIT: Solaris defines that AUE_OPEN will never be returned, it
387 * is just a placeholder. However, in Darwin we return that in
388 * preference to other events.
390 * XXXRW: This behavior differs from FreeBSD, so possibly revise this
391 * code or this comment.
400 if (error
== ENOENT
) {
408 * Convert an open flags specifier into a specific type of open_extended event
409 * for auditing purposes.
412 audit_flags_and_error_to_openextendedevent(int oflags
, int error
)
417 * Need to check only those flags we care about.
419 oflags
= oflags
& (O_RDONLY
| O_CREAT
| O_TRUNC
| O_RDWR
| O_WRONLY
);
422 * These checks determine what flags are on with the condition that
423 * ONLY that combination is on, and no other flags are on.
427 aevent
= AUE_OPEN_EXTENDED_R
;
430 case (O_RDONLY
| O_CREAT
):
431 aevent
= AUE_OPEN_EXTENDED_RC
;
434 case (O_RDONLY
| O_CREAT
| O_TRUNC
):
435 aevent
= AUE_OPEN_EXTENDED_RTC
;
438 case (O_RDONLY
| O_TRUNC
):
439 aevent
= AUE_OPEN_EXTENDED_RT
;
443 aevent
= AUE_OPEN_EXTENDED_RW
;
446 case (O_RDWR
| O_CREAT
):
447 aevent
= AUE_OPEN_EXTENDED_RWC
;
450 case (O_RDWR
| O_CREAT
| O_TRUNC
):
451 aevent
= AUE_OPEN_EXTENDED_RWTC
;
454 case (O_RDWR
| O_TRUNC
):
455 aevent
= AUE_OPEN_EXTENDED_RWT
;
459 aevent
= AUE_OPEN_EXTENDED_W
;
462 case (O_WRONLY
| O_CREAT
):
463 aevent
= AUE_OPEN_EXTENDED_WC
;
466 case (O_WRONLY
| O_CREAT
| O_TRUNC
):
467 aevent
= AUE_OPEN_EXTENDED_WTC
;
470 case (O_WRONLY
| O_TRUNC
):
471 aevent
= AUE_OPEN_EXTENDED_WT
;
475 aevent
= AUE_OPEN_EXTENDED
;
480 * Convert chatty errors to better matching events. Failures to
481 * find a file are really just attribute events -- so recast them as
484 * XXXAUDIT: Solaris defines that AUE_OPEN will never be returned, it
485 * is just a placeholder. However, in Darwin we return that in
486 * preference to other events.
488 * XXXRW: This behavior differs from FreeBSD, so possibly revise this
489 * code or this comment.
492 case AUE_OPEN_EXTENDED_R
:
493 case AUE_OPEN_EXTENDED_RT
:
494 case AUE_OPEN_EXTENDED_RW
:
495 case AUE_OPEN_EXTENDED_RWT
:
496 case AUE_OPEN_EXTENDED_W
:
497 case AUE_OPEN_EXTENDED_WT
:
498 if (error
== ENOENT
) {
499 aevent
= AUE_OPEN_EXTENDED
;
506 * Convert an open flags specifier into a specific type of open_extended event
507 * for auditing purposes.
510 audit_flags_and_error_to_openatevent(int oflags
, int error
)
515 * Need to check only those flags we care about.
517 oflags
= oflags
& (O_RDONLY
| O_CREAT
| O_TRUNC
| O_RDWR
| O_WRONLY
);
520 * These checks determine what flags are on with the condition that
521 * ONLY that combination is on, and no other flags are on.
525 aevent
= AUE_OPENAT_R
;
528 case (O_RDONLY
| O_CREAT
):
529 aevent
= AUE_OPENAT_RC
;
532 case (O_RDONLY
| O_CREAT
| O_TRUNC
):
533 aevent
= AUE_OPENAT_RTC
;
536 case (O_RDONLY
| O_TRUNC
):
537 aevent
= AUE_OPENAT_RT
;
541 aevent
= AUE_OPENAT_RW
;
544 case (O_RDWR
| O_CREAT
):
545 aevent
= AUE_OPENAT_RWC
;
548 case (O_RDWR
| O_CREAT
| O_TRUNC
):
549 aevent
= AUE_OPENAT_RWTC
;
552 case (O_RDWR
| O_TRUNC
):
553 aevent
= AUE_OPENAT_RWT
;
557 aevent
= AUE_OPENAT_W
;
560 case (O_WRONLY
| O_CREAT
):
561 aevent
= AUE_OPENAT_WC
;
564 case (O_WRONLY
| O_CREAT
| O_TRUNC
):
565 aevent
= AUE_OPENAT_WTC
;
568 case (O_WRONLY
| O_TRUNC
):
569 aevent
= AUE_OPENAT_WT
;
578 * Convert chatty errors to better matching events. Failures to
579 * find a file are really just attribute events -- so recast them as
582 * XXXAUDIT: Solaris defines that AUE_OPENAT will never be returned, it
583 * is just a placeholder. However, in Darwin we return that in
584 * preference to other events.
586 * XXXRW: This behavior differs from FreeBSD, so possibly revise this
587 * code or this comment.
596 if (error
== ENOENT
) {
604 * Convert an open flags specifier into a specific type of openbyid event
605 * for auditing purposes.
608 audit_flags_and_error_to_openbyidevent(int oflags
, int error
)
613 * Need to check only those flags we care about.
615 oflags
= oflags
& (O_RDONLY
| O_TRUNC
| O_RDWR
| O_WRONLY
);
618 * These checks determine what flags are on with the condition that
619 * ONLY that combination is on, and no other flags are on.
623 aevent
= AUE_OPENBYID_R
;
626 case (O_RDONLY
| O_TRUNC
):
627 aevent
= AUE_OPENBYID_RT
;
631 aevent
= AUE_OPENBYID_RW
;
634 case (O_RDWR
| O_TRUNC
):
635 aevent
= AUE_OPENBYID_RWT
;
639 aevent
= AUE_OPENBYID_W
;
642 case (O_WRONLY
| O_TRUNC
):
643 aevent
= AUE_OPENBYID_WT
;
647 aevent
= AUE_OPENBYID
;
652 * Convert chatty errors to better matching events. Failures to
653 * find a file are really just attribute events -- so recast them as
658 case AUE_OPENBYID_RT
:
659 case AUE_OPENBYID_RW
:
660 case AUE_OPENBYID_RWT
:
662 case AUE_OPENBYID_WT
:
663 if (error
== ENOENT
) {
664 aevent
= AUE_OPENBYID
;
671 * Convert a MSGCTL command to a specific event.
674 audit_msgctl_to_event(int cmd
)
678 return AUE_MSGCTL_RMID
;
681 return AUE_MSGCTL_SET
;
684 return AUE_MSGCTL_STAT
;
687 /* We will audit a bad command. */
693 * Convert a SEMCTL command to a specific event.
696 audit_semctl_to_event(int cmd
)
700 return AUE_SEMCTL_GETALL
;
703 return AUE_SEMCTL_GETNCNT
;
706 return AUE_SEMCTL_GETPID
;
709 return AUE_SEMCTL_GETVAL
;
712 return AUE_SEMCTL_GETZCNT
;
715 return AUE_SEMCTL_RMID
;
718 return AUE_SEMCTL_SET
;
721 return AUE_SEMCTL_SETALL
;
724 return AUE_SEMCTL_SETVAL
;
727 return AUE_SEMCTL_STAT
;
730 /* We will audit a bad command. */
736 * Convert a command for the auditon() system call to a audit event.
739 auditon_command_event(int cmd
)
743 return AUE_AUDITON_GPOLICY
;
746 return AUE_AUDITON_SPOLICY
;
749 return AUE_AUDITON_GETKMASK
;
752 return AUE_AUDITON_SETKMASK
;
755 return AUE_AUDITON_GQCTRL
;
758 return AUE_AUDITON_SQCTRL
;
761 return AUE_AUDITON_GETCWD
;
764 return AUE_AUDITON_GETCAR
;
767 return AUE_AUDITON_GETSTAT
;
770 return AUE_AUDITON_SETSTAT
;
773 return AUE_AUDITON_SETUMASK
;
776 return AUE_AUDITON_SETSMASK
;
779 return AUE_AUDITON_GETCOND
;
782 return AUE_AUDITON_SETCOND
;
785 return AUE_AUDITON_GETCLASS
;
788 return AUE_AUDITON_SETCLASS
;
794 case A_GETPINFO_ADDR
:
797 case A_GETSINFO_ADDR
:
799 return AUE_AUDITON
; /* No special record */
804 * For darwin we rewrite events generated by fcntl(F_OPENFROM,...) and
805 * fcntl(F_UNLINKFROM,...) system calls to AUE_OPENAT_* and AUE_UNLINKAT audit
809 audit_fcntl_command_event(int cmd
, int oflags
, int error
)
813 return audit_flags_and_error_to_openatevent(oflags
, error
);
819 return AUE_FCNTL
; /* Don't change from AUE_FCNTL. */
824 * Create a canonical path from given path by prefixing either the root
825 * directory, or the current working directory.
828 audit_canon_path(struct vnode
*cwd_vp
, char *path
, char *cpath
)
835 * Convert multiple leading '/' into a single '/' if the cwd_vp is
836 * NULL (i.e. an absolute path), and strip them entirely if the
837 * cwd_vp represents a chroot directory (i.e. the caller checked for
838 * an initial '/' character itself, saw one, and passed fdp->fd_rdir).
839 * Somewhat complicated, but it places the onus for locking structs
840 * involved on the caller, and makes proxy operations explicit rather
843 if (*(path
) == '/') {
844 while (*(bufp
) == '/') {
845 bufp
++; /* skip leading '/'s */
847 if (cwd_vp
== NULL
) {
848 bufp
--; /* restore one '/' */
851 if (cwd_vp
!= NULL
) {
853 ret
= vn_getpath(cwd_vp
, cpath
, &len
);
858 if (len
< MAXPATHLEN
) {
859 cpath
[len
- 1] = '/';
861 strlcpy(cpath
+ len
, bufp
, MAXPATHLEN
- len
);
863 strlcpy(cpath
, bufp
, MAXPATHLEN
);
867 #endif /* CONFIG_AUDIT */