]> git.saurik.com Git - apple/xnu.git/blob - bsd/security/audit/audit_syscalls.c
359717f7b71a1c31de889175f5395a534eb6dd06
[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_kevents.h>
64
65 #include <security/audit/audit.h>
66 #include <security/audit/audit_bsd.h>
67 #include <security/audit/audit_private.h>
68
69 #include <mach/host_priv.h>
70 #include <mach/host_special_ports.h>
71 #include <mach/audit_triggers_server.h>
72
73 #include <kern/host.h>
74 #include <kern/kalloc.h>
75 #include <kern/zalloc.h>
76 #include <kern/lock.h>
77 #include <kern/wait_queue.h>
78 #include <kern/sched_prim.h>
79
80 #if CONFIG_MACF
81 #include <bsm/audit_record.h>
82 #include <security/mac.h>
83 #include <security/mac_framework.h>
84 #include <security/mac_policy.h>
85 #endif
86
87 #include <net/route.h>
88
89 #include <netinet/in.h>
90 #include <netinet/in_pcb.h>
91
92 #if CONFIG_AUDIT
93
94 #define IS_NOT_VALID_PID(p) ((p) < 1 || (p) > PID_MAX)
95
96 #ifdef AUDIT_API_WARNINGS
97 /*
98 * Macro to warn about auditinfo_addr_t/auditpinfo_addr_t changing sizes
99 * to encourage the userland code to be recompiled and updated.
100 */
101 #define WARN_IF_AINFO_ADDR_CHANGED(sz1, sz2, scall, tp) do { \
102 if ((size_t)(sz1) != (size_t)(sz2)) { \
103 char pn[MAXCOMLEN + 1]; \
104 \
105 proc_selfname(pn, MAXCOMLEN + 1); \
106 printf("Size of %s used by %s in %s is different from " \
107 "kernel's. Please recompile %s.\n", (tp), \
108 (scall), pn, pn); \
109 } \
110 } while (0)
111
112 /*
113 * Macro to warn about using ASID's outside the range [1 to PID_MAX] to
114 * encourage userland code changes.
115 */
116 #define WARN_IF_BAD_ASID(asid, scall) do { \
117 if (((asid) < 1 || (asid) > PID_MAX) && \
118 (asid) != AU_ASSIGN_ASID) { \
119 char pn[MAXCOMLEN + 1]; \
120 \
121 proc_selfname(pn, MAXCOMLEN + 1); \
122 printf("%s in %s is using an ASID (%u) outside the " \
123 "range [1 to %d]. Please change %s to use an ASID "\
124 "within this range or use AU_ASSIGN_ASID.\n", \
125 (scall), pn, (uint32_t)(asid), PID_MAX, pn); \
126 } \
127 } while (0)
128
129 #else /* ! AUDIT_API_WARNINGS */
130
131 #define WARN_IF_AINFO_ADDR_CHANGED(sz1, sz2, scall, tp) do { \
132 } while (0)
133
134 #define WARN_IF_BAD_ASID(asid, scall) do { \
135 } while (0)
136
137 #endif /* AUDIT_API_WARNINGS */
138
139 /*
140 * System call to allow a user space application to submit a BSM audit record
141 * to the kernel for inclusion in the audit log. This function does little
142 * verification on the audit record that is submitted.
143 *
144 * XXXAUDIT: Audit preselection for user records does not currently work,
145 * since we pre-select only based on the AUE_audit event type, not the event
146 * type submitted as part of the user audit data.
147 */
148 /* ARGSUSED */
149 int
150 audit(proc_t p, struct audit_args *uap, __unused int32_t *retval)
151 {
152 int error;
153 void * rec;
154 struct kaudit_record *ar;
155 struct uthread *uthr;
156
157 error = suser(kauth_cred_get(), &p->p_acflag);
158 if (error)
159 return (error);
160
161 mtx_lock(&audit_mtx);
162 if ((uap->length <= 0) || (uap->length > (int)audit_qctrl.aq_bufsz)) {
163 mtx_unlock(&audit_mtx);
164 return (EINVAL);
165 }
166 mtx_unlock(&audit_mtx);
167
168 ar = currecord();
169
170 /*
171 * If there's no current audit record (audit() itself not audited)
172 * commit the user audit record.
173 */
174 if (ar == NULL) {
175 uthr = curthread();
176 if (uthr == NULL) /* can this happen? */
177 return (ENOTSUP);
178
179 /*
180 * This is not very efficient; we're required to allocate a
181 * complete kernel audit record just so the user record can
182 * tag along.
183 */
184 uthr->uu_ar = audit_new(AUE_NULL, p, uthr);
185 if (uthr->uu_ar == NULL)
186 return (ENOTSUP);
187 ar = uthr->uu_ar;
188 }
189
190 if (uap->length > MAX_AUDIT_RECORD_SIZE)
191 return (EINVAL);
192
193 rec = malloc(uap->length, M_AUDITDATA, M_WAITOK);
194
195 error = copyin(uap->record, rec, uap->length);
196 if (error)
197 goto free_out;
198
199 #if CONFIG_MACF
200 error = mac_system_check_audit(kauth_cred_get(), rec, uap->length);
201 if (error)
202 goto free_out;
203 #endif
204
205 /* Verify the record. */
206 if (bsm_rec_verify(rec) == 0) {
207 error = EINVAL;
208 goto free_out;
209 }
210
211 /*
212 * Attach the user audit record to the kernel audit record. Because
213 * this system call is an auditable event, we will write the user
214 * record along with the record for this audit event.
215 *
216 * XXXAUDIT: KASSERT appropriate starting values of k_udata, k_ulen,
217 * k_ar_commit & AR_COMMIT_USER?
218 */
219 ar->k_udata = rec;
220 ar->k_ulen = uap->length;
221 ar->k_ar_commit |= AR_COMMIT_USER;
222
223 /*
224 * Currently we assume that all preselection has been performed in
225 * userspace. We unconditionally set these masks so that the records
226 * get committed both to the trail and pipe. In the future we will
227 * want to setup kernel based preselection.
228 */
229 ar->k_ar_commit |= (AR_PRESELECT_USER_TRAIL | AR_PRESELECT_USER_PIPE);
230 return (0);
231
232 free_out:
233 /*
234 * audit_syscall_exit() will free the audit record on the thread even
235 * if we allocated it above.
236 */
237 free(rec, M_AUDITDATA);
238 return (error);
239 }
240
241 /*
242 * System call to manipulate auditing.
243 */
244 /* ARGSUSED */
245 int
246 auditon(proc_t p, struct auditon_args *uap, __unused int32_t *retval)
247 {
248 kauth_cred_t scred;
249 int error = 0;
250 union auditon_udata udata;
251 proc_t tp = PROC_NULL;
252 struct auditinfo_addr aia;
253
254 AUDIT_ARG(cmd, uap->cmd);
255
256 #if CONFIG_MACF
257 error = mac_system_check_auditon(kauth_cred_get(), uap->cmd);
258 if (error)
259 return (error);
260 #endif
261
262 if ((uap->length <= 0) || (uap->length >
263 (int)sizeof(union auditon_udata)))
264 return (EINVAL);
265
266 memset((void *)&udata, 0, sizeof(udata));
267
268 /*
269 * Some of the GET commands use the arguments too.
270 */
271 switch (uap->cmd) {
272 case A_SETPOLICY:
273 case A_OLDSETPOLICY:
274 case A_SETKMASK:
275 case A_SETQCTRL:
276 case A_OLDSETQCTRL:
277 case A_SETSTAT:
278 case A_SETUMASK:
279 case A_SETSMASK:
280 case A_SETCOND:
281 case A_OLDSETCOND:
282 case A_SETCLASS:
283 case A_SETPMASK:
284 case A_SETFSIZE:
285 case A_SETKAUDIT:
286 case A_GETCLASS:
287 case A_GETPINFO:
288 case A_GETPINFO_ADDR:
289 case A_SENDTRIGGER:
290 case A_GETSINFO_ADDR:
291 case A_GETSFLAGS:
292 case A_SETSFLAGS:
293 error = copyin(uap->data, (void *)&udata, uap->length);
294 if (error)
295 return (error);
296 AUDIT_ARG(auditon, &udata);
297 AUDIT_ARG(len, uap->length);
298 break;
299 }
300
301 /* Check appropriate privilege. */
302 switch (uap->cmd) {
303 /*
304 * A_GETSINFO doesn't require priviledge but only superuser
305 * gets to see the audit masks.
306 */
307 case A_GETSINFO_ADDR:
308 if ((sizeof(udata.au_kau_info) != uap->length) ||
309 (audit_session_lookup(udata.au_kau_info.ai_asid,
310 &udata.au_kau_info) != 0))
311 error = EINVAL;
312 else if (!kauth_cred_issuser(kauth_cred_get())) {
313 udata.au_kau_info.ai_mask.am_success = ~0;
314 udata.au_kau_info.ai_mask.am_failure = ~0;
315 }
316 break;
317 case A_GETSFLAGS:
318 case A_SETSFLAGS:
319 /* Getting one's own audit session flags requires no
320 * privilege. Setting the flags is subject to access
321 * control implemented in audit_session_setaia().
322 */
323 break;
324 default:
325 error = suser(kauth_cred_get(), &p->p_acflag);
326 break;
327 }
328 if (error)
329 return (error);
330
331 /*
332 * XXX Need to implement these commands by accessing the global
333 * values associated with the commands.
334 */
335 switch (uap->cmd) {
336 case A_OLDGETPOLICY:
337 case A_GETPOLICY:
338 if (sizeof(udata.au_policy64) == uap->length) {
339 mtx_lock(&audit_mtx);
340 if (!audit_fail_stop)
341 udata.au_policy64 |= AUDIT_CNT;
342 if (audit_panic_on_write_fail)
343 udata.au_policy64 |= AUDIT_AHLT;
344 if (audit_argv)
345 udata.au_policy64 |= AUDIT_ARGV;
346 if (audit_arge)
347 udata.au_policy64 |= AUDIT_ARGE;
348 mtx_unlock(&audit_mtx);
349 break;
350 }
351 if (sizeof(udata.au_policy) != uap->length)
352 return (EINVAL);
353 mtx_lock(&audit_mtx);
354 if (!audit_fail_stop)
355 udata.au_policy |= AUDIT_CNT;
356 if (audit_panic_on_write_fail)
357 udata.au_policy |= AUDIT_AHLT;
358 if (audit_argv)
359 udata.au_policy |= AUDIT_ARGV;
360 if (audit_arge)
361 udata.au_policy |= AUDIT_ARGE;
362 mtx_unlock(&audit_mtx);
363 break;
364
365 case A_OLDSETPOLICY:
366 case A_SETPOLICY:
367 if (sizeof(udata.au_policy64) == uap->length) {
368 if (udata.au_policy64 & ~(AUDIT_CNT|AUDIT_AHLT|
369 AUDIT_ARGV|AUDIT_ARGE))
370 return (EINVAL);
371 mtx_lock(&audit_mtx);
372 audit_fail_stop = ((udata.au_policy64 & AUDIT_CNT) ==
373 0);
374 audit_panic_on_write_fail = (udata.au_policy64 &
375 AUDIT_AHLT);
376 audit_argv = (udata.au_policy64 & AUDIT_ARGV);
377 audit_arge = (udata.au_policy64 & AUDIT_ARGE);
378 mtx_unlock(&audit_mtx);
379 break;
380 }
381 if ((sizeof(udata.au_policy) != uap->length) ||
382 (udata.au_policy & ~(AUDIT_CNT|AUDIT_AHLT|AUDIT_ARGV|
383 AUDIT_ARGE)))
384 return (EINVAL);
385 /*
386 * XXX - Need to wake up waiters if the policy relaxes?
387 */
388 mtx_lock(&audit_mtx);
389 audit_fail_stop = ((udata.au_policy & AUDIT_CNT) == 0);
390 audit_panic_on_write_fail = (udata.au_policy & AUDIT_AHLT);
391 audit_argv = (udata.au_policy & AUDIT_ARGV);
392 audit_arge = (udata.au_policy & AUDIT_ARGE);
393 mtx_unlock(&audit_mtx);
394 break;
395
396 case A_GETKMASK:
397 if (sizeof(udata.au_mask) != uap->length)
398 return (EINVAL);
399 mtx_lock(&audit_mtx);
400 udata.au_mask = audit_nae_mask;
401 mtx_unlock(&audit_mtx);
402 break;
403
404 case A_SETKMASK:
405 if (sizeof(udata.au_mask) != uap->length)
406 return (EINVAL);
407 mtx_lock(&audit_mtx);
408 audit_nae_mask = udata.au_mask;
409 AUDIT_CHECK_IF_KEVENTS_MASK(audit_nae_mask);
410 mtx_unlock(&audit_mtx);
411 break;
412
413 case A_OLDGETQCTRL:
414 case A_GETQCTRL:
415 if (sizeof(udata.au_qctrl64) == uap->length) {
416 mtx_lock(&audit_mtx);
417 udata.au_qctrl64.aq64_hiwater =
418 (u_int64_t)audit_qctrl.aq_hiwater;
419 udata.au_qctrl64.aq64_lowater =
420 (u_int64_t)audit_qctrl.aq_lowater;
421 udata.au_qctrl64.aq64_bufsz =
422 (u_int64_t)audit_qctrl.aq_bufsz;
423 udata.au_qctrl64.aq64_delay =
424 (u_int64_t)audit_qctrl.aq_delay;
425 udata.au_qctrl64.aq64_minfree =
426 (int64_t)audit_qctrl.aq_minfree;
427 mtx_unlock(&audit_mtx);
428 break;
429 }
430 if (sizeof(udata.au_qctrl) != uap->length)
431 return (EINVAL);
432 mtx_lock(&audit_mtx);
433 udata.au_qctrl = audit_qctrl;
434 mtx_unlock(&audit_mtx);
435 break;
436
437 case A_OLDSETQCTRL:
438 case A_SETQCTRL:
439 if (sizeof(udata.au_qctrl64) == uap->length) {
440 if ((udata.au_qctrl64.aq64_hiwater > AQ_MAXHIGH) ||
441 (udata.au_qctrl64.aq64_lowater >=
442 udata.au_qctrl64.aq64_hiwater) ||
443 (udata.au_qctrl64.aq64_bufsz > AQ_MAXBUFSZ) ||
444 (udata.au_qctrl64.aq64_minfree < 0) ||
445 (udata.au_qctrl64.aq64_minfree > 100))
446 return (EINVAL);
447 mtx_lock(&audit_mtx);
448 audit_qctrl.aq_hiwater =
449 (int)udata.au_qctrl64.aq64_hiwater;
450 audit_qctrl.aq_lowater =
451 (int)udata.au_qctrl64.aq64_lowater;
452 audit_qctrl.aq_bufsz =
453 (int)udata.au_qctrl64.aq64_bufsz;
454 audit_qctrl.aq_minfree =
455 (int)udata.au_qctrl64.aq64_minfree;
456 audit_qctrl.aq_delay = -1; /* Not used. */
457 mtx_unlock(&audit_mtx);
458 break;
459 }
460 if ((sizeof(udata.au_qctrl) != uap->length) ||
461 (udata.au_qctrl.aq_hiwater > AQ_MAXHIGH) ||
462 (udata.au_qctrl.aq_lowater >= udata.au_qctrl.aq_hiwater) ||
463 (udata.au_qctrl.aq_bufsz > AQ_MAXBUFSZ) ||
464 (udata.au_qctrl.aq_minfree < 0) ||
465 (udata.au_qctrl.aq_minfree > 100))
466 return (EINVAL);
467
468 mtx_lock(&audit_mtx);
469 audit_qctrl = udata.au_qctrl;
470 /* XXX The queue delay value isn't used with the kernel. */
471 audit_qctrl.aq_delay = -1;
472 mtx_unlock(&audit_mtx);
473 break;
474
475 case A_GETCWD:
476 return (ENOSYS);
477
478 case A_GETCAR:
479 return (ENOSYS);
480
481 case A_GETSTAT:
482 return (ENOSYS);
483
484 case A_SETSTAT:
485 return (ENOSYS);
486
487 case A_SETUMASK:
488 return (ENOSYS);
489
490 case A_SETSMASK:
491 return (ENOSYS);
492
493 case A_OLDGETCOND:
494 case A_GETCOND:
495 if (sizeof(udata.au_cond64) == uap->length) {
496 mtx_lock(&audit_mtx);
497 if (audit_enabled && !audit_suspended)
498 udata.au_cond64 = AUC_AUDITING;
499 else
500 udata.au_cond64 = AUC_NOAUDIT;
501 mtx_unlock(&audit_mtx);
502 break;
503 }
504 if (sizeof(udata.au_cond) != uap->length)
505 return (EINVAL);
506 mtx_lock(&audit_mtx);
507 if (audit_enabled && !audit_suspended)
508 udata.au_cond = AUC_AUDITING;
509 else
510 udata.au_cond = AUC_NOAUDIT;
511 mtx_unlock(&audit_mtx);
512 break;
513
514 case A_OLDSETCOND:
515 case A_SETCOND:
516 if (sizeof(udata.au_cond64) == uap->length) {
517 mtx_lock(&audit_mtx);
518 if (udata.au_cond64 == AUC_NOAUDIT)
519 audit_suspended = 1;
520 if (udata.au_cond64 == AUC_AUDITING)
521 audit_suspended = 0;
522 if (udata.au_cond64 == AUC_DISABLED) {
523 audit_suspended = 1;
524 mtx_unlock(&audit_mtx);
525 audit_shutdown();
526 break;
527 }
528 mtx_unlock(&audit_mtx);
529 break;
530 }
531 if (sizeof(udata.au_cond) != uap->length) {
532 return (EINVAL);
533 }
534 mtx_lock(&audit_mtx);
535 if (udata.au_cond == AUC_NOAUDIT)
536 audit_suspended = 1;
537 if (udata.au_cond == AUC_AUDITING)
538 audit_suspended = 0;
539 if (udata.au_cond == AUC_DISABLED) {
540 audit_suspended = 1;
541 mtx_unlock(&audit_mtx);
542 audit_shutdown();
543 break;
544 }
545 mtx_unlock(&audit_mtx);
546 break;
547
548 case A_GETCLASS:
549 if (sizeof(udata.au_evclass) != uap->length)
550 return (EINVAL);
551 udata.au_evclass.ec_class = au_event_class(
552 udata.au_evclass.ec_number);
553 break;
554
555 case A_SETCLASS:
556 if (sizeof(udata.au_evclass) != uap->length)
557 return (EINVAL);
558 au_evclassmap_insert(udata.au_evclass.ec_number,
559 udata.au_evclass.ec_class);
560 break;
561
562 case A_GETPINFO:
563 if ((sizeof(udata.au_aupinfo) != uap->length) ||
564 IS_NOT_VALID_PID(udata.au_aupinfo.ap_pid))
565 return (EINVAL);
566 if ((tp = proc_find(udata.au_aupinfo.ap_pid)) == NULL)
567 return (ESRCH);
568
569 scred = kauth_cred_proc_ref(tp);
570 if (scred->cr_audit.as_aia_p->ai_termid.at_type == AU_IPv6) {
571 kauth_cred_unref(&scred);
572 proc_rele(tp);
573 return (EINVAL);
574 }
575
576 udata.au_aupinfo.ap_auid =
577 scred->cr_audit.as_aia_p->ai_auid;
578 udata.au_aupinfo.ap_mask.am_success =
579 scred->cr_audit.as_mask.am_success;
580 udata.au_aupinfo.ap_mask.am_failure =
581 scred->cr_audit.as_mask.am_failure;
582 udata.au_aupinfo.ap_termid.machine =
583 scred->cr_audit.as_aia_p->ai_termid.at_addr[0];
584 udata.au_aupinfo.ap_termid.port =
585 scred->cr_audit.as_aia_p->ai_termid.at_port;
586 udata.au_aupinfo.ap_asid =
587 scred->cr_audit.as_aia_p->ai_asid;
588 kauth_cred_unref(&scred);
589 proc_rele(tp);
590 tp = PROC_NULL;
591 break;
592
593 case A_SETPMASK:
594 if ((sizeof(udata.au_aupinfo) != uap->length) ||
595 IS_NOT_VALID_PID(udata.au_aupinfo.ap_pid))
596 return (EINVAL);
597 if ((tp = proc_find(udata.au_aupinfo.ap_pid)) == NULL)
598 return (ESRCH);
599 scred = kauth_cred_proc_ref(tp);
600 bcopy(scred->cr_audit.as_aia_p, &aia, sizeof(aia));
601 kauth_cred_unref(&scred);
602 aia.ai_mask.am_success =
603 udata.au_aupinfo.ap_mask.am_success;
604 aia.ai_mask.am_failure =
605 udata.au_aupinfo.ap_mask.am_failure;
606 AUDIT_CHECK_IF_KEVENTS_MASK(aia.ai_mask);
607 error = audit_session_setaia(tp, &aia);
608 proc_rele(tp);
609 tp = PROC_NULL;
610 if (error)
611 return (error);
612 break;
613
614 case A_SETFSIZE:
615 if ((sizeof(udata.au_fstat) != uap->length) ||
616 ((udata.au_fstat.af_filesz != 0) &&
617 (udata.au_fstat.af_filesz < MIN_AUDIT_FILE_SIZE)))
618 return (EINVAL);
619 mtx_lock(&audit_mtx);
620 audit_fstat.af_filesz = udata.au_fstat.af_filesz;
621 mtx_unlock(&audit_mtx);
622 break;
623
624 case A_GETFSIZE:
625 if (sizeof(udata.au_fstat) != uap->length)
626 return (EINVAL);
627 mtx_lock(&audit_mtx);
628 udata.au_fstat.af_filesz = audit_fstat.af_filesz;
629 udata.au_fstat.af_currsz = audit_fstat.af_currsz;
630 mtx_unlock(&audit_mtx);
631 break;
632
633 case A_GETPINFO_ADDR:
634 if ((sizeof(udata.au_aupinfo_addr) != uap->length) ||
635 IS_NOT_VALID_PID(udata.au_aupinfo_addr.ap_pid))
636 return (EINVAL);
637 if ((tp = proc_find(udata.au_aupinfo.ap_pid)) == NULL)
638 return (ESRCH);
639 WARN_IF_AINFO_ADDR_CHANGED(uap->length,
640 sizeof(auditpinfo_addr_t), "auditon(A_GETPINFO_ADDR,...)",
641 "auditpinfo_addr_t");
642 scred = kauth_cred_proc_ref(tp);
643 udata.au_aupinfo_addr.ap_auid =
644 scred->cr_audit.as_aia_p->ai_auid;
645 udata.au_aupinfo_addr.ap_asid =
646 scred->cr_audit.as_aia_p->ai_asid;
647 udata.au_aupinfo_addr.ap_mask.am_success =
648 scred->cr_audit.as_mask.am_success;
649 udata.au_aupinfo_addr.ap_mask.am_failure =
650 scred->cr_audit.as_mask.am_failure;
651 bcopy(&scred->cr_audit.as_aia_p->ai_termid,
652 &udata.au_aupinfo_addr.ap_termid,
653 sizeof(au_tid_addr_t));
654 udata.au_aupinfo_addr.ap_flags =
655 scred->cr_audit.as_aia_p->ai_flags;
656 kauth_cred_unref(&scred);
657 proc_rele(tp);
658 tp = PROC_NULL;
659 break;
660
661 case A_GETKAUDIT:
662 if (sizeof(udata.au_kau_info) != uap->length)
663 return (EINVAL);
664 audit_get_kinfo(&udata.au_kau_info);
665 break;
666
667 case A_SETKAUDIT:
668 if ((sizeof(udata.au_kau_info) != uap->length) ||
669 (udata.au_kau_info.ai_termid.at_type != AU_IPv4 &&
670 udata.au_kau_info.ai_termid.at_type != AU_IPv6))
671 return (EINVAL);
672 audit_set_kinfo(&udata.au_kau_info);
673 break;
674
675 case A_SENDTRIGGER:
676 if ((sizeof(udata.au_trigger) != uap->length) ||
677 (udata.au_trigger < AUDIT_TRIGGER_MIN) ||
678 (udata.au_trigger > AUDIT_TRIGGER_MAX))
679 return (EINVAL);
680 return (audit_send_trigger(udata.au_trigger));
681
682 case A_GETSINFO_ADDR:
683 /* Handled above before switch(). */
684 break;
685
686 case A_GETSFLAGS:
687 if (sizeof(udata.au_flags) != uap->length)
688 return (EINVAL);
689 bcopy(&(kauth_cred_get()->cr_audit.as_aia_p->ai_flags),
690 &udata.au_flags, sizeof(udata.au_flags));
691 break;
692
693 case A_SETSFLAGS:
694 if (sizeof(udata.au_flags) != uap->length)
695 return (EINVAL);
696 bcopy(kauth_cred_get()->cr_audit.as_aia_p, &aia, sizeof(aia));
697 aia.ai_flags = udata.au_flags;
698 error = audit_session_setaia(p, &aia);
699 if (error)
700 return (error);
701 break;
702
703 default:
704 return (EINVAL);
705 }
706
707 /*
708 * Copy data back to userspace for the GET comands.
709 */
710 switch (uap->cmd) {
711 case A_GETPOLICY:
712 case A_OLDGETPOLICY:
713 case A_GETKMASK:
714 case A_GETQCTRL:
715 case A_OLDGETQCTRL:
716 case A_GETCWD:
717 case A_GETCAR:
718 case A_GETSTAT:
719 case A_GETCOND:
720 case A_OLDGETCOND:
721 case A_GETCLASS:
722 case A_GETPINFO:
723 case A_GETFSIZE:
724 case A_GETPINFO_ADDR:
725 case A_GETKAUDIT:
726 case A_GETSINFO_ADDR:
727 case A_GETSFLAGS:
728 error = copyout((void *)&udata, uap->data, uap->length);
729 if (error)
730 return (ENOSYS);
731 break;
732 }
733
734 return (0);
735 }
736
737 /*
738 * System calls to manage the user audit information.
739 */
740 /* ARGSUSED */
741 int
742 getauid(proc_t p, struct getauid_args *uap, __unused int32_t *retval)
743 {
744 au_id_t id;
745 int error;
746 kauth_cred_t scred;
747
748 #if CONFIG_MACF
749 error = mac_proc_check_getauid(p);
750 if (error)
751 return (error);
752 #endif
753 scred = kauth_cred_proc_ref(p);
754 id = scred->cr_audit.as_aia_p->ai_auid;
755 kauth_cred_unref(&scred);
756
757 error = copyout((void *)&id, uap->auid, sizeof(id));
758 if (error)
759 return (error);
760
761 return (0);
762 }
763
764 /* ARGSUSED */
765 int
766 setauid(proc_t p, struct setauid_args *uap, __unused int32_t *retval)
767 {
768 int error;
769 au_id_t id;
770 kauth_cred_t scred;
771 struct auditinfo_addr aia;
772
773 error = copyin(uap->auid, &id, sizeof(id));
774 if (error)
775 return (error);
776 AUDIT_ARG(auid, id);
777
778 #if CONFIG_MACF
779 error = mac_proc_check_setauid(p, id);
780 if (error)
781 return (error);
782 #endif
783
784 scred = kauth_cred_proc_ref(p);
785 error = suser(scred, &p->p_acflag);
786 if (error) {
787 kauth_cred_unref(&scred);
788 return (error);
789 }
790
791 bcopy(scred->cr_audit.as_aia_p, &aia, sizeof(aia));
792 if (aia.ai_asid == AU_DEFAUDITSID) {
793 aia.ai_asid = AU_ASSIGN_ASID;
794 }
795 bcopy(&scred->cr_audit.as_mask, &aia.ai_mask, sizeof(au_mask_t));
796 kauth_cred_unref(&scred);
797 aia.ai_auid = id;
798 error = audit_session_setaia(p, &aia);
799
800 return (error);
801 }
802
803 static int
804 getaudit_addr_internal(proc_t p, user_addr_t user_addr, size_t length)
805 {
806 kauth_cred_t scred;
807 auditinfo_addr_t aia;
808
809 scred = kauth_cred_proc_ref(p);
810 bcopy(scred->cr_audit.as_aia_p, &aia, sizeof (auditinfo_addr_t));
811 /*
812 * Only superuser gets to see the real mask.
813 */
814 if (suser(scred, &p->p_acflag)) {
815 aia.ai_mask.am_success = ~0;
816 aia.ai_mask.am_failure = ~0;
817 }
818 kauth_cred_unref(&scred);
819
820 return (copyout(&aia, user_addr, min(sizeof(aia), length)));
821 }
822
823 /* ARGSUSED */
824 int
825 getaudit_addr(proc_t p, struct getaudit_addr_args *uap,
826 __unused int32_t *retval)
827 {
828
829 WARN_IF_AINFO_ADDR_CHANGED(uap->length, sizeof(auditinfo_addr_t),
830 "getaudit_addr(2)", "auditinfo_addr_t");
831
832 return (getaudit_addr_internal(p, uap->auditinfo_addr, uap->length));
833 }
834
835 /* ARGSUSED */
836 int
837 setaudit_addr(proc_t p, struct setaudit_addr_args *uap,
838 __unused int32_t *retval)
839 {
840 struct auditinfo_addr aia;
841 kauth_cred_t scred;
842 int error;
843
844 bzero(&aia, sizeof(auditinfo_addr_t));
845 error = copyin(uap->auditinfo_addr, &aia,
846 min(sizeof(aia), uap->length));
847 if (error)
848 return (error);
849 AUDIT_ARG(auditinfo_addr, &aia);
850 if (aia.ai_termid.at_type != AU_IPv6 &&
851 aia.ai_termid.at_type != AU_IPv4)
852 return (EINVAL);
853 if (aia.ai_asid != AU_ASSIGN_ASID &&
854 (uint32_t)aia.ai_asid > ASSIGNED_ASID_MAX)
855 return (EINVAL);
856
857 #if CONFIG_MACF
858 error = mac_proc_check_setaudit(p, &aia);
859 if (error)
860 return (error);
861 #endif
862
863 scred = kauth_cred_proc_ref(p);
864 error = suser(scred, &p->p_acflag);
865 if (error) {
866 kauth_cred_unref(&scred);
867 return (error);
868 }
869
870 WARN_IF_AINFO_ADDR_CHANGED(uap->length, sizeof(auditinfo_addr_t),
871 "setaudit_addr(2)", "auditinfo_addr_t");
872 WARN_IF_BAD_ASID(aia.ai_asid, "setaudit_addr(2)");
873 kauth_cred_unref(&scred);
874
875 AUDIT_CHECK_IF_KEVENTS_MASK(aia.ai_mask);
876 if (aia.ai_asid == AU_DEFAUDITSID)
877 aia.ai_asid = AU_ASSIGN_ASID;
878
879 error = audit_session_setaia(p, &aia);
880 if (error)
881 return (error);
882
883 /*
884 * If asked to assign an ASID then let the user know what the ASID is
885 * by copying the auditinfo_addr struct back out.
886 */
887 if (aia.ai_asid == AU_ASSIGN_ASID)
888 error = getaudit_addr_internal(p, uap->auditinfo_addr,
889 uap->length);
890
891 return (error);
892 }
893
894 /*
895 * Syscall to manage audit files.
896 *
897 */
898 /* ARGSUSED */
899 int
900 auditctl(proc_t p, struct auditctl_args *uap, __unused int32_t *retval)
901 {
902 struct nameidata nd;
903 kauth_cred_t cred;
904 struct vnode *vp;
905 int error = 0;
906
907 error = suser(kauth_cred_get(), &p->p_acflag);
908 if (error)
909 return (error);
910
911 vp = NULL;
912 cred = NULL;
913
914 /*
915 * If a path is specified, open the replacement vnode, perform
916 * validity checks, and grab another reference to the current
917 * credential.
918 *
919 * XXX Changes API slightly. NULL path no longer disables audit but
920 * returns EINVAL.
921 */
922 if (uap->path == USER_ADDR_NULL)
923 return (EINVAL);
924
925 NDINIT(&nd, LOOKUP, OP_OPEN, FOLLOW | LOCKLEAF | AUDITVNPATH1,
926 (IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 :
927 UIO_USERSPACE32), uap->path, vfs_context_current());
928 error = vn_open(&nd, AUDIT_OPEN_FLAGS, 0);
929 if (error)
930 return (error);
931 vp = nd.ni_vp;
932 #if CONFIG_MACF
933 /*
934 * Accessibility of the vnode was determined in vn_open; the
935 * mac_system_check_auditctl should only determine whether that vnode
936 * is appropriate for storing audit data, or that the caller was
937 * permitted to control the auditing system at all. For example, a
938 * confidentiality policy may want to ensure that audit files are
939 * always high sensitivity.
940 */
941 error = mac_system_check_auditctl(kauth_cred_get(), vp);
942 if (error) {
943 vn_close(vp, AUDIT_CLOSE_FLAGS, vfs_context_current());
944 vnode_put(vp);
945 return (error);
946 }
947 #endif
948 if (vp->v_type != VREG) {
949 vn_close(vp, AUDIT_CLOSE_FLAGS, vfs_context_current());
950 vnode_put(vp);
951 return (EINVAL);
952 }
953 mtx_lock(&audit_mtx);
954 /*
955 * XXXAUDIT: Should audit_suspended actually be cleared by
956 * audit_worker?
957 */
958 audit_suspended = 0;
959 mtx_unlock(&audit_mtx);
960
961 /*
962 * The following gets unreferenced in audit_rotate_vnode()
963 * after the rotation and it is no longer needed.
964 */
965 cred = kauth_cred_get_with_ref();
966 audit_rotate_vnode(cred, vp);
967 vnode_put(vp);
968
969 return (error);
970 }
971
972 #else /* !CONFIG_AUDIT */
973
974 int
975 audit(proc_t p, struct audit_args *uap, int32_t *retval)
976 {
977 #pragma unused(p, uap, retval)
978
979 return (ENOSYS);
980 }
981
982 int
983 auditon(proc_t p, struct auditon_args *uap, int32_t *retval)
984 {
985 #pragma unused(p, uap, retval)
986
987 return (ENOSYS);
988 }
989
990 int
991 getauid(proc_t p, struct getauid_args *uap, int32_t *retval)
992 {
993 #pragma unused(p, uap, retval)
994
995 return (ENOSYS);
996 }
997
998 int
999 setauid(proc_t p, struct setauid_args *uap, int32_t *retval)
1000 {
1001 #pragma unused(p, uap, retval)
1002
1003 return (ENOSYS);
1004 }
1005
1006 int
1007 getaudit_addr(proc_t p, struct getaudit_addr_args *uap, int32_t *retval)
1008 {
1009 #pragma unused(p, uap, retval)
1010
1011 return (ENOSYS);
1012 }
1013
1014 int
1015 setaudit_addr(proc_t p, struct setaudit_addr_args *uap, int32_t *retval)
1016 {
1017 #pragma unused(p, uap, retval)
1018
1019 return (ENOSYS);
1020 }
1021
1022 int
1023 auditctl(proc_t p, struct auditctl_args *uap, int32_t *retval)
1024 {
1025 #pragma unused(p, uap, retval)
1026
1027 return (ENOSYS);
1028 }
1029
1030 #endif /* CONFIG_AUDIT */