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