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