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