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