audit_syscalls.c revision 165624
1/*
2 * Copyright (c) 1999-2005 Apple Computer, 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 Computer, 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 * $FreeBSD: head/sys/security/audit/audit_syscalls.c 165624 2006-12-29 10:49:13Z rwatson $
30 */
31
32#include <sys/param.h>
33#include <sys/mount.h>
34#include <sys/namei.h>
35#include <sys/priv.h>
36#include <sys/proc.h>
37#include <sys/sysproto.h>
38#include <sys/systm.h>
39#include <sys/vnode.h>
40#include <sys/jail.h>
41
42#include <bsm/audit.h>
43#include <bsm/audit_kevents.h>
44#include <security/audit/audit.h>
45#include <security/audit/audit_private.h>
46
47#ifdef AUDIT
48
49/*
50 * MPSAFE
51 *
52 * System call to allow a user space application to submit a BSM audit record
53 * to the kernel for inclusion in the audit log. This function does little
54 * verification on the audit record that is submitted.
55 *
56 * XXXAUDIT: Audit preselection for user records does not currently work,
57 * since we pre-select only based on the AUE_audit event type, not the event
58 * type submitted as part of the user audit data.
59 */
60/* ARGSUSED */
61int
62audit(struct thread *td, struct audit_args *uap)
63{
64	int error;
65	void * rec;
66	struct kaudit_record *ar;
67
68	if (jailed(td->td_ucred))
69		return (ENOSYS);
70	error = priv_check(td, PRIV_AUDIT_SUBMIT);
71	if (error)
72		return (error);
73
74	if ((uap->length <= 0) || (uap->length > audit_qctrl.aq_bufsz))
75		return (EINVAL);
76
77	ar = currecord();
78
79	/*
80	 * If there's no current audit record (audit() itself not audited)
81	 * commit the user audit record.
82	 */
83	if (ar == NULL) {
84
85		/*
86		 * This is not very efficient; we're required to allocate a
87		 * complete kernel audit record just so the user record can
88		 * tag along.
89		 *
90		 * XXXAUDIT: Maybe AUE_AUDIT in the system call context and
91		 * special pre-select handling?
92		 */
93		td->td_ar = audit_new(AUE_NULL, td);
94		if (td->td_ar == NULL)
95			return (ENOTSUP);
96		ar = td->td_ar;
97	}
98
99	if (uap->length > MAX_AUDIT_RECORD_SIZE)
100		return (EINVAL);
101
102	rec = malloc(uap->length, M_AUDITDATA, M_WAITOK);
103
104	error = copyin(uap->record, rec, uap->length);
105	if (error)
106		goto free_out;
107
108	/* Verify the record. */
109	if (bsm_rec_verify(rec) == 0) {
110		error = EINVAL;
111		goto free_out;
112	}
113
114	/*
115	 * Attach the user audit record to the kernel audit record. Because
116	 * this system call is an auditable event, we will write the user
117	 * record along with the record for this audit event.
118	 *
119	 * XXXAUDIT: KASSERT appropriate starting values of k_udata, k_ulen,
120	 * k_ar_commit & AR_COMMIT_USER?
121	 */
122	ar->k_udata = rec;
123	ar->k_ulen  = uap->length;
124	ar->k_ar_commit |= AR_COMMIT_USER;
125
126	/*
127	 * Currently we assume that all preselection has been performed in
128	 * userspace. We unconditionally set these masks so that the records
129	 * get committed both to the trail and pipe.  In the future we will
130	 * want to setup kernel based preselection.
131	 */
132	ar->k_ar_commit |= (AR_PRESELECT_USER_TRAIL | AR_PRESELECT_USER_PIPE);
133	return (0);
134
135free_out:
136	/*
137	 * audit_syscall_exit() will free the audit record on the thread even
138	 * if we allocated it above.
139	 */
140	free(rec, M_AUDITDATA);
141	return (error);
142}
143
144/*
145 * MPSAFE
146 *
147 *  System call to manipulate auditing.
148 */
149/* ARGSUSED */
150int
151auditon(struct thread *td, struct auditon_args *uap)
152{
153	int error;
154	union auditon_udata udata;
155	struct proc *tp;
156
157	if (jailed(td->td_ucred))
158		return (ENOSYS);
159	AUDIT_ARG(cmd, uap->cmd);
160	error = priv_check(td, PRIV_AUDIT_CONTROL);
161	if (error)
162		return (error);
163
164	if ((uap->length <= 0) || (uap->length > sizeof(union auditon_udata)))
165		return (EINVAL);
166
167	memset((void *)&udata, 0, sizeof(udata));
168
169	/*
170	 * Some of the GET commands use the arguments too.
171	 */
172	switch (uap->cmd) {
173	case A_SETPOLICY:
174	case A_SETKMASK:
175	case A_SETQCTRL:
176	case A_SETSTAT:
177	case A_SETUMASK:
178	case A_SETSMASK:
179	case A_SETCOND:
180	case A_SETCLASS:
181	case A_SETPMASK:
182	case A_SETFSIZE:
183	case A_SETKAUDIT:
184	case A_GETCLASS:
185	case A_GETPINFO:
186	case A_GETPINFO_ADDR:
187	case A_SENDTRIGGER:
188		error = copyin(uap->data, (void *)&udata, uap->length);
189		if (error)
190			return (error);
191		AUDIT_ARG(auditon, &udata);
192		break;
193	}
194
195	/*
196	 * XXX Need to implement these commands by accessing the global
197	 * values associated with the commands.
198	 *
199	 * XXXAUDIT: Locking?
200	 */
201	switch (uap->cmd) {
202	case A_GETPOLICY:
203		if (!audit_fail_stop)
204			udata.au_policy |= AUDIT_CNT;
205		if (audit_panic_on_write_fail)
206			udata.au_policy |= AUDIT_AHLT;
207		if (audit_argv)
208			udata.au_policy |= AUDIT_ARGV;
209		if (audit_arge)
210			udata.au_policy |= AUDIT_ARGE;
211		break;
212
213	case A_SETPOLICY:
214		if (udata.au_policy & ~(AUDIT_CNT|AUDIT_AHLT|AUDIT_ARGV|
215		    AUDIT_ARGE))
216			return (EINVAL);
217		/*
218		 * XXX - Need to wake up waiters if the policy relaxes?
219		 */
220		audit_fail_stop = ((udata.au_policy & AUDIT_CNT) == 0);
221		audit_panic_on_write_fail = (udata.au_policy & AUDIT_AHLT);
222		audit_argv = (udata.au_policy & AUDIT_ARGV);
223		audit_arge = (udata.au_policy & AUDIT_ARGE);
224		break;
225
226	case A_GETKMASK:
227		udata.au_mask = audit_nae_mask;
228		break;
229
230	case A_SETKMASK:
231		audit_nae_mask = udata.au_mask;
232		break;
233
234	case A_GETQCTRL:
235		udata.au_qctrl = audit_qctrl;
236		break;
237
238	case A_SETQCTRL:
239		if ((udata.au_qctrl.aq_hiwater > AQ_MAXHIGH) ||
240		    (udata.au_qctrl.aq_lowater >= udata.au_qctrl.aq_hiwater) ||
241		    (udata.au_qctrl.aq_bufsz > AQ_MAXBUFSZ) ||
242		    (udata.au_qctrl.aq_minfree < 0) ||
243		    (udata.au_qctrl.aq_minfree > 100))
244			return (EINVAL);
245
246		audit_qctrl = udata.au_qctrl;
247		/* XXX The queue delay value isn't used with the kernel. */
248		audit_qctrl.aq_delay = -1;
249		break;
250
251	case A_GETCWD:
252		return (ENOSYS);
253		break;
254
255	case A_GETCAR:
256		return (ENOSYS);
257		break;
258
259	case A_GETSTAT:
260		return (ENOSYS);
261		break;
262
263	case A_SETSTAT:
264		return (ENOSYS);
265		break;
266
267	case A_SETUMASK:
268		return (ENOSYS);
269		break;
270
271	case A_SETSMASK:
272		return (ENOSYS);
273		break;
274
275	case A_GETCOND:
276		if (audit_enabled && !audit_suspended)
277			udata.au_cond = AUC_AUDITING;
278		else
279			udata.au_cond = AUC_NOAUDIT;
280		break;
281
282	case A_SETCOND:
283		if (udata.au_cond == AUC_NOAUDIT)
284			audit_suspended = 1;
285		if (udata.au_cond == AUC_AUDITING)
286			audit_suspended = 0;
287		if (udata.au_cond == AUC_DISABLED) {
288			audit_suspended = 1;
289			audit_shutdown(NULL, 0);
290		}
291		break;
292
293	case A_GETCLASS:
294		udata.au_evclass.ec_class = au_event_class(
295		    udata.au_evclass.ec_number);
296		break;
297
298	case A_SETCLASS:
299		au_evclassmap_insert(udata.au_evclass.ec_number,
300		    udata.au_evclass.ec_class);
301		break;
302
303	case A_GETPINFO:
304		if (udata.au_aupinfo.ap_pid < 1)
305			return (EINVAL);
306
307		if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL)
308			return (EINVAL);
309		if (p_cansee(td, tp) != 0) {
310			PROC_UNLOCK(tp);
311			return (EINVAL);
312		}
313
314		udata.au_aupinfo.ap_auid = tp->p_au->ai_auid;
315		udata.au_aupinfo.ap_mask.am_success =
316		    tp->p_au->ai_mask.am_success;
317		udata.au_aupinfo.ap_mask.am_failure =
318		    tp->p_au->ai_mask.am_failure;
319		udata.au_aupinfo.ap_termid.machine =
320		    tp->p_au->ai_termid.machine;
321		udata.au_aupinfo.ap_termid.port = tp->p_au->ai_termid.port;
322		udata.au_aupinfo.ap_asid = tp->p_au->ai_asid;
323		PROC_UNLOCK(tp);
324		break;
325
326	case A_SETPMASK:
327		if (udata.au_aupinfo.ap_pid < 1)
328			return (EINVAL);
329
330		if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL)
331			return (EINVAL);
332		if (p_cansee(td, tp) != 0) {
333			PROC_UNLOCK(tp);
334			return (EINVAL);
335		}
336
337		tp->p_au->ai_mask.am_success =
338		    udata.au_aupinfo.ap_mask.am_success;
339		tp->p_au->ai_mask.am_failure =
340		    udata.au_aupinfo.ap_mask.am_failure;
341		PROC_UNLOCK(tp);
342		break;
343
344	case A_SETFSIZE:
345		if ((udata.au_fstat.af_filesz != 0) &&
346		   (udata.au_fstat.af_filesz < MIN_AUDIT_FILE_SIZE))
347			return (EINVAL);
348		audit_fstat.af_filesz = udata.au_fstat.af_filesz;
349		break;
350
351	case A_GETFSIZE:
352		udata.au_fstat.af_filesz = audit_fstat.af_filesz;
353		udata.au_fstat.af_currsz = audit_fstat.af_currsz;
354		break;
355
356	case A_GETPINFO_ADDR:
357		return (ENOSYS);
358		break;
359
360	case A_GETKAUDIT:
361		return (ENOSYS);
362		break;
363
364	case A_SETKAUDIT:
365		return (ENOSYS);
366		break;
367
368	case A_SENDTRIGGER:
369		if ((udata.au_trigger < AUDIT_TRIGGER_MIN) ||
370		    (udata.au_trigger > AUDIT_TRIGGER_MAX))
371			return (EINVAL);
372		return (send_trigger(udata.au_trigger));
373	}
374
375	/*
376	 * Copy data back to userspace for the GET comands.
377	 */
378	switch (uap->cmd) {
379	case A_GETPOLICY:
380	case A_GETKMASK:
381	case A_GETQCTRL:
382	case A_GETCWD:
383	case A_GETCAR:
384	case A_GETSTAT:
385	case A_GETCOND:
386	case A_GETCLASS:
387	case A_GETPINFO:
388	case A_GETFSIZE:
389	case A_GETPINFO_ADDR:
390	case A_GETKAUDIT:
391		error = copyout((void *)&udata, uap->data, uap->length);
392		if (error)
393			return (error);
394		break;
395	}
396
397	return (0);
398}
399
400/*
401 * MPSAFE
402 *
403 * System calls to manage the user audit information.
404 */
405/* ARGSUSED */
406int
407getauid(struct thread *td, struct getauid_args *uap)
408{
409	int error;
410	au_id_t id;
411
412	if (jailed(td->td_ucred))
413		return (ENOSYS);
414	error = priv_check(td, PRIV_AUDIT_GETAUDIT);
415	if (error)
416		return (error);
417
418	/*
419	 * XXX: Integer read on static pointer dereference: doesn't need
420	 * locking?
421	 */
422	PROC_LOCK(td->td_proc);
423	id = td->td_proc->p_au->ai_auid;
424	PROC_UNLOCK(td->td_proc);
425	return copyout(&id, uap->auid, sizeof(id));
426}
427
428/* MPSAFE */
429/* ARGSUSED */
430int
431setauid(struct thread *td, struct setauid_args *uap)
432{
433	int error;
434	au_id_t id;
435
436	if (jailed(td->td_ucred))
437		return (ENOSYS);
438	error = priv_check(td, PRIV_AUDIT_SETAUDIT);
439	if (error)
440		return (error);
441
442	error = copyin(uap->auid, &id, sizeof(id));
443	if (error)
444		return (error);
445
446	audit_arg_auid(id);
447
448	/*
449	 * XXX: Integer write on static pointer dereference: doesn't need
450	 * locking?
451	 *
452	 * XXXAUDIT: Might need locking to serialize audit events in the same
453	 * order as change events?  Or maybe that's an under-solveable
454	 * problem.
455	 *
456	 * XXXRW: Test privilege while holding the proc lock?
457	 */
458	PROC_LOCK(td->td_proc);
459	td->td_proc->p_au->ai_auid = id;
460	PROC_UNLOCK(td->td_proc);
461
462	return (0);
463}
464
465/*
466 * MPSAFE
467 * System calls to get and set process audit information.
468 */
469/* ARGSUSED */
470int
471getaudit(struct thread *td, struct getaudit_args *uap)
472{
473	struct auditinfo ai;
474	int error;
475
476	if (jailed(td->td_ucred))
477		return (ENOSYS);
478	error = priv_check(td, PRIV_AUDIT_GETAUDIT);
479	if (error)
480		return (error);
481
482	PROC_LOCK(td->td_proc);
483	ai = *td->td_proc->p_au;
484	PROC_UNLOCK(td->td_proc);
485
486	return (copyout(&ai, uap->auditinfo, sizeof(ai)));
487}
488
489/* MPSAFE */
490/* ARGSUSED */
491int
492setaudit(struct thread *td, struct setaudit_args *uap)
493{
494	struct auditinfo ai;
495	int error;
496
497	if (jailed(td->td_ucred))
498		return (ENOSYS);
499	error = priv_check(td, PRIV_AUDIT_SETAUDIT);
500	if (error)
501		return (error);
502
503	error = copyin(uap->auditinfo, &ai, sizeof(ai));
504	if (error)
505		return (error);
506
507	audit_arg_auditinfo(&ai);
508
509	/*
510	 * XXXRW: Test privilege while holding the proc lock?
511	*/
512	PROC_LOCK(td->td_proc);
513	*td->td_proc->p_au = ai;
514	PROC_UNLOCK(td->td_proc);
515
516	return (0);
517}
518
519/* MPSAFE */
520/* ARGSUSED */
521int
522getaudit_addr(struct thread *td, struct getaudit_addr_args *uap)
523{
524	int error;
525
526	if (jailed(td->td_ucred))
527		return (ENOSYS);
528	error = priv_check(td, PRIV_AUDIT_GETAUDIT);
529	if (error)
530		return (error);
531	return (ENOSYS);
532}
533
534/* MPSAFE */
535/* ARGSUSED */
536int
537setaudit_addr(struct thread *td, struct setaudit_addr_args *uap)
538{
539	int error;
540
541	if (jailed(td->td_ucred))
542		return (ENOSYS);
543	error = priv_check(td, PRIV_AUDIT_SETAUDIT);
544	if (error)
545		return (error);
546	return (ENOSYS);
547}
548
549/*
550 * MPSAFE
551 * Syscall to manage audit files.
552 *
553 * XXX: Should generate an audit event.
554 */
555/* ARGSUSED */
556int
557auditctl(struct thread *td, struct auditctl_args *uap)
558{
559	struct nameidata nd;
560	struct ucred *cred;
561	struct vnode *vp;
562	int error = 0;
563	int flags, vfslocked;
564
565	if (jailed(td->td_ucred))
566		return (ENOSYS);
567	error = priv_check(td, PRIV_AUDIT_CONTROL);
568	if (error)
569		return (error);
570
571	vp = NULL;
572	cred = NULL;
573
574	/*
575	 * If a path is specified, open the replacement vnode, perform
576	 * validity checks, and grab another reference to the current
577	 * credential.
578	 *
579	 * On Darwin, a NULL path argument is also used to disable audit.
580	 */
581	if (uap->path == NULL)
582		return (EINVAL);
583
584	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1,
585	    UIO_USERSPACE, uap->path, td);
586	flags = AUDIT_OPEN_FLAGS;
587	error = vn_open(&nd, &flags, 0, -1);
588	if (error)
589		return (error);
590	vfslocked = NDHASGIANT(&nd);
591	vp = nd.ni_vp;
592	VOP_UNLOCK(vp, 0, td);
593	NDFREE(&nd, NDF_ONLY_PNBUF);
594	if (vp->v_type != VREG) {
595		vn_close(vp, AUDIT_CLOSE_FLAGS, td->td_ucred, td);
596		VFS_UNLOCK_GIANT(vfslocked);
597		return (EINVAL);
598	}
599	VFS_UNLOCK_GIANT(vfslocked);
600	cred = td->td_ucred;
601	crhold(cred);
602
603	/*
604	 * XXXAUDIT: Should audit_suspended actually be cleared by
605	 * audit_worker?
606	 */
607	audit_suspended = 0;
608
609	audit_rotate_vnode(cred, vp);
610
611	return (error);
612}
613
614#else /* !AUDIT */
615
616int
617audit(struct thread *td, struct audit_args *uap)
618{
619
620	return (ENOSYS);
621}
622
623int
624auditon(struct thread *td, struct auditon_args *uap)
625{
626
627	return (ENOSYS);
628}
629
630int
631getauid(struct thread *td, struct getauid_args *uap)
632{
633
634	return (ENOSYS);
635}
636
637int
638setauid(struct thread *td, struct setauid_args *uap)
639{
640
641	return (ENOSYS);
642}
643
644int
645getaudit(struct thread *td, struct getaudit_args *uap)
646{
647
648	return (ENOSYS);
649}
650
651int
652setaudit(struct thread *td, struct setaudit_args *uap)
653{
654
655	return (ENOSYS);
656}
657
658int
659getaudit_addr(struct thread *td, struct getaudit_addr_args *uap)
660{
661
662	return (ENOSYS);
663}
664
665int
666setaudit_addr(struct thread *td, struct setaudit_addr_args *uap)
667{
668
669	return (ENOSYS);
670}
671
672int
673auditctl(struct thread *td, struct auditctl_args *uap)
674{
675
676	return (ENOSYS);
677}
678
679void
680audit_proc_init(struct proc *p)
681{
682
683}
684
685void
686audit_proc_fork(struct proc *parent, struct proc *child)
687{
688
689}
690
691void
692audit_proc_free(struct proc *p)
693{
694
695}
696
697#endif /* AUDIT */
698