Deleted Added
full compact
audit_syscalls.c (225617) audit_syscalls.c (241896)
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#include <sys/cdefs.h>
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#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: head/sys/security/audit/audit_syscalls.c 225617 2011-09-16 13:58:51Z kmacy $");
31__FBSDID("$FreeBSD: head/sys/security/audit/audit_syscalls.c 241896 2012-10-22 17:50:54Z kib $");
32
33#include <sys/param.h>
34#include <sys/mount.h>
35#include <sys/namei.h>
36#include <sys/priv.h>
37#include <sys/proc.h>
38#include <sys/sysproto.h>
39#include <sys/systm.h>
40#include <sys/vnode.h>
41#include <sys/jail.h>
42
43#include <bsm/audit.h>
44#include <bsm/audit_kevents.h>
45
46#include <security/audit/audit.h>
47#include <security/audit/audit_private.h>
48#include <security/mac/mac_framework.h>
49
50#ifdef AUDIT
51
52/*
53 * System call to allow a user space application to submit a BSM audit record
54 * to the kernel for inclusion in the audit log. This function does little
55 * verification on the audit record that is submitted.
56 *
57 * XXXAUDIT: Audit preselection for user records does not currently work,
58 * since we pre-select only based on the AUE_audit event type, not the event
59 * type submitted as part of the user audit data.
60 */
61/* ARGSUSED */
62int
63sys_audit(struct thread *td, struct audit_args *uap)
64{
65 int error;
66 void * rec;
67 struct kaudit_record *ar;
68
69 if (jailed(td->td_ucred))
70 return (ENOSYS);
71 error = priv_check(td, PRIV_AUDIT_SUBMIT);
72 if (error)
73 return (error);
74
75 if ((uap->length <= 0) || (uap->length > audit_qctrl.aq_bufsz))
76 return (EINVAL);
77
78 ar = currecord();
79
80 /*
81 * If there's no current audit record (audit() itself not audited)
82 * commit the user audit record.
83 */
84 if (ar == NULL) {
85
86 /*
87 * This is not very efficient; we're required to allocate a
88 * complete kernel audit record just so the user record can
89 * tag along.
90 *
91 * XXXAUDIT: Maybe AUE_AUDIT in the system call context and
92 * special pre-select handling?
93 */
94 td->td_ar = audit_new(AUE_NULL, td);
95 if (td->td_ar == NULL)
96 return (ENOTSUP);
97 td->td_pflags |= TDP_AUDITREC;
98 ar = td->td_ar;
99 }
100
101 if (uap->length > MAX_AUDIT_RECORD_SIZE)
102 return (EINVAL);
103
104 rec = malloc(uap->length, M_AUDITDATA, M_WAITOK);
105
106 error = copyin(uap->record, rec, uap->length);
107 if (error)
108 goto free_out;
109
110 /* Verify the record. */
111 if (bsm_rec_verify(rec) == 0) {
112 error = EINVAL;
113 goto free_out;
114 }
115
116#ifdef MAC
117 error = mac_system_check_audit(td->td_ucred, rec, uap->length);
118 if (error)
119 goto free_out;
120#endif
121
122 /*
123 * Attach the user audit record to the kernel audit record. Because
124 * this system call is an auditable event, we will write the user
125 * record along with the record for this audit event.
126 *
127 * XXXAUDIT: KASSERT appropriate starting values of k_udata, k_ulen,
128 * k_ar_commit & AR_COMMIT_USER?
129 */
130 ar->k_udata = rec;
131 ar->k_ulen = uap->length;
132 ar->k_ar_commit |= AR_COMMIT_USER;
133
134 /*
135 * Currently we assume that all preselection has been performed in
136 * userspace. We unconditionally set these masks so that the records
137 * get committed both to the trail and pipe. In the future we will
138 * want to setup kernel based preselection.
139 */
140 ar->k_ar_commit |= (AR_PRESELECT_USER_TRAIL | AR_PRESELECT_USER_PIPE);
141 return (0);
142
143free_out:
144 /*
145 * audit_syscall_exit() will free the audit record on the thread even
146 * if we allocated it above.
147 */
148 free(rec, M_AUDITDATA);
149 return (error);
150}
151
152/*
153 * System call to manipulate auditing.
154 */
155/* ARGSUSED */
156int
157sys_auditon(struct thread *td, struct auditon_args *uap)
158{
159 struct ucred *cred, *newcred, *oldcred;
160 int error;
161 union auditon_udata udata;
162 struct proc *tp;
163
164 if (jailed(td->td_ucred))
165 return (ENOSYS);
166 AUDIT_ARG_CMD(uap->cmd);
167
168#ifdef MAC
169 error = mac_system_check_auditon(td->td_ucred, uap->cmd);
170 if (error)
171 return (error);
172#endif
173
174 error = priv_check(td, PRIV_AUDIT_CONTROL);
175 if (error)
176 return (error);
177
178 if ((uap->length <= 0) || (uap->length > sizeof(union auditon_udata)))
179 return (EINVAL);
180
181 memset((void *)&udata, 0, sizeof(udata));
182
183 /*
184 * Some of the GET commands use the arguments too.
185 */
186 switch (uap->cmd) {
187 case A_SETPOLICY:
188 case A_OLDSETPOLICY:
189 case A_SETKMASK:
190 case A_SETQCTRL:
191 case A_OLDSETQCTRL:
192 case A_SETSTAT:
193 case A_SETUMASK:
194 case A_SETSMASK:
195 case A_SETCOND:
196 case A_OLDSETCOND:
197 case A_SETCLASS:
198 case A_SETPMASK:
199 case A_SETFSIZE:
200 case A_SETKAUDIT:
201 case A_GETCLASS:
202 case A_GETPINFO:
203 case A_GETPINFO_ADDR:
204 case A_SENDTRIGGER:
205 error = copyin(uap->data, (void *)&udata, uap->length);
206 if (error)
207 return (error);
208 AUDIT_ARG_AUDITON(&udata);
209 break;
210 }
211
212 /*
213 * XXXAUDIT: Locking?
214 */
215 switch (uap->cmd) {
216 case A_OLDGETPOLICY:
217 case A_GETPOLICY:
218 if (uap->length == sizeof(udata.au_policy64)) {
219 if (!audit_fail_stop)
220 udata.au_policy64 |= AUDIT_CNT;
221 if (audit_panic_on_write_fail)
222 udata.au_policy64 |= AUDIT_AHLT;
223 if (audit_argv)
224 udata.au_policy64 |= AUDIT_ARGV;
225 if (audit_arge)
226 udata.au_policy64 |= AUDIT_ARGE;
227 break;
228 }
229 if (uap->length != sizeof(udata.au_policy))
230 return (EINVAL);
231 if (!audit_fail_stop)
232 udata.au_policy |= AUDIT_CNT;
233 if (audit_panic_on_write_fail)
234 udata.au_policy |= AUDIT_AHLT;
235 if (audit_argv)
236 udata.au_policy |= AUDIT_ARGV;
237 if (audit_arge)
238 udata.au_policy |= AUDIT_ARGE;
239 break;
240
241 case A_OLDSETPOLICY:
242 case A_SETPOLICY:
243 if (uap->length == sizeof(udata.au_policy64)) {
244 if (udata.au_policy & (~AUDIT_CNT|AUDIT_AHLT|
245 AUDIT_ARGV|AUDIT_ARGE))
246 return (EINVAL);
247 audit_fail_stop = ((udata.au_policy64 & AUDIT_CNT) ==
248 0);
249 audit_panic_on_write_fail = (udata.au_policy64 &
250 AUDIT_AHLT);
251 audit_argv = (udata.au_policy64 & AUDIT_ARGV);
252 audit_arge = (udata.au_policy64 & AUDIT_ARGE);
253 break;
254 }
255 if (uap->length != sizeof(udata.au_policy))
256 return (EINVAL);
257 if (udata.au_policy & ~(AUDIT_CNT|AUDIT_AHLT|AUDIT_ARGV|
258 AUDIT_ARGE))
259 return (EINVAL);
260 /*
261 * XXX - Need to wake up waiters if the policy relaxes?
262 */
263 audit_fail_stop = ((udata.au_policy & AUDIT_CNT) == 0);
264 audit_panic_on_write_fail = (udata.au_policy & AUDIT_AHLT);
265 audit_argv = (udata.au_policy & AUDIT_ARGV);
266 audit_arge = (udata.au_policy & AUDIT_ARGE);
267 break;
268
269 case A_GETKMASK:
270 if (uap->length != sizeof(udata.au_mask))
271 return (EINVAL);
272 udata.au_mask = audit_nae_mask;
273 break;
274
275 case A_SETKMASK:
276 if (uap->length != sizeof(udata.au_mask))
277 return (EINVAL);
278 audit_nae_mask = udata.au_mask;
279 break;
280
281 case A_OLDGETQCTRL:
282 case A_GETQCTRL:
283 if (uap->length == sizeof(udata.au_qctrl64)) {
284 udata.au_qctrl64.aq64_hiwater =
285 (u_int64_t)audit_qctrl.aq_hiwater;
286 udata.au_qctrl64.aq64_lowater =
287 (u_int64_t)audit_qctrl.aq_lowater;
288 udata.au_qctrl64.aq64_bufsz =
289 (u_int64_t)audit_qctrl.aq_bufsz;
290 udata.au_qctrl64.aq64_minfree =
291 (u_int64_t)audit_qctrl.aq_minfree;
292 break;
293 }
294 if (uap->length != sizeof(udata.au_qctrl))
295 return (EINVAL);
296 udata.au_qctrl = audit_qctrl;
297 break;
298
299 case A_OLDSETQCTRL:
300 case A_SETQCTRL:
301 if (uap->length == sizeof(udata.au_qctrl64)) {
302 if ((udata.au_qctrl64.aq64_hiwater > AQ_MAXHIGH) ||
303 (udata.au_qctrl64.aq64_lowater >=
304 udata.au_qctrl.aq_hiwater) ||
305 (udata.au_qctrl64.aq64_bufsz > AQ_MAXBUFSZ) ||
306 (udata.au_qctrl64.aq64_minfree < 0) ||
307 (udata.au_qctrl64.aq64_minfree > 100))
308 return (EINVAL);
309 audit_qctrl.aq_hiwater =
310 (int)udata.au_qctrl64.aq64_hiwater;
311 audit_qctrl.aq_lowater =
312 (int)udata.au_qctrl64.aq64_lowater;
313 audit_qctrl.aq_bufsz =
314 (int)udata.au_qctrl64.aq64_bufsz;
315 audit_qctrl.aq_minfree =
316 (int)udata.au_qctrl64.aq64_minfree;
317 audit_qctrl.aq_delay = -1; /* Not used. */
318 break;
319 }
320 if (uap->length != sizeof(udata.au_qctrl))
321 return (EINVAL);
322 if ((udata.au_qctrl.aq_hiwater > AQ_MAXHIGH) ||
323 (udata.au_qctrl.aq_lowater >= udata.au_qctrl.aq_hiwater) ||
324 (udata.au_qctrl.aq_bufsz > AQ_MAXBUFSZ) ||
325 (udata.au_qctrl.aq_minfree < 0) ||
326 (udata.au_qctrl.aq_minfree > 100))
327 return (EINVAL);
328
329 audit_qctrl = udata.au_qctrl;
330 /* XXX The queue delay value isn't used with the kernel. */
331 audit_qctrl.aq_delay = -1;
332 break;
333
334 case A_GETCWD:
335 return (ENOSYS);
336 break;
337
338 case A_GETCAR:
339 return (ENOSYS);
340 break;
341
342 case A_GETSTAT:
343 return (ENOSYS);
344 break;
345
346 case A_SETSTAT:
347 return (ENOSYS);
348 break;
349
350 case A_SETUMASK:
351 return (ENOSYS);
352 break;
353
354 case A_SETSMASK:
355 return (ENOSYS);
356 break;
357
358 case A_OLDGETCOND:
359 case A_GETCOND:
360 if (uap->length == sizeof(udata.au_cond64)) {
361 if (audit_enabled && !audit_suspended)
362 udata.au_cond64 = AUC_AUDITING;
363 else
364 udata.au_cond64 = AUC_NOAUDIT;
365 break;
366 }
367 if (uap->length != sizeof(udata.au_cond))
368 return (EINVAL);
369 if (audit_enabled && !audit_suspended)
370 udata.au_cond = AUC_AUDITING;
371 else
372 udata.au_cond = AUC_NOAUDIT;
373 break;
374
375 case A_OLDSETCOND:
376 case A_SETCOND:
377 if (uap->length == sizeof(udata.au_cond64)) {
378 if (udata.au_cond64 == AUC_NOAUDIT)
379 audit_suspended = 1;
380 if (udata.au_cond64 == AUC_AUDITING)
381 audit_suspended = 0;
382 if (udata.au_cond64 == AUC_DISABLED) {
383 audit_suspended = 1;
384 audit_shutdown(NULL, 0);
385 }
386 break;
387 }
388 if (uap->length != sizeof(udata.au_cond))
389 return (EINVAL);
390 if (udata.au_cond == AUC_NOAUDIT)
391 audit_suspended = 1;
392 if (udata.au_cond == AUC_AUDITING)
393 audit_suspended = 0;
394 if (udata.au_cond == AUC_DISABLED) {
395 audit_suspended = 1;
396 audit_shutdown(NULL, 0);
397 }
398 break;
399
400 case A_GETCLASS:
401 if (uap->length != sizeof(udata.au_evclass))
402 return (EINVAL);
403 udata.au_evclass.ec_class = au_event_class(
404 udata.au_evclass.ec_number);
405 break;
406
407 case A_SETCLASS:
408 if (uap->length != sizeof(udata.au_evclass))
409 return (EINVAL);
410 au_evclassmap_insert(udata.au_evclass.ec_number,
411 udata.au_evclass.ec_class);
412 break;
413
414 case A_GETPINFO:
415 if (uap->length != sizeof(udata.au_aupinfo))
416 return (EINVAL);
417 if (udata.au_aupinfo.ap_pid < 1)
418 return (ESRCH);
419 if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL)
420 return (ESRCH);
421 if ((error = p_cansee(td, tp)) != 0) {
422 PROC_UNLOCK(tp);
423 return (error);
424 }
425 cred = tp->p_ucred;
426 if (cred->cr_audit.ai_termid.at_type == AU_IPv6) {
427 PROC_UNLOCK(tp);
428 return (EINVAL);
429 }
430 udata.au_aupinfo.ap_auid = cred->cr_audit.ai_auid;
431 udata.au_aupinfo.ap_mask.am_success =
432 cred->cr_audit.ai_mask.am_success;
433 udata.au_aupinfo.ap_mask.am_failure =
434 cred->cr_audit.ai_mask.am_failure;
435 udata.au_aupinfo.ap_termid.machine =
436 cred->cr_audit.ai_termid.at_addr[0];
437 udata.au_aupinfo.ap_termid.port =
438 (dev_t)cred->cr_audit.ai_termid.at_port;
439 udata.au_aupinfo.ap_asid = cred->cr_audit.ai_asid;
440 PROC_UNLOCK(tp);
441 break;
442
443 case A_SETPMASK:
444 if (uap->length != sizeof(udata.au_aupinfo))
445 return (EINVAL);
446 if (udata.au_aupinfo.ap_pid < 1)
447 return (ESRCH);
448 newcred = crget();
449 if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL) {
450 crfree(newcred);
451 return (ESRCH);
452 }
453 if ((error = p_cansee(td, tp)) != 0) {
454 PROC_UNLOCK(tp);
455 crfree(newcred);
456 return (error);
457 }
458 oldcred = tp->p_ucred;
459 crcopy(newcred, oldcred);
460 newcred->cr_audit.ai_mask.am_success =
461 udata.au_aupinfo.ap_mask.am_success;
462 newcred->cr_audit.ai_mask.am_failure =
463 udata.au_aupinfo.ap_mask.am_failure;
464 td->td_proc->p_ucred = newcred;
465 PROC_UNLOCK(tp);
466 crfree(oldcred);
467 break;
468
469 case A_SETFSIZE:
470 if (uap->length != sizeof(udata.au_fstat))
471 return (EINVAL);
472 if ((udata.au_fstat.af_filesz != 0) &&
473 (udata.au_fstat.af_filesz < MIN_AUDIT_FILE_SIZE))
474 return (EINVAL);
475 audit_fstat.af_filesz = udata.au_fstat.af_filesz;
476 break;
477
478 case A_GETFSIZE:
479 if (uap->length != sizeof(udata.au_fstat))
480 return (EINVAL);
481 udata.au_fstat.af_filesz = audit_fstat.af_filesz;
482 udata.au_fstat.af_currsz = audit_fstat.af_currsz;
483 break;
484
485 case A_GETPINFO_ADDR:
486 if (uap->length != sizeof(udata.au_aupinfo_addr))
487 return (EINVAL);
488 if (udata.au_aupinfo_addr.ap_pid < 1)
489 return (ESRCH);
490 if ((tp = pfind(udata.au_aupinfo_addr.ap_pid)) == NULL)
491 return (ESRCH);
492 cred = tp->p_ucred;
493 udata.au_aupinfo_addr.ap_auid = cred->cr_audit.ai_auid;
494 udata.au_aupinfo_addr.ap_mask.am_success =
495 cred->cr_audit.ai_mask.am_success;
496 udata.au_aupinfo_addr.ap_mask.am_failure =
497 cred->cr_audit.ai_mask.am_failure;
498 udata.au_aupinfo_addr.ap_termid = cred->cr_audit.ai_termid;
499 udata.au_aupinfo_addr.ap_asid = cred->cr_audit.ai_asid;
500 PROC_UNLOCK(tp);
501 break;
502
503 case A_GETKAUDIT:
504 if (uap->length != sizeof(udata.au_kau_info))
505 return (EINVAL);
506 audit_get_kinfo(&udata.au_kau_info);
507 break;
508
509 case A_SETKAUDIT:
510 if (uap->length != sizeof(udata.au_kau_info))
511 return (EINVAL);
512 if (udata.au_kau_info.ai_termid.at_type != AU_IPv4 &&
513 udata.au_kau_info.ai_termid.at_type != AU_IPv6)
514 return (EINVAL);
515 audit_set_kinfo(&udata.au_kau_info);
516 break;
517
518 case A_SENDTRIGGER:
519 if (uap->length != sizeof(udata.au_trigger))
520 return (EINVAL);
521 if ((udata.au_trigger < AUDIT_TRIGGER_MIN) ||
522 (udata.au_trigger > AUDIT_TRIGGER_MAX))
523 return (EINVAL);
524 return (audit_send_trigger(udata.au_trigger));
525
526 default:
527 return (EINVAL);
528 }
529
530 /*
531 * Copy data back to userspace for the GET comands.
532 */
533 switch (uap->cmd) {
534 case A_GETPOLICY:
535 case A_OLDGETPOLICY:
536 case A_GETKMASK:
537 case A_GETQCTRL:
538 case A_OLDGETQCTRL:
539 case A_GETCWD:
540 case A_GETCAR:
541 case A_GETSTAT:
542 case A_GETCOND:
543 case A_OLDGETCOND:
544 case A_GETCLASS:
545 case A_GETPINFO:
546 case A_GETFSIZE:
547 case A_GETPINFO_ADDR:
548 case A_GETKAUDIT:
549 error = copyout((void *)&udata, uap->data, uap->length);
550 if (error)
551 return (error);
552 break;
553 }
554
555 return (0);
556}
557
558/*
559 * System calls to manage the user audit information.
560 */
561/* ARGSUSED */
562int
563sys_getauid(struct thread *td, struct getauid_args *uap)
564{
565 int error;
566
567 if (jailed(td->td_ucred))
568 return (ENOSYS);
569 error = priv_check(td, PRIV_AUDIT_GETAUDIT);
570 if (error)
571 return (error);
572 return (copyout(&td->td_ucred->cr_audit.ai_auid, uap->auid,
573 sizeof(td->td_ucred->cr_audit.ai_auid)));
574}
575
576/* ARGSUSED */
577int
578sys_setauid(struct thread *td, struct setauid_args *uap)
579{
580 struct ucred *newcred, *oldcred;
581 au_id_t id;
582 int error;
583
584 if (jailed(td->td_ucred))
585 return (ENOSYS);
586 error = copyin(uap->auid, &id, sizeof(id));
587 if (error)
588 return (error);
589 audit_arg_auid(id);
590 newcred = crget();
591 PROC_LOCK(td->td_proc);
592 oldcred = td->td_proc->p_ucred;
593 crcopy(newcred, oldcred);
594#ifdef MAC
595 error = mac_cred_check_setauid(oldcred, id);
596 if (error)
597 goto fail;
598#endif
599 error = priv_check_cred(oldcred, PRIV_AUDIT_SETAUDIT, 0);
600 if (error)
601 goto fail;
602 newcred->cr_audit.ai_auid = id;
603 td->td_proc->p_ucred = newcred;
604 PROC_UNLOCK(td->td_proc);
605 crfree(oldcred);
606 return (0);
607fail:
608 PROC_UNLOCK(td->td_proc);
609 crfree(newcred);
610 return (error);
611}
612
613/*
614 * System calls to get and set process audit information.
615 */
616/* ARGSUSED */
617int
618sys_getaudit(struct thread *td, struct getaudit_args *uap)
619{
620 struct auditinfo ai;
621 struct ucred *cred;
622 int error;
623
624 cred = td->td_ucred;
625 if (jailed(cred))
626 return (ENOSYS);
627 error = priv_check(td, PRIV_AUDIT_GETAUDIT);
628 if (error)
629 return (error);
630 if (cred->cr_audit.ai_termid.at_type == AU_IPv6)
631 return (E2BIG);
632 bzero(&ai, sizeof(ai));
633 ai.ai_auid = cred->cr_audit.ai_auid;
634 ai.ai_mask = cred->cr_audit.ai_mask;
635 ai.ai_asid = cred->cr_audit.ai_asid;
636 ai.ai_termid.machine = cred->cr_audit.ai_termid.at_addr[0];
637 ai.ai_termid.port = cred->cr_audit.ai_termid.at_port;
638 return (copyout(&ai, uap->auditinfo, sizeof(ai)));
639}
640
641/* ARGSUSED */
642int
643sys_setaudit(struct thread *td, struct setaudit_args *uap)
644{
645 struct ucred *newcred, *oldcred;
646 struct auditinfo ai;
647 int error;
648
649 if (jailed(td->td_ucred))
650 return (ENOSYS);
651 error = copyin(uap->auditinfo, &ai, sizeof(ai));
652 if (error)
653 return (error);
654 audit_arg_auditinfo(&ai);
655 newcred = crget();
656 PROC_LOCK(td->td_proc);
657 oldcred = td->td_proc->p_ucred;
658 crcopy(newcred, oldcred);
659#ifdef MAC
660 error = mac_cred_check_setaudit(oldcred, &ai);
661 if (error)
662 goto fail;
663#endif
664 error = priv_check_cred(oldcred, PRIV_AUDIT_SETAUDIT, 0);
665 if (error)
666 goto fail;
667 bzero(&newcred->cr_audit, sizeof(newcred->cr_audit));
668 newcred->cr_audit.ai_auid = ai.ai_auid;
669 newcred->cr_audit.ai_mask = ai.ai_mask;
670 newcred->cr_audit.ai_asid = ai.ai_asid;
671 newcred->cr_audit.ai_termid.at_addr[0] = ai.ai_termid.machine;
672 newcred->cr_audit.ai_termid.at_port = ai.ai_termid.port;
673 newcred->cr_audit.ai_termid.at_type = AU_IPv4;
674 td->td_proc->p_ucred = newcred;
675 PROC_UNLOCK(td->td_proc);
676 crfree(oldcred);
677 return (0);
678fail:
679 PROC_UNLOCK(td->td_proc);
680 crfree(newcred);
681 return (error);
682}
683
684/* ARGSUSED */
685int
686sys_getaudit_addr(struct thread *td, struct getaudit_addr_args *uap)
687{
688 int error;
689
690 if (jailed(td->td_ucred))
691 return (ENOSYS);
692 if (uap->length < sizeof(*uap->auditinfo_addr))
693 return (EOVERFLOW);
694 error = priv_check(td, PRIV_AUDIT_GETAUDIT);
695 if (error)
696 return (error);
697 return (copyout(&td->td_ucred->cr_audit, uap->auditinfo_addr,
698 sizeof(*uap->auditinfo_addr)));
699}
700
701/* ARGSUSED */
702int
703sys_setaudit_addr(struct thread *td, struct setaudit_addr_args *uap)
704{
705 struct ucred *newcred, *oldcred;
706 struct auditinfo_addr aia;
707 int error;
708
709 if (jailed(td->td_ucred))
710 return (ENOSYS);
711 error = copyin(uap->auditinfo_addr, &aia, sizeof(aia));
712 if (error)
713 return (error);
714 audit_arg_auditinfo_addr(&aia);
715 if (aia.ai_termid.at_type != AU_IPv6 &&
716 aia.ai_termid.at_type != AU_IPv4)
717 return (EINVAL);
718 newcred = crget();
719 PROC_LOCK(td->td_proc);
720 oldcred = td->td_proc->p_ucred;
721 crcopy(newcred, oldcred);
722#ifdef MAC
723 error = mac_cred_check_setaudit_addr(oldcred, &aia);
724 if (error)
725 goto fail;
726#endif
727 error = priv_check_cred(oldcred, PRIV_AUDIT_SETAUDIT, 0);
728 if (error)
729 goto fail;
730 newcred->cr_audit = aia;
731 td->td_proc->p_ucred = newcred;
732 PROC_UNLOCK(td->td_proc);
733 crfree(oldcred);
734 return (0);
735fail:
736 PROC_UNLOCK(td->td_proc);
737 crfree(newcred);
738 return (error);
739}
740
741/*
742 * Syscall to manage audit files.
743 */
744/* ARGSUSED */
745int
746sys_auditctl(struct thread *td, struct auditctl_args *uap)
747{
748 struct nameidata nd;
749 struct ucred *cred;
750 struct vnode *vp;
751 int error = 0;
32
33#include <sys/param.h>
34#include <sys/mount.h>
35#include <sys/namei.h>
36#include <sys/priv.h>
37#include <sys/proc.h>
38#include <sys/sysproto.h>
39#include <sys/systm.h>
40#include <sys/vnode.h>
41#include <sys/jail.h>
42
43#include <bsm/audit.h>
44#include <bsm/audit_kevents.h>
45
46#include <security/audit/audit.h>
47#include <security/audit/audit_private.h>
48#include <security/mac/mac_framework.h>
49
50#ifdef AUDIT
51
52/*
53 * System call to allow a user space application to submit a BSM audit record
54 * to the kernel for inclusion in the audit log. This function does little
55 * verification on the audit record that is submitted.
56 *
57 * XXXAUDIT: Audit preselection for user records does not currently work,
58 * since we pre-select only based on the AUE_audit event type, not the event
59 * type submitted as part of the user audit data.
60 */
61/* ARGSUSED */
62int
63sys_audit(struct thread *td, struct audit_args *uap)
64{
65 int error;
66 void * rec;
67 struct kaudit_record *ar;
68
69 if (jailed(td->td_ucred))
70 return (ENOSYS);
71 error = priv_check(td, PRIV_AUDIT_SUBMIT);
72 if (error)
73 return (error);
74
75 if ((uap->length <= 0) || (uap->length > audit_qctrl.aq_bufsz))
76 return (EINVAL);
77
78 ar = currecord();
79
80 /*
81 * If there's no current audit record (audit() itself not audited)
82 * commit the user audit record.
83 */
84 if (ar == NULL) {
85
86 /*
87 * This is not very efficient; we're required to allocate a
88 * complete kernel audit record just so the user record can
89 * tag along.
90 *
91 * XXXAUDIT: Maybe AUE_AUDIT in the system call context and
92 * special pre-select handling?
93 */
94 td->td_ar = audit_new(AUE_NULL, td);
95 if (td->td_ar == NULL)
96 return (ENOTSUP);
97 td->td_pflags |= TDP_AUDITREC;
98 ar = td->td_ar;
99 }
100
101 if (uap->length > MAX_AUDIT_RECORD_SIZE)
102 return (EINVAL);
103
104 rec = malloc(uap->length, M_AUDITDATA, M_WAITOK);
105
106 error = copyin(uap->record, rec, uap->length);
107 if (error)
108 goto free_out;
109
110 /* Verify the record. */
111 if (bsm_rec_verify(rec) == 0) {
112 error = EINVAL;
113 goto free_out;
114 }
115
116#ifdef MAC
117 error = mac_system_check_audit(td->td_ucred, rec, uap->length);
118 if (error)
119 goto free_out;
120#endif
121
122 /*
123 * Attach the user audit record to the kernel audit record. Because
124 * this system call is an auditable event, we will write the user
125 * record along with the record for this audit event.
126 *
127 * XXXAUDIT: KASSERT appropriate starting values of k_udata, k_ulen,
128 * k_ar_commit & AR_COMMIT_USER?
129 */
130 ar->k_udata = rec;
131 ar->k_ulen = uap->length;
132 ar->k_ar_commit |= AR_COMMIT_USER;
133
134 /*
135 * Currently we assume that all preselection has been performed in
136 * userspace. We unconditionally set these masks so that the records
137 * get committed both to the trail and pipe. In the future we will
138 * want to setup kernel based preselection.
139 */
140 ar->k_ar_commit |= (AR_PRESELECT_USER_TRAIL | AR_PRESELECT_USER_PIPE);
141 return (0);
142
143free_out:
144 /*
145 * audit_syscall_exit() will free the audit record on the thread even
146 * if we allocated it above.
147 */
148 free(rec, M_AUDITDATA);
149 return (error);
150}
151
152/*
153 * System call to manipulate auditing.
154 */
155/* ARGSUSED */
156int
157sys_auditon(struct thread *td, struct auditon_args *uap)
158{
159 struct ucred *cred, *newcred, *oldcred;
160 int error;
161 union auditon_udata udata;
162 struct proc *tp;
163
164 if (jailed(td->td_ucred))
165 return (ENOSYS);
166 AUDIT_ARG_CMD(uap->cmd);
167
168#ifdef MAC
169 error = mac_system_check_auditon(td->td_ucred, uap->cmd);
170 if (error)
171 return (error);
172#endif
173
174 error = priv_check(td, PRIV_AUDIT_CONTROL);
175 if (error)
176 return (error);
177
178 if ((uap->length <= 0) || (uap->length > sizeof(union auditon_udata)))
179 return (EINVAL);
180
181 memset((void *)&udata, 0, sizeof(udata));
182
183 /*
184 * Some of the GET commands use the arguments too.
185 */
186 switch (uap->cmd) {
187 case A_SETPOLICY:
188 case A_OLDSETPOLICY:
189 case A_SETKMASK:
190 case A_SETQCTRL:
191 case A_OLDSETQCTRL:
192 case A_SETSTAT:
193 case A_SETUMASK:
194 case A_SETSMASK:
195 case A_SETCOND:
196 case A_OLDSETCOND:
197 case A_SETCLASS:
198 case A_SETPMASK:
199 case A_SETFSIZE:
200 case A_SETKAUDIT:
201 case A_GETCLASS:
202 case A_GETPINFO:
203 case A_GETPINFO_ADDR:
204 case A_SENDTRIGGER:
205 error = copyin(uap->data, (void *)&udata, uap->length);
206 if (error)
207 return (error);
208 AUDIT_ARG_AUDITON(&udata);
209 break;
210 }
211
212 /*
213 * XXXAUDIT: Locking?
214 */
215 switch (uap->cmd) {
216 case A_OLDGETPOLICY:
217 case A_GETPOLICY:
218 if (uap->length == sizeof(udata.au_policy64)) {
219 if (!audit_fail_stop)
220 udata.au_policy64 |= AUDIT_CNT;
221 if (audit_panic_on_write_fail)
222 udata.au_policy64 |= AUDIT_AHLT;
223 if (audit_argv)
224 udata.au_policy64 |= AUDIT_ARGV;
225 if (audit_arge)
226 udata.au_policy64 |= AUDIT_ARGE;
227 break;
228 }
229 if (uap->length != sizeof(udata.au_policy))
230 return (EINVAL);
231 if (!audit_fail_stop)
232 udata.au_policy |= AUDIT_CNT;
233 if (audit_panic_on_write_fail)
234 udata.au_policy |= AUDIT_AHLT;
235 if (audit_argv)
236 udata.au_policy |= AUDIT_ARGV;
237 if (audit_arge)
238 udata.au_policy |= AUDIT_ARGE;
239 break;
240
241 case A_OLDSETPOLICY:
242 case A_SETPOLICY:
243 if (uap->length == sizeof(udata.au_policy64)) {
244 if (udata.au_policy & (~AUDIT_CNT|AUDIT_AHLT|
245 AUDIT_ARGV|AUDIT_ARGE))
246 return (EINVAL);
247 audit_fail_stop = ((udata.au_policy64 & AUDIT_CNT) ==
248 0);
249 audit_panic_on_write_fail = (udata.au_policy64 &
250 AUDIT_AHLT);
251 audit_argv = (udata.au_policy64 & AUDIT_ARGV);
252 audit_arge = (udata.au_policy64 & AUDIT_ARGE);
253 break;
254 }
255 if (uap->length != sizeof(udata.au_policy))
256 return (EINVAL);
257 if (udata.au_policy & ~(AUDIT_CNT|AUDIT_AHLT|AUDIT_ARGV|
258 AUDIT_ARGE))
259 return (EINVAL);
260 /*
261 * XXX - Need to wake up waiters if the policy relaxes?
262 */
263 audit_fail_stop = ((udata.au_policy & AUDIT_CNT) == 0);
264 audit_panic_on_write_fail = (udata.au_policy & AUDIT_AHLT);
265 audit_argv = (udata.au_policy & AUDIT_ARGV);
266 audit_arge = (udata.au_policy & AUDIT_ARGE);
267 break;
268
269 case A_GETKMASK:
270 if (uap->length != sizeof(udata.au_mask))
271 return (EINVAL);
272 udata.au_mask = audit_nae_mask;
273 break;
274
275 case A_SETKMASK:
276 if (uap->length != sizeof(udata.au_mask))
277 return (EINVAL);
278 audit_nae_mask = udata.au_mask;
279 break;
280
281 case A_OLDGETQCTRL:
282 case A_GETQCTRL:
283 if (uap->length == sizeof(udata.au_qctrl64)) {
284 udata.au_qctrl64.aq64_hiwater =
285 (u_int64_t)audit_qctrl.aq_hiwater;
286 udata.au_qctrl64.aq64_lowater =
287 (u_int64_t)audit_qctrl.aq_lowater;
288 udata.au_qctrl64.aq64_bufsz =
289 (u_int64_t)audit_qctrl.aq_bufsz;
290 udata.au_qctrl64.aq64_minfree =
291 (u_int64_t)audit_qctrl.aq_minfree;
292 break;
293 }
294 if (uap->length != sizeof(udata.au_qctrl))
295 return (EINVAL);
296 udata.au_qctrl = audit_qctrl;
297 break;
298
299 case A_OLDSETQCTRL:
300 case A_SETQCTRL:
301 if (uap->length == sizeof(udata.au_qctrl64)) {
302 if ((udata.au_qctrl64.aq64_hiwater > AQ_MAXHIGH) ||
303 (udata.au_qctrl64.aq64_lowater >=
304 udata.au_qctrl.aq_hiwater) ||
305 (udata.au_qctrl64.aq64_bufsz > AQ_MAXBUFSZ) ||
306 (udata.au_qctrl64.aq64_minfree < 0) ||
307 (udata.au_qctrl64.aq64_minfree > 100))
308 return (EINVAL);
309 audit_qctrl.aq_hiwater =
310 (int)udata.au_qctrl64.aq64_hiwater;
311 audit_qctrl.aq_lowater =
312 (int)udata.au_qctrl64.aq64_lowater;
313 audit_qctrl.aq_bufsz =
314 (int)udata.au_qctrl64.aq64_bufsz;
315 audit_qctrl.aq_minfree =
316 (int)udata.au_qctrl64.aq64_minfree;
317 audit_qctrl.aq_delay = -1; /* Not used. */
318 break;
319 }
320 if (uap->length != sizeof(udata.au_qctrl))
321 return (EINVAL);
322 if ((udata.au_qctrl.aq_hiwater > AQ_MAXHIGH) ||
323 (udata.au_qctrl.aq_lowater >= udata.au_qctrl.aq_hiwater) ||
324 (udata.au_qctrl.aq_bufsz > AQ_MAXBUFSZ) ||
325 (udata.au_qctrl.aq_minfree < 0) ||
326 (udata.au_qctrl.aq_minfree > 100))
327 return (EINVAL);
328
329 audit_qctrl = udata.au_qctrl;
330 /* XXX The queue delay value isn't used with the kernel. */
331 audit_qctrl.aq_delay = -1;
332 break;
333
334 case A_GETCWD:
335 return (ENOSYS);
336 break;
337
338 case A_GETCAR:
339 return (ENOSYS);
340 break;
341
342 case A_GETSTAT:
343 return (ENOSYS);
344 break;
345
346 case A_SETSTAT:
347 return (ENOSYS);
348 break;
349
350 case A_SETUMASK:
351 return (ENOSYS);
352 break;
353
354 case A_SETSMASK:
355 return (ENOSYS);
356 break;
357
358 case A_OLDGETCOND:
359 case A_GETCOND:
360 if (uap->length == sizeof(udata.au_cond64)) {
361 if (audit_enabled && !audit_suspended)
362 udata.au_cond64 = AUC_AUDITING;
363 else
364 udata.au_cond64 = AUC_NOAUDIT;
365 break;
366 }
367 if (uap->length != sizeof(udata.au_cond))
368 return (EINVAL);
369 if (audit_enabled && !audit_suspended)
370 udata.au_cond = AUC_AUDITING;
371 else
372 udata.au_cond = AUC_NOAUDIT;
373 break;
374
375 case A_OLDSETCOND:
376 case A_SETCOND:
377 if (uap->length == sizeof(udata.au_cond64)) {
378 if (udata.au_cond64 == AUC_NOAUDIT)
379 audit_suspended = 1;
380 if (udata.au_cond64 == AUC_AUDITING)
381 audit_suspended = 0;
382 if (udata.au_cond64 == AUC_DISABLED) {
383 audit_suspended = 1;
384 audit_shutdown(NULL, 0);
385 }
386 break;
387 }
388 if (uap->length != sizeof(udata.au_cond))
389 return (EINVAL);
390 if (udata.au_cond == AUC_NOAUDIT)
391 audit_suspended = 1;
392 if (udata.au_cond == AUC_AUDITING)
393 audit_suspended = 0;
394 if (udata.au_cond == AUC_DISABLED) {
395 audit_suspended = 1;
396 audit_shutdown(NULL, 0);
397 }
398 break;
399
400 case A_GETCLASS:
401 if (uap->length != sizeof(udata.au_evclass))
402 return (EINVAL);
403 udata.au_evclass.ec_class = au_event_class(
404 udata.au_evclass.ec_number);
405 break;
406
407 case A_SETCLASS:
408 if (uap->length != sizeof(udata.au_evclass))
409 return (EINVAL);
410 au_evclassmap_insert(udata.au_evclass.ec_number,
411 udata.au_evclass.ec_class);
412 break;
413
414 case A_GETPINFO:
415 if (uap->length != sizeof(udata.au_aupinfo))
416 return (EINVAL);
417 if (udata.au_aupinfo.ap_pid < 1)
418 return (ESRCH);
419 if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL)
420 return (ESRCH);
421 if ((error = p_cansee(td, tp)) != 0) {
422 PROC_UNLOCK(tp);
423 return (error);
424 }
425 cred = tp->p_ucred;
426 if (cred->cr_audit.ai_termid.at_type == AU_IPv6) {
427 PROC_UNLOCK(tp);
428 return (EINVAL);
429 }
430 udata.au_aupinfo.ap_auid = cred->cr_audit.ai_auid;
431 udata.au_aupinfo.ap_mask.am_success =
432 cred->cr_audit.ai_mask.am_success;
433 udata.au_aupinfo.ap_mask.am_failure =
434 cred->cr_audit.ai_mask.am_failure;
435 udata.au_aupinfo.ap_termid.machine =
436 cred->cr_audit.ai_termid.at_addr[0];
437 udata.au_aupinfo.ap_termid.port =
438 (dev_t)cred->cr_audit.ai_termid.at_port;
439 udata.au_aupinfo.ap_asid = cred->cr_audit.ai_asid;
440 PROC_UNLOCK(tp);
441 break;
442
443 case A_SETPMASK:
444 if (uap->length != sizeof(udata.au_aupinfo))
445 return (EINVAL);
446 if (udata.au_aupinfo.ap_pid < 1)
447 return (ESRCH);
448 newcred = crget();
449 if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL) {
450 crfree(newcred);
451 return (ESRCH);
452 }
453 if ((error = p_cansee(td, tp)) != 0) {
454 PROC_UNLOCK(tp);
455 crfree(newcred);
456 return (error);
457 }
458 oldcred = tp->p_ucred;
459 crcopy(newcred, oldcred);
460 newcred->cr_audit.ai_mask.am_success =
461 udata.au_aupinfo.ap_mask.am_success;
462 newcred->cr_audit.ai_mask.am_failure =
463 udata.au_aupinfo.ap_mask.am_failure;
464 td->td_proc->p_ucred = newcred;
465 PROC_UNLOCK(tp);
466 crfree(oldcred);
467 break;
468
469 case A_SETFSIZE:
470 if (uap->length != sizeof(udata.au_fstat))
471 return (EINVAL);
472 if ((udata.au_fstat.af_filesz != 0) &&
473 (udata.au_fstat.af_filesz < MIN_AUDIT_FILE_SIZE))
474 return (EINVAL);
475 audit_fstat.af_filesz = udata.au_fstat.af_filesz;
476 break;
477
478 case A_GETFSIZE:
479 if (uap->length != sizeof(udata.au_fstat))
480 return (EINVAL);
481 udata.au_fstat.af_filesz = audit_fstat.af_filesz;
482 udata.au_fstat.af_currsz = audit_fstat.af_currsz;
483 break;
484
485 case A_GETPINFO_ADDR:
486 if (uap->length != sizeof(udata.au_aupinfo_addr))
487 return (EINVAL);
488 if (udata.au_aupinfo_addr.ap_pid < 1)
489 return (ESRCH);
490 if ((tp = pfind(udata.au_aupinfo_addr.ap_pid)) == NULL)
491 return (ESRCH);
492 cred = tp->p_ucred;
493 udata.au_aupinfo_addr.ap_auid = cred->cr_audit.ai_auid;
494 udata.au_aupinfo_addr.ap_mask.am_success =
495 cred->cr_audit.ai_mask.am_success;
496 udata.au_aupinfo_addr.ap_mask.am_failure =
497 cred->cr_audit.ai_mask.am_failure;
498 udata.au_aupinfo_addr.ap_termid = cred->cr_audit.ai_termid;
499 udata.au_aupinfo_addr.ap_asid = cred->cr_audit.ai_asid;
500 PROC_UNLOCK(tp);
501 break;
502
503 case A_GETKAUDIT:
504 if (uap->length != sizeof(udata.au_kau_info))
505 return (EINVAL);
506 audit_get_kinfo(&udata.au_kau_info);
507 break;
508
509 case A_SETKAUDIT:
510 if (uap->length != sizeof(udata.au_kau_info))
511 return (EINVAL);
512 if (udata.au_kau_info.ai_termid.at_type != AU_IPv4 &&
513 udata.au_kau_info.ai_termid.at_type != AU_IPv6)
514 return (EINVAL);
515 audit_set_kinfo(&udata.au_kau_info);
516 break;
517
518 case A_SENDTRIGGER:
519 if (uap->length != sizeof(udata.au_trigger))
520 return (EINVAL);
521 if ((udata.au_trigger < AUDIT_TRIGGER_MIN) ||
522 (udata.au_trigger > AUDIT_TRIGGER_MAX))
523 return (EINVAL);
524 return (audit_send_trigger(udata.au_trigger));
525
526 default:
527 return (EINVAL);
528 }
529
530 /*
531 * Copy data back to userspace for the GET comands.
532 */
533 switch (uap->cmd) {
534 case A_GETPOLICY:
535 case A_OLDGETPOLICY:
536 case A_GETKMASK:
537 case A_GETQCTRL:
538 case A_OLDGETQCTRL:
539 case A_GETCWD:
540 case A_GETCAR:
541 case A_GETSTAT:
542 case A_GETCOND:
543 case A_OLDGETCOND:
544 case A_GETCLASS:
545 case A_GETPINFO:
546 case A_GETFSIZE:
547 case A_GETPINFO_ADDR:
548 case A_GETKAUDIT:
549 error = copyout((void *)&udata, uap->data, uap->length);
550 if (error)
551 return (error);
552 break;
553 }
554
555 return (0);
556}
557
558/*
559 * System calls to manage the user audit information.
560 */
561/* ARGSUSED */
562int
563sys_getauid(struct thread *td, struct getauid_args *uap)
564{
565 int error;
566
567 if (jailed(td->td_ucred))
568 return (ENOSYS);
569 error = priv_check(td, PRIV_AUDIT_GETAUDIT);
570 if (error)
571 return (error);
572 return (copyout(&td->td_ucred->cr_audit.ai_auid, uap->auid,
573 sizeof(td->td_ucred->cr_audit.ai_auid)));
574}
575
576/* ARGSUSED */
577int
578sys_setauid(struct thread *td, struct setauid_args *uap)
579{
580 struct ucred *newcred, *oldcred;
581 au_id_t id;
582 int error;
583
584 if (jailed(td->td_ucred))
585 return (ENOSYS);
586 error = copyin(uap->auid, &id, sizeof(id));
587 if (error)
588 return (error);
589 audit_arg_auid(id);
590 newcred = crget();
591 PROC_LOCK(td->td_proc);
592 oldcred = td->td_proc->p_ucred;
593 crcopy(newcred, oldcred);
594#ifdef MAC
595 error = mac_cred_check_setauid(oldcred, id);
596 if (error)
597 goto fail;
598#endif
599 error = priv_check_cred(oldcred, PRIV_AUDIT_SETAUDIT, 0);
600 if (error)
601 goto fail;
602 newcred->cr_audit.ai_auid = id;
603 td->td_proc->p_ucred = newcred;
604 PROC_UNLOCK(td->td_proc);
605 crfree(oldcred);
606 return (0);
607fail:
608 PROC_UNLOCK(td->td_proc);
609 crfree(newcred);
610 return (error);
611}
612
613/*
614 * System calls to get and set process audit information.
615 */
616/* ARGSUSED */
617int
618sys_getaudit(struct thread *td, struct getaudit_args *uap)
619{
620 struct auditinfo ai;
621 struct ucred *cred;
622 int error;
623
624 cred = td->td_ucred;
625 if (jailed(cred))
626 return (ENOSYS);
627 error = priv_check(td, PRIV_AUDIT_GETAUDIT);
628 if (error)
629 return (error);
630 if (cred->cr_audit.ai_termid.at_type == AU_IPv6)
631 return (E2BIG);
632 bzero(&ai, sizeof(ai));
633 ai.ai_auid = cred->cr_audit.ai_auid;
634 ai.ai_mask = cred->cr_audit.ai_mask;
635 ai.ai_asid = cred->cr_audit.ai_asid;
636 ai.ai_termid.machine = cred->cr_audit.ai_termid.at_addr[0];
637 ai.ai_termid.port = cred->cr_audit.ai_termid.at_port;
638 return (copyout(&ai, uap->auditinfo, sizeof(ai)));
639}
640
641/* ARGSUSED */
642int
643sys_setaudit(struct thread *td, struct setaudit_args *uap)
644{
645 struct ucred *newcred, *oldcred;
646 struct auditinfo ai;
647 int error;
648
649 if (jailed(td->td_ucred))
650 return (ENOSYS);
651 error = copyin(uap->auditinfo, &ai, sizeof(ai));
652 if (error)
653 return (error);
654 audit_arg_auditinfo(&ai);
655 newcred = crget();
656 PROC_LOCK(td->td_proc);
657 oldcred = td->td_proc->p_ucred;
658 crcopy(newcred, oldcred);
659#ifdef MAC
660 error = mac_cred_check_setaudit(oldcred, &ai);
661 if (error)
662 goto fail;
663#endif
664 error = priv_check_cred(oldcred, PRIV_AUDIT_SETAUDIT, 0);
665 if (error)
666 goto fail;
667 bzero(&newcred->cr_audit, sizeof(newcred->cr_audit));
668 newcred->cr_audit.ai_auid = ai.ai_auid;
669 newcred->cr_audit.ai_mask = ai.ai_mask;
670 newcred->cr_audit.ai_asid = ai.ai_asid;
671 newcred->cr_audit.ai_termid.at_addr[0] = ai.ai_termid.machine;
672 newcred->cr_audit.ai_termid.at_port = ai.ai_termid.port;
673 newcred->cr_audit.ai_termid.at_type = AU_IPv4;
674 td->td_proc->p_ucred = newcred;
675 PROC_UNLOCK(td->td_proc);
676 crfree(oldcred);
677 return (0);
678fail:
679 PROC_UNLOCK(td->td_proc);
680 crfree(newcred);
681 return (error);
682}
683
684/* ARGSUSED */
685int
686sys_getaudit_addr(struct thread *td, struct getaudit_addr_args *uap)
687{
688 int error;
689
690 if (jailed(td->td_ucred))
691 return (ENOSYS);
692 if (uap->length < sizeof(*uap->auditinfo_addr))
693 return (EOVERFLOW);
694 error = priv_check(td, PRIV_AUDIT_GETAUDIT);
695 if (error)
696 return (error);
697 return (copyout(&td->td_ucred->cr_audit, uap->auditinfo_addr,
698 sizeof(*uap->auditinfo_addr)));
699}
700
701/* ARGSUSED */
702int
703sys_setaudit_addr(struct thread *td, struct setaudit_addr_args *uap)
704{
705 struct ucred *newcred, *oldcred;
706 struct auditinfo_addr aia;
707 int error;
708
709 if (jailed(td->td_ucred))
710 return (ENOSYS);
711 error = copyin(uap->auditinfo_addr, &aia, sizeof(aia));
712 if (error)
713 return (error);
714 audit_arg_auditinfo_addr(&aia);
715 if (aia.ai_termid.at_type != AU_IPv6 &&
716 aia.ai_termid.at_type != AU_IPv4)
717 return (EINVAL);
718 newcred = crget();
719 PROC_LOCK(td->td_proc);
720 oldcred = td->td_proc->p_ucred;
721 crcopy(newcred, oldcred);
722#ifdef MAC
723 error = mac_cred_check_setaudit_addr(oldcred, &aia);
724 if (error)
725 goto fail;
726#endif
727 error = priv_check_cred(oldcred, PRIV_AUDIT_SETAUDIT, 0);
728 if (error)
729 goto fail;
730 newcred->cr_audit = aia;
731 td->td_proc->p_ucred = newcred;
732 PROC_UNLOCK(td->td_proc);
733 crfree(oldcred);
734 return (0);
735fail:
736 PROC_UNLOCK(td->td_proc);
737 crfree(newcred);
738 return (error);
739}
740
741/*
742 * Syscall to manage audit files.
743 */
744/* ARGSUSED */
745int
746sys_auditctl(struct thread *td, struct auditctl_args *uap)
747{
748 struct nameidata nd;
749 struct ucred *cred;
750 struct vnode *vp;
751 int error = 0;
752 int flags, vfslocked;
752 int flags;
753
754 if (jailed(td->td_ucred))
755 return (ENOSYS);
756 error = priv_check(td, PRIV_AUDIT_CONTROL);
757 if (error)
758 return (error);
759
760 vp = NULL;
761 cred = NULL;
762
763 /*
764 * If a path is specified, open the replacement vnode, perform
765 * validity checks, and grab another reference to the current
766 * credential.
767 *
768 * On Darwin, a NULL path argument is also used to disable audit.
769 */
770 if (uap->path == NULL)
771 return (EINVAL);
772
753
754 if (jailed(td->td_ucred))
755 return (ENOSYS);
756 error = priv_check(td, PRIV_AUDIT_CONTROL);
757 if (error)
758 return (error);
759
760 vp = NULL;
761 cred = NULL;
762
763 /*
764 * If a path is specified, open the replacement vnode, perform
765 * validity checks, and grab another reference to the current
766 * credential.
767 *
768 * On Darwin, a NULL path argument is also used to disable audit.
769 */
770 if (uap->path == NULL)
771 return (EINVAL);
772
773 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1,
773 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1,
774 UIO_USERSPACE, uap->path, td);
775 flags = AUDIT_OPEN_FLAGS;
776 error = vn_open(&nd, &flags, 0, NULL);
777 if (error)
778 return (error);
774 UIO_USERSPACE, uap->path, td);
775 flags = AUDIT_OPEN_FLAGS;
776 error = vn_open(&nd, &flags, 0, NULL);
777 if (error)
778 return (error);
779 vfslocked = NDHASGIANT(&nd);
780 vp = nd.ni_vp;
781#ifdef MAC
782 error = mac_system_check_auditctl(td->td_ucred, vp);
783 VOP_UNLOCK(vp, 0);
784 if (error) {
785 vn_close(vp, AUDIT_CLOSE_FLAGS, td->td_ucred, td);
779 vp = nd.ni_vp;
780#ifdef MAC
781 error = mac_system_check_auditctl(td->td_ucred, vp);
782 VOP_UNLOCK(vp, 0);
783 if (error) {
784 vn_close(vp, AUDIT_CLOSE_FLAGS, td->td_ucred, td);
786 VFS_UNLOCK_GIANT(vfslocked);
787 return (error);
788 }
789#else
790 VOP_UNLOCK(vp, 0);
791#endif
792 NDFREE(&nd, NDF_ONLY_PNBUF);
793 if (vp->v_type != VREG) {
794 vn_close(vp, AUDIT_CLOSE_FLAGS, td->td_ucred, td);
785 return (error);
786 }
787#else
788 VOP_UNLOCK(vp, 0);
789#endif
790 NDFREE(&nd, NDF_ONLY_PNBUF);
791 if (vp->v_type != VREG) {
792 vn_close(vp, AUDIT_CLOSE_FLAGS, td->td_ucred, td);
795 VFS_UNLOCK_GIANT(vfslocked);
796 return (EINVAL);
797 }
793 return (EINVAL);
794 }
798 VFS_UNLOCK_GIANT(vfslocked);
799 cred = td->td_ucred;
800 crhold(cred);
801
802 /*
803 * XXXAUDIT: Should audit_suspended actually be cleared by
804 * audit_worker?
805 */
806 audit_suspended = 0;
807
808 audit_rotate_vnode(cred, vp);
809
810 return (error);
811}
812
813#else /* !AUDIT */
814
815int
816sys_audit(struct thread *td, struct audit_args *uap)
817{
818
819 return (ENOSYS);
820}
821
822int
823sys_auditon(struct thread *td, struct auditon_args *uap)
824{
825
826 return (ENOSYS);
827}
828
829int
830sys_getauid(struct thread *td, struct getauid_args *uap)
831{
832
833 return (ENOSYS);
834}
835
836int
837sys_setauid(struct thread *td, struct setauid_args *uap)
838{
839
840 return (ENOSYS);
841}
842
843int
844sys_getaudit(struct thread *td, struct getaudit_args *uap)
845{
846
847 return (ENOSYS);
848}
849
850int
851sys_setaudit(struct thread *td, struct setaudit_args *uap)
852{
853
854 return (ENOSYS);
855}
856
857int
858sys_getaudit_addr(struct thread *td, struct getaudit_addr_args *uap)
859{
860
861 return (ENOSYS);
862}
863
864int
865sys_setaudit_addr(struct thread *td, struct setaudit_addr_args *uap)
866{
867
868 return (ENOSYS);
869}
870
871int
872sys_auditctl(struct thread *td, struct auditctl_args *uap)
873{
874
875 return (ENOSYS);
876}
877#endif /* AUDIT */
795 cred = td->td_ucred;
796 crhold(cred);
797
798 /*
799 * XXXAUDIT: Should audit_suspended actually be cleared by
800 * audit_worker?
801 */
802 audit_suspended = 0;
803
804 audit_rotate_vnode(cred, vp);
805
806 return (error);
807}
808
809#else /* !AUDIT */
810
811int
812sys_audit(struct thread *td, struct audit_args *uap)
813{
814
815 return (ENOSYS);
816}
817
818int
819sys_auditon(struct thread *td, struct auditon_args *uap)
820{
821
822 return (ENOSYS);
823}
824
825int
826sys_getauid(struct thread *td, struct getauid_args *uap)
827{
828
829 return (ENOSYS);
830}
831
832int
833sys_setauid(struct thread *td, struct setauid_args *uap)
834{
835
836 return (ENOSYS);
837}
838
839int
840sys_getaudit(struct thread *td, struct getaudit_args *uap)
841{
842
843 return (ENOSYS);
844}
845
846int
847sys_setaudit(struct thread *td, struct setaudit_args *uap)
848{
849
850 return (ENOSYS);
851}
852
853int
854sys_getaudit_addr(struct thread *td, struct getaudit_addr_args *uap)
855{
856
857 return (ENOSYS);
858}
859
860int
861sys_setaudit_addr(struct thread *td, struct setaudit_addr_args *uap)
862{
863
864 return (ENOSYS);
865}
866
867int
868sys_auditctl(struct thread *td, struct auditctl_args *uap)
869{
870
871 return (ENOSYS);
872}
873#endif /* AUDIT */