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