xref: /freebsd/sys/security/audit/audit_trigger.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
1718c8510SRobert Watson /*-
2718c8510SRobert Watson  * Copyright (c) 2005 Wayne J. Salamon
3718c8510SRobert Watson  * All rights reserved.
4718c8510SRobert Watson  *
5718c8510SRobert Watson  * This software was developed by Wayne Salamon for the TrustedBSD Project.
6718c8510SRobert Watson  *
7718c8510SRobert Watson  * Redistribution and use in source and binary forms, with or without
8718c8510SRobert Watson  * modification, are permitted provided that the following conditions
9718c8510SRobert Watson  * are met:
10718c8510SRobert Watson  * 1. Redistributions of source code must retain the above copyright
11718c8510SRobert Watson  *    notice, this list of conditions and the following disclaimer.
12718c8510SRobert Watson  * 2. Redistributions in binary form must reproduce the above copyright
13718c8510SRobert Watson  *    notice, this list of conditions and the following disclaimer in the
14718c8510SRobert Watson  *    documentation and/or other materials provided with the distribution.
15718c8510SRobert Watson  *
16718c8510SRobert Watson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17718c8510SRobert Watson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18718c8510SRobert Watson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19718c8510SRobert Watson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20718c8510SRobert Watson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21718c8510SRobert Watson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22718c8510SRobert Watson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23718c8510SRobert Watson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24718c8510SRobert Watson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25718c8510SRobert Watson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26718c8510SRobert Watson  * SUCH DAMAGE.
27718c8510SRobert Watson  */
28718c8510SRobert Watson 
29718c8510SRobert Watson #include <sys/param.h>
30718c8510SRobert Watson #include <sys/conf.h>
31718c8510SRobert Watson #include <sys/kernel.h>
32*e2e050c8SConrad Meyer #include <sys/lock.h>
33718c8510SRobert Watson #include <sys/malloc.h>
34*e2e050c8SConrad Meyer #include <sys/mutex.h>
35718c8510SRobert Watson #include <sys/proc.h>
36718c8510SRobert Watson #include <sys/queue.h>
37718c8510SRobert Watson #include <sys/systm.h>
38718c8510SRobert Watson #include <sys/uio.h>
39718c8510SRobert Watson 
40718c8510SRobert Watson #include <security/audit/audit.h>
41718c8510SRobert Watson #include <security/audit/audit_private.h>
42718c8510SRobert Watson 
43718c8510SRobert Watson /*
44718c8510SRobert Watson  * Structures and operations to support the basic character special device
451afabae4SRobert Watson  * used to communicate with userland.  /dev/audit reliably delivers one-byte
461afabae4SRobert Watson  * messages to a listening application (or discards them if there is no
471afabae4SRobert Watson  * listening application).
481afabae4SRobert Watson  *
491afabae4SRobert Watson  * Currently, select/poll are not supported on the trigger device.
50718c8510SRobert Watson  */
51718c8510SRobert Watson struct trigger_info {
52718c8510SRobert Watson 	unsigned int			trigger;
53718c8510SRobert Watson 	TAILQ_ENTRY(trigger_info)	list;
54718c8510SRobert Watson };
551afabae4SRobert Watson 
56718c8510SRobert Watson static MALLOC_DEFINE(M_AUDITTRIGGER, "audit_trigger", "Audit trigger events");
57718c8510SRobert Watson static struct cdev *audit_dev;
58718c8510SRobert Watson static int audit_isopen = 0;
59718c8510SRobert Watson static TAILQ_HEAD(, trigger_info) trigger_list;
60718c8510SRobert Watson static struct mtx audit_trigger_mtx;
61718c8510SRobert Watson 
62718c8510SRobert Watson static int
audit_open(struct cdev * dev,int oflags,int devtype,struct thread * td)63718c8510SRobert Watson audit_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
64718c8510SRobert Watson {
65718c8510SRobert Watson 	int error;
66718c8510SRobert Watson 
67ec914adfSRobert Watson 	/* Only one process may open the device at a time. */
68718c8510SRobert Watson 	mtx_lock(&audit_trigger_mtx);
69718c8510SRobert Watson 	if (!audit_isopen) {
70718c8510SRobert Watson 		error = 0;
71718c8510SRobert Watson 		audit_isopen = 1;
72718c8510SRobert Watson 	} else
73718c8510SRobert Watson 		error = EBUSY;
74718c8510SRobert Watson 	mtx_unlock(&audit_trigger_mtx);
75718c8510SRobert Watson 
76718c8510SRobert Watson 	return (error);
77718c8510SRobert Watson }
78718c8510SRobert Watson 
79718c8510SRobert Watson static int
audit_close(struct cdev * dev,int fflag,int devtype,struct thread * td)80718c8510SRobert Watson audit_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
81718c8510SRobert Watson {
82718c8510SRobert Watson 	struct trigger_info *ti;
83718c8510SRobert Watson 
84718c8510SRobert Watson 	/* Flush the queue of pending trigger events. */
85718c8510SRobert Watson 	mtx_lock(&audit_trigger_mtx);
86718c8510SRobert Watson 	audit_isopen = 0;
87718c8510SRobert Watson 	while (!TAILQ_EMPTY(&trigger_list)) {
88718c8510SRobert Watson 		ti = TAILQ_FIRST(&trigger_list);
89718c8510SRobert Watson 		TAILQ_REMOVE(&trigger_list, ti, list);
90718c8510SRobert Watson 		free(ti, M_AUDITTRIGGER);
91718c8510SRobert Watson 	}
92718c8510SRobert Watson 	mtx_unlock(&audit_trigger_mtx);
93718c8510SRobert Watson 
94718c8510SRobert Watson 	return (0);
95718c8510SRobert Watson }
96718c8510SRobert Watson 
97718c8510SRobert Watson static int
audit_read(struct cdev * dev,struct uio * uio,int ioflag)98718c8510SRobert Watson audit_read(struct cdev *dev, struct uio *uio, int ioflag)
99718c8510SRobert Watson {
100718c8510SRobert Watson 	int error = 0;
101718c8510SRobert Watson 	struct trigger_info *ti = NULL;
102718c8510SRobert Watson 
103718c8510SRobert Watson 	mtx_lock(&audit_trigger_mtx);
104718c8510SRobert Watson 	while (TAILQ_EMPTY(&trigger_list)) {
105718c8510SRobert Watson 		error = msleep(&trigger_list, &audit_trigger_mtx,
106718c8510SRobert Watson 		    PSOCK | PCATCH, "auditd", 0);
107718c8510SRobert Watson 		if (error)
108718c8510SRobert Watson 			break;
109718c8510SRobert Watson 	}
110718c8510SRobert Watson 	if (!error) {
111718c8510SRobert Watson 		ti = TAILQ_FIRST(&trigger_list);
112718c8510SRobert Watson 		TAILQ_REMOVE(&trigger_list, ti, list);
113718c8510SRobert Watson 	}
114718c8510SRobert Watson 	mtx_unlock(&audit_trigger_mtx);
115718c8510SRobert Watson 	if (!error) {
1168805ca53SRobert Watson 		error = uiomove(&ti->trigger, sizeof(ti->trigger), uio);
117718c8510SRobert Watson 		free(ti, M_AUDITTRIGGER);
118718c8510SRobert Watson 	}
119718c8510SRobert Watson 	return (error);
120718c8510SRobert Watson }
121718c8510SRobert Watson 
122718c8510SRobert Watson static int
audit_write(struct cdev * dev,struct uio * uio,int ioflag)123718c8510SRobert Watson audit_write(struct cdev *dev, struct uio *uio, int ioflag)
124718c8510SRobert Watson {
125718c8510SRobert Watson 
126718c8510SRobert Watson 	/* Communication is kernel->userspace only. */
127718c8510SRobert Watson 	return (EOPNOTSUPP);
128718c8510SRobert Watson }
129718c8510SRobert Watson 
1305ec68199SRobert Watson int
audit_send_trigger(unsigned int trigger)131fb4ed8c9SRobert Watson audit_send_trigger(unsigned int trigger)
132718c8510SRobert Watson {
133718c8510SRobert Watson 	struct trigger_info *ti;
134718c8510SRobert Watson 
135718c8510SRobert Watson 	ti = malloc(sizeof *ti, M_AUDITTRIGGER, M_WAITOK);
136718c8510SRobert Watson 	mtx_lock(&audit_trigger_mtx);
1376a9a600bSRobert Watson 	if (!audit_isopen) {
1386a9a600bSRobert Watson 		/* If nobody's listening, we ain't talking. */
1396a9a600bSRobert Watson 		mtx_unlock(&audit_trigger_mtx);
1406a9a600bSRobert Watson 		free(ti, M_AUDITTRIGGER);
1416a9a600bSRobert Watson 		return (ENODEV);
1426a9a600bSRobert Watson 	}
143718c8510SRobert Watson 	ti->trigger = trigger;
144718c8510SRobert Watson 	TAILQ_INSERT_TAIL(&trigger_list, ti, list);
145718c8510SRobert Watson 	wakeup(&trigger_list);
146718c8510SRobert Watson 	mtx_unlock(&audit_trigger_mtx);
1475ec68199SRobert Watson 	return (0);
148718c8510SRobert Watson }
149718c8510SRobert Watson 
150718c8510SRobert Watson static struct cdevsw audit_cdevsw = {
151718c8510SRobert Watson 	.d_version =	D_VERSION,
152718c8510SRobert Watson 	.d_open =	audit_open,
153718c8510SRobert Watson 	.d_close =	audit_close,
154718c8510SRobert Watson 	.d_read =	audit_read,
155718c8510SRobert Watson 	.d_write =	audit_write,
156718c8510SRobert Watson 	.d_name =	"audit"
157718c8510SRobert Watson };
158718c8510SRobert Watson 
159718c8510SRobert Watson void
audit_trigger_init(void)160718c8510SRobert Watson audit_trigger_init(void)
161718c8510SRobert Watson {
162718c8510SRobert Watson 
163718c8510SRobert Watson 	TAILQ_INIT(&trigger_list);
164718c8510SRobert Watson 	mtx_init(&audit_trigger_mtx, "audit_trigger_mtx", NULL, MTX_DEF);
165718c8510SRobert Watson }
166718c8510SRobert Watson 
167718c8510SRobert Watson static void
audit_trigger_cdev_init(void * unused)168718c8510SRobert Watson audit_trigger_cdev_init(void *unused)
169718c8510SRobert Watson {
170718c8510SRobert Watson 
171718c8510SRobert Watson 	/* Create the special device file. */
172718c8510SRobert Watson 	audit_dev = make_dev(&audit_cdevsw, 0, UID_ROOT, GID_KMEM, 0600,
173718c8510SRobert Watson 	    AUDITDEV_FILENAME);
174718c8510SRobert Watson }
175718c8510SRobert Watson 
176718c8510SRobert Watson SYSINIT(audit_trigger_cdev_init, SI_SUB_DRIVERS, SI_ORDER_MIDDLE,
177718c8510SRobert Watson     audit_trigger_cdev_init, NULL);
178