1 /*-
2 * Copyright (c) 1999-2019 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of Apple Inc. ("Apple") nor the names of
13 * its contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28 /*
29 * NOTICE: This file was modified by McAfee Research in 2004 to introduce
30 * support for mandatory and extensible security protections. This notice
31 * is included in support of clause 2.2 (b) of the Apple Public License,
32 * Version 2.0.
33 */
34
35 #include <sys/param.h>
36 #include <sys/fcntl.h>
37 #include <sys/kernel.h>
38 #include <sys/lock.h>
39 #include <sys/namei.h>
40 #include <sys/proc_internal.h>
41 #include <sys/kauth.h>
42 #include <sys/queue.h>
43 #include <sys/systm.h>
44 #include <sys/time.h>
45 #include <sys/ucred.h>
46 #include <sys/uio.h>
47 #include <sys/unistd.h>
48 #include <sys/file_internal.h>
49 #include <sys/vnode_internal.h>
50 #include <sys/user.h>
51 #include <sys/syscall.h>
52 #include <sys/un.h>
53 #include <sys/sysent.h>
54 #include <sys/sysproto.h>
55 #include <sys/vfs_context.h>
56 #include <sys/domain.h>
57 #include <sys/protosw.h>
58 #include <sys/socketvar.h>
59
60 #include <bsm/audit.h>
61 #include <bsm/audit_internal.h>
62 #include <bsm/audit_kevents.h>
63
64 #include <security/audit/audit.h>
65 #include <security/audit/audit_bsd.h>
66 #include <security/audit/audit_private.h>
67
68 #include <mach/host_priv.h>
69 #include <mach/host_special_ports.h>
70 #include <mach/audit_triggers_server.h>
71
72 #include <kern/host.h>
73 #include <kern/sched_prim.h>
74
75 #if CONFIG_MACF
76 #include <bsm/audit_record.h>
77 #include <security/mac.h>
78 #include <security/mac_framework.h>
79 #include <security/mac_policy.h>
80 #endif
81
82 #include <net/route.h>
83
84 #include <netinet/in.h>
85 #include <netinet/in_pcb.h>
86
87 #include <IOKit/IOBSD.h>
88
89 #if CONFIG_AUDIT
90
91 #define IS_NOT_VALID_PID(p) ((p) < 1 || (p) > PID_MAX)
92
93 #ifdef AUDIT_API_WARNINGS
94 /*
95 * Macro to warn about auditinfo_addr_t/auditpinfo_addr_t changing sizes
96 * to encourage the userland code to be recompiled and updated.
97 */
98 #define WARN_IF_AINFO_ADDR_CHANGED(sz1, sz2, scall, tp) do { \
99 if ((size_t)(sz1) != (size_t)(sz2)) { \
100 char pn[MAXCOMLEN + 1]; \
101 \
102 proc_selfname(pn, MAXCOMLEN + 1); \
103 printf("Size of %s used by %s in %s is different from " \
104 "kernel's. Please recompile %s.\n", (tp), \
105 (scall), pn, pn); \
106 } \
107 } while (0)
108
109 /*
110 * Macro to warn about using ASID's outside the range [1 to PID_MAX] to
111 * encourage userland code changes.
112 */
113 #define WARN_IF_BAD_ASID(asid, scall) do { \
114 if (((asid) < 1 || (asid) > PID_MAX) && \
115 (asid) != AU_ASSIGN_ASID) { \
116 char pn[MAXCOMLEN + 1]; \
117 \
118 proc_selfname(pn, MAXCOMLEN + 1); \
119 printf("%s in %s is using an ASID (%u) outside the " \
120 "range [1 to %d]. Please change %s to use an ASID "\
121 "within this range or use AU_ASSIGN_ASID.\n", \
122 (scall), pn, (uint32_t)(asid), PID_MAX, pn); \
123 } \
124 } while (0)
125
126 #else /* ! AUDIT_API_WARNINGS */
127
128 #define WARN_IF_AINFO_ADDR_CHANGED(sz1, sz2, scall, tp) do { \
129 } while (0)
130
131 #define WARN_IF_BAD_ASID(asid, scall) do { \
132 } while (0)
133
134 #endif /* AUDIT_API_WARNINGS */
135
136 /*
137 * System call to allow a user space application to submit a BSM audit record
138 * to the kernel for inclusion in the audit log. This function does little
139 * verification on the audit record that is submitted.
140 *
141 * XXXAUDIT: Audit preselection for user records does not currently work,
142 * since we pre-select only based on the AUE_audit event type, not the event
143 * type submitted as part of the user audit data.
144 */
145 /* ARGSUSED */
146 int
audit(proc_t p,struct audit_args * uap,__unused int32_t * retval)147 audit(proc_t p, struct audit_args *uap, __unused int32_t *retval)
148 {
149 int error = 0;
150 void * rec = NULL;
151 void * full_rec = NULL;
152 struct kaudit_record *ar = NULL;
153 struct uthread *uthr = NULL;
154 int add_identity_token = 1;
155 int max_record_length = MAX_AUDIT_RECORD_SIZE;
156 void *udata = NULL;
157 u_int ulen = 0;
158 struct au_identity_info id_info = {
159 .signer_type = 0,
160 .signing_id = NULL,
161 .signing_id_trunc = 0,
162 .team_id = NULL,
163 .team_id_trunc = 0,
164 .cdhash = NULL,
165 .cdhash_len = 0
166 };
167 token_t *id_tok = NULL;
168 boolean_t kern_events_allowed = FALSE;
169 char *signing_id = NULL;
170 char process_name[MAXCOMLEN + 1] = {};
171 int signer_type = 0;
172
173 error = suser(kauth_cred_get(), &p->p_acflag);
174 if (error) {
175 /*
176 * If a process is not running as root but is properly
177 * entitled, allow it to audit non-kernel events only.
178 */
179 if (!IOCurrentTaskHasEntitlement(AU_AUDIT_USER_ENTITLEMENT)) {
180 goto free_out;
181 }
182 } else {
183 kern_events_allowed = TRUE;
184 }
185
186 mtx_lock(&audit_mtx);
187 max_record_length = MIN(audit_qctrl.aq_bufsz, MAX_AUDIT_RECORD_SIZE);
188 mtx_unlock(&audit_mtx);
189
190 if (IOCurrentTaskHasEntitlement(AU_CLASS_RESERVED_ENTITLEMENT)) {
191 /* Entitled tasks are trusted to add appropriate identity info */
192 add_identity_token = 0;
193 } else {
194 /*
195 * If the caller is unentitled, an identity token will be added and
196 * the space must be accounted for
197 */
198 max_record_length -= MAX_AUDIT_IDENTITY_SIZE;
199 }
200
201 if ((uap->length <= 0) || (uap->length > max_record_length)) {
202 error = EINVAL;
203 goto free_out;
204 }
205
206 ar = currecord();
207
208 /*
209 * If there's no current audit record (audit() itself not audited)
210 * commit the user audit record.
211 */
212 if (ar == NULL) {
213 uthr = curthread();
214 if (uthr == NULL) {
215 /* can this happen? */
216 error = ENOTSUP;
217 goto free_out;
218 }
219
220 /*
221 * This is not very efficient; we're required to allocate a
222 * complete kernel audit record just so the user record can
223 * tag along.
224 */
225 uthr->uu_ar = audit_new(AUE_NULL, p, uthr);
226 if (uthr->uu_ar == NULL) {
227 error = ENOTSUP;
228 goto free_out;
229 }
230 ar = uthr->uu_ar;
231 }
232
233 rec = kalloc_data(uap->length, Z_WAITOK);
234 if (!rec) {
235 error = ENOMEM;
236 goto free_out;
237 }
238
239 error = copyin(uap->record, rec, uap->length);
240 if (error) {
241 goto free_out;
242 }
243
244 #if CONFIG_MACF
245 error = mac_system_check_audit(kauth_cred_get(), rec, uap->length);
246 if (error) {
247 goto free_out;
248 }
249 #endif
250
251 /* Verify the record. */
252 if (bsm_rec_verify(rec, uap->length, kern_events_allowed) == 0) {
253 error = EINVAL;
254 goto free_out;
255 }
256
257 if (add_identity_token) {
258 struct hdr_tok_partial *hdr;
259 struct trl_tok_partial *trl;
260 int bytes_copied = 0;
261
262 /* Create a new identity token for this buffer */
263 audit_identity_info_construct(&id_info);
264 id_tok = au_to_identity(id_info.signer_type, id_info.signing_id,
265 id_info.signing_id_trunc, id_info.team_id, id_info.team_id_trunc,
266 id_info.cdhash, id_info.cdhash_len);
267 if (!id_tok) {
268 error = ENOMEM;
269 goto free_out;
270 }
271
272 /* Splice the record together using a new buffer */
273 full_rec = kalloc_data(uap->length + id_tok->len, Z_WAITOK);
274 if (!full_rec) {
275 error = ENOMEM;
276 goto free_out;
277 }
278
279 signing_id = id_info.signing_id;
280 signer_type = id_info.signer_type;
281
282 /* Copy the original buffer up to but not including the trailer */
283 memcpy(full_rec, rec, uap->length - AUDIT_TRAILER_SIZE);
284 bytes_copied = uap->length - AUDIT_TRAILER_SIZE;
285
286 /* Copy the identity token */
287 memcpy((void *)((uintptr_t)full_rec + bytes_copied), id_tok->t_data, id_tok->len);
288 bytes_copied += id_tok->len;
289
290 /* Copy the old trailer */
291 memcpy((void *)((uintptr_t)full_rec + bytes_copied),
292 (const void *)((uintptr_t)rec + (uap->length - AUDIT_TRAILER_SIZE)),
293 AUDIT_TRAILER_SIZE);
294 bytes_copied += AUDIT_TRAILER_SIZE;
295
296 /* Fix the record size stored in the header token */
297 hdr = (struct hdr_tok_partial*)full_rec;
298 hdr->len = htonl(bytes_copied);
299
300 /* Fix the record size stored in the trailer token */
301 trl = (struct trl_tok_partial*)
302 ((uintptr_t)full_rec + bytes_copied - AUDIT_TRAILER_SIZE);
303 trl->len = htonl(bytes_copied);
304
305 udata = full_rec;
306 ulen = bytes_copied;
307 } else {
308 udata = rec;
309 ulen = uap->length;
310 }
311
312 /*
313 * Attach the user audit record to the kernel audit record. Because
314 * this system call is an auditable event, we will write the user
315 * record along with the record for this audit event.
316 *
317 * XXXAUDIT: KASSERT appropriate starting values of k_udata, k_ulen,
318 * k_ar_commit & AR_COMMIT_USER?
319 */
320 ar->k_udata = udata;
321 ar->k_ulen = ulen;
322 ar->k_ar_commit |= AR_COMMIT_USER;
323
324 /*
325 * Currently we assume that all preselection has been performed in
326 * userspace. We unconditionally set these masks so that the records
327 * get committed both to the trail and pipe. In the future we will
328 * want to setup kernel based preselection.
329 */
330 ar->k_ar_commit |= (AR_PRESELECT_USER_TRAIL | AR_PRESELECT_USER_PIPE);
331
332 // Send data for analytics for non-platform binaries only
333 if (signer_type == 0 && add_identity_token) {
334 proc_name(proc_pid(p), process_name, sizeof(process_name));
335 (void)audit_send_analytics(signing_id, process_name);
336 }
337
338 free_out:
339 /*
340 * If rec was allocated, it must be freed if an identity token was added
341 * (since full_rec will be used) OR there was an error (since nothing
342 * will be attached to the kernel structure).
343 */
344 if (rec && (add_identity_token || error)) {
345 kfree_data_addr(rec);
346 }
347
348 /* Only free full_rec if an error occurred */
349 if (full_rec && error) {
350 kfree_data_addr(full_rec);
351 }
352
353 audit_identity_info_destruct(&id_info);
354 if (id_tok) {
355 kfree_data(id_tok->t_data, id_tok->len);
356 kfree_type(struct au_token, id_tok);
357 }
358
359 return error;
360 }
361
362 /*
363 * System call to manipulate auditing.
364 */
365 /* ARGSUSED */
366 int
auditon(proc_t p,struct auditon_args * uap,__unused int32_t * retval)367 auditon(proc_t p, struct auditon_args *uap, __unused int32_t *retval)
368 {
369 kauth_cred_t scred;
370 int error = 0;
371 union auditon_udata udata;
372 proc_t tp = PROC_NULL;
373 struct auditinfo_addr aia;
374
375 AUDIT_ARG(cmd, uap->cmd);
376
377 #if CONFIG_MACF
378 error = mac_system_check_auditon(kauth_cred_get(), uap->cmd);
379 if (error) {
380 return error;
381 }
382 #endif
383
384 if ((uap->length <= 0) || (uap->length >
385 (int)sizeof(union auditon_udata))) {
386 return EINVAL;
387 }
388
389 memset((void *)&udata, 0, sizeof(udata));
390
391 /*
392 * Some of the GET commands use the arguments too.
393 */
394 switch (uap->cmd) {
395 case A_SETPOLICY:
396 case A_OLDSETPOLICY:
397 case A_SETKMASK:
398 case A_SETQCTRL:
399 case A_OLDSETQCTRL:
400 case A_SETSTAT:
401 case A_SETUMASK:
402 case A_SETSMASK:
403 case A_SETCOND:
404 case A_OLDSETCOND:
405 case A_SETCLASS:
406 case A_SETPMASK:
407 case A_SETFSIZE:
408 case A_SETKAUDIT:
409 case A_GETCLASS:
410 case A_GETPINFO:
411 case A_GETPINFO_ADDR:
412 case A_SENDTRIGGER:
413 case A_GETSINFO_ADDR:
414 case A_GETSFLAGS:
415 case A_SETSFLAGS:
416 case A_SETCTLMODE:
417 case A_SETEXPAFTER:
418 error = copyin(uap->data, (void *)&udata, uap->length);
419 if (error) {
420 return error;
421 }
422 AUDIT_ARG(auditon, &udata);
423 AUDIT_ARG(len, uap->length);
424 break;
425 }
426
427 /* Check appropriate privilege. */
428 switch (uap->cmd) {
429 /*
430 * A_GETSINFO doesn't require priviledge but only superuser
431 * gets to see the audit masks.
432 */
433 case A_GETSINFO_ADDR:
434 if ((sizeof(udata.au_kau_info) != uap->length) ||
435 (audit_session_lookup(udata.au_kau_info.ai_asid,
436 &udata.au_kau_info) != 0)) {
437 error = EINVAL;
438 } else if (!kauth_cred_issuser(kauth_cred_get())) {
439 udata.au_kau_info.ai_mask.am_success = ~0;
440 udata.au_kau_info.ai_mask.am_failure = ~0;
441 }
442 break;
443 case A_GETSFLAGS:
444 case A_SETSFLAGS:
445 /* Getting one's own audit session flags requires no
446 * privilege. Setting the flags is subject to access
447 * control implemented in audit_session_setaia().
448 */
449 break;
450 case A_SETCTLMODE:
451 case A_SETEXPAFTER:
452 if (!IOCurrentTaskHasEntitlement(AU_CLASS_RESERVED_ENTITLEMENT)) {
453 error = EPERM;
454 }
455 break;
456 default:
457 error = suser(kauth_cred_get(), &p->p_acflag);
458 break;
459 }
460 if (error) {
461 return error;
462 }
463
464 /*
465 * If the audit subsytem is in external control mode, additional
466 * privilege checks are required for a subset of auditon commands
467 */
468 if (audit_ctl_mode == AUDIT_CTLMODE_EXTERNAL) {
469 switch (uap->cmd) {
470 case A_SETCOND:
471 case A_SETFSIZE:
472 case A_SETPOLICY:
473 case A_SETQCTRL:
474 if (!IOCurrentTaskHasEntitlement(AU_CLASS_RESERVED_ENTITLEMENT)) {
475 error = EPERM;
476 }
477 break;
478 }
479 if (error) {
480 return error;
481 }
482 }
483
484 /*
485 * XXX Need to implement these commands by accessing the global
486 * values associated with the commands.
487 */
488 switch (uap->cmd) {
489 case A_OLDGETPOLICY:
490 case A_GETPOLICY:
491 if (sizeof(udata.au_policy64) == uap->length) {
492 mtx_lock(&audit_mtx);
493 if (!audit_fail_stop) {
494 udata.au_policy64 |= AUDIT_CNT;
495 }
496 if (audit_panic_on_write_fail) {
497 udata.au_policy64 |= AUDIT_AHLT;
498 }
499 if (audit_argv) {
500 udata.au_policy64 |= AUDIT_ARGV;
501 }
502 if (audit_arge) {
503 udata.au_policy64 |= AUDIT_ARGE;
504 }
505 mtx_unlock(&audit_mtx);
506 break;
507 }
508 if (sizeof(udata.au_policy) != uap->length) {
509 return EINVAL;
510 }
511 mtx_lock(&audit_mtx);
512 if (!audit_fail_stop) {
513 udata.au_policy |= AUDIT_CNT;
514 }
515 if (audit_panic_on_write_fail) {
516 udata.au_policy |= AUDIT_AHLT;
517 }
518 if (audit_argv) {
519 udata.au_policy |= AUDIT_ARGV;
520 }
521 if (audit_arge) {
522 udata.au_policy |= AUDIT_ARGE;
523 }
524 mtx_unlock(&audit_mtx);
525 break;
526
527 case A_OLDSETPOLICY:
528 case A_SETPOLICY:
529 if (sizeof(udata.au_policy64) == uap->length) {
530 if (udata.au_policy64 & ~(AUDIT_CNT | AUDIT_AHLT |
531 AUDIT_ARGV | AUDIT_ARGE)) {
532 return EINVAL;
533 }
534 mtx_lock(&audit_mtx);
535 audit_fail_stop = ((udata.au_policy64 & AUDIT_CNT) ==
536 0);
537 audit_panic_on_write_fail = (udata.au_policy64 &
538 AUDIT_AHLT);
539 audit_argv = (udata.au_policy64 & AUDIT_ARGV);
540 audit_arge = (udata.au_policy64 & AUDIT_ARGE);
541 mtx_unlock(&audit_mtx);
542 break;
543 }
544 if ((sizeof(udata.au_policy) != uap->length) ||
545 (udata.au_policy & ~(AUDIT_CNT | AUDIT_AHLT | AUDIT_ARGV |
546 AUDIT_ARGE))) {
547 return EINVAL;
548 }
549 /*
550 * XXX - Need to wake up waiters if the policy relaxes?
551 */
552 mtx_lock(&audit_mtx);
553 audit_fail_stop = ((udata.au_policy & AUDIT_CNT) == 0);
554 audit_panic_on_write_fail = (udata.au_policy & AUDIT_AHLT);
555 audit_argv = (udata.au_policy & AUDIT_ARGV);
556 audit_arge = (udata.au_policy & AUDIT_ARGE);
557 mtx_unlock(&audit_mtx);
558 break;
559
560 case A_GETKMASK:
561 if (sizeof(udata.au_mask) != uap->length) {
562 return EINVAL;
563 }
564 mtx_lock(&audit_mtx);
565 udata.au_mask = audit_nae_mask;
566 mtx_unlock(&audit_mtx);
567 break;
568
569 case A_SETKMASK:
570 if (sizeof(udata.au_mask) != uap->length) {
571 return EINVAL;
572 }
573 mtx_lock(&audit_mtx);
574 audit_nae_mask = udata.au_mask;
575 AUDIT_CHECK_IF_KEVENTS_MASK(audit_nae_mask);
576 mtx_unlock(&audit_mtx);
577 break;
578
579 case A_OLDGETQCTRL:
580 case A_GETQCTRL:
581 if (sizeof(udata.au_qctrl64) == uap->length) {
582 mtx_lock(&audit_mtx);
583 udata.au_qctrl64.aq64_hiwater =
584 (u_int64_t)audit_qctrl.aq_hiwater;
585 udata.au_qctrl64.aq64_lowater =
586 (u_int64_t)audit_qctrl.aq_lowater;
587 udata.au_qctrl64.aq64_bufsz =
588 (u_int64_t)audit_qctrl.aq_bufsz;
589 udata.au_qctrl64.aq64_delay =
590 (u_int64_t)audit_qctrl.aq_delay;
591 udata.au_qctrl64.aq64_minfree =
592 (int64_t)audit_qctrl.aq_minfree;
593 mtx_unlock(&audit_mtx);
594 break;
595 }
596 if (sizeof(udata.au_qctrl) != uap->length) {
597 return EINVAL;
598 }
599 mtx_lock(&audit_mtx);
600 udata.au_qctrl = audit_qctrl;
601 mtx_unlock(&audit_mtx);
602 break;
603
604 case A_OLDSETQCTRL:
605 case A_SETQCTRL:
606 if (sizeof(udata.au_qctrl64) == uap->length) {
607 if ((udata.au_qctrl64.aq64_hiwater > AQ_MAXHIGH) ||
608 (udata.au_qctrl64.aq64_lowater >=
609 udata.au_qctrl64.aq64_hiwater) ||
610 (udata.au_qctrl64.aq64_bufsz > AQ_MAXBUFSZ) ||
611 (udata.au_qctrl64.aq64_minfree < 0) ||
612 (udata.au_qctrl64.aq64_minfree > 100)) {
613 return EINVAL;
614 }
615 mtx_lock(&audit_mtx);
616 audit_qctrl.aq_hiwater =
617 (int)udata.au_qctrl64.aq64_hiwater;
618 audit_qctrl.aq_lowater =
619 (int)udata.au_qctrl64.aq64_lowater;
620 audit_qctrl.aq_bufsz =
621 (int)udata.au_qctrl64.aq64_bufsz;
622 audit_qctrl.aq_minfree =
623 (int)udata.au_qctrl64.aq64_minfree;
624 audit_qctrl.aq_delay = -1; /* Not used. */
625 mtx_unlock(&audit_mtx);
626 break;
627 }
628 if ((sizeof(udata.au_qctrl) != uap->length) ||
629 (udata.au_qctrl.aq_hiwater > AQ_MAXHIGH) ||
630 (udata.au_qctrl.aq_lowater >= udata.au_qctrl.aq_hiwater) ||
631 (udata.au_qctrl.aq_bufsz > AQ_MAXBUFSZ) ||
632 (udata.au_qctrl.aq_minfree < 0) ||
633 (udata.au_qctrl.aq_minfree > 100)) {
634 return EINVAL;
635 }
636
637 mtx_lock(&audit_mtx);
638 audit_qctrl = udata.au_qctrl;
639 /* XXX The queue delay value isn't used with the kernel. */
640 audit_qctrl.aq_delay = -1;
641 mtx_unlock(&audit_mtx);
642 break;
643
644 case A_GETCWD:
645 return ENOSYS;
646
647 case A_GETCAR:
648 return ENOSYS;
649
650 case A_GETSTAT:
651 return ENOSYS;
652
653 case A_SETSTAT:
654 return ENOSYS;
655
656 case A_SETUMASK:
657 return ENOSYS;
658
659 case A_SETSMASK:
660 return ENOSYS;
661
662 case A_OLDGETCOND:
663 case A_GETCOND:
664 if (sizeof(udata.au_cond64) == uap->length) {
665 mtx_lock(&audit_mtx);
666 if (audit_enabled && !audit_suspended) {
667 udata.au_cond64 = AUC_AUDITING;
668 } else {
669 udata.au_cond64 = AUC_NOAUDIT;
670 }
671 mtx_unlock(&audit_mtx);
672 break;
673 }
674 if (sizeof(udata.au_cond) != uap->length) {
675 return EINVAL;
676 }
677 mtx_lock(&audit_mtx);
678 if (audit_enabled && !audit_suspended) {
679 udata.au_cond = AUC_AUDITING;
680 } else {
681 udata.au_cond = AUC_NOAUDIT;
682 }
683 mtx_unlock(&audit_mtx);
684 break;
685
686 case A_OLDSETCOND:
687 case A_SETCOND:
688 if (sizeof(udata.au_cond64) == uap->length) {
689 mtx_lock(&audit_mtx);
690 if (udata.au_cond64 == AUC_NOAUDIT) {
691 audit_suspended = 1;
692 }
693 if (udata.au_cond64 == AUC_AUDITING) {
694 audit_suspended = 0;
695 }
696 if (udata.au_cond64 == AUC_DISABLED) {
697 audit_suspended = 1;
698 mtx_unlock(&audit_mtx);
699 audit_shutdown();
700 break;
701 }
702 mtx_unlock(&audit_mtx);
703 break;
704 }
705 if (sizeof(udata.au_cond) != uap->length) {
706 return EINVAL;
707 }
708 mtx_lock(&audit_mtx);
709 if (udata.au_cond == AUC_NOAUDIT) {
710 audit_suspended = 1;
711 }
712 if (udata.au_cond == AUC_AUDITING) {
713 audit_suspended = 0;
714 }
715 if (udata.au_cond == AUC_DISABLED) {
716 audit_suspended = 1;
717 mtx_unlock(&audit_mtx);
718 audit_shutdown();
719 break;
720 }
721 mtx_unlock(&audit_mtx);
722 break;
723
724 case A_GETCLASS:
725 if (sizeof(udata.au_evclass) != uap->length) {
726 return EINVAL;
727 }
728 udata.au_evclass.ec_class = au_event_class(
729 udata.au_evclass.ec_number);
730 break;
731
732 case A_SETCLASS:
733 if (sizeof(udata.au_evclass) != uap->length) {
734 return EINVAL;
735 }
736 au_evclassmap_insert(udata.au_evclass.ec_number,
737 udata.au_evclass.ec_class);
738 break;
739
740 case A_GETPINFO:
741 if ((sizeof(udata.au_aupinfo) != uap->length) ||
742 IS_NOT_VALID_PID(udata.au_aupinfo.ap_pid)) {
743 return EINVAL;
744 }
745 if ((tp = proc_find(udata.au_aupinfo.ap_pid)) == NULL) {
746 return ESRCH;
747 }
748
749 scred = kauth_cred_proc_ref(tp);
750 if (scred->cr_audit.as_aia_p->ai_termid.at_type == AU_IPv6) {
751 kauth_cred_unref(&scred);
752 proc_rele(tp);
753 return EINVAL;
754 }
755
756 udata.au_aupinfo.ap_auid =
757 scred->cr_audit.as_aia_p->ai_auid;
758 udata.au_aupinfo.ap_mask.am_success =
759 scred->cr_audit.as_mask.am_success;
760 udata.au_aupinfo.ap_mask.am_failure =
761 scred->cr_audit.as_mask.am_failure;
762 udata.au_aupinfo.ap_termid.machine =
763 scred->cr_audit.as_aia_p->ai_termid.at_addr[0];
764 udata.au_aupinfo.ap_termid.port =
765 scred->cr_audit.as_aia_p->ai_termid.at_port;
766 udata.au_aupinfo.ap_asid =
767 scred->cr_audit.as_aia_p->ai_asid;
768 kauth_cred_unref(&scred);
769 proc_rele(tp);
770 tp = PROC_NULL;
771 break;
772
773 case A_SETPMASK:
774 if ((sizeof(udata.au_aupinfo) != uap->length) ||
775 IS_NOT_VALID_PID(udata.au_aupinfo.ap_pid)) {
776 return EINVAL;
777 }
778 if ((tp = proc_find(udata.au_aupinfo.ap_pid)) == NULL) {
779 return ESRCH;
780 }
781 scred = kauth_cred_proc_ref(tp);
782 bcopy(scred->cr_audit.as_aia_p, &aia, sizeof(aia));
783 kauth_cred_unref(&scred);
784 aia.ai_mask.am_success =
785 udata.au_aupinfo.ap_mask.am_success;
786 aia.ai_mask.am_failure =
787 udata.au_aupinfo.ap_mask.am_failure;
788 AUDIT_CHECK_IF_KEVENTS_MASK(aia.ai_mask);
789 error = audit_session_setaia(tp, &aia);
790 proc_rele(tp);
791 tp = PROC_NULL;
792 if (error) {
793 return error;
794 }
795 break;
796
797 case A_SETFSIZE:
798 if ((sizeof(udata.au_fstat) != uap->length) ||
799 ((udata.au_fstat.af_filesz != 0) &&
800 (udata.au_fstat.af_filesz < MIN_AUDIT_FILE_SIZE))) {
801 return EINVAL;
802 }
803 mtx_lock(&audit_mtx);
804 audit_fstat.af_filesz = udata.au_fstat.af_filesz;
805 mtx_unlock(&audit_mtx);
806 break;
807
808 case A_GETFSIZE:
809 if (sizeof(udata.au_fstat) != uap->length) {
810 return EINVAL;
811 }
812 mtx_lock(&audit_mtx);
813 udata.au_fstat.af_filesz = audit_fstat.af_filesz;
814 udata.au_fstat.af_currsz = audit_fstat.af_currsz;
815 mtx_unlock(&audit_mtx);
816 break;
817
818 case A_GETPINFO_ADDR:
819 if ((sizeof(udata.au_aupinfo_addr) != uap->length) ||
820 IS_NOT_VALID_PID(udata.au_aupinfo_addr.ap_pid)) {
821 return EINVAL;
822 }
823 if ((tp = proc_find(udata.au_aupinfo.ap_pid)) == NULL) {
824 return ESRCH;
825 }
826 WARN_IF_AINFO_ADDR_CHANGED(uap->length,
827 sizeof(auditpinfo_addr_t), "auditon(A_GETPINFO_ADDR,...)",
828 "auditpinfo_addr_t");
829 scred = kauth_cred_proc_ref(tp);
830 udata.au_aupinfo_addr.ap_auid =
831 scred->cr_audit.as_aia_p->ai_auid;
832 udata.au_aupinfo_addr.ap_asid =
833 scred->cr_audit.as_aia_p->ai_asid;
834 udata.au_aupinfo_addr.ap_mask.am_success =
835 scred->cr_audit.as_mask.am_success;
836 udata.au_aupinfo_addr.ap_mask.am_failure =
837 scred->cr_audit.as_mask.am_failure;
838 bcopy(&scred->cr_audit.as_aia_p->ai_termid,
839 &udata.au_aupinfo_addr.ap_termid,
840 sizeof(au_tid_addr_t));
841 udata.au_aupinfo_addr.ap_flags =
842 scred->cr_audit.as_aia_p->ai_flags;
843 kauth_cred_unref(&scred);
844 proc_rele(tp);
845 tp = PROC_NULL;
846 break;
847
848 case A_GETKAUDIT:
849 if (sizeof(udata.au_kau_info) != uap->length) {
850 return EINVAL;
851 }
852 audit_get_kinfo(&udata.au_kau_info);
853 break;
854
855 case A_SETKAUDIT:
856 if ((sizeof(udata.au_kau_info) != uap->length) ||
857 (udata.au_kau_info.ai_termid.at_type != AU_IPv4 &&
858 udata.au_kau_info.ai_termid.at_type != AU_IPv6)) {
859 return EINVAL;
860 }
861 audit_set_kinfo(&udata.au_kau_info);
862 break;
863
864 case A_SENDTRIGGER:
865 if ((sizeof(udata.au_trigger) != uap->length) ||
866 (udata.au_trigger < AUDIT_TRIGGER_MIN) ||
867 (udata.au_trigger > AUDIT_TRIGGER_MAX)) {
868 return EINVAL;
869 }
870 return audit_send_trigger(udata.au_trigger);
871
872 case A_GETSINFO_ADDR:
873 /* Handled above before switch(). */
874 break;
875
876 case A_GETSFLAGS:
877 if (sizeof(udata.au_flags) != uap->length) {
878 return EINVAL;
879 }
880 bcopy(&(kauth_cred_get()->cr_audit.as_aia_p->ai_flags),
881 &udata.au_flags, sizeof(udata.au_flags));
882 break;
883
884 case A_SETSFLAGS:
885 if (sizeof(udata.au_flags) != uap->length) {
886 return EINVAL;
887 }
888 scred = kauth_cred_get();
889 bcopy(scred->cr_audit.as_aia_p, &aia, sizeof(aia));
890 bcopy(&scred->cr_audit.as_mask, &aia.ai_mask, sizeof(au_mask_t));
891 aia.ai_flags = udata.au_flags;
892 error = audit_session_setaia(p, &aia);
893 if (error) {
894 return error;
895 }
896 break;
897
898 case A_GETCTLMODE:
899 if (sizeof(udata.au_ctl_mode) != uap->length) {
900 return EINVAL;
901 }
902 mtx_lock(&audit_mtx);
903 udata.au_ctl_mode = audit_ctl_mode;
904 mtx_unlock(&audit_mtx);
905 break;
906
907 case A_SETCTLMODE:
908 if (sizeof(udata.au_ctl_mode) != uap->length) {
909 return EINVAL;
910 }
911
912 mtx_lock(&audit_mtx);
913
914 if (udata.au_ctl_mode == AUDIT_CTLMODE_NORMAL) {
915 audit_ctl_mode = AUDIT_CTLMODE_NORMAL;
916 } else if (udata.au_ctl_mode == AUDIT_CTLMODE_EXTERNAL) {
917 audit_ctl_mode = AUDIT_CTLMODE_EXTERNAL;
918 } else {
919 mtx_unlock(&audit_mtx);
920 return EINVAL;
921 }
922
923 mtx_unlock(&audit_mtx);
924 break;
925
926 case A_GETEXPAFTER:
927 if (sizeof(udata.au_expire_after) != uap->length) {
928 return EINVAL;
929 }
930 mtx_lock(&audit_mtx);
931 udata.au_expire_after.age = audit_expire_after.age;
932 udata.au_expire_after.size = audit_expire_after.size;
933 udata.au_expire_after.op_type = audit_expire_after.op_type;
934 mtx_unlock(&audit_mtx);
935 break;
936
937 case A_SETEXPAFTER:
938 if (sizeof(udata.au_expire_after) != uap->length) {
939 return EINVAL;
940 }
941 mtx_lock(&audit_mtx);
942 audit_expire_after.age = udata.au_expire_after.age;
943 audit_expire_after.size = udata.au_expire_after.size;
944 audit_expire_after.op_type = udata.au_expire_after.op_type;
945 mtx_unlock(&audit_mtx);
946 break;
947
948 default:
949 return EINVAL;
950 }
951
952 /*
953 * Copy data back to userspace for the GET comands.
954 */
955 switch (uap->cmd) {
956 case A_GETPOLICY:
957 case A_OLDGETPOLICY:
958 case A_GETKMASK:
959 case A_GETQCTRL:
960 case A_OLDGETQCTRL:
961 case A_GETCWD:
962 case A_GETCAR:
963 case A_GETSTAT:
964 case A_GETCOND:
965 case A_OLDGETCOND:
966 case A_GETCLASS:
967 case A_GETPINFO:
968 case A_GETFSIZE:
969 case A_GETPINFO_ADDR:
970 case A_GETKAUDIT:
971 case A_GETSINFO_ADDR:
972 case A_GETSFLAGS:
973 case A_GETCTLMODE:
974 case A_GETEXPAFTER:
975 error = copyout((void *)&udata, uap->data, uap->length);
976 if (error) {
977 return ENOSYS;
978 }
979 break;
980 }
981
982 return 0;
983 }
984
985 /*
986 * System calls to manage the user audit information.
987 */
988 /* ARGSUSED */
989 int
getauid(proc_t p,struct getauid_args * uap,__unused int32_t * retval)990 getauid(proc_t p, struct getauid_args *uap, __unused int32_t *retval)
991 {
992 au_id_t id;
993 int error;
994 kauth_cred_t scred;
995
996 #if CONFIG_MACF
997 error = mac_proc_check_getauid(p);
998 if (error) {
999 return error;
1000 }
1001 #endif
1002 scred = kauth_cred_proc_ref(p);
1003 id = scred->cr_audit.as_aia_p->ai_auid;
1004 kauth_cred_unref(&scred);
1005
1006 error = copyout((void *)&id, uap->auid, sizeof(id));
1007 if (error) {
1008 return error;
1009 }
1010
1011 return 0;
1012 }
1013
1014 /* ARGSUSED */
1015 int
setauid(proc_t p,struct setauid_args * uap,__unused int32_t * retval)1016 setauid(proc_t p, struct setauid_args *uap, __unused int32_t *retval)
1017 {
1018 int error;
1019 au_id_t id;
1020 kauth_cred_t scred;
1021 struct auditinfo_addr aia;
1022
1023 error = copyin(uap->auid, &id, sizeof(id));
1024 if (error) {
1025 return error;
1026 }
1027 AUDIT_ARG(auid, id);
1028
1029 #if CONFIG_MACF
1030 error = mac_proc_check_setauid(p, id);
1031 if (error) {
1032 return error;
1033 }
1034 #endif
1035
1036 scred = kauth_cred_proc_ref(p);
1037 error = suser(scred, &p->p_acflag);
1038 if (error) {
1039 kauth_cred_unref(&scred);
1040 return error;
1041 }
1042
1043 bcopy(scred->cr_audit.as_aia_p, &aia, sizeof(aia));
1044 if (aia.ai_asid == AU_DEFAUDITSID) {
1045 aia.ai_asid = AU_ASSIGN_ASID;
1046 }
1047 bcopy(&scred->cr_audit.as_mask, &aia.ai_mask, sizeof(au_mask_t));
1048 kauth_cred_unref(&scred);
1049 aia.ai_auid = id;
1050 error = audit_session_setaia(p, &aia);
1051
1052 return error;
1053 }
1054
1055 static int
getaudit_addr_internal(proc_t p,user_addr_t user_addr,size_t length)1056 getaudit_addr_internal(proc_t p, user_addr_t user_addr, size_t length)
1057 {
1058 kauth_cred_t scred;
1059 auditinfo_addr_t aia;
1060
1061 scred = kauth_cred_proc_ref(p);
1062 bcopy(scred->cr_audit.as_aia_p, &aia, sizeof(auditinfo_addr_t));
1063 /*
1064 * Only superuser gets to see the real mask.
1065 */
1066 if (suser(scred, &p->p_acflag)) {
1067 aia.ai_mask.am_success = ~0;
1068 aia.ai_mask.am_failure = ~0;
1069 } else {
1070 bcopy(&scred->cr_audit.as_mask, &aia.ai_mask, sizeof(au_mask_t));
1071 }
1072 kauth_cred_unref(&scred);
1073
1074 return copyout(&aia, user_addr, min(sizeof(aia), length));
1075 }
1076
1077 /* ARGSUSED */
1078 int
getaudit_addr(proc_t p,struct getaudit_addr_args * uap,__unused int32_t * retval)1079 getaudit_addr(proc_t p, struct getaudit_addr_args *uap,
1080 __unused int32_t *retval)
1081 {
1082 #if CONFIG_MACF
1083 int error = mac_proc_check_getaudit(p);
1084
1085 if (error) {
1086 return error;
1087 }
1088 #endif /* CONFIG_MACF */
1089 WARN_IF_AINFO_ADDR_CHANGED(uap->length, sizeof(auditinfo_addr_t),
1090 "getaudit_addr(2)", "auditinfo_addr_t");
1091
1092 return getaudit_addr_internal(p, uap->auditinfo_addr, uap->length);
1093 }
1094
1095 /* ARGSUSED */
1096 int
setaudit_addr(proc_t p,struct setaudit_addr_args * uap,__unused int32_t * retval)1097 setaudit_addr(proc_t p, struct setaudit_addr_args *uap,
1098 __unused int32_t *retval)
1099 {
1100 struct auditinfo_addr aia;
1101 kauth_cred_t scred;
1102 int error;
1103
1104 bzero(&aia, sizeof(auditinfo_addr_t));
1105 error = copyin(uap->auditinfo_addr, &aia,
1106 min(sizeof(aia), uap->length));
1107 if (error) {
1108 return error;
1109 }
1110 AUDIT_ARG(auditinfo_addr, &aia);
1111 if (aia.ai_termid.at_type != AU_IPv6 &&
1112 aia.ai_termid.at_type != AU_IPv4) {
1113 return EINVAL;
1114 }
1115 if (aia.ai_asid != AU_ASSIGN_ASID &&
1116 (uint32_t)aia.ai_asid > ASSIGNED_ASID_MAX) {
1117 return EINVAL;
1118 }
1119
1120 #if CONFIG_MACF
1121 error = mac_proc_check_setaudit(p, &aia);
1122 if (error) {
1123 return error;
1124 }
1125 #endif
1126
1127 scred = kauth_cred_proc_ref(p);
1128 error = suser(scred, &p->p_acflag);
1129 if (error) {
1130 kauth_cred_unref(&scred);
1131 return error;
1132 }
1133
1134 WARN_IF_AINFO_ADDR_CHANGED(uap->length, sizeof(auditinfo_addr_t),
1135 "setaudit_addr(2)", "auditinfo_addr_t");
1136 WARN_IF_BAD_ASID(aia.ai_asid, "setaudit_addr(2)");
1137 kauth_cred_unref(&scred);
1138
1139 AUDIT_CHECK_IF_KEVENTS_MASK(aia.ai_mask);
1140 if (aia.ai_asid == AU_DEFAUDITSID) {
1141 aia.ai_asid = AU_ASSIGN_ASID;
1142 }
1143
1144 error = audit_session_setaia(p, &aia);
1145 if (error) {
1146 return error;
1147 }
1148
1149 /*
1150 * If asked to assign an ASID then let the user know what the ASID is
1151 * by copying the auditinfo_addr struct back out.
1152 */
1153 if (aia.ai_asid == AU_ASSIGN_ASID) {
1154 error = getaudit_addr_internal(p, uap->auditinfo_addr,
1155 uap->length);
1156 }
1157
1158 return error;
1159 }
1160
1161 /*
1162 * Syscall to manage audit files.
1163 *
1164 */
1165 /* ARGSUSED */
1166 int
auditctl(proc_t p,struct auditctl_args * uap,__unused int32_t * retval)1167 auditctl(proc_t p, struct auditctl_args *uap, __unused int32_t *retval)
1168 {
1169 struct nameidata nd;
1170 kauth_cred_t cred;
1171 struct vnode *vp;
1172 int error = 0;
1173 au_ctlmode_t ctlmode;
1174
1175 error = suser(kauth_cred_get(), &p->p_acflag);
1176 if (error) {
1177 return error;
1178 }
1179
1180 ctlmode = audit_ctl_mode;
1181
1182 /*
1183 * Do not allow setting of a path when auditing is in reserved mode
1184 */
1185 if (ctlmode == AUDIT_CTLMODE_EXTERNAL &&
1186 !IOCurrentTaskHasEntitlement(AU_AUDITCTL_RESERVED_ENTITLEMENT)) {
1187 return EPERM;
1188 }
1189
1190 vp = NULL;
1191 cred = NULL;
1192
1193 /*
1194 * If a path is specified, open the replacement vnode, perform
1195 * validity checks, and grab another reference to the current
1196 * credential.
1197 *
1198 * XXX Changes API slightly. NULL path no longer disables audit but
1199 * returns EINVAL.
1200 */
1201 if (uap->path == USER_ADDR_NULL) {
1202 return EINVAL;
1203 }
1204
1205 NDINIT(&nd, LOOKUP, OP_OPEN, FOLLOW | LOCKLEAF | AUDITVNPATH1,
1206 (IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 :
1207 UIO_USERSPACE32), uap->path, vfs_context_current());
1208 error = vn_open(&nd, AUDIT_OPEN_FLAGS, 0);
1209 if (error) {
1210 return error;
1211 }
1212 vp = nd.ni_vp;
1213 #if CONFIG_MACF
1214 /*
1215 * Accessibility of the vnode was determined in vn_open; the
1216 * mac_system_check_auditctl should only determine whether that vnode
1217 * is appropriate for storing audit data, or that the caller was
1218 * permitted to control the auditing system at all. For example, a
1219 * confidentiality policy may want to ensure that audit files are
1220 * always high sensitivity.
1221 */
1222 error = mac_system_check_auditctl(kauth_cred_get(), vp);
1223 if (error) {
1224 vn_close(vp, AUDIT_CLOSE_FLAGS, vfs_context_current());
1225 vnode_put(vp);
1226 return error;
1227 }
1228 #endif
1229 if (vp->v_type != VREG) {
1230 vn_close(vp, AUDIT_CLOSE_FLAGS, vfs_context_current());
1231 vnode_put(vp);
1232 return EINVAL;
1233 }
1234 mtx_lock(&audit_mtx);
1235 /*
1236 * XXXAUDIT: Should audit_suspended actually be cleared by
1237 * audit_worker?
1238 */
1239 audit_suspended = 0;
1240 mtx_unlock(&audit_mtx);
1241
1242 /*
1243 * The following gets unreferenced in audit_rotate_vnode()
1244 * after the rotation and it is no longer needed.
1245 */
1246 cred = kauth_cred_get_with_ref();
1247 audit_rotate_vnode(cred, vp);
1248 vnode_put(vp);
1249
1250 return error;
1251 }
1252
1253 #else /* !CONFIG_AUDIT */
1254
1255 int
audit(proc_t p,struct audit_args * uap,int32_t * retval)1256 audit(proc_t p, struct audit_args *uap, int32_t *retval)
1257 {
1258 #pragma unused(p, uap, retval)
1259
1260 return ENOSYS;
1261 }
1262
1263 int
auditon(proc_t p,struct auditon_args * uap,int32_t * retval)1264 auditon(proc_t p, struct auditon_args *uap, int32_t *retval)
1265 {
1266 #pragma unused(p, uap, retval)
1267
1268 return ENOSYS;
1269 }
1270
1271 int
getauid(proc_t p,struct getauid_args * uap,int32_t * retval)1272 getauid(proc_t p, struct getauid_args *uap, int32_t *retval)
1273 {
1274 #pragma unused(p, uap, retval)
1275
1276 return ENOSYS;
1277 }
1278
1279 int
setauid(proc_t p,struct setauid_args * uap,int32_t * retval)1280 setauid(proc_t p, struct setauid_args *uap, int32_t *retval)
1281 {
1282 #pragma unused(p, uap, retval)
1283
1284 return ENOSYS;
1285 }
1286
1287 int
getaudit_addr(proc_t p,struct getaudit_addr_args * uap,int32_t * retval)1288 getaudit_addr(proc_t p, struct getaudit_addr_args *uap, int32_t *retval)
1289 {
1290 #pragma unused(p, uap, retval)
1291
1292 return ENOSYS;
1293 }
1294
1295 int
setaudit_addr(proc_t p,struct setaudit_addr_args * uap,int32_t * retval)1296 setaudit_addr(proc_t p, struct setaudit_addr_args *uap, int32_t *retval)
1297 {
1298 #pragma unused(p, uap, retval)
1299
1300 return ENOSYS;
1301 }
1302
1303 int
auditctl(proc_t p,struct auditctl_args * uap,int32_t * retval)1304 auditctl(proc_t p, struct auditctl_args *uap, int32_t *retval)
1305 {
1306 #pragma unused(p, uap, retval)
1307
1308 return ENOSYS;
1309 }
1310
1311 #endif /* CONFIG_AUDIT */
1312