From owner-p4-projects@FreeBSD.ORG Mon Jun 5 15:18:14 2006 Return-Path: X-Original-To: p4-projects@freebsd.org Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 71D9616A5E2; Mon, 5 Jun 2006 15:18:13 +0000 (UTC) X-Original-To: perforce@freebsd.org Delivered-To: perforce@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id D627016A513 for ; Mon, 5 Jun 2006 15:18:12 +0000 (UTC) (envelope-from bb+lists.freebsd.perforce@cyrus.watson.org) Received: from repoman.freebsd.org (repoman.freebsd.org [216.136.204.115]) by mx1.FreeBSD.org (Postfix) with ESMTP id 7EE2A43D48 for ; Mon, 5 Jun 2006 15:18:12 +0000 (GMT) (envelope-from bb+lists.freebsd.perforce@cyrus.watson.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.13.6/8.13.6) with ESMTP id k55FGSDl097261 for ; Mon, 5 Jun 2006 15:16:28 GMT (envelope-from bb+lists.freebsd.perforce@cyrus.watson.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.6/8.13.4/Submit) id k55FGR44097257 for perforce@freebsd.org; Mon, 5 Jun 2006 15:16:27 GMT (envelope-from bb+lists.freebsd.perforce@cyrus.watson.org) Date: Mon, 5 Jun 2006 15:16:27 GMT Message-Id: <200606051516.k55FGR44097257@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to bb+lists.freebsd.perforce@cyrus.watson.org using -f From: Robert Watson To: Perforce Change Reviews Cc: Subject: PERFORCE change 98565 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 05 Jun 2006 15:18:20 -0000 http://perforce.freebsd.org/chv.cgi?CH=98565 Change 98565 by rwatson@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 -__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 -__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 -__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 -__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 @@ -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 @@ -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 @@ -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) <<<