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