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