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