xref: /xnu-10002.1.13/bsd/security/audit/audit_mac.c (revision 1031c584a5e37aff177559b9f69dbd3c8c3fd30a)
1 /*-
2  * Copyright (c) 1999-2020 Apple Inc.
3  * All rights reserved.
4  *
5  * @APPLE_BSD_LICENSE_HEADER_START@
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1.  Redistributions of source code must retain the above copyright
11  *     notice, this list of conditions and the following disclaimer.
12  * 2.  Redistributions in binary form must reproduce the above copyright
13  *     notice, this list of conditions and the following disclaimer in the
14  *     documentation and/or other materials provided with the distribution.
15  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
16  *     its contributors may be used to endorse or promote products derived
17  *     from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
23  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
28  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  * @APPLE_BSD_LICENSE_HEADER_END@
32  */
33 /*
34  * NOTICE: This file was modified by McAfee Research in 2004 to introduce
35  * support for mandatory and extensible security protections.  This notice
36  * is included in support of clause 2.2 (b) of the Apple Public License,
37  * Version 2.0.
38  */
39 
40 #include <sys/kernel.h>
41 #include <sys/proc.h>
42 #include <sys/kauth.h>
43 #include <sys/queue.h>
44 #include <sys/systm.h>
45 
46 #include <bsm/audit.h>
47 #include <bsm/audit_internal.h>
48 #include <bsm/audit_kevents.h>
49 
50 #include <security/audit/audit.h>
51 #include <security/audit/audit_private.h>
52 
53 #include <mach/host_priv.h>
54 #include <mach/host_special_ports.h>
55 #include <mach/audit_triggers_server.h>
56 
57 #include <kern/host.h>
58 #include <kern/zalloc.h>
59 #include <kern/sched_prim.h>
60 
61 #if CONFIG_AUDIT
62 
63 #if CONFIG_MACF
64 #include <bsm/audit_record.h>
65 #include <security/mac.h>
66 #include <security/mac_framework.h>
67 #include <security/mac_policy.h>
68 #define MAC_ARG_PREFIX "arg: "
69 #define MAC_ARG_PREFIX_LEN 5
70 
71 ZONE_DEFINE(audit_mac_label_zone, "audit_mac_label_zone",
72     MAC_AUDIT_LABEL_LEN, ZC_NONE);
73 
74 int
audit_mac_new(proc_t p,struct kaudit_record * ar)75 audit_mac_new(proc_t p, struct kaudit_record *ar)
76 {
77 	struct mac mac;
78 
79 	/*
80 	 * Retrieve the MAC labels for the process.
81 	 */
82 	ar->k_ar.ar_cred_mac_labels = zalloc_flags(audit_mac_label_zone,
83 	    Z_WAITOK | Z_NOFAIL);
84 	mac.m_buflen = MAC_AUDIT_LABEL_LEN;
85 	mac.m_string = ar->k_ar.ar_cred_mac_labels;
86 	if (mac_cred_label_externalize_audit(p, &mac)) {
87 		zfree(audit_mac_label_zone, ar->k_ar.ar_cred_mac_labels);
88 		return 1;
89 	}
90 
91 	/*
92 	 * grab space for the reconds.
93 	 */
94 	ar->k_ar.ar_mac_records = (struct mac_audit_record_list_t *)
95 	    kalloc_type(struct mac_audit_record_list_t, Z_WAITOK);
96 	if (ar->k_ar.ar_mac_records == NULL) {
97 		zfree(audit_mac_label_zone, ar->k_ar.ar_cred_mac_labels);
98 		return 1;
99 	}
100 	LIST_INIT(ar->k_ar.ar_mac_records);
101 	ar->k_ar.ar_forced_by_mac = 0;
102 
103 	return 0;
104 }
105 
106 void
audit_mac_free(struct kaudit_record * ar)107 audit_mac_free(struct kaudit_record *ar)
108 {
109 	struct mac_audit_record *head, *next;
110 
111 	if (ar->k_ar.ar_vnode1_mac_labels != NULL) {
112 		zfree(audit_mac_label_zone, ar->k_ar.ar_vnode1_mac_labels);
113 	}
114 	if (ar->k_ar.ar_vnode2_mac_labels != NULL) {
115 		zfree(audit_mac_label_zone, ar->k_ar.ar_vnode2_mac_labels);
116 	}
117 	if (ar->k_ar.ar_cred_mac_labels != NULL) {
118 		zfree(audit_mac_label_zone, ar->k_ar.ar_cred_mac_labels);
119 	}
120 	if (ar->k_ar.ar_arg_mac_string != NULL) {
121 		kfree_data(ar->k_ar.ar_arg_mac_string,
122 		    MAC_MAX_LABEL_BUF_LEN + MAC_ARG_PREFIX_LEN);
123 	}
124 
125 	/*
126 	 * Free the audit data from the MAC policies.
127 	 */
128 	head = LIST_FIRST(ar->k_ar.ar_mac_records);
129 	while (head != NULL) {
130 		next = LIST_NEXT(head, records);
131 		zfree(mac_audit_data_zone, head->data);
132 		kfree_type(struct mac_audit_record, head);
133 		head = next;
134 	}
135 	kfree_type(struct mac_audit_record_list_t, ar->k_ar.ar_mac_records);
136 }
137 
138 int
audit_mac_syscall_enter(unsigned short code,proc_t p,struct uthread * uthread,kauth_cred_t my_cred,au_event_t event)139 audit_mac_syscall_enter(unsigned short code, proc_t p, struct uthread *uthread,
140     kauth_cred_t my_cred, au_event_t event)
141 {
142 	int error;
143 
144 	error = mac_audit_check_preselect(my_cred, code,
145 	    (void *)uthread->uu_arg);
146 	if (error == MAC_AUDIT_YES) {
147 		uthread->uu_ar = audit_new(event, p, uthread);
148 		if (uthread->uu_ar) {
149 			uthread->uu_ar->k_ar.ar_forced_by_mac = 1;
150 		}
151 		return 1;
152 	} else if (error == MAC_AUDIT_NO) {
153 		return 0;
154 	} else if (error == MAC_AUDIT_DEFAULT) {
155 		return 1;
156 	}
157 
158 	return 0;
159 }
160 
161 int
audit_mac_syscall_exit(unsigned short code,struct uthread * uthread,int error,int retval)162 audit_mac_syscall_exit(unsigned short code, struct uthread *uthread, int error,
163     int retval)
164 {
165 	int mac_error;
166 
167 	if (uthread->uu_ar == NULL) { /* syscall wasn't audited */
168 		return 1;
169 	}
170 
171 	/*
172 	 * Note, no other postselect mechanism exists.  If
173 	 * mac_audit_check_postselect returns MAC_AUDIT_NO, the record will be
174 	 * suppressed.  Other values at this point result in the audit record
175 	 * being committed.  This suppression behavior will probably go away in
176 	 * the port to 10.3.4.
177 	 */
178 	mac_error = mac_audit_check_postselect(kauth_cred_get(), code,
179 	    (void *) uthread->uu_arg, error, retval,
180 	    uthread->uu_ar->k_ar.ar_forced_by_mac);
181 
182 	if (mac_error == MAC_AUDIT_YES) {
183 		uthread->uu_ar->k_ar_commit |= AR_COMMIT_KERNEL;
184 	} else if (mac_error == MAC_AUDIT_NO) {
185 		audit_free(uthread->uu_ar);
186 		return 1;
187 	}
188 	return 0;
189 }
190 
191 /*
192  * This function is called by the MAC Framework to add audit data
193  * from a policy to the current audit record.
194  */
195 int
audit_mac_data(int type,int len,u_char * data)196 audit_mac_data(int type, int len, u_char *data)
197 {
198 	struct kaudit_record *cur;
199 	struct mac_audit_record *record;
200 
201 	if (audit_enabled == 0) {
202 		zfree(mac_audit_data_zone, data);
203 		return ENOTSUP;
204 	}
205 
206 	cur = currecord();
207 	if (cur == NULL) {
208 		zfree(mac_audit_data_zone, data);
209 		return ENOTSUP;
210 	}
211 
212 	/*
213 	 * XXX: Note that we silently drop the audit data if this
214 	 * allocation fails - this is consistent with the rest of the
215 	 * audit implementation.
216 	 */
217 	record = kalloc_type(struct mac_audit_record, Z_WAITOK | Z_NOFAIL);
218 
219 	record->type = type;
220 	record->length = len;
221 	record->data = data;
222 	LIST_INSERT_HEAD(cur->k_ar.ar_mac_records, record, records);
223 
224 	return 0;
225 }
226 
227 void
audit_arg_mac_string(struct kaudit_record * ar,char * string)228 audit_arg_mac_string(struct kaudit_record *ar, char *string)
229 {
230 	if (ar->k_ar.ar_arg_mac_string == NULL) {
231 		ar->k_ar.ar_arg_mac_string = kalloc_data(MAC_MAX_LABEL_BUF_LEN + MAC_ARG_PREFIX_LEN, Z_WAITOK);
232 	}
233 
234 	/*
235 	 * XXX This should be a rare event. If kalloc_data() returns NULL,
236 	 * the system is low on kernel virtual memory. To be
237 	 * consistent with the rest of audit, just return
238 	 * (may need to panic if required to for audit).
239 	 */
240 	if (ar->k_ar.ar_arg_mac_string == NULL) {
241 		return;
242 	}
243 
244 	strlcpy(ar->k_ar.ar_arg_mac_string, MAC_ARG_PREFIX,
245 	    MAC_ARG_PREFIX_LEN);
246 	strlcpy(ar->k_ar.ar_arg_mac_string + MAC_ARG_PREFIX_LEN, string,
247 	    MAC_MAX_LABEL_BUF_LEN);
248 	ARG_SET_VALID(ar, ARG_MAC_STRING);
249 }
250 #endif  /* MAC */
251 
252 #endif /* CONFIG_AUDIT */
253