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 */
150int
151audit(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
313free_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 */
343int
344auditon(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#endif
359
360 if ((uap->length <= 0) || (uap->length >
361 (int)sizeof(union auditon_udata)))
362 return (EINVAL);
363
364 memset((void *)&udata, 0, sizeof(udata));
365
366 /*
367 * Some of the GET commands use the arguments too.
368 */
369 switch (uap->cmd) {
370 case A_SETPOLICY:
371 case A_OLDSETPOLICY:
372 case A_SETKMASK:
373 case A_SETQCTRL:
374 case A_OLDSETQCTRL:
375 case A_SETSTAT:
376 case A_SETUMASK:
377 case A_SETSMASK:
378 case A_SETCOND:
379 case A_OLDSETCOND:
380 case A_SETCLASS:
381 case A_SETPMASK:
382 case A_SETFSIZE:
383 case A_SETKAUDIT:
384 case A_GETCLASS:
385 case A_GETPINFO:
386 case A_GETPINFO_ADDR:
387 case A_SENDTRIGGER:
388 case A_GETSINFO_ADDR:
389 case A_GETSFLAGS:
390 case A_SETSFLAGS:
391 case A_SETCTLMODE:
392 case A_SETEXPAFTER:
393 error = copyin(uap->data, (void *)&udata, uap->length);
394 if (error)
395 return (error);
396 AUDIT_ARG(auditon, &udata);
397 AUDIT_ARG(len, uap->length);
398 break;
399 }
400
401 /* Check appropriate privilege. */
402 switch (uap->cmd) {
403 /*
404 * A_GETSINFO doesn't require priviledge but only superuser
405 * gets to see the audit masks.
406 */
407 case A_GETSINFO_ADDR:
408 if ((sizeof(udata.au_kau_info) != uap->length) ||
409 (audit_session_lookup(udata.au_kau_info.ai_asid,
410 &udata.au_kau_info) != 0))
411 error = EINVAL;
412 else if (!kauth_cred_issuser(kauth_cred_get())) {
413 udata.au_kau_info.ai_mask.am_success = ~0;
414 udata.au_kau_info.ai_mask.am_failure = ~0;
415 }
416 break;
417 case A_GETSFLAGS:
418 case A_SETSFLAGS:
419 /* Getting one's own audit session flags requires no
420 * privilege. Setting the flags is subject to access
421 * control implemented in audit_session_setaia().
422 */
423 break;
424 case A_SETCTLMODE:
425 case A_SETEXPAFTER:
426 if (!IOTaskHasEntitlement(current_task(),
427 AU_CLASS_RESERVED_ENTITLEMENT)) {
428 error = EPERM;
429 }
430 break;
431 default:
432 error = suser(kauth_cred_get(), &p->p_acflag);
433 break;
434 }
435 if (error)
436 return (error);
437
438 /*
439 * If the audit subsytem is in external control mode, additional
440 * privilege checks are required for a subset of auditon commands
441 */
442 if (audit_ctl_mode == AUDIT_CTLMODE_EXTERNAL) {
443 switch (uap->cmd) {
444 case A_SETCOND:
445 case A_SETFSIZE:
446 case A_SETPOLICY:
447 case A_SETQCTRL:
448 if (!IOTaskHasEntitlement(current_task(),
449 AU_CLASS_RESERVED_ENTITLEMENT)) {
450 error = EPERM;
451 }
452 break;
453 }
454 if (error)
455 return (error);
456 }
457
458 /*
459 * XXX Need to implement these commands by accessing the global
460 * values associated with the commands.
461 */
462 switch (uap->cmd) {
463 case A_OLDGETPOLICY:
464 case A_GETPOLICY:
465 if (sizeof(udata.au_policy64) == uap->length) {
466 mtx_lock(&audit_mtx);
467 if (!audit_fail_stop)
468 udata.au_policy64 |= AUDIT_CNT;
469 if (audit_panic_on_write_fail)
470 udata.au_policy64 |= AUDIT_AHLT;
471 if (audit_argv)
472 udata.au_policy64 |= AUDIT_ARGV;
473 if (audit_arge)
474 udata.au_policy64 |= AUDIT_ARGE;
475 mtx_unlock(&audit_mtx);
476 break;
477 }
478 if (sizeof(udata.au_policy) != uap->length)
479 return (EINVAL);
480 mtx_lock(&audit_mtx);
481 if (!audit_fail_stop)
482 udata.au_policy |= AUDIT_CNT;
483 if (audit_panic_on_write_fail)
484 udata.au_policy |= AUDIT_AHLT;
485 if (audit_argv)
486 udata.au_policy |= AUDIT_ARGV;
487 if (audit_arge)
488 udata.au_policy |= AUDIT_ARGE;
489 mtx_unlock(&audit_mtx);
490 break;
491
492 case A_OLDSETPOLICY:
493 case A_SETPOLICY:
494 if (sizeof(udata.au_policy64) == uap->length) {
495 if (udata.au_policy64 & ~(AUDIT_CNT|AUDIT_AHLT|
496 AUDIT_ARGV|AUDIT_ARGE))
497 return (EINVAL);
498 mtx_lock(&audit_mtx);
499 audit_fail_stop = ((udata.au_policy64 & AUDIT_CNT) ==
500 0);
501 audit_panic_on_write_fail = (udata.au_policy64 &
502 AUDIT_AHLT);
503 audit_argv = (udata.au_policy64 & AUDIT_ARGV);
504 audit_arge = (udata.au_policy64 & AUDIT_ARGE);
505 mtx_unlock(&audit_mtx);
506 break;
507 }
508 if ((sizeof(udata.au_policy) != uap->length) ||
509 (udata.au_policy & ~(AUDIT_CNT|AUDIT_AHLT|AUDIT_ARGV|
510 AUDIT_ARGE)))
511 return (EINVAL);
512 /*
513 * XXX - Need to wake up waiters if the policy relaxes?
514 */
515 mtx_lock(&audit_mtx);
516 audit_fail_stop = ((udata.au_policy & AUDIT_CNT) == 0);
517 audit_panic_on_write_fail = (udata.au_policy & AUDIT_AHLT);
518 audit_argv = (udata.au_policy & AUDIT_ARGV);
519 audit_arge = (udata.au_policy & AUDIT_ARGE);
520 mtx_unlock(&audit_mtx);
521 break;
522
523 case A_GETKMASK:
524 if (sizeof(udata.au_mask) != uap->length)
525 return (EINVAL);
526 mtx_lock(&audit_mtx);
527 udata.au_mask = audit_nae_mask;
528 mtx_unlock(&audit_mtx);
529 break;
530
531 case A_SETKMASK:
532 if (sizeof(udata.au_mask) != uap->length)
533 return (EINVAL);
534 mtx_lock(&audit_mtx);
535 audit_nae_mask = udata.au_mask;
536 AUDIT_CHECK_IF_KEVENTS_MASK(audit_nae_mask);
537 mtx_unlock(&audit_mtx);
538 break;
539
540 case A_OLDGETQCTRL:
541 case A_GETQCTRL:
542 if (sizeof(udata.au_qctrl64) == uap->length) {
543 mtx_lock(&audit_mtx);
544 udata.au_qctrl64.aq64_hiwater =
545 (u_int64_t)audit_qctrl.aq_hiwater;
546 udata.au_qctrl64.aq64_lowater =
547 (u_int64_t)audit_qctrl.aq_lowater;
548 udata.au_qctrl64.aq64_bufsz =
549 (u_int64_t)audit_qctrl.aq_bufsz;
550 udata.au_qctrl64.aq64_delay =
551 (u_int64_t)audit_qctrl.aq_delay;
552 udata.au_qctrl64.aq64_minfree =
553 (int64_t)audit_qctrl.aq_minfree;
554 mtx_unlock(&audit_mtx);
555 break;
556 }
557 if (sizeof(udata.au_qctrl) != uap->length)
558 return (EINVAL);
559 mtx_lock(&audit_mtx);
560 udata.au_qctrl = audit_qctrl;
561 mtx_unlock(&audit_mtx);
562 break;
563
564 case A_OLDSETQCTRL:
565 case A_SETQCTRL:
566 if (sizeof(udata.au_qctrl64) == uap->length) {
567 if ((udata.au_qctrl64.aq64_hiwater > AQ_MAXHIGH) ||
568 (udata.au_qctrl64.aq64_lowater >=
569 udata.au_qctrl64.aq64_hiwater) ||
570 (udata.au_qctrl64.aq64_bufsz > AQ_MAXBUFSZ) ||
571 (udata.au_qctrl64.aq64_minfree < 0) ||
572 (udata.au_qctrl64.aq64_minfree > 100))
573 return (EINVAL);
574 mtx_lock(&audit_mtx);
575 audit_qctrl.aq_hiwater =
576 (int)udata.au_qctrl64.aq64_hiwater;
577 audit_qctrl.aq_lowater =
578 (int)udata.au_qctrl64.aq64_lowater;
579 audit_qctrl.aq_bufsz =
580 (int)udata.au_qctrl64.aq64_bufsz;
581 audit_qctrl.aq_minfree =
582 (int)udata.au_qctrl64.aq64_minfree;
583 audit_qctrl.aq_delay = -1; /* Not used. */
584 mtx_unlock(&audit_mtx);
585 break;
586 }
587 if ((sizeof(udata.au_qctrl) != uap->length) ||
588 (udata.au_qctrl.aq_hiwater > AQ_MAXHIGH) ||
589 (udata.au_qctrl.aq_lowater >= udata.au_qctrl.aq_hiwater) ||
590 (udata.au_qctrl.aq_bufsz > AQ_MAXBUFSZ) ||
591 (udata.au_qctrl.aq_minfree < 0) ||
592 (udata.au_qctrl.aq_minfree > 100))
593 return (EINVAL);
594
595 mtx_lock(&audit_mtx);
596 audit_qctrl = udata.au_qctrl;
597 /* XXX The queue delay value isn't used with the kernel. */
598 audit_qctrl.aq_delay = -1;
599 mtx_unlock(&audit_mtx);
600 break;
601
602 case A_GETCWD:
603 return (ENOSYS);
604
605 case A_GETCAR:
606 return (ENOSYS);
607
608 case A_GETSTAT:
609 return (ENOSYS);
610
611 case A_SETSTAT:
612 return (ENOSYS);
613
614 case A_SETUMASK:
615 return (ENOSYS);
616
617 case A_SETSMASK:
618 return (ENOSYS);
619
620 case A_OLDGETCOND:
621 case A_GETCOND:
622 if (sizeof(udata.au_cond64) == uap->length) {
623 mtx_lock(&audit_mtx);
624 if (audit_enabled && !audit_suspended)
625 udata.au_cond64 = AUC_AUDITING;
626 else
627 udata.au_cond64 = AUC_NOAUDIT;
628 mtx_unlock(&audit_mtx);
629 break;
630 }
631 if (sizeof(udata.au_cond) != uap->length)
632 return (EINVAL);
633 mtx_lock(&audit_mtx);
634 if (audit_enabled && !audit_suspended)
635 udata.au_cond = AUC_AUDITING;
636 else
637 udata.au_cond = AUC_NOAUDIT;
638 mtx_unlock(&audit_mtx);
639 break;
640
641 case A_OLDSETCOND:
642 case A_SETCOND:
643 if (sizeof(udata.au_cond64) == uap->length) {
644 mtx_lock(&audit_mtx);
645 if (udata.au_cond64 == AUC_NOAUDIT)
646 audit_suspended = 1;
647 if (udata.au_cond64 == AUC_AUDITING)
648 audit_suspended = 0;
649 if (udata.au_cond64 == AUC_DISABLED) {
650 audit_suspended = 1;
651 mtx_unlock(&audit_mtx);
652 audit_shutdown();
653 break;
654 }
655 mtx_unlock(&audit_mtx);
656 break;
657 }
658 if (sizeof(udata.au_cond) != uap->length) {
659 return (EINVAL);
660 }
661 mtx_lock(&audit_mtx);
662 if (udata.au_cond == AUC_NOAUDIT)
663 audit_suspended = 1;
664 if (udata.au_cond == AUC_AUDITING)
665 audit_suspended = 0;
666 if (udata.au_cond == AUC_DISABLED) {
667 audit_suspended = 1;
668 mtx_unlock(&audit_mtx);
669 audit_shutdown();
670 break;
671 }
672 mtx_unlock(&audit_mtx);
673 break;
674
675 case A_GETCLASS:
676 if (sizeof(udata.au_evclass) != uap->length)
677 return (EINVAL);
678 udata.au_evclass.ec_class = au_event_class(
679 udata.au_evclass.ec_number);
680 break;
681
682 case A_SETCLASS:
683 if (sizeof(udata.au_evclass) != uap->length)
684 return (EINVAL);
685 au_evclassmap_insert(udata.au_evclass.ec_number,
686 udata.au_evclass.ec_class);
687 break;
688
689 case A_GETPINFO:
690 if ((sizeof(udata.au_aupinfo) != uap->length) ||
691 IS_NOT_VALID_PID(udata.au_aupinfo.ap_pid))
692 return (EINVAL);
693 if ((tp = proc_find(udata.au_aupinfo.ap_pid)) == NULL)
694 return (ESRCH);
695
696 scred = kauth_cred_proc_ref(tp);
697 if (scred->cr_audit.as_aia_p->ai_termid.at_type == AU_IPv6) {
698 kauth_cred_unref(&scred);
699 proc_rele(tp);
700 return (EINVAL);
701 }
702
703 udata.au_aupinfo.ap_auid =
704 scred->cr_audit.as_aia_p->ai_auid;
705 udata.au_aupinfo.ap_mask.am_success =
706 scred->cr_audit.as_mask.am_success;
707 udata.au_aupinfo.ap_mask.am_failure =
708 scred->cr_audit.as_mask.am_failure;
709 udata.au_aupinfo.ap_termid.machine =
710 scred->cr_audit.as_aia_p->ai_termid.at_addr[0];
711 udata.au_aupinfo.ap_termid.port =
712 scred->cr_audit.as_aia_p->ai_termid.at_port;
713 udata.au_aupinfo.ap_asid =
714 scred->cr_audit.as_aia_p->ai_asid;
715 kauth_cred_unref(&scred);
716 proc_rele(tp);
717 tp = PROC_NULL;
718 break;
719
720 case A_SETPMASK:
721 if ((sizeof(udata.au_aupinfo) != uap->length) ||
722 IS_NOT_VALID_PID(udata.au_aupinfo.ap_pid))
723 return (EINVAL);
724 if ((tp = proc_find(udata.au_aupinfo.ap_pid)) == NULL)
725 return (ESRCH);
726 scred = kauth_cred_proc_ref(tp);
727 bcopy(scred->cr_audit.as_aia_p, &aia, sizeof(aia));
728 kauth_cred_unref(&scred);
729 aia.ai_mask.am_success =
730 udata.au_aupinfo.ap_mask.am_success;
731 aia.ai_mask.am_failure =
732 udata.au_aupinfo.ap_mask.am_failure;
733 AUDIT_CHECK_IF_KEVENTS_MASK(aia.ai_mask);
734 error = audit_session_setaia(tp, &aia);
735 proc_rele(tp);
736 tp = PROC_NULL;
737 if (error)
738 return (error);
739 break;
740
741 case A_SETFSIZE:
742 if ((sizeof(udata.au_fstat) != uap->length) ||
743 ((udata.au_fstat.af_filesz != 0) &&
744 (udata.au_fstat.af_filesz < MIN_AUDIT_FILE_SIZE)))
745 return (EINVAL);
746 mtx_lock(&audit_mtx);
747 audit_fstat.af_filesz = udata.au_fstat.af_filesz;
748 mtx_unlock(&audit_mtx);
749 break;
750
751 case A_GETFSIZE:
752 if (sizeof(udata.au_fstat) != uap->length)
753 return (EINVAL);
754 mtx_lock(&audit_mtx);
755 udata.au_fstat.af_filesz = audit_fstat.af_filesz;
756 udata.au_fstat.af_currsz = audit_fstat.af_currsz;
757 mtx_unlock(&audit_mtx);
758 break;
759
760 case A_GETPINFO_ADDR:
761 if ((sizeof(udata.au_aupinfo_addr) != uap->length) ||
762 IS_NOT_VALID_PID(udata.au_aupinfo_addr.ap_pid))
763 return (EINVAL);
764 if ((tp = proc_find(udata.au_aupinfo.ap_pid)) == NULL)
765 return (ESRCH);
766 WARN_IF_AINFO_ADDR_CHANGED(uap->length,
767 sizeof(auditpinfo_addr_t), "auditon(A_GETPINFO_ADDR,...)",
768 "auditpinfo_addr_t");
769 scred = kauth_cred_proc_ref(tp);
770 udata.au_aupinfo_addr.ap_auid =
771 scred->cr_audit.as_aia_p->ai_auid;
772 udata.au_aupinfo_addr.ap_asid =
773 scred->cr_audit.as_aia_p->ai_asid;
774 udata.au_aupinfo_addr.ap_mask.am_success =
775 scred->cr_audit.as_mask.am_success;
776 udata.au_aupinfo_addr.ap_mask.am_failure =
777 scred->cr_audit.as_mask.am_failure;
778 bcopy(&scred->cr_audit.as_aia_p->ai_termid,
779 &udata.au_aupinfo_addr.ap_termid,
780 sizeof(au_tid_addr_t));
781 udata.au_aupinfo_addr.ap_flags =
782 scred->cr_audit.as_aia_p->ai_flags;
783 kauth_cred_unref(&scred);
784 proc_rele(tp);
785 tp = PROC_NULL;
786 break;
787
788 case A_GETKAUDIT:
789 if (sizeof(udata.au_kau_info) != uap->length)
790 return (EINVAL);
791 audit_get_kinfo(&udata.au_kau_info);
792 break;
793
794 case A_SETKAUDIT:
795 if ((sizeof(udata.au_kau_info) != uap->length) ||
796 (udata.au_kau_info.ai_termid.at_type != AU_IPv4 &&
797 udata.au_kau_info.ai_termid.at_type != AU_IPv6))
798 return (EINVAL);
799 audit_set_kinfo(&udata.au_kau_info);
800 break;
801
802 case A_SENDTRIGGER:
803 if ((sizeof(udata.au_trigger) != uap->length) ||
804 (udata.au_trigger < AUDIT_TRIGGER_MIN) ||
805 (udata.au_trigger > AUDIT_TRIGGER_MAX))
806 return (EINVAL);
807 return (audit_send_trigger(udata.au_trigger));
808
809 case A_GETSINFO_ADDR:
810 /* Handled above before switch(). */
811 break;
812
813 case A_GETSFLAGS:
814 if (sizeof(udata.au_flags) != uap->length)
815 return (EINVAL);
816 bcopy(&(kauth_cred_get()->cr_audit.as_aia_p->ai_flags),
817 &udata.au_flags, sizeof(udata.au_flags));
818 break;
819
820 case A_SETSFLAGS:
821 if (sizeof(udata.au_flags) != uap->length)
822 return (EINVAL);
823 bcopy(kauth_cred_get()->cr_audit.as_aia_p, &aia, sizeof(aia));
824 aia.ai_flags = udata.au_flags;
825 error = audit_session_setaia(p, &aia);
826 if (error)
827 return (error);
828 break;
829
830 case A_GETCTLMODE:
831 if (sizeof(udata.au_ctl_mode) != uap->length) {
832 return (EINVAL);
833 }
834 mtx_lock(&audit_mtx);
835 udata.au_ctl_mode = audit_ctl_mode;
836 mtx_unlock(&audit_mtx);
837 break;
838
839 case A_SETCTLMODE:
840 if (sizeof(udata.au_ctl_mode) != uap->length) {
841 return (EINVAL);
842 }
843
844 mtx_lock(&audit_mtx);
845
846 if (udata.au_ctl_mode == AUDIT_CTLMODE_NORMAL) {
847 audit_ctl_mode = AUDIT_CTLMODE_NORMAL;
848 } else if (udata.au_ctl_mode == AUDIT_CTLMODE_EXTERNAL) {
849 audit_ctl_mode = AUDIT_CTLMODE_EXTERNAL;
850 } else {
851 mtx_unlock(&audit_mtx);
852 return (EINVAL);
853 }
854
855 mtx_unlock(&audit_mtx);
856 break;
857
858 case A_GETEXPAFTER:
859 if (sizeof(udata.au_expire_after) != uap->length) {
860 return (EINVAL);
861 }
862 mtx_lock(&audit_mtx);
863 udata.au_expire_after.age = audit_expire_after.age;
864 udata.au_expire_after.size = audit_expire_after.size;
865 udata.au_expire_after.op_type = audit_expire_after.op_type;
866 mtx_unlock(&audit_mtx);
867 break;
868
869 case A_SETEXPAFTER:
870 if (sizeof(udata.au_expire_after) != uap->length) {
871 return (EINVAL);
872 }
873 mtx_lock(&audit_mtx);
874 audit_expire_after.age = udata.au_expire_after.age;
875 audit_expire_after.size = udata.au_expire_after.size;
876 audit_expire_after.op_type = udata.au_expire_after.op_type;
877 mtx_unlock(&audit_mtx);
878 break;
879
880 default:
881 return (EINVAL);
882 }
883
884 /*
885 * Copy data back to userspace for the GET comands.
886 */
887 switch (uap->cmd) {
888 case A_GETPOLICY:
889 case A_OLDGETPOLICY:
890 case A_GETKMASK:
891 case A_GETQCTRL:
892 case A_OLDGETQCTRL:
893 case A_GETCWD:
894 case A_GETCAR:
895 case A_GETSTAT:
896 case A_GETCOND:
897 case A_OLDGETCOND:
898 case A_GETCLASS:
899 case A_GETPINFO:
900 case A_GETFSIZE:
901 case A_GETPINFO_ADDR:
902 case A_GETKAUDIT:
903 case A_GETSINFO_ADDR:
904 case A_GETSFLAGS:
905 case A_GETCTLMODE:
906 case A_GETEXPAFTER:
907 error = copyout((void *)&udata, uap->data, uap->length);
908 if (error)
909 return (ENOSYS);
910 break;
911 }
912
913 return (0);
914}
915
916/*
917 * System calls to manage the user audit information.
918 */
919/* ARGSUSED */
920int
921getauid(proc_t p, struct getauid_args *uap, __unused int32_t *retval)
922{
923 au_id_t id;
924 int error;
925 kauth_cred_t scred;
926
927#if CONFIG_MACF
928 error = mac_proc_check_getauid(p);
929 if (error)
930 return (error);
931#endif
932 scred = kauth_cred_proc_ref(p);
933 id = scred->cr_audit.as_aia_p->ai_auid;
934 kauth_cred_unref(&scred);
935
936 error = copyout((void *)&id, uap->auid, sizeof(id));
937 if (error)
938 return (error);
939
940 return (0);
941}
942
943/* ARGSUSED */
944int
945setauid(proc_t p, struct setauid_args *uap, __unused int32_t *retval)
946{
947 int error;
948 au_id_t id;
949 kauth_cred_t scred;
950 struct auditinfo_addr aia;
951
952 error = copyin(uap->auid, &id, sizeof(id));
953 if (error)
954 return (error);
955 AUDIT_ARG(auid, id);
956
957#if CONFIG_MACF
958 error = mac_proc_check_setauid(p, id);
959 if (error)
960 return (error);
961#endif
962
963 scred = kauth_cred_proc_ref(p);
964 error = suser(scred, &p->p_acflag);
965 if (error) {
966 kauth_cred_unref(&scred);
967 return (error);
968 }
969
970 bcopy(scred->cr_audit.as_aia_p, &aia, sizeof(aia));
971 if (aia.ai_asid == AU_DEFAUDITSID) {
972 aia.ai_asid = AU_ASSIGN_ASID;
973 }
974 bcopy(&scred->cr_audit.as_mask, &aia.ai_mask, sizeof(au_mask_t));
975 kauth_cred_unref(&scred);
976 aia.ai_auid = id;
977 error = audit_session_setaia(p, &aia);
978
979 return (error);
980}
981
982static int
983getaudit_addr_internal(proc_t p, user_addr_t user_addr, size_t length)
984{
985 kauth_cred_t scred;
986 auditinfo_addr_t aia;
987
988 scred = kauth_cred_proc_ref(p);
989 bcopy(scred->cr_audit.as_aia_p, &aia, sizeof (auditinfo_addr_t));
990 /*
991 * Only superuser gets to see the real mask.
992 */
993 if (suser(scred, &p->p_acflag)) {
994 aia.ai_mask.am_success = ~0;
995 aia.ai_mask.am_failure = ~0;
996 }
997 kauth_cred_unref(&scred);
998
999 return (copyout(&aia, user_addr, min(sizeof(aia), length)));
1000}
1001
1002/* ARGSUSED */
1003int
1004getaudit_addr(proc_t p, struct getaudit_addr_args *uap,
1005 __unused int32_t *retval)
1006{
1007#if CONFIG_MACF
1008 int error = mac_proc_check_getaudit(p);
1009
1010 if (error)
1011 return (error);
1012#endif /* CONFIG_MACF */
1013 WARN_IF_AINFO_ADDR_CHANGED(uap->length, sizeof(auditinfo_addr_t),
1014 "getaudit_addr(2)", "auditinfo_addr_t");
1015
1016 return (getaudit_addr_internal(p, uap->auditinfo_addr, uap->length));
1017}
1018
1019/* ARGSUSED */
1020int
1021setaudit_addr(proc_t p, struct setaudit_addr_args *uap,
1022 __unused int32_t *retval)
1023{
1024 struct auditinfo_addr aia;
1025 kauth_cred_t scred;
1026 int error;
1027
1028 bzero(&aia, sizeof(auditinfo_addr_t));
1029 error = copyin(uap->auditinfo_addr, &aia,
1030 min(sizeof(aia), uap->length));
1031 if (error)
1032 return (error);
1033 AUDIT_ARG(auditinfo_addr, &aia);
1034 if (aia.ai_termid.at_type != AU_IPv6 &&
1035 aia.ai_termid.at_type != AU_IPv4)
1036 return (EINVAL);
1037 if (aia.ai_asid != AU_ASSIGN_ASID &&
1038 (uint32_t)aia.ai_asid > ASSIGNED_ASID_MAX)
1039 return (EINVAL);
1040
1041#if CONFIG_MACF
1042 error = mac_proc_check_setaudit(p, &aia);
1043 if (error)
1044 return (error);
1045#endif
1046
1047 scred = kauth_cred_proc_ref(p);
1048 error = suser(scred, &p->p_acflag);
1049 if (error) {
1050 kauth_cred_unref(&scred);
1051 return (error);
1052 }
1053
1054 WARN_IF_AINFO_ADDR_CHANGED(uap->length, sizeof(auditinfo_addr_t),
1055 "setaudit_addr(2)", "auditinfo_addr_t");
1056 WARN_IF_BAD_ASID(aia.ai_asid, "setaudit_addr(2)");
1057 kauth_cred_unref(&scred);
1058
1059 AUDIT_CHECK_IF_KEVENTS_MASK(aia.ai_mask);
1060 if (aia.ai_asid == AU_DEFAUDITSID)
1061 aia.ai_asid = AU_ASSIGN_ASID;
1062
1063 error = audit_session_setaia(p, &aia);
1064 if (error)
1065 return (error);
1066
1067 /*
1068 * If asked to assign an ASID then let the user know what the ASID is
1069 * by copying the auditinfo_addr struct back out.
1070 */
1071 if (aia.ai_asid == AU_ASSIGN_ASID)
1072 error = getaudit_addr_internal(p, uap->auditinfo_addr,
1073 uap->length);
1074
1075 return (error);
1076}
1077
1078/*
1079 * Syscall to manage audit files.
1080 *
1081 */
1082/* ARGSUSED */
1083int
1084auditctl(proc_t p, struct auditctl_args *uap, __unused int32_t *retval)
1085{
1086 struct nameidata nd;
1087 kauth_cred_t cred;
1088 struct vnode *vp;
1089 int error = 0;
1090 au_ctlmode_t ctlmode;
1091
1092 error = suser(kauth_cred_get(), &p->p_acflag);
1093 if (error)
1094 return (error);
1095
1096 ctlmode = audit_ctl_mode;
1097
1098 /*
1099 * Do not allow setting of a path when auditing is in reserved mode
1100 */
1101 if (ctlmode == AUDIT_CTLMODE_EXTERNAL &&
1102 !IOTaskHasEntitlement(current_task(), AU_AUDITCTL_RESERVED_ENTITLEMENT)) {
1103 return (EPERM);
1104 }
1105
1106 vp = NULL;
1107 cred = NULL;
1108
1109 /*
1110 * If a path is specified, open the replacement vnode, perform
1111 * validity checks, and grab another reference to the current
1112 * credential.
1113 *
1114 * XXX Changes API slightly. NULL path no longer disables audit but
1115 * returns EINVAL.
1116 */
1117 if (uap->path == USER_ADDR_NULL)
1118 return (EINVAL);
1119
1120 NDINIT(&nd, LOOKUP, OP_OPEN, FOLLOW | LOCKLEAF | AUDITVNPATH1,
1121 (IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 :
1122 UIO_USERSPACE32), uap->path, vfs_context_current());
1123 error = vn_open(&nd, AUDIT_OPEN_FLAGS, 0);
1124 if (error)
1125 return (error);
1126 vp = nd.ni_vp;
1127#if CONFIG_MACF
1128 /*
1129 * Accessibility of the vnode was determined in vn_open; the
1130 * mac_system_check_auditctl should only determine whether that vnode
1131 * is appropriate for storing audit data, or that the caller was
1132 * permitted to control the auditing system at all. For example, a
1133 * confidentiality policy may want to ensure that audit files are
1134 * always high sensitivity.
1135 */
1136 error = mac_system_check_auditctl(kauth_cred_get(), vp);
1137 if (error) {
1138 vn_close(vp, AUDIT_CLOSE_FLAGS, vfs_context_current());
1139 vnode_put(vp);
1140 return (error);
1141 }
1142#endif
1143 if (vp->v_type != VREG) {
1144 vn_close(vp, AUDIT_CLOSE_FLAGS, vfs_context_current());
1145 vnode_put(vp);
1146 return (EINVAL);
1147 }
1148 mtx_lock(&audit_mtx);
1149 /*
1150 * XXXAUDIT: Should audit_suspended actually be cleared by
1151 * audit_worker?
1152 */
1153 audit_suspended = 0;
1154 mtx_unlock(&audit_mtx);
1155
1156 /*
1157 * The following gets unreferenced in audit_rotate_vnode()
1158 * after the rotation and it is no longer needed.
1159 */
1160 cred = kauth_cred_get_with_ref();
1161 audit_rotate_vnode(cred, vp);
1162 vnode_put(vp);
1163
1164 return (error);
1165}
1166
1167#else /* !CONFIG_AUDIT */
1168
1169int
1170audit(proc_t p, struct audit_args *uap, int32_t *retval)
1171{
1172#pragma unused(p, uap, retval)
1173
1174 return (ENOSYS);
1175}
1176
1177int
1178auditon(proc_t p, struct auditon_args *uap, int32_t *retval)
1179{
1180#pragma unused(p, uap, retval)
1181
1182 return (ENOSYS);
1183}
1184
1185int
1186getauid(proc_t p, struct getauid_args *uap, int32_t *retval)
1187{
1188#pragma unused(p, uap, retval)
1189
1190 return (ENOSYS);
1191}
1192
1193int
1194setauid(proc_t p, struct setauid_args *uap, int32_t *retval)
1195{
1196#pragma unused(p, uap, retval)
1197
1198 return (ENOSYS);
1199}
1200
1201int
1202getaudit_addr(proc_t p, struct getaudit_addr_args *uap, int32_t *retval)
1203{
1204#pragma unused(p, uap, retval)
1205
1206 return (ENOSYS);
1207}
1208
1209int
1210setaudit_addr(proc_t p, struct setaudit_addr_args *uap, int32_t *retval)
1211{
1212#pragma unused(p, uap, retval)
1213
1214 return (ENOSYS);
1215}
1216
1217int
1218auditctl(proc_t p, struct auditctl_args *uap, int32_t *retval)
1219{
1220#pragma unused(p, uap, retval)
1221
1222 return (ENOSYS);
1223}
1224
1225#endif /* CONFIG_AUDIT */
1226