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