PERFORCE change 98565 for review

Robert Watson rwatson at FreeBSD.org
Mon Jun 5 08:18:29 PDT 2006


http://perforce.freebsd.org/chv.cgi?CH=98565

Change 98565 by rwatson at rwatson_zoo on 2006/06/05 15:15:58

	Integrate TrustedBSD base branch from FreeBSD CVS to loop back audit
	work:
	
	- audit_submit.3 hooked up.
	- Audit additional VFS system call arguments.
	- Audit cleanup and per-audit pipe preselection.
	
	Also:
	
	- USB cleanup.

Affected files ...

.. //depot/projects/trustedbsd/base/lib/libbsm/Makefile#2 integrate
.. //depot/projects/trustedbsd/base/sys/dev/usb/ugen.c#27 integrate
.. //depot/projects/trustedbsd/base/sys/kern/vfs_syscalls.c#69 integrate
.. //depot/projects/trustedbsd/base/sys/nfsserver/nfs_serv.c#41 integrate
.. //depot/projects/trustedbsd/base/sys/nfsserver/nfs_srvsubs.c#23 integrate
.. //depot/projects/trustedbsd/base/sys/security/audit/audit.c#6 integrate
.. //depot/projects/trustedbsd/base/sys/security/audit/audit_bsm_klib.c#4 integrate
.. //depot/projects/trustedbsd/base/sys/security/audit/audit_ioctl.h#2 integrate
.. //depot/projects/trustedbsd/base/sys/security/audit/audit_pipe.c#5 integrate
.. //depot/projects/trustedbsd/base/sys/security/audit/audit_private.h#5 integrate
.. //depot/projects/trustedbsd/base/sys/security/audit/audit_worker.c#2 integrate

Differences ...

==== //depot/projects/trustedbsd/base/lib/libbsm/Makefile#2 (text+ko) ====

@@ -1,5 +1,5 @@
 #
-# $FreeBSD: src/lib/libbsm/Makefile,v 1.1 2006/02/02 10:05:39 rwatson Exp $
+# $FreeBSD: src/lib/libbsm/Makefile,v 1.2 2006/06/05 12:53:44 rwatson Exp $
 #
 
 OPENBSMDIR=		${.CURDIR}/../../contrib/openbsm
@@ -40,7 +40,8 @@
 	au_io.3								\
 	au_mask.3							\
 	au_token.3							\
-	au_user.3
+	au_user.3							\
+	audit_submit.3
 
 #
 # It seems like maybe some of these should be installed separately, since

==== //depot/projects/trustedbsd/base/sys/dev/usb/ugen.c#27 (text+ko) ====

@@ -1,4 +1,4 @@
-/*	$NetBSD: ugen.c,v 1.59 2002/07/11 21:14:28 augustss Exp $	*/
+/*	$NetBSD: ugen.c,v 1.79 2006/03/01 12:38:13 yamt Exp $	*/
 
 /* Also already merged from NetBSD:
  *	$NetBSD: ugen.c,v 1.61 2002/09/23 05:51:20 simonb Exp $
@@ -8,7 +8,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/dev/usb/ugen.c,v 1.105 2006/06/03 10:37:42 iedowse Exp $");
+__FBSDID("$FreeBSD: src/sys/dev/usb/ugen.c,v 1.106 2006/06/05 14:44:39 iedowse Exp $");
 
 /*-
  * Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -284,6 +284,9 @@
 	ugen_make_devnodes(sc);
 #endif
 
+	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
+	    USBDEV(sc->sc_dev));
+
 	USB_ATTACH_SUCCESS_RETURN;
 }
 
@@ -322,9 +325,11 @@
 Static void
 ugen_destroy_devnodes(struct ugen_softc *sc)
 {
-	int endptno;
+	int endptno, prev_sc_dying;
 	struct cdev *dev;
 
+	prev_sc_dying = sc->sc_dying;
+	sc->sc_dying = 1;
 	/* destroy all devices for the other (existing) endpoints as well */
 	for (endptno = 1; endptno < USB_MAX_ENDPOINTS; endptno++) {
 		if (sc->sc_endpoints[endptno][IN].sc != NULL ||
@@ -341,9 +346,17 @@
 				dev = sc->sc_endpoints[endptno][IN].dev;
 			else
 				dev = sc->sc_endpoints[endptno][OUT].dev;
-			destroy_dev(dev);
+
+			KASSERT(dev != NULL,
+			    ("ugen_destroy_devnodes: NULL dev"));
+			if(dev != NULL)
+				destroy_dev(dev);
+
+			sc->sc_endpoints[endptno][IN].sc = NULL;
+			sc->sc_endpoints[endptno][OUT].sc = NULL;
 		}
 	}
+	sc->sc_dying = prev_sc_dying;
 }
 #endif
 
@@ -378,9 +391,10 @@
 		return (err);
 	/* store an array of endpoint descriptors to clear if the configuration
 	 * change succeeds - these aren't available afterwards */
-	nendpt_cache = malloc(sizeof(u_int8_t) * niface, M_TEMP, M_WAITOK);
+	nendpt_cache = malloc(sizeof(u_int8_t) * niface, M_TEMP, M_WAITOK |
+	    M_ZERO);
 	sce_cache_arr = malloc(sizeof(struct ugen_endpoint **) * niface, M_TEMP,
-		 M_WAITOK);
+	    M_WAITOK | M_ZERO);
 	niface_cache = niface;
 
 	for (ifaceno = 0; ifaceno < niface; ifaceno++) {
@@ -727,13 +741,12 @@
 			sce->state |= UGEN_ASLP;
 			DPRINTFN(5, ("ugenread: sleep on %p\n", sce));
 			error = tsleep(sce, PZERO | PCATCH, "ugenri", 0);
+			sce->state &= ~UGEN_ASLP;
 			DPRINTFN(5, ("ugenread: woke, error=%d\n", error));
 			if (sc->sc_dying)
 				error = EIO;
-			if (error) {
-				sce->state &= ~UGEN_ASLP;
+			if (error)
 				break;
-			}
 		}
 		splx(s);
 
@@ -793,13 +806,12 @@
 			sce->state |= UGEN_ASLP;
 			DPRINTFN(5, ("ugenread: sleep on %p\n", sce));
 			error = tsleep(sce, PZERO | PCATCH, "ugenri", 0);
+			sce->state &= ~UGEN_ASLP;
 			DPRINTFN(5, ("ugenread: woke, error=%d\n", error));
 			if (sc->sc_dying)
 				error = EIO;
-			if (error) {
-				sce->state &= ~UGEN_ASLP;
+			if (error)
 				break;
-			}
 		}
 
 		while (sce->cur != sce->fill && uio->uio_resid > 0 && !error) {
@@ -837,6 +849,9 @@
 
 	USB_GET_SC(ugen, UGENUNIT(dev), sc);
 
+	if (sc->sc_dying)
+		return (EIO);
+
 	UGEN_DEV_REF(dev, sc);
 	error = ugen_do_read(sc, endpt, uio, flag);
 	UGEN_DEV_RELE(dev, sc);
@@ -938,6 +953,9 @@
 
 	USB_GET_SC(ugen, UGENUNIT(dev), sc);
 
+	if (sc->sc_dying)
+		return (EIO);
+
 	UGEN_DEV_REF(dev, sc);
 	error = ugen_do_write(sc, endpt, uio, flag);
 	UGEN_DEV_RELE(dev, sc);
@@ -976,6 +994,20 @@
 	sce = &sc->sc_endpoints[endpt][IN];
 	if (sce->pipeh)
 		usbd_abort_pipe(sce->pipeh);
+	if (sce->state & UGEN_ASLP) {
+		DPRINTFN(5, ("ugenpurge: waking %p\n", sce));
+		wakeup(sce);
+	}
+	selwakeuppri(&sce->rsel, PZERO);
+
+	sce = &sc->sc_endpoints[endpt][OUT];
+	if (sce->pipeh)
+		usbd_abort_pipe(sce->pipeh);
+	if (sce->state & UGEN_ASLP) {
+		DPRINTFN(5, ("ugenpurge: waking %p\n", sce));
+		wakeup(sce);
+	}
+	selwakeuppri(&sce->rsel, PZERO);
 }
 #endif
 
@@ -1001,6 +1033,7 @@
 			sce = &sc->sc_endpoints[i][dir];
 			if (sce->pipeh)
 				usbd_abort_pipe(sce->pipeh);
+			selwakeuppri(&sce->rsel, PZERO);
 		}
 	}
 
@@ -1040,6 +1073,9 @@
 	destroy_dev(sc->dev);
 #endif
 
+	usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
+	    USBDEV(sc->sc_dev));
+
 	return (0);
 }
 
@@ -1548,6 +1584,9 @@
 
 	USB_GET_SC(ugen, UGENUNIT(dev), sc);
 
+	if (sc->sc_dying)
+		return (EIO);
+
 	UGEN_DEV_REF(dev, sc);
 	error = ugen_do_ioctl(sc, endpt, cmd, addr, flag, p);
 	UGEN_DEV_RELE(dev, sc);
@@ -1558,43 +1597,57 @@
 ugenpoll(struct cdev *dev, int events, usb_proc_ptr p)
 {
 	struct ugen_softc *sc;
-	struct ugen_endpoint *sce;
+	struct ugen_endpoint *sce_in, *sce_out;
+	usb_endpoint_descriptor_t *edesc;
 	int revents = 0;
 	int s;
 
 	USB_GET_SC(ugen, UGENUNIT(dev), sc);
 
 	if (sc->sc_dying)
-		return (EIO);
+		return ((events & (POLLIN | POLLOUT | POLLRDNORM |
+		    POLLWRNORM)) | POLLHUP);
+	/* Do not allow to poll a control endpoint */
+	if (UGENENDPOINT(dev) == USB_CONTROL_ENDPOINT)
+		return (events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
+
+	sce_in = &sc->sc_endpoints[UGENENDPOINT(dev)][IN];
+	sce_out = &sc->sc_endpoints[UGENENDPOINT(dev)][OUT];
+	edesc = (sce_in->edesc != NULL) ? sce_in->edesc : sce_out->edesc;
+	KASSERT(edesc != NULL, ("ugenpoll: NULL edesc"));
+	if (sce_in->edesc == NULL || sce_in->pipeh == NULL)
+		sce_in = NULL;
+	if (sce_out->edesc == NULL || sce_out->pipeh == NULL)
+		sce_out = NULL;
 
-	/* XXX always IN */
-	sce = &sc->sc_endpoints[UGENENDPOINT(dev)][IN];
-#ifdef DIAGNOSTIC
-	if (!sce->edesc) {
-		printf("ugenpoll: no edesc\n");
-		return (EIO);
-	}
-	if (!sce->pipeh) {
-		printf("ugenpoll: no pipe\n");
-		return (EIO);
-	}
-#endif
 	s = splusb();
-	switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
+	switch (edesc->bmAttributes & UE_XFERTYPE) {
 	case UE_INTERRUPT:
-		if (events & (POLLIN | POLLRDNORM)) {
-			if (sce->q.c_cc > 0)
+		if (sce_in != NULL && (events & (POLLIN | POLLRDNORM))) {
+			if (sce_in->q.c_cc > 0)
 				revents |= events & (POLLIN | POLLRDNORM);
 			else
-				selrecord(p, &sce->rsel);
+				selrecord(p, &sce_in->rsel);
+		}
+		if (sce_out != NULL && (events & (POLLOUT | POLLWRNORM))) {
+			if (sce_out->q.c_cc > 0)
+				revents |= events & (POLLOUT | POLLWRNORM);
+			else
+				selrecord(p, &sce_out->rsel);
 		}
 		break;
 	case UE_ISOCHRONOUS:
-		if (events & (POLLIN | POLLRDNORM)) {
-			if (sce->cur != sce->fill)
+		if (sce_in != NULL && (events & (POLLIN | POLLRDNORM))) {
+			if (sce_in->cur != sce_in->fill)
 				revents |= events & (POLLIN | POLLRDNORM);
 			else
-				selrecord(p, &sce->rsel);
+				selrecord(p, &sce_in->rsel);
+		}
+		if (sce_out != NULL && (events & (POLLOUT | POLLWRNORM))) {
+			if (sce_out->cur != sce_out->fill)
+				revents |= events & (POLLOUT | POLLWRNORM);
+			else
+				selrecord(p, &sce_out->rsel);
 		}
 		break;
 	case UE_BULK:

==== //depot/projects/trustedbsd/base/sys/kern/vfs_syscalls.c#69 (text+ko) ====

@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/kern/vfs_syscalls.c,v 1.414 2006/03/31 03:54:19 jeff Exp $");
+__FBSDID("$FreeBSD: src/sys/kern/vfs_syscalls.c,v 1.415 2006/06/05 13:34:23 rwatson Exp $");
 
 #include "opt_compat.h"
 #include "opt_mac.h"
@@ -183,6 +183,8 @@
 	int error;
 	struct nameidata nd;
 
+	AUDIT_ARG(cmd, uap->cmd);
+	AUDIT_ARG(uid, uap->uid);
 	if (jailed(td->td_ucred) && !prison_quotas)
 		return (EPERM);
 	NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE | AUDITVNODE1,
@@ -1303,6 +1305,7 @@
 	struct nameidata nd;
 	int vfslocked;
 
+	AUDIT_ARG(mode, mode);
 restart:
 	bwillwrite();
 	NDINIT(&nd, CREATE, LOCKPARENT | SAVENAME | MPSAFE | AUDITVNODE1,
@@ -1518,6 +1521,7 @@
 		if ((error = copyinstr(path, syspath, MAXPATHLEN, NULL)) != 0)
 			goto out;
 	}
+	AUDIT_ARG(text, syspath);
 restart:
 	bwillwrite();
 	NDINIT(&nd, CREATE, LOCKPARENT | SAVENAME | MPSAFE | AUDITVNODE1,

==== //depot/projects/trustedbsd/base/sys/nfsserver/nfs_serv.c#41 (text+ko) ====

@@ -33,7 +33,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/nfsserver/nfs_serv.c,v 1.164 2006/03/31 03:54:19 jeff Exp $");
+__FBSDID("$FreeBSD: src/sys/nfsserver/nfs_serv.c,v 1.165 2006/06/05 14:48:02 kib Exp $");
 
 /*
  * nfs version 2 and 3 server calls to vnode ops
@@ -570,6 +570,10 @@
 
 			error = lookup(&ind);
 			ind.ni_dvp = NULL;
+			if (ind.ni_cnd.cn_flags & GIANTHELD) {
+				mtx_unlock(&Giant);
+				ind.ni_cnd.cn_flags &= ~GIANTHELD;
+			}
 
 			if (error == 0) {
 				/*
@@ -1918,6 +1922,10 @@
 
 			error = lookup(&nd);
 			nd.ni_dvp = NULL;
+			if (nd.ni_cnd.cn_flags & GIANTHELD) {
+				mtx_unlock(&Giant);
+				nd.ni_cnd.cn_flags &= ~GIANTHELD;
+			}
 			if (error)
 				goto ereply;
 
@@ -2145,6 +2153,10 @@
 
 		error = lookup(&nd);
 		nd.ni_dvp = NULL;
+		if (nd.ni_cnd.cn_flags & GIANTHELD) {
+			mtx_unlock(&Giant);
+			nd.ni_cnd.cn_flags &= ~GIANTHELD;
+		}
 
 		if (error)
 			goto out;
@@ -2886,6 +2898,10 @@
 
 		error = lookup(&nd);
 		nd.ni_dvp = NULL;
+		if (nd.ni_cnd.cn_flags & GIANTHELD) {
+			mtx_unlock(&Giant);
+			nd.ni_cnd.cn_flags &= ~GIANTHELD;
+		}
 
 		if (error == 0) {
 			bzero((caddr_t)fhp, sizeof(nfh));

==== //depot/projects/trustedbsd/base/sys/nfsserver/nfs_srvsubs.c#23 (text+ko) ====

@@ -33,7 +33,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/nfsserver/nfs_srvsubs.c,v 1.140 2006/04/02 04:24:57 cel Exp $");
+__FBSDID("$FreeBSD: src/sys/nfsserver/nfs_srvsubs.c,v 1.141 2006/06/05 14:48:02 kib Exp $");
 
 /*
  * These functions support the macros and help fiddle mbuf chains for
@@ -876,6 +876,10 @@
 	}
 	if (!lockleaf)
 		cnp->cn_flags &= ~LOCKLEAF;
+	if (cnp->cn_flags & GIANTHELD) {
+		mtx_unlock(&Giant);
+		cnp->cn_flags &= ~GIANTHELD;
+	}
 
 	/*
 	 * nfs_namei() guarentees that fields will not contain garbage

==== //depot/projects/trustedbsd/base/sys/security/audit/audit.c#6 (text) ====

@@ -27,7 +27,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/security/audit/audit.c,v 1.12 2006/03/19 17:34:00 rwatson Exp $
+ * $FreeBSD: src/sys/security/audit/audit.c,v 1.15 2006/06/05 14:48:17 rwatson Exp $
  */
 
 #include <sys/param.h>
@@ -136,16 +136,14 @@
  * either new records are in the queue, or a log replacement is taking
  * place.
  */
-struct cv		audit_cv;
+struct cv		audit_worker_cv;
 
 /*
- * Condition variable to signal to the worker that it has work to do:
- * either new records are in the queue, or a log replacement is taking
- * place.
- *
- * XXXRW: This description is incorrect.
+ * Condition variable to flag when crossing the low watermark, meaning that
+ * threads blocked due to hitting the high watermark can wake up and continue
+ * to commit records.
  */
-struct cv		audit_commit_cv;
+struct cv		audit_watermark_cv;
 
 /*
  * Condition variable for  auditing threads wait on when in fail-stop mode.
@@ -239,11 +237,11 @@
 	audit_qctrl.aq_minfree = AU_FS_MINFREE;
 
 	mtx_init(&audit_mtx, "audit_mtx", NULL, MTX_DEF);
-	cv_init(&audit_cv, "audit_cv");
-	cv_init(&audit_commit_cv, "audit_commit_cv");
+	cv_init(&audit_worker_cv, "audit_worker_cv");
+	cv_init(&audit_watermark_cv, "audit_watermark_cv");
 	cv_init(&audit_fail_cv, "audit_fail_cv");
 
-	audit_record_zone = uma_zcreate("audit_record_zone",
+	audit_record_zone = uma_zcreate("audit_record",
 	    sizeof(struct kaudit_record), audit_record_ctor,
 	    audit_record_dtor, NULL, NULL, UMA_ALIGN_PTR, 0);
 
@@ -334,6 +332,9 @@
 void
 audit_commit(struct kaudit_record *ar, int error, int retval)
 {
+	au_event_t event;
+	au_class_t class;
+	au_id_t auid;
 	int sorf;
 	struct au_mask *aumask;
 
@@ -379,14 +380,18 @@
 		break;
 	}
 
-	if (au_preselect(ar->k_ar.ar_event, aumask, sorf) != 0)
-		ar->k_ar_commit |= AR_COMMIT_KERNEL;
+	auid = ar->k_ar.ar_subj_auid;
+	event = ar->k_ar.ar_event;
+	class = au_event_class(event);
 
-	/*
-	 * XXXRW: Why is this necessary?  Should we ever accept a record that
-	 * we're not willing to commit?
-	 */
-	if ((ar->k_ar_commit & (AR_COMMIT_USER | AR_COMMIT_KERNEL)) == 0) {
+	ar->k_ar_commit |= AR_COMMIT_KERNEL;
+	if (au_preselect(event, class, aumask, sorf) != 0)
+		ar->k_ar_commit |= AR_PRESELECT_TRAIL;
+	if (audit_pipe_preselect(auid, event, class, sorf,
+	    ar->k_ar_commit & AR_PRESELECT_TRAIL) != 0)
+		ar->k_ar_commit |= AR_PRESELECT_PIPE;
+	if ((ar->k_ar_commit & (AR_PRESELECT_TRAIL | AR_PRESELECT_PIPE)) ==
+	    0) {
 		mtx_lock(&audit_mtx);
 		audit_pre_q_len--;
 		mtx_unlock(&audit_mtx);
@@ -427,7 +432,7 @@
 	while (audit_q_len >= audit_qctrl.aq_hiwater) {
 		AUDIT_PRINTF(("audit_commit: sleeping to wait for "
 		   "audit queue to drain below high water mark\n"));
-		cv_wait(&audit_commit_cv, &audit_mtx);
+		cv_wait(&audit_watermark_cv, &audit_mtx);
 		AUDIT_PRINTF(("audit_commit: woke up waiting for "
 		   "audit queue draining\n"));
 	}
@@ -435,7 +440,7 @@
 	TAILQ_INSERT_TAIL(&audit_q, ar, k_q);
 	audit_q_len++;
 	audit_pre_q_len--;
-	cv_signal(&audit_cv);
+	cv_signal(&audit_worker_cv);
 	mtx_unlock(&audit_mtx);
 }
 
@@ -448,8 +453,10 @@
 void
 audit_syscall_enter(unsigned short code, struct thread *td)
 {
-	int audit_event;
 	struct au_mask *aumask;
+	au_class_t class;
+	au_event_t event;
+	au_id_t auid;
 
 	KASSERT(td->td_ar == NULL, ("audit_syscall_enter: td->td_ar != NULL"));
 
@@ -466,15 +473,16 @@
 	if (code >= td->td_proc->p_sysent->sv_size)
 		return;
 
-	audit_event = td->td_proc->p_sysent->sv_table[code].sy_auevent;
-	if (audit_event == AUE_NULL)
+	event = td->td_proc->p_sysent->sv_table[code].sy_auevent;
+	if (event == AUE_NULL)
 		return;
 
 	/*
 	 * Check which audit mask to use; either the kernel non-attributable
 	 * event mask or the process audit mask.
 	 */
-	if (td->td_proc->p_au->ai_auid == AU_DEFAUDITID)
+	auid = td->td_proc->p_au->ai_auid;
+	if (auid == AU_DEFAUDITID)
 		aumask = &audit_nae_mask;
 	else
 		aumask = &td->td_proc->p_au->ai_mask;
@@ -483,8 +491,8 @@
 	 * Allocate an audit record, if preselection allows it, and store
 	 * in the thread for later use.
 	 */
-	if (au_preselect(audit_event, aumask,
-			AU_PRS_FAILURE | AU_PRS_SUCCESS)) {
+	class = au_event_class(event);
+	if (au_preselect(event, class, aumask, AU_PRS_BOTH)) {
 		/*
 		 * If we're out of space and need to suspend unprivileged
 		 * processes, do that here rather than trying to allocate
@@ -501,8 +509,10 @@
 			cv_wait(&audit_fail_cv, &audit_mtx);
 			panic("audit_failing_stop: thread continued");
 		}
-		td->td_ar = audit_new(audit_event, td);
-	} else
+		td->td_ar = audit_new(event, td);
+	} else if (audit_pipe_preselect(auid, event, class, AU_PRS_BOTH, 0))
+		td->td_ar = audit_new(event, td);
+	else
 		td->td_ar = NULL;
 }
 

==== //depot/projects/trustedbsd/base/sys/security/audit/audit_bsm_klib.c#4 (text) ====

@@ -27,7 +27,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/security/audit/audit_bsm_klib.c,v 1.3 2006/06/01 15:38:30 csjp Exp $
+ * $FreeBSD: src/sys/security/audit/audit_bsm_klib.c,v 1.4 2006/06/05 14:48:17 rwatson Exp $
  */
 
 #include <sys/param.h>
@@ -154,24 +154,21 @@
  * event is part of against the given mask.
  */
 int
-au_preselect(au_event_t event, au_mask_t *mask_p, int sorf)
+au_preselect(au_event_t event, au_class_t class, au_mask_t *mask_p, int sorf)
 {
 	au_class_t effmask = 0;
-	au_class_t ae_class;
 
 	if (mask_p == NULL)
 		return (-1);
 
-	ae_class = au_event_class(event);
-
 	/*
 	 * Perform the actual check of the masks against the event.
 	 */
 	if (sorf & AU_PRS_SUCCESS)
-		effmask |= (mask_p->am_success & ae_class);
+		effmask |= (mask_p->am_success & class);
 
 	if (sorf & AU_PRS_FAILURE)
-		effmask |= (mask_p->am_failure & ae_class);
+		effmask |= (mask_p->am_failure & class);
 
 	if (effmask)
 		return (1);

==== //depot/projects/trustedbsd/base/sys/security/audit/audit_ioctl.h#2 (text) ====

@@ -25,7 +25,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/security/audit/audit_ioctl.h,v 1.2 2006/03/19 17:34:00 rwatson Exp $
+ * $FreeBSD: src/sys/security/audit/audit_ioctl.h,v 1.3 2006/06/05 14:48:17 rwatson Exp $
  */
 
 #ifndef _SECURITY_AUDIT_AUDIT_IOCTL_H_
@@ -34,6 +34,25 @@
 #define	AUDITPIPE_IOBASE	'A'
 
 /*
+ * Data structures used for complex ioctl arguments.  Do not change existing
+ * structures, add new revised ones to be used by new ioctls, and keep the
+ * old structures and ioctls for backwards compatibility.
+ */
+struct auditpipe_ioctl_preselect {
+	au_id_t		aip_auid;
+	au_mask_t	aip_mask;
+};
+
+/*
+ * Possible modes of operation for audit pipe preselection.
+ */
+#define	AUDITPIPE_PRESELECT_MODE_TRAIL	1	/* Global audit trail. */
+#define	AUDITPIPE_PRESELECT_MODE_LOCAL	2	/* Local audit trail. */
+#ifdef NOTYET
+#define	AUDITPIPE_PRESELECT_MODE_PRIORITY	3	/* Prioritized trail. */
+#endif
+
+/*
  * Ioctls to read and control the behavior of individual audit pipe devices.
  */
 #define	AUDITPIPE_GET_QLEN		_IOR(AUDITPIPE_IOBASE, 1, u_int)
@@ -41,6 +60,19 @@
 #define	AUDITPIPE_SET_QLIMIT		_IOW(AUDITPIPE_IOBASE, 3, u_int)
 #define	AUDITPIPE_GET_QLIMIT_MIN	_IOR(AUDITPIPE_IOBASE, 4, u_int)
 #define	AUDITPIPE_GET_QLIMIT_MAX	_IOR(AUDITPIPE_IOBASE, 5, u_int)
+#define	AUDITPIPE_GET_PRESELECT_FLAGS	_IOR(AUDITPIPE_IOBASE, 6, au_mask_t)
+#define	AUDITPIPE_SET_PRESELECT_FLAGS	_IOW(AUDITPIPE_IOBASE, 7, au_mask_t)
+#define	AUDITPIPE_GET_PRESELECT_NAFLAGS	_IOR(AUDITPIPE_IOBASE, 8, au_mask_t)
+#define	AUDITPIPE_SET_PRESELECT_NAFLAGS	_IOW(AUDITPIPE_IOBASE, 9, au_mask_t)
+#define	AUDITPIPE_GET_PRESELECT_AUID	_IOR(AUDITPIPE_IOBASE, 10,	\
+					    struct auditpipe_ioctl_preselect)
+#define	AUDITPIPE_SET_PRESELECT_AUID	_IOW(AUDITPIPE_IOBASE, 11,	\
+					    struct auditpipe_ioctl_preselect)
+#define	AUDITPIPE_DELETE_PRESELECT_AUID	_IOW(AUDITPIPE_IOBASE, 12, au_id_t)
+#define	AUDITPIPE_FLUSH_PRESELECT_AUID	_IO(AUDITPIPE_IOBASE, 13)
+#define	AUDITPIPE_GET_PRESELECT_MODE	_IOR(AUDITPIPE_IOBASE, 14, int)
+#define	AUDITPIPE_SET_PRESELECT_MODE	_IOW(AUDITPIPE_IOBASE, 15, int)
+#define	AUDITPIPE_FLUSH			_IO(AUDITPIPE_IOBASE, 16)
 
 /*
  * Ioctls to retrieve audit pipe statistics.

==== //depot/projects/trustedbsd/base/sys/security/audit/audit_pipe.c#5 (text) ====

@@ -25,7 +25,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/security/audit/audit_pipe.c,v 1.6 2006/03/19 15:39:03 rwatson Exp $
+ * $FreeBSD: src/sys/security/audit/audit_pipe.c,v 1.7 2006/06/05 14:48:17 rwatson Exp $
  */
 
 #include <sys/param.h>
@@ -55,7 +55,8 @@
  * Implementation of a clonable special device providing a live stream of BSM
  * audit data.  This is a "tee" of the data going to the file.  It provides
  * unreliable but timely access to audit events.  Consumers of this interface
- * should be very careful to avoid introducing event cycles.
+ * should be very careful to avoid introducing event cycles.  Consumers may
+ * express interest via a set of preselection ioctls.
  */
 
 /*
@@ -64,6 +65,8 @@
 static MALLOC_DEFINE(M_AUDIT_PIPE, "audit_pipe", "Audit pipes");
 static MALLOC_DEFINE(M_AUDIT_PIPE_ENTRY, "audit_pipeent",
     "Audit pipe entries and buffers");
+static MALLOC_DEFINE(M_AUDIT_PIPE_PRESELECT, "audit_pipe_preselect",
+    "Audit pipe preselection structure");
 
 /*
  * Audit pipe buffer parameters.
@@ -82,6 +85,23 @@
 };
 
 /*
+ * Audit pipes allow processes to express "interest" in the set of records
+ * that are delivered via the pipe.  They do this in a similar manner to the
+ * mechanism for audit trail configuration, by expressing two global masks,
+ * and optionally expressing per-auid masks.  The following data structure is
+ * the per-auid mask description.  The global state is stored in the audit
+ * pipe data structure.
+ *
+ * We may want to consider a more space/time-efficient data structure once
+ * usage patterns for per-auid specifications are clear.
+ */
+struct audit_pipe_preselect {
+	au_id_t					 app_auid;
+	au_mask_t				 app_mask;
+	TAILQ_ENTRY(audit_pipe_preselect)	 app_list;
+};
+
+/*
  * Description of an individual audit_pipe.  Consists largely of a bounded
  * length queue.
  */
@@ -102,21 +122,38 @@
 	u_int64_t			 ap_drops;	/* Records dropped. */
 	u_int64_t			 ap_truncates;	/* Records too long. */
 
+	/*
+	 * Fields relating to pipe interest: global masks for unmatched
+	 * processes (attributable, non-attributable), and a list of specific
+	 * interest specifications by auid.
+	 */
+	int				 ap_preselect_mode;
+	au_mask_t			 ap_preselect_flags;
+	au_mask_t			 ap_preselect_naflags;
+	TAILQ_HEAD(, audit_pipe_preselect)	ap_preselect_list;
+
+	/*
+	 * Current pending record list.
+	 */
 	TAILQ_HEAD(, audit_pipe_entry)	 ap_queue;
 
+	/*
+	 * Global pipe list.
+	 */
 	TAILQ_ENTRY(audit_pipe)		 ap_list;
 };
 
 /*
- * Global list of audit pipes, mutex to protect it and the pipes.  Finder
+ * Global list of audit pipes, mutex to protect it and the pipes.  Finer
  * grained locking may be desirable at some point.
  */
 static TAILQ_HEAD(, audit_pipe)	 audit_pipe_list;
 static struct mtx		 audit_pipe_mtx;
 
 /*
- * This CV is used to wakeup on an audit record write.  Eventually, it should
- * probably be per-pipe.
+ * This CV is used to wakeup on an audit record write.  Eventually, it might
+ * be per-pipe to avoid unnecessary wakeups when several pipes with different
+ * preselection masks are present.
  */
 static struct cv		 audit_pipe_cv;
 
@@ -138,7 +175,7 @@
 
 static struct cdevsw	audit_pipe_cdevsw = {
 	.d_version =	D_VERSION,
-	.d_flags =	D_PSEUDO,
+	.d_flags =	D_PSEUDO | D_NEEDGIANT,
 	.d_open =	audit_pipe_open,
 	.d_close =	audit_pipe_close,
 	.d_read =	audit_pipe_read,
@@ -167,7 +204,185 @@
 }
 
 /*
- * Apparent individual record to a queue -- allocate queue-local buffer, and
+ * Find an audit pipe preselection specification for an auid, if any.
+ */
+static struct audit_pipe_preselect *
+audit_pipe_preselect_find(struct audit_pipe *ap, au_id_t auid)
+{
+	struct audit_pipe_preselect *app;
+
+	mtx_assert(&audit_pipe_mtx, MA_OWNED);
+
+	TAILQ_FOREACH(app, &ap->ap_preselect_list, app_list) {
+		if (app->app_auid == auid)
+			return (app);
+	}
+	return (NULL);
+}
+
+/*
+ * Query the per-pipe mask for a specific auid.
+ */
+static int
+audit_pipe_preselect_get(struct audit_pipe *ap, au_id_t auid,
+    au_mask_t *maskp)
+{
+	struct audit_pipe_preselect *app;
+	int error;
+
+	mtx_lock(&audit_pipe_mtx);
+	app = audit_pipe_preselect_find(ap, auid);
+	if (app != NULL) {
+		*maskp = app->app_mask;
+		error = 0;
+	} else
+		error = ENOENT;
+	mtx_unlock(&audit_pipe_mtx);
+	return (error);
+}
+
+/*
+ * Set the per-pipe mask for a specific auid.  Add a new entry if needed;
+ * otherwise, update the current entry.
+ */
+static void
+audit_pipe_preselect_set(struct audit_pipe *ap, au_id_t auid, au_mask_t mask)
+{
+	struct audit_pipe_preselect *app, *app_new;
+
+	/*
+	 * Pessimistically assume that the auid doesn't already have a mask
+	 * set, and allocate.  We will free it if it is unneeded.
+	 */
+	app_new = malloc(sizeof(*app_new), M_AUDIT_PIPE_PRESELECT, M_WAITOK);
+	mtx_lock(&audit_pipe_mtx);
+	app = audit_pipe_preselect_find(ap, auid);
+	if (app == NULL) {
+		app = app_new;
+		app_new = NULL;
+		app->app_auid = auid;
+		TAILQ_INSERT_TAIL(&ap->ap_preselect_list, app, app_list);
+	}
+	app->app_mask = mask;
+	mtx_unlock(&audit_pipe_mtx);
+	if (app_new != NULL)
+		free(app_new, M_AUDIT_PIPE_PRESELECT);
+}
+
+/*
+ * Delete a per-auid mask on an audit pipe.
+ */
+static int
+audit_pipe_preselect_delete(struct audit_pipe *ap, au_id_t auid)
+{
+	struct audit_pipe_preselect *app;
+	int error;
+
+	mtx_lock(&audit_pipe_mtx);
+	app = audit_pipe_preselect_find(ap, auid);
+	if (app != NULL) {
+		TAILQ_REMOVE(&ap->ap_preselect_list, app, app_list);
+		error = 0;
+	} else
+		error = ENOENT;
+	mtx_unlock(&audit_pipe_mtx);
+	if (app != NULL)
+		free(app, M_AUDIT_PIPE_PRESELECT);
+	return (error);
+}
+
+/*
+ * Delete all per-auid masks on an audit pipe.
+ */
+static void
+audit_pipe_preselect_flush_locked(struct audit_pipe *ap)
+{
+	struct audit_pipe_preselect *app;
+
+	mtx_assert(&audit_pipe_mtx, MA_OWNED);
+
+	while ((app = TAILQ_FIRST(&ap->ap_preselect_list)) != NULL) {
+		TAILQ_REMOVE(&ap->ap_preselect_list, app, app_list);
+		free(app, M_AUDIT_PIPE_PRESELECT);
+	}
+}
+
+static void
+audit_pipe_preselect_flush(struct audit_pipe *ap)
+{
+
+	mtx_lock(&audit_pipe_mtx);
+	audit_pipe_preselect_flush_locked(ap);
+	mtx_unlock(&audit_pipe_mtx);
+}
+
+/*
+ * Determine whether a specific audit pipe matches a record with these
+ * properties.  Algorithm is as follows:
+ *
+ * - If the pipe is configured to track the default trail configuration, then
+ *   use the results of global preselection matching.
+ * - If not, search for a specifically configured auid entry matching the
+ *   event.  If an entry is found, use that.
+ * - Otherwise, use the default flags or naflags configured for the pipe.
+ */
+static int
+audit_pipe_preselect_check(struct audit_pipe *ap, au_id_t auid,
+    au_event_t event, au_class_t class, int sorf, int trail_preselect)
+{
+	struct audit_pipe_preselect *app;
+
+	mtx_assert(&audit_pipe_mtx, MA_OWNED);
+
+	switch (ap->ap_preselect_mode) {
+	case AUDITPIPE_PRESELECT_MODE_TRAIL:
+		return (trail_preselect);
+
+	case AUDITPIPE_PRESELECT_MODE_LOCAL:
+		app = audit_pipe_preselect_find(ap, auid);
+		if (app == NULL) {
+			if (auid == AU_DEFAUDITID)
+				return (au_preselect(event, class,
+				    &ap->ap_preselect_naflags, sorf));
+			else
+				return (au_preselect(event, class,
+				    &ap->ap_preselect_flags, sorf));
+		} else
+			return (au_preselect(event, class, &app->app_mask,
+			    sorf));
+
+	default:
+		panic("audit_pipe_preselect_check: mode %d",
+		    ap->ap_preselect_mode);
+	}
+
+	return (0);
+}
+
+/*
+ * Determine whether there exists a pipe interested in a record with specific
+ * properties.
+ */
+int
+audit_pipe_preselect(au_id_t auid, au_event_t event, au_class_t class,
+    int sorf, int trail_preselect)
+{
+	struct audit_pipe *ap;
+
+	mtx_lock(&audit_pipe_mtx);
+	TAILQ_FOREACH(ap, &audit_pipe_list, ap_list) {
+		if (audit_pipe_preselect_check(ap, auid, event, class, sorf,
+		    trail_preselect)) {
+			mtx_unlock(&audit_pipe_mtx);
+			return (1);
+		}
+	}
+	mtx_unlock(&audit_pipe_mtx);
+	return (0);
+}
+
+/*
+ * Append individual record to a queue -- allocate queue-local buffer, and
  * add to the queue.  We try to drop from the head of the queue so that more
  * recent events take precedence over older ones, but if allocation fails we
  * do drop the new event.
@@ -219,7 +434,38 @@
  * interface, which arranges for them to be delivered to pipe queues.
  */
 void
-audit_pipe_submit(void *record, u_int record_len)
+audit_pipe_submit(au_id_t auid, au_event_t event, au_class_t class, int sorf,
+    int trail_select, void *record, u_int record_len)
+{
+	struct audit_pipe *ap;
+
+	/*
+	 * Lockless read to avoid mutex overhead if pipes are not in use.
+	 */
+	if (TAILQ_FIRST(&audit_pipe_list) == NULL)
+		return;
+
+	mtx_lock(&audit_pipe_mtx);
+	TAILQ_FOREACH(ap, &audit_pipe_list, ap_list) {
+		if (audit_pipe_preselect_check(ap, auid, event, class, sorf,
+		    trail_select))
+			audit_pipe_append(ap, record, record_len);
+	}
+	audit_pipe_records++;
+	mtx_unlock(&audit_pipe_mtx);
+	cv_signal(&audit_pipe_cv);
+}
+
+/*
+ * audit_pipe_submit_user(): the same as audit_pipe_submit(), except that
+ * since we don't currently have selection information available, it is
+ * delivered to the pipe unconditionally.
+ *
+ * XXXRW: This is a bug.  The BSM check routine for submitting a user record

>>> TRUNCATED FOR MAIL (1000 lines) <<<


More information about the trustedbsd-cvs mailing list