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