1 | /*- |
2 | * Copyright (c) 1999-2016 Apple Inc. |
3 | * All rights reserved. |
4 | * |
5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions |
7 | * are met: |
8 | * 1. Redistributions of source code must retain the above copyright |
9 | * notice, this list of conditions and the following disclaimer. |
10 | * 2. Redistributions in binary form must reproduce the above copyright |
11 | * notice, this list of conditions and the following disclaimer in the |
12 | * documentation and/or other materials provided with the distribution. |
13 | * 3. Neither the name of Apple Inc. ("Apple") nor the names of |
14 | * its contributors may be used to endorse or promote products derived |
15 | * from this software without specific prior written permission. |
16 | * |
17 | * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND |
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
20 | * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR |
21 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
25 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
26 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
27 | * POSSIBILITY OF SUCH DAMAGE. |
28 | * |
29 | */ |
30 | /* |
31 | * NOTICE: This file was modified by McAfee Research in 2004 to introduce |
32 | * support for mandatory and extensible security protections. This notice |
33 | * is included in support of clause 2.2 (b) of the Apple Public License, |
34 | * Version 2.0. |
35 | */ |
36 | |
37 | #include <sys/param.h> |
38 | #include <sys/fcntl.h> |
39 | #include <sys/kernel.h> |
40 | #include <sys/lock.h> |
41 | #include <sys/namei.h> |
42 | #include <sys/proc_internal.h> |
43 | #include <sys/kauth.h> |
44 | #include <sys/queue.h> |
45 | #include <sys/systm.h> |
46 | #include <sys/time.h> |
47 | #include <sys/ucred.h> |
48 | #include <sys/uio.h> |
49 | #include <sys/unistd.h> |
50 | #include <sys/file_internal.h> |
51 | #include <sys/vnode_internal.h> |
52 | #include <sys/user.h> |
53 | #include <sys/syscall.h> |
54 | #include <sys/un.h> |
55 | #include <sys/sysent.h> |
56 | #include <sys/sysproto.h> |
57 | #include <sys/vfs_context.h> |
58 | #include <sys/domain.h> |
59 | #include <sys/protosw.h> |
60 | #include <sys/socketvar.h> |
61 | #include <sys/codesign.h> |
62 | #include <sys/ubc.h> |
63 | |
64 | #include <bsm/audit.h> |
65 | #include <bsm/audit_internal.h> |
66 | #include <bsm/audit_kevents.h> |
67 | |
68 | #include <security/audit/audit.h> |
69 | #include <security/audit/audit_bsd.h> |
70 | #include <security/audit/audit_private.h> |
71 | |
72 | #include <mach/host_priv.h> |
73 | #include <mach/host_special_ports.h> |
74 | #include <mach/audit_triggers_server.h> |
75 | |
76 | #include <kern/host.h> |
77 | #include <kern/zalloc.h> |
78 | #include <kern/sched_prim.h> |
79 | |
80 | #if CONFIG_MACF |
81 | #include <bsm/audit_record.h> |
82 | #include <security/mac.h> |
83 | #include <security/mac_framework.h> |
84 | #include <security/mac_policy.h> |
85 | extern zone_t audit_mac_label_zone; |
86 | #endif |
87 | |
88 | #include <net/route.h> |
89 | |
90 | #include <netinet/in.h> |
91 | #include <netinet/in_pcb.h> |
92 | |
93 | #if CONFIG_AUDIT |
94 | /* |
95 | * Calls to manipulate elements of the audit record structure from system |
96 | * call code. Macro wrappers will prevent this functions from being entered |
97 | * if auditing is disabled, avoiding the function call cost. We check the |
98 | * thread audit record pointer anyway, as the audit condition could change, |
99 | * and pre-selection may not have allocated an audit record for this event. |
100 | * |
101 | * XXXAUDIT: Should we assert, in each case, that this field of the record |
102 | * hasn't already been filled in? |
103 | */ |
104 | void |
105 | audit_arg_addr(struct kaudit_record *ar, user_addr_t addr) |
106 | { |
107 | struct proc *p = current_proc(); |
108 | |
109 | ar->k_ar.ar_arg_addr = addr; |
110 | |
111 | /* |
112 | * If the process is 64-bit then flag the address as such. |
113 | */ |
114 | if (proc_is64bit(p)) { |
115 | ARG_SET_VALID(ar, ARG_ADDR64); |
116 | } else { |
117 | ARG_SET_VALID(ar, ARG_ADDR32); |
118 | } |
119 | } |
120 | |
121 | void |
122 | audit_arg_exit(struct kaudit_record *ar, int status, int retval) |
123 | { |
124 | ar->k_ar.ar_arg_exitstatus = status; |
125 | ar->k_ar.ar_arg_exitretval = retval; |
126 | ARG_SET_VALID(ar, ARG_EXIT); |
127 | } |
128 | |
129 | void |
130 | audit_arg_len(struct kaudit_record *ar, user_size_t len) |
131 | { |
132 | ar->k_ar.ar_arg_len = len; |
133 | ARG_SET_VALID(ar, ARG_LEN); |
134 | } |
135 | |
136 | void |
137 | audit_arg_fd2(struct kaudit_record *ar, int fd) |
138 | { |
139 | ar->k_ar.ar_arg_fd2 = fd; |
140 | ARG_SET_VALID(ar, ARG_FD2); |
141 | } |
142 | |
143 | void |
144 | audit_arg_fd(struct kaudit_record *ar, int fd) |
145 | { |
146 | ar->k_ar.ar_arg_fd = fd; |
147 | ARG_SET_VALID(ar, ARG_FD); |
148 | } |
149 | |
150 | void |
151 | audit_arg_fflags(struct kaudit_record *ar, int fflags) |
152 | { |
153 | ar->k_ar.ar_arg_fflags = fflags; |
154 | ARG_SET_VALID(ar, ARG_FFLAGS); |
155 | } |
156 | |
157 | void |
158 | audit_arg_gid(struct kaudit_record *ar, gid_t gid) |
159 | { |
160 | ar->k_ar.ar_arg_gid = gid; |
161 | ARG_SET_VALID(ar, ARG_GID); |
162 | } |
163 | |
164 | void |
165 | audit_arg_uid(struct kaudit_record *ar, uid_t uid) |
166 | { |
167 | ar->k_ar.ar_arg_uid = uid; |
168 | ARG_SET_VALID(ar, ARG_UID); |
169 | } |
170 | |
171 | void |
172 | audit_arg_egid(struct kaudit_record *ar, gid_t egid) |
173 | { |
174 | ar->k_ar.ar_arg_egid = egid; |
175 | ARG_SET_VALID(ar, ARG_EGID); |
176 | } |
177 | |
178 | void |
179 | audit_arg_euid(struct kaudit_record *ar, uid_t euid) |
180 | { |
181 | ar->k_ar.ar_arg_euid = euid; |
182 | ARG_SET_VALID(ar, ARG_EUID); |
183 | } |
184 | |
185 | void |
186 | audit_arg_rgid(struct kaudit_record *ar, gid_t rgid) |
187 | { |
188 | ar->k_ar.ar_arg_rgid = rgid; |
189 | ARG_SET_VALID(ar, ARG_RGID); |
190 | } |
191 | |
192 | void |
193 | audit_arg_ruid(struct kaudit_record *ar, uid_t ruid) |
194 | { |
195 | ar->k_ar.ar_arg_ruid = ruid; |
196 | ARG_SET_VALID(ar, ARG_RUID); |
197 | } |
198 | |
199 | void |
200 | audit_arg_sgid(struct kaudit_record *ar, gid_t sgid) |
201 | { |
202 | ar->k_ar.ar_arg_sgid = sgid; |
203 | ARG_SET_VALID(ar, ARG_SGID); |
204 | } |
205 | |
206 | void |
207 | audit_arg_suid(struct kaudit_record *ar, uid_t suid) |
208 | { |
209 | ar->k_ar.ar_arg_suid = suid; |
210 | ARG_SET_VALID(ar, ARG_SUID); |
211 | } |
212 | |
213 | void |
214 | audit_arg_groupset(struct kaudit_record *ar, const gid_t *gidset, u_int gidset_size) |
215 | { |
216 | u_int i; |
217 | |
218 | for (i = 0; i < gidset_size; i++) { |
219 | ar->k_ar.ar_arg_groups.gidset[i] = gidset[i]; |
220 | } |
221 | ar->k_ar.ar_arg_groups.gidset_size = gidset_size; |
222 | ARG_SET_VALID(ar, ARG_GROUPSET); |
223 | } |
224 | |
225 | void |
226 | audit_arg_login(struct kaudit_record *ar, const char *login) |
227 | { |
228 | strlcpy(dst: ar->k_ar.ar_arg_login, src: login, MAXLOGNAME); |
229 | ARG_SET_VALID(ar, ARG_LOGIN); |
230 | } |
231 | |
232 | void |
233 | audit_arg_ctlname(struct kaudit_record *ar, const int *name, int namelen) |
234 | { |
235 | bcopy(src: name, dst: &ar->k_ar.ar_arg_ctlname, n: namelen * sizeof(int)); |
236 | ar->k_ar.ar_arg_len = namelen; |
237 | ARG_SET_VALID(ar, ARG_CTLNAME | ARG_LEN); |
238 | } |
239 | |
240 | void |
241 | audit_arg_mask(struct kaudit_record *ar, int mask) |
242 | { |
243 | ar->k_ar.ar_arg_mask = mask; |
244 | ARG_SET_VALID(ar, ARG_MASK); |
245 | } |
246 | |
247 | void |
248 | audit_arg_mode(struct kaudit_record *ar, mode_t mode) |
249 | { |
250 | ar->k_ar.ar_arg_mode = mode; |
251 | ARG_SET_VALID(ar, ARG_MODE); |
252 | } |
253 | |
254 | void |
255 | audit_arg_value32(struct kaudit_record *ar, uint32_t value32) |
256 | { |
257 | ar->k_ar.ar_arg_value32 = value32; |
258 | ARG_SET_VALID(ar, ARG_VALUE32); |
259 | } |
260 | |
261 | void |
262 | audit_arg_value64(struct kaudit_record *ar, uint64_t value64) |
263 | { |
264 | ar->k_ar.ar_arg_value64 = value64; |
265 | ARG_SET_VALID(ar, ARG_VALUE64); |
266 | } |
267 | |
268 | void |
269 | audit_arg_owner(struct kaudit_record *ar, uid_t uid, gid_t gid) |
270 | { |
271 | ar->k_ar.ar_arg_uid = uid; |
272 | ar->k_ar.ar_arg_gid = gid; |
273 | ARG_SET_VALID(ar, ARG_UID | ARG_GID); |
274 | } |
275 | |
276 | void |
277 | audit_arg_pid(struct kaudit_record *ar, pid_t pid) |
278 | { |
279 | ar->k_ar.ar_arg_pid = pid; |
280 | ARG_SET_VALID(ar, ARG_PID); |
281 | } |
282 | |
283 | void |
284 | audit_arg_process(struct kaudit_record *ar, proc_t p) |
285 | { |
286 | kauth_cred_t my_cred; |
287 | |
288 | KASSERT(p != NULL, ("audit_arg_process: p == NULL" )); |
289 | |
290 | if (p == NULL) { |
291 | return; |
292 | } |
293 | |
294 | my_cred = kauth_cred_proc_ref(procp: p); |
295 | ar->k_ar.ar_arg_auid = my_cred->cr_audit.as_aia_p->ai_auid; |
296 | ar->k_ar.ar_arg_asid = my_cred->cr_audit.as_aia_p->ai_asid; |
297 | bcopy(src: &my_cred->cr_audit.as_aia_p->ai_termid, |
298 | dst: &ar->k_ar.ar_arg_termid_addr, n: sizeof(au_tid_addr_t)); |
299 | ar->k_ar.ar_arg_euid = kauth_cred_getuid(cred: my_cred); |
300 | ar->k_ar.ar_arg_egid = kauth_cred_getgid(cred: my_cred); |
301 | ar->k_ar.ar_arg_ruid = kauth_cred_getruid(cred: my_cred); |
302 | ar->k_ar.ar_arg_rgid = kauth_cred_getrgid(cred: my_cred); |
303 | kauth_cred_unref(&my_cred); |
304 | ar->k_ar.ar_arg_pid = proc_getpid(p); |
305 | ARG_SET_VALID(ar, ARG_AUID | ARG_EUID | ARG_EGID | ARG_RUID | |
306 | ARG_RGID | ARG_ASID | ARG_TERMID_ADDR | ARG_PID | ARG_PROCESS); |
307 | } |
308 | |
309 | void |
310 | audit_arg_signum(struct kaudit_record *ar, u_int signum) |
311 | { |
312 | ar->k_ar.ar_arg_signum = signum; |
313 | ARG_SET_VALID(ar, ARG_SIGNUM); |
314 | } |
315 | |
316 | void |
317 | audit_arg_socket(struct kaudit_record *ar, int sodomain, int sotype, |
318 | int soprotocol) |
319 | { |
320 | ar->k_ar.ar_arg_sockinfo.sai_domain = sodomain; |
321 | ar->k_ar.ar_arg_sockinfo.sai_type = sotype; |
322 | ar->k_ar.ar_arg_sockinfo.sai_protocol = soprotocol; |
323 | ARG_SET_VALID(ar, ARG_SOCKINFO); |
324 | } |
325 | |
326 | /* |
327 | * Note that the current working directory vp must be supplied at the audit |
328 | * call site to permit per thread current working directories, and that it |
329 | * must take a upath starting with '/' into account for chroot if the path |
330 | * is absolute. This results in the real (non-chroot) path being recorded |
331 | * in the audit record. |
332 | */ |
333 | void |
334 | audit_arg_sockaddr(struct kaudit_record *ar, struct vnode *cwd_vp, |
335 | struct sockaddr *sa) |
336 | { |
337 | char path[SOCK_MAXADDRLEN - offsetof(struct sockaddr_un, sun_path) + 1] = "" ; |
338 | struct sockaddr_un *sun; |
339 | ssize_t namelen; |
340 | |
341 | KASSERT(sa != NULL, ("audit_arg_sockaddr: sa == NULL" )); |
342 | |
343 | if (cwd_vp == NULL || sa == NULL) { |
344 | return; |
345 | } |
346 | |
347 | if (sa->sa_len > sizeof(ar->k_ar.ar_arg_sockaddr)) { |
348 | bcopy(src: sa, dst: &ar->k_ar.ar_arg_sockaddr, n: sizeof(ar->k_ar.ar_arg_sockaddr)); |
349 | } else { |
350 | bcopy(src: sa, dst: &ar->k_ar.ar_arg_sockaddr, n: sa->sa_len); |
351 | } |
352 | |
353 | switch (sa->sa_family) { |
354 | case AF_INET: |
355 | ARG_SET_VALID(ar, ARG_SADDRINET); |
356 | break; |
357 | |
358 | case AF_INET6: |
359 | ARG_SET_VALID(ar, ARG_SADDRINET6); |
360 | break; |
361 | |
362 | case AF_UNIX: |
363 | sun = (struct sockaddr_un *)sa; |
364 | namelen = sun->sun_len - offsetof(struct sockaddr_un, sun_path); |
365 | if (namelen > 0 && (size_t)namelen < sizeof(path)) { |
366 | /* |
367 | * Make sure the path is NUL-terminated |
368 | */ |
369 | bcopy(src: sun->sun_path, dst: path, n: namelen); |
370 | path[namelen] = 0; |
371 | audit_arg_upath(ar, cwd_vp, upath: path, ARG_UPATH1); |
372 | } |
373 | ARG_SET_VALID(ar, ARG_SADDRUNIX); |
374 | break; |
375 | /* XXXAUDIT: default:? */ |
376 | } |
377 | } |
378 | |
379 | void |
380 | audit_arg_auid(struct kaudit_record *ar, uid_t auid) |
381 | { |
382 | ar->k_ar.ar_arg_auid = auid; |
383 | ARG_SET_VALID(ar, ARG_AUID); |
384 | } |
385 | |
386 | void |
387 | audit_arg_auditinfo(struct kaudit_record *ar, const struct auditinfo *au_info) |
388 | { |
389 | ar->k_ar.ar_arg_auid = au_info->ai_auid; |
390 | ar->k_ar.ar_arg_asid = au_info->ai_asid; |
391 | ar->k_ar.ar_arg_amask.am_success = au_info->ai_mask.am_success; |
392 | ar->k_ar.ar_arg_amask.am_failure = au_info->ai_mask.am_failure; |
393 | ar->k_ar.ar_arg_termid.port = au_info->ai_termid.port; |
394 | ar->k_ar.ar_arg_termid.machine = au_info->ai_termid.machine; |
395 | ARG_SET_VALID(ar, ARG_AUID | ARG_ASID | ARG_AMASK | ARG_TERMID); |
396 | } |
397 | |
398 | void |
399 | audit_arg_auditinfo_addr(struct kaudit_record *ar, |
400 | const struct auditinfo_addr *au_info) |
401 | { |
402 | ar->k_ar.ar_arg_auid = au_info->ai_auid; |
403 | ar->k_ar.ar_arg_asid = au_info->ai_asid; |
404 | ar->k_ar.ar_arg_amask.am_success = au_info->ai_mask.am_success; |
405 | ar->k_ar.ar_arg_amask.am_failure = au_info->ai_mask.am_failure; |
406 | ar->k_ar.ar_arg_termid_addr.at_type = au_info->ai_termid.at_type; |
407 | ar->k_ar.ar_arg_termid_addr.at_port = au_info->ai_termid.at_port; |
408 | ar->k_ar.ar_arg_termid_addr.at_addr[0] = au_info->ai_termid.at_addr[0]; |
409 | ar->k_ar.ar_arg_termid_addr.at_addr[1] = au_info->ai_termid.at_addr[1]; |
410 | ar->k_ar.ar_arg_termid_addr.at_addr[2] = au_info->ai_termid.at_addr[2]; |
411 | ar->k_ar.ar_arg_termid_addr.at_addr[3] = au_info->ai_termid.at_addr[3]; |
412 | ARG_SET_VALID(ar, ARG_AUID | ARG_ASID | ARG_AMASK | ARG_TERMID_ADDR); |
413 | } |
414 | |
415 | void |
416 | audit_arg_text(struct kaudit_record *ar, const char *text) |
417 | { |
418 | KASSERT(text != NULL, ("audit_arg_text: text == NULL" )); |
419 | |
420 | /* Invalidate the text string */ |
421 | ar->k_ar.ar_valid_arg &= (ARG_ALL ^ ARG_TEXT); |
422 | if (text == NULL) { |
423 | return; |
424 | } |
425 | |
426 | if (ar->k_ar.ar_arg_text == NULL) { |
427 | ar->k_ar.ar_arg_text = zalloc(view: ZV_NAMEI); |
428 | } |
429 | |
430 | strlcpy(dst: ar->k_ar.ar_arg_text, src: text, MAXPATHLEN); |
431 | ARG_SET_VALID(ar, ARG_TEXT); |
432 | } |
433 | |
434 | void |
435 | audit_arg_opaque(struct kaudit_record *ar, const void *data, size_t size) |
436 | { |
437 | KASSERT(data != NULL, ("audit_arg_opaque: data == NULL" )); |
438 | KASSERT(size <= UINT16_MAX, ("audit_arg_opaque: size > UINT16_MAX" )); |
439 | |
440 | if (data == NULL || size > UINT16_MAX) { |
441 | return; |
442 | } |
443 | |
444 | if (ar->k_ar.ar_arg_opaque == NULL) { |
445 | ar->k_ar.ar_arg_opaque = kalloc_data(size, Z_WAITOK); |
446 | } else { |
447 | return; |
448 | } |
449 | |
450 | if (ar->k_ar.ar_arg_opaque == NULL) { |
451 | return; |
452 | } |
453 | |
454 | memcpy(dst: ar->k_ar.ar_arg_opaque, src: data, n: size); |
455 | ar->k_ar.ar_arg_opq_size = (u_int16_t) size; |
456 | ARG_SET_VALID(ar, ARG_OPAQUE); |
457 | } |
458 | |
459 | void |
460 | audit_arg_data(struct kaudit_record *ar, const void *data, size_t size, size_t number) |
461 | { |
462 | size_t sz; |
463 | |
464 | KASSERT(data != NULL, ("audit_arg_data: data == NULL" )); |
465 | KASSERT(size >= AUR_BYTE_SIZE && size <= AUR_INT64_SIZE, |
466 | ("audit_arg_data: size < AUR_BYTE_SIZE or size > AUR_INT64_SIZE" )); |
467 | KASSERT(number <= UINT8_MAX, |
468 | ("audit_arg_data: number > UINT8_MAX" )); |
469 | |
470 | if (data == NULL || size < AUR_BYTE_SIZE || size > AUR_INT64_SIZE || |
471 | number > UINT8_MAX) { |
472 | return; |
473 | } |
474 | |
475 | sz = size * number; |
476 | |
477 | if (ar->k_ar.ar_arg_data == NULL) { |
478 | ar->k_ar.ar_arg_data = kalloc_data(sz, Z_WAITOK); |
479 | } else { |
480 | return; |
481 | } |
482 | |
483 | if (ar->k_ar.ar_arg_data == NULL) { |
484 | return; |
485 | } |
486 | |
487 | memcpy(dst: ar->k_ar.ar_arg_data, src: data, n: sz); |
488 | |
489 | switch (size) { |
490 | case AUR_BYTE_SIZE: |
491 | ar->k_ar.ar_arg_data_type = AUR_BYTE; |
492 | break; |
493 | |
494 | case AUR_SHORT_SIZE: |
495 | ar->k_ar.ar_arg_data_type = AUR_SHORT; |
496 | break; |
497 | |
498 | case AUR_INT32_SIZE: |
499 | ar->k_ar.ar_arg_data_type = AUR_INT32; |
500 | break; |
501 | |
502 | case AUR_INT64_SIZE: |
503 | ar->k_ar.ar_arg_data_type = AUR_INT64; |
504 | break; |
505 | |
506 | default: |
507 | kfree_data(ar->k_ar.ar_arg_data, sz); |
508 | ar->k_ar.ar_arg_data = NULL; |
509 | return; |
510 | } |
511 | |
512 | ar->k_ar.ar_arg_data_count = (u_char)number; |
513 | |
514 | ARG_SET_VALID(ar, ARG_DATA); |
515 | } |
516 | |
517 | void |
518 | audit_arg_cmd(struct kaudit_record *ar, int cmd) |
519 | { |
520 | ar->k_ar.ar_arg_cmd = cmd; |
521 | ARG_SET_VALID(ar, ARG_CMD); |
522 | } |
523 | |
524 | void |
525 | audit_arg_svipc_cmd(struct kaudit_record *ar, int cmd) |
526 | { |
527 | ar->k_ar.ar_arg_svipc_cmd = cmd; |
528 | ARG_SET_VALID(ar, ARG_SVIPC_CMD); |
529 | } |
530 | |
531 | void |
532 | audit_arg_svipc_perm(struct kaudit_record *ar, const struct ipc_perm *perm) |
533 | { |
534 | bcopy(src: perm, dst: &ar->k_ar.ar_arg_svipc_perm, |
535 | n: sizeof(ar->k_ar.ar_arg_svipc_perm)); |
536 | ARG_SET_VALID(ar, ARG_SVIPC_PERM); |
537 | } |
538 | |
539 | void |
540 | audit_arg_svipc_id(struct kaudit_record *ar, int id) |
541 | { |
542 | ar->k_ar.ar_arg_svipc_id = id; |
543 | ARG_SET_VALID(ar, ARG_SVIPC_ID); |
544 | } |
545 | |
546 | void |
547 | audit_arg_svipc_addr(struct kaudit_record *ar, user_addr_t addr) |
548 | { |
549 | ar->k_ar.ar_arg_svipc_addr = addr; |
550 | ARG_SET_VALID(ar, ARG_SVIPC_ADDR); |
551 | } |
552 | |
553 | void |
554 | audit_arg_posix_ipc_perm(struct kaudit_record *ar, uid_t uid, gid_t gid, |
555 | mode_t mode) |
556 | { |
557 | ar->k_ar.ar_arg_pipc_perm.pipc_uid = uid; |
558 | ar->k_ar.ar_arg_pipc_perm.pipc_gid = gid; |
559 | ar->k_ar.ar_arg_pipc_perm.pipc_mode = mode; |
560 | ARG_SET_VALID(ar, ARG_POSIX_IPC_PERM); |
561 | } |
562 | |
563 | void |
564 | audit_arg_auditon(struct kaudit_record *ar, const union auditon_udata *udata) |
565 | { |
566 | bcopy(src: (const void *)udata, dst: &ar->k_ar.ar_arg_auditon, |
567 | n: sizeof(ar->k_ar.ar_arg_auditon)); |
568 | ARG_SET_VALID(ar, ARG_AUDITON); |
569 | } |
570 | |
571 | /* |
572 | * Audit information about a file, either the file's vnode info, or its |
573 | * socket address info. |
574 | */ |
575 | void |
576 | audit_arg_file(struct kaudit_record *ar, __unused proc_t p, |
577 | struct fileproc *fp) |
578 | { |
579 | struct socket *so; |
580 | struct inpcb *pcb; |
581 | struct sockaddr_in *sin; |
582 | struct sockaddr_in6 *sin6; |
583 | |
584 | switch (FILEGLOB_DTYPE(fp->fp_glob)) { |
585 | case DTYPE_VNODE: |
586 | /* case DTYPE_FIFO: */ |
587 | audit_arg_vnpath_withref(ar, |
588 | vp: (struct vnode *)fp_get_data(fp), ARG_VNODE1); |
589 | break; |
590 | |
591 | case DTYPE_SOCKET: |
592 | so = (struct socket *)fp_get_data(fp); |
593 | if (SOCK_CHECK_DOM(so, PF_INET)) { |
594 | if (so->so_pcb == NULL) { |
595 | break; |
596 | } |
597 | ar->k_ar.ar_arg_sockinfo.sai_type = |
598 | so->so_type; |
599 | ar->k_ar.ar_arg_sockinfo.sai_domain = SOCK_DOM(so); |
600 | ar->k_ar.ar_arg_sockinfo.sai_protocol = SOCK_PROTO(so); |
601 | pcb = (struct inpcb *)so->so_pcb; |
602 | sin = (struct sockaddr_in *) |
603 | &ar->k_ar.ar_arg_sockinfo.sai_faddr; |
604 | sin->sin_addr.s_addr = pcb->inp_faddr.s_addr; |
605 | sin->sin_port = pcb->inp_fport; |
606 | sin = (struct sockaddr_in *) |
607 | &ar->k_ar.ar_arg_sockinfo.sai_laddr; |
608 | sin->sin_addr.s_addr = pcb->inp_laddr.s_addr; |
609 | sin->sin_port = pcb->inp_lport; |
610 | ARG_SET_VALID(ar, ARG_SOCKINFO); |
611 | } |
612 | if (SOCK_CHECK_DOM(so, PF_INET6)) { |
613 | if (so->so_pcb == NULL) { |
614 | break; |
615 | } |
616 | ar->k_ar.ar_arg_sockinfo.sai_type = |
617 | so->so_type; |
618 | ar->k_ar.ar_arg_sockinfo.sai_domain = SOCK_DOM(so); |
619 | ar->k_ar.ar_arg_sockinfo.sai_protocol = SOCK_PROTO(so); |
620 | pcb = (struct inpcb *)so->so_pcb; |
621 | sin6 = (struct sockaddr_in6 *) |
622 | &ar->k_ar.ar_arg_sockinfo.sai_faddr; |
623 | sin6->sin6_addr = pcb->in6p_faddr; |
624 | sin6->sin6_port = pcb->in6p_fport; |
625 | sin6 = (struct sockaddr_in6 *) |
626 | &ar->k_ar.ar_arg_sockinfo.sai_laddr; |
627 | sin6->sin6_addr = pcb->in6p_laddr; |
628 | sin6->sin6_port = pcb->in6p_lport; |
629 | ARG_SET_VALID(ar, ARG_SOCKINFO); |
630 | } |
631 | break; |
632 | |
633 | default: |
634 | /* XXXAUDIT: else? */ |
635 | break; |
636 | } |
637 | } |
638 | |
639 | /* |
640 | * Store a path as given by the user process for auditing into the audit |
641 | * record stored on the user thread. This function will allocate the memory |
642 | * to store the path info if not already available. This memory will be |
643 | * freed when the audit record is freed. |
644 | * |
645 | * Note that the current working directory vp must be supplied at the audit call |
646 | * site to permit per thread current working directories, and that it must take |
647 | * a upath starting with '/' into account for chroot if the path is absolute. |
648 | * This results in the real (non-chroot) path being recorded in the audit |
649 | * record. |
650 | * |
651 | * XXXAUDIT: Possibly assert that the memory isn't already allocated? |
652 | */ |
653 | void |
654 | audit_arg_upath(struct kaudit_record *ar, struct vnode *cwd_vp, const char *upath, u_int64_t flag) |
655 | { |
656 | char **pathp; |
657 | |
658 | KASSERT(upath != NULL, ("audit_arg_upath: upath == NULL" )); |
659 | KASSERT((flag == ARG_UPATH1) || (flag == ARG_UPATH2), |
660 | ("audit_arg_upath: flag %llu" , (unsigned long long)flag)); |
661 | KASSERT((flag != ARG_UPATH1) || (flag != ARG_UPATH2), |
662 | ("audit_arg_upath: flag %llu" , (unsigned long long)flag)); |
663 | |
664 | if (flag == ARG_UPATH1) { |
665 | pathp = &ar->k_ar.ar_arg_upath1; |
666 | } else { |
667 | pathp = &ar->k_ar.ar_arg_upath2; |
668 | } |
669 | |
670 | if (*pathp == NULL) { |
671 | *pathp = zalloc(view: ZV_NAMEI); |
672 | } else { |
673 | return; |
674 | } |
675 | |
676 | if (audit_canon_path(cwd_vp, path: upath, cpath: *pathp) == 0) { |
677 | ARG_SET_VALID(ar, flag); |
678 | } else { |
679 | zfree(ZV_NAMEI, *pathp); |
680 | *pathp = NULL; |
681 | } |
682 | } |
683 | |
684 | void |
685 | audit_arg_kpath(struct kaudit_record *ar, const char *kpath, u_int64_t flag) |
686 | { |
687 | char **pathp; |
688 | |
689 | KASSERT(kpath != NULL, ("audit_arg_kpath: kpath == NULL" )); |
690 | KASSERT((flag == ARG_KPATH1) || (flag == ARG_KPATH2), |
691 | ("audit_arg_kpath: flag %llu" , (unsigned long long)flag)); |
692 | KASSERT((flag != ARG_KPATH1) || (flag != ARG_KPATH2), |
693 | ("audit_arg_kpath: flag %llu" , (unsigned long long)flag)); |
694 | |
695 | if (flag == ARG_KPATH1) { |
696 | pathp = &ar->k_ar.ar_arg_kpath1; |
697 | } else { |
698 | pathp = &ar->k_ar.ar_arg_kpath2; |
699 | } |
700 | |
701 | if (*pathp == NULL) { |
702 | *pathp = zalloc(view: ZV_NAMEI); |
703 | } else { |
704 | return; |
705 | } |
706 | |
707 | strlcpy(dst: *pathp, src: kpath, MAXPATHLEN); |
708 | ARG_SET_VALID(ar, flag); |
709 | } |
710 | |
711 | /* |
712 | * Function to save the path and vnode attr information into the audit |
713 | * record. |
714 | * |
715 | * It is assumed that the caller will hold any vnode locks necessary to |
716 | * perform a VNOP_GETATTR() on the passed vnode. |
717 | * |
718 | * XXX: The attr code is very similar to vfs_vnops.c:vn_stat(), but always |
719 | * provides access to the generation number as we need that to construct the |
720 | * BSM file ID. |
721 | * |
722 | * XXX: We should accept the process argument from the caller, since it's |
723 | * very likely they already have a reference. |
724 | * |
725 | * XXX: Error handling in this function is poor. |
726 | * |
727 | * XXXAUDIT: Possibly KASSERT the path pointer is NULL? |
728 | */ |
729 | void |
730 | audit_arg_vnpath(struct kaudit_record *ar, struct vnode *vp, u_int64_t flags) |
731 | { |
732 | struct vnode_attr va; |
733 | int error; |
734 | int len; |
735 | char **pathp; |
736 | struct vnode_au_info *vnp; |
737 | proc_t p; |
738 | #if CONFIG_MACF |
739 | char **vnode_mac_labelp; |
740 | struct mac mac; |
741 | #endif |
742 | |
743 | KASSERT(vp != NULL, ("audit_arg_vnpath: vp == NULL" )); |
744 | KASSERT((flags == ARG_VNODE1) || (flags == ARG_VNODE2), |
745 | ("audit_arg_vnpath: flags != ARG_VNODE[1,2]" )); |
746 | |
747 | p = current_proc(); |
748 | |
749 | /* |
750 | * XXXAUDIT: The below clears, and then resets the flags for valid |
751 | * arguments. Ideally, either the new vnode is used, or the old one |
752 | * would be. |
753 | */ |
754 | if (flags & ARG_VNODE1) { |
755 | ar->k_ar.ar_valid_arg &= (ARG_ALL ^ ARG_KPATH1); |
756 | ar->k_ar.ar_valid_arg &= (ARG_ALL ^ ARG_VNODE1); |
757 | pathp = &ar->k_ar.ar_arg_kpath1; |
758 | vnp = &ar->k_ar.ar_arg_vnode1; |
759 | #if CONFIG_MACF |
760 | vnode_mac_labelp = &ar->k_ar.ar_vnode1_mac_labels; |
761 | #endif |
762 | } else { |
763 | ar->k_ar.ar_valid_arg &= (ARG_ALL ^ ARG_KPATH2); |
764 | ar->k_ar.ar_valid_arg &= (ARG_ALL ^ ARG_VNODE2); |
765 | pathp = &ar->k_ar.ar_arg_kpath2; |
766 | vnp = &ar->k_ar.ar_arg_vnode2; |
767 | #if CONFIG_MACF |
768 | vnode_mac_labelp = &ar->k_ar.ar_vnode2_mac_labels; |
769 | #endif |
770 | } |
771 | |
772 | if (*pathp == NULL) { |
773 | *pathp = zalloc(view: ZV_NAMEI); |
774 | } else { |
775 | return; |
776 | } |
777 | |
778 | /* |
779 | * If vn_getpath() succeeds, place it in a string buffer |
780 | * attached to the audit record, and set a flag indicating |
781 | * it is present. |
782 | */ |
783 | len = MAXPATHLEN; |
784 | if (vn_getpath(vp, pathbuf: *pathp, len: &len) == 0) { |
785 | if (flags & ARG_VNODE1) { |
786 | ARG_SET_VALID(ar, ARG_KPATH1); |
787 | } else { |
788 | ARG_SET_VALID(ar, ARG_KPATH2); |
789 | } |
790 | } else { |
791 | zfree(ZV_NAMEI, *pathp); |
792 | *pathp = NULL; |
793 | } |
794 | |
795 | VATTR_INIT(&va); |
796 | VATTR_WANTED(&va, va_mode); |
797 | VATTR_WANTED(&va, va_uid); |
798 | VATTR_WANTED(&va, va_gid); |
799 | VATTR_WANTED(&va, va_rdev); |
800 | VATTR_WANTED(&va, va_fsid); |
801 | VATTR_WANTED(&va, va_fileid); |
802 | VATTR_WANTED(&va, va_gen); |
803 | error = vnode_getattr(vp, vap: &va, ctx: vfs_context_current()); |
804 | if (error) { |
805 | /* XXX: How to handle this case? */ |
806 | return; |
807 | } |
808 | |
809 | #if CONFIG_MACF |
810 | if (*vnode_mac_labelp == NULL && (vp->v_lflag & VL_LABELED) == VL_LABELED) { |
811 | *vnode_mac_labelp = zalloc_flags(audit_mac_label_zone, |
812 | Z_WAITOK | Z_NOFAIL); |
813 | mac.m_buflen = MAC_AUDIT_LABEL_LEN; |
814 | mac.m_string = *vnode_mac_labelp; |
815 | if (mac_vnode_label_externalize_audit(vp, mac: &mac)) { |
816 | return; |
817 | } |
818 | } |
819 | #endif |
820 | |
821 | /* |
822 | * XXX do we want to fall back here when these aren't supported? |
823 | */ |
824 | vnp->vn_mode = va.va_mode; |
825 | vnp->vn_uid = va.va_uid; |
826 | vnp->vn_gid = va.va_gid; |
827 | vnp->vn_dev = va.va_rdev; |
828 | vnp->vn_fsid = va.va_fsid; |
829 | vnp->vn_fileid = (u_int32_t)va.va_fileid; |
830 | vnp->vn_gen = va.va_gen; |
831 | if (flags & ARG_VNODE1) { |
832 | ARG_SET_VALID(ar, ARG_VNODE1); |
833 | } else { |
834 | ARG_SET_VALID(ar, ARG_VNODE2); |
835 | } |
836 | } |
837 | |
838 | void |
839 | audit_arg_vnpath_withref(struct kaudit_record *ar, struct vnode *vp, u_int64_t flags) |
840 | { |
841 | if (vp == NULL || vnode_getwithref(vp)) { |
842 | return; |
843 | } |
844 | audit_arg_vnpath(ar, vp, flags); |
845 | (void)vnode_put(vp); |
846 | } |
847 | |
848 | void |
849 | audit_arg_mach_port1(struct kaudit_record *ar, mach_port_name_t port) |
850 | { |
851 | ar->k_ar.ar_arg_mach_port1 = port; |
852 | ARG_SET_VALID(ar, ARG_MACHPORT1); |
853 | } |
854 | |
855 | void |
856 | audit_arg_mach_port2(struct kaudit_record *ar, mach_port_name_t port) |
857 | { |
858 | ar->k_ar.ar_arg_mach_port2 = port; |
859 | ARG_SET_VALID(ar, ARG_MACHPORT2); |
860 | } |
861 | |
862 | |
863 | /* |
864 | * Audit the argument strings passed to exec. |
865 | */ |
866 | void |
867 | audit_arg_argv(struct kaudit_record *ar, const char *argv, int argc, size_t length) |
868 | { |
869 | if (audit_argv == 0 || argc == 0) { |
870 | return; |
871 | } |
872 | |
873 | if (ar->k_ar.ar_arg_argv == NULL) { |
874 | ar->k_ar.ar_arg_argv = kalloc_data(length, Z_WAITOK); |
875 | } |
876 | |
877 | if (ar->k_ar.ar_arg_argv == NULL) { |
878 | return; |
879 | } |
880 | |
881 | bcopy(src: argv, dst: ar->k_ar.ar_arg_argv, n: length); |
882 | ar->k_ar.ar_arg_argc = argc; |
883 | ARG_SET_VALID(ar, ARG_ARGV); |
884 | } |
885 | |
886 | /* |
887 | * Audit the environment strings passed to exec. |
888 | */ |
889 | void |
890 | audit_arg_envv(struct kaudit_record *ar, const char *envv, int envc, size_t length) |
891 | { |
892 | if (audit_arge == 0 || envc == 0) { |
893 | return; |
894 | } |
895 | |
896 | if (ar->k_ar.ar_arg_envv == NULL) { |
897 | ar->k_ar.ar_arg_envv = kalloc_data(length, Z_WAITOK); |
898 | } |
899 | |
900 | if (ar->k_ar.ar_arg_envv == NULL) { |
901 | return; |
902 | } |
903 | |
904 | bcopy(src: envv, dst: ar->k_ar.ar_arg_envv, n: length); |
905 | ar->k_ar.ar_arg_envc = envc; |
906 | ARG_SET_VALID(ar, ARG_ENVV); |
907 | } |
908 | |
909 | /* |
910 | * The close() system call uses it's own audit call to capture the path/vnode |
911 | * information because those pieces are not easily obtained within the system |
912 | * call itself. |
913 | */ |
914 | void |
915 | audit_sysclose(struct kaudit_record *ar, proc_t p, int fd) |
916 | { |
917 | struct fileproc *fp; |
918 | struct vnode *vp; |
919 | |
920 | KASSERT(p != NULL, ("audit_sysclose: p == NULL" )); |
921 | |
922 | audit_arg_fd(ar, fd); |
923 | |
924 | if (fp_getfvp(p, fd, resultfp: &fp, resultvp: &vp) != 0) { |
925 | return; |
926 | } |
927 | |
928 | audit_arg_vnpath_withref(ar, vp: (struct vnode *)fp_get_data(fp), |
929 | ARG_VNODE1); |
930 | fp_drop(p, fd, fp, locked: 0); |
931 | } |
932 | |
933 | void |
934 | audit_identity_info_destruct(struct au_identity_info *id_info) |
935 | { |
936 | if (!id_info) { |
937 | return; |
938 | } |
939 | |
940 | if (id_info->signing_id != NULL) { |
941 | kfree_data(id_info->signing_id, MAX_AU_IDENTITY_SIGNING_ID_LENGTH); |
942 | id_info->signing_id = NULL; |
943 | } |
944 | |
945 | if (id_info->team_id != NULL) { |
946 | kfree_data(id_info->team_id, MAX_AU_IDENTITY_TEAM_ID_LENGTH); |
947 | id_info->team_id = NULL; |
948 | } |
949 | |
950 | if (id_info->cdhash != NULL) { |
951 | kfree_data(id_info->cdhash, id_info->cdhash_len); |
952 | id_info->cdhash = NULL; |
953 | } |
954 | } |
955 | |
956 | void |
957 | audit_identity_info_construct(struct au_identity_info *id_info) |
958 | { |
959 | struct proc *p; |
960 | struct cs_blob *blob; |
961 | unsigned int signer_type = 0; |
962 | const char *signing_id = NULL; |
963 | const char* team_id = NULL; |
964 | const uint8_t *cdhash = NULL; |
965 | size_t src_len = 0; |
966 | |
967 | p = current_proc(); |
968 | blob = csproc_get_blob(p); |
969 | if (blob) { |
970 | signing_id = csblob_get_identity(blob); |
971 | cdhash = csblob_get_cdhash(blob); |
972 | team_id = csblob_get_teamid(blob); |
973 | signer_type = csblob_get_platform_binary(blob) ? 1 : 0; |
974 | } |
975 | |
976 | id_info->signer_type = signer_type; |
977 | |
978 | if (id_info->signing_id == NULL && signing_id != NULL) { |
979 | id_info->signing_id = kalloc_data(MAX_AU_IDENTITY_SIGNING_ID_LENGTH, |
980 | Z_WAITOK | Z_NOFAIL); |
981 | src_len = strlcpy(dst: id_info->signing_id, |
982 | src: signing_id, MAX_AU_IDENTITY_SIGNING_ID_LENGTH); |
983 | |
984 | if (src_len >= MAX_AU_IDENTITY_SIGNING_ID_LENGTH) { |
985 | id_info->signing_id_trunc = 1; |
986 | } |
987 | } |
988 | |
989 | if (id_info->team_id == NULL && team_id != NULL) { |
990 | id_info->team_id = kalloc_data(MAX_AU_IDENTITY_TEAM_ID_LENGTH, |
991 | Z_WAITOK | Z_NOFAIL); |
992 | src_len = strlcpy(dst: id_info->team_id, src: team_id, |
993 | MAX_AU_IDENTITY_TEAM_ID_LENGTH); |
994 | |
995 | if (src_len >= MAX_AU_IDENTITY_TEAM_ID_LENGTH) { |
996 | id_info->team_id_trunc = 1; |
997 | } |
998 | } |
999 | |
1000 | if (id_info->cdhash == NULL && cdhash != NULL) { |
1001 | id_info->cdhash = kalloc_data(CS_CDHASH_LEN, Z_WAITOK | Z_NOFAIL); |
1002 | memcpy(dst: id_info->cdhash, src: cdhash, n: CS_CDHASH_LEN); |
1003 | id_info->cdhash_len = CS_CDHASH_LEN; |
1004 | } |
1005 | } |
1006 | |
1007 | void |
1008 | audit_arg_identity(struct kaudit_record *ar) |
1009 | { |
1010 | audit_identity_info_construct(id_info: &ar->k_ar.ar_arg_identity); |
1011 | ARG_SET_VALID(ar, ARG_IDENTITY); |
1012 | } |
1013 | |
1014 | #endif /* CONFIG_AUDIT */ |
1015 | |