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