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