109daf1c8SRobert Watson /*- 209daf1c8SRobert Watson * Copyright (c) 2006 Robert N. M. Watson 38f8dedbeSRobert Watson * Copyright (c) 2008-2009 Apple, Inc. 409daf1c8SRobert Watson * All rights reserved. 509daf1c8SRobert Watson * 609daf1c8SRobert Watson * This software was developed by Robert Watson for the TrustedBSD Project. 709daf1c8SRobert Watson * 809daf1c8SRobert Watson * Redistribution and use in source and binary forms, with or without 909daf1c8SRobert Watson * modification, are permitted provided that the following conditions 1009daf1c8SRobert Watson * are met: 1109daf1c8SRobert Watson * 1. Redistributions of source code must retain the above copyright 1209daf1c8SRobert Watson * notice, this list of conditions and the following disclaimer. 1309daf1c8SRobert Watson * 2. Redistributions in binary form must reproduce the above copyright 1409daf1c8SRobert Watson * notice, this list of conditions and the following disclaimer in the 1509daf1c8SRobert Watson * documentation and/or other materials provided with the distribution. 1609daf1c8SRobert Watson * 1709daf1c8SRobert Watson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1809daf1c8SRobert Watson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1909daf1c8SRobert Watson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2009daf1c8SRobert Watson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2109daf1c8SRobert Watson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2209daf1c8SRobert Watson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2309daf1c8SRobert Watson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2409daf1c8SRobert Watson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2509daf1c8SRobert Watson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2609daf1c8SRobert Watson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2709daf1c8SRobert Watson * SUCH DAMAGE. 2809daf1c8SRobert Watson */ 2909daf1c8SRobert Watson 3009daf1c8SRobert Watson #include <sys/param.h> 3109daf1c8SRobert Watson #include <sys/condvar.h> 3209daf1c8SRobert Watson #include <sys/conf.h> 3309daf1c8SRobert Watson #include <sys/eventhandler.h> 3409daf1c8SRobert Watson #include <sys/filio.h> 3509daf1c8SRobert Watson #include <sys/kernel.h> 3609daf1c8SRobert Watson #include <sys/lock.h> 3709daf1c8SRobert Watson #include <sys/malloc.h> 3809daf1c8SRobert Watson #include <sys/mutex.h> 3909daf1c8SRobert Watson #include <sys/poll.h> 4009daf1c8SRobert Watson #include <sys/proc.h> 4109daf1c8SRobert Watson #include <sys/queue.h> 42846f37f1SRobert Watson #include <sys/rwlock.h> 4309daf1c8SRobert Watson #include <sys/selinfo.h> 4409daf1c8SRobert Watson #include <sys/sigio.h> 4509daf1c8SRobert Watson #include <sys/signal.h> 4609daf1c8SRobert Watson #include <sys/signalvar.h> 475a9d15cdSRobert Watson #include <sys/sx.h> 4809daf1c8SRobert Watson #include <sys/systm.h> 4909daf1c8SRobert Watson #include <sys/uio.h> 5009daf1c8SRobert Watson 5109daf1c8SRobert Watson #include <security/audit/audit.h> 52ed708e1fSRobert Watson #include <security/audit/audit_ioctl.h> 5309daf1c8SRobert Watson #include <security/audit/audit_private.h> 5409daf1c8SRobert Watson 5509daf1c8SRobert Watson /* 5609daf1c8SRobert Watson * Implementation of a clonable special device providing a live stream of BSM 57d2f6bb07SRobert Watson * audit data. Consumers receive a "tee" of the system audit trail by 58d2f6bb07SRobert Watson * default, but may also define alternative event selections using ioctls. 59d2f6bb07SRobert Watson * This interface provides unreliable but timely access to audit events. 60d2f6bb07SRobert Watson * Consumers should be very careful to avoid introducing event cycles. 6109daf1c8SRobert Watson */ 6209daf1c8SRobert Watson 6309daf1c8SRobert Watson /* 6409daf1c8SRobert Watson * Memory types. 6509daf1c8SRobert Watson */ 6609daf1c8SRobert Watson static MALLOC_DEFINE(M_AUDIT_PIPE, "audit_pipe", "Audit pipes"); 6709daf1c8SRobert Watson static MALLOC_DEFINE(M_AUDIT_PIPE_ENTRY, "audit_pipeent", 6809daf1c8SRobert Watson "Audit pipe entries and buffers"); 697a9d5a45SWojciech A. Koszek static MALLOC_DEFINE(M_AUDIT_PIPE_PRESELECT, "audit_pipe_presel", 70e257c20eSRobert Watson "Audit pipe preselection structure"); 7109daf1c8SRobert Watson 7209daf1c8SRobert Watson /* 7309daf1c8SRobert Watson * Audit pipe buffer parameters. 7409daf1c8SRobert Watson */ 756a4bde1bSRobert Watson #define AUDIT_PIPE_QLIMIT_DEFAULT (128) 768f8dedbeSRobert Watson #define AUDIT_PIPE_QLIMIT_MIN (1) 7709daf1c8SRobert Watson #define AUDIT_PIPE_QLIMIT_MAX (1024) 7809daf1c8SRobert Watson 7909daf1c8SRobert Watson /* 8009daf1c8SRobert Watson * Description of an entry in an audit_pipe. 8109daf1c8SRobert Watson */ 8209daf1c8SRobert Watson struct audit_pipe_entry { 8309daf1c8SRobert Watson void *ape_record; 8409daf1c8SRobert Watson u_int ape_record_len; 8509daf1c8SRobert Watson TAILQ_ENTRY(audit_pipe_entry) ape_queue; 8609daf1c8SRobert Watson }; 8709daf1c8SRobert Watson 8809daf1c8SRobert Watson /* 89e257c20eSRobert Watson * Audit pipes allow processes to express "interest" in the set of records 90e257c20eSRobert Watson * that are delivered via the pipe. They do this in a similar manner to the 91e257c20eSRobert Watson * mechanism for audit trail configuration, by expressing two global masks, 92e257c20eSRobert Watson * and optionally expressing per-auid masks. The following data structure is 93e257c20eSRobert Watson * the per-auid mask description. The global state is stored in the audit 94e257c20eSRobert Watson * pipe data structure. 95e257c20eSRobert Watson * 96e257c20eSRobert Watson * We may want to consider a more space/time-efficient data structure once 97e257c20eSRobert Watson * usage patterns for per-auid specifications are clear. 98e257c20eSRobert Watson */ 99e257c20eSRobert Watson struct audit_pipe_preselect { 100e257c20eSRobert Watson au_id_t app_auid; 101e257c20eSRobert Watson au_mask_t app_mask; 102e257c20eSRobert Watson TAILQ_ENTRY(audit_pipe_preselect) app_list; 103e257c20eSRobert Watson }; 104e257c20eSRobert Watson 105e257c20eSRobert Watson /* 10609daf1c8SRobert Watson * Description of an individual audit_pipe. Consists largely of a bounded 10709daf1c8SRobert Watson * length queue. 10809daf1c8SRobert Watson */ 10909daf1c8SRobert Watson #define AUDIT_PIPE_ASYNC 0x00000001 11009daf1c8SRobert Watson #define AUDIT_PIPE_NBIO 0x00000002 11109daf1c8SRobert Watson struct audit_pipe { 11209daf1c8SRobert Watson u_int ap_flags; 11309daf1c8SRobert Watson 11409daf1c8SRobert Watson struct selinfo ap_selinfo; 11509daf1c8SRobert Watson struct sigio *ap_sigio; 11609daf1c8SRobert Watson 117846f37f1SRobert Watson /* 118846f37f1SRobert Watson * Per-pipe mutex protecting most fields in this data structure. 119846f37f1SRobert Watson */ 1205a9d15cdSRobert Watson struct mtx ap_mtx; 1215a9d15cdSRobert Watson 1225a9d15cdSRobert Watson /* 1235a9d15cdSRobert Watson * Per-pipe sleep lock serializing user-generated reads and flushes. 1245a9d15cdSRobert Watson * uiomove() is called to copy out the current head record's data 1255a9d15cdSRobert Watson * while the record remains in the queue, so we prevent other threads 1265a9d15cdSRobert Watson * from removing it using this lock. 1275a9d15cdSRobert Watson */ 1285a9d15cdSRobert Watson struct sx ap_sx; 129846f37f1SRobert Watson 130846f37f1SRobert Watson /* 131846f37f1SRobert Watson * Condition variable to signal when data has been delivered to a 132846f37f1SRobert Watson * pipe. 133846f37f1SRobert Watson */ 134846f37f1SRobert Watson struct cv ap_cv; 135846f37f1SRobert Watson 136cff9c52eSRobert Watson /* 137cff9c52eSRobert Watson * Various queue-reated variables: qlen and qlimit are a count of 138cff9c52eSRobert Watson * records in the queue; qbyteslen is the number of bytes of data 139cff9c52eSRobert Watson * across all records, and qoffset is the amount read so far of the 140cff9c52eSRobert Watson * first record in the queue. The number of bytes available for 141cff9c52eSRobert Watson * reading in the queue is qbyteslen - qoffset. 142cff9c52eSRobert Watson */ 14309daf1c8SRobert Watson u_int ap_qlen; 14409daf1c8SRobert Watson u_int ap_qlimit; 145cff9c52eSRobert Watson u_int ap_qbyteslen; 146cff9c52eSRobert Watson u_int ap_qoffset; 14709daf1c8SRobert Watson 148e4565e20SRobert Watson /* 149e4565e20SRobert Watson * Per-pipe operation statistics. 150e4565e20SRobert Watson */ 15109daf1c8SRobert Watson u_int64_t ap_inserts; /* Records added. */ 15209daf1c8SRobert Watson u_int64_t ap_reads; /* Records read. */ 15309daf1c8SRobert Watson u_int64_t ap_drops; /* Records dropped. */ 15409daf1c8SRobert Watson 155e257c20eSRobert Watson /* 156e257c20eSRobert Watson * Fields relating to pipe interest: global masks for unmatched 157e257c20eSRobert Watson * processes (attributable, non-attributable), and a list of specific 158e257c20eSRobert Watson * interest specifications by auid. 159e257c20eSRobert Watson */ 160e257c20eSRobert Watson int ap_preselect_mode; 161e257c20eSRobert Watson au_mask_t ap_preselect_flags; 162e257c20eSRobert Watson au_mask_t ap_preselect_naflags; 163e257c20eSRobert Watson TAILQ_HEAD(, audit_pipe_preselect) ap_preselect_list; 164e257c20eSRobert Watson 165e257c20eSRobert Watson /* 1665a9d15cdSRobert Watson * Current pending record list. Protected by a combination of ap_mtx 1675a9d15cdSRobert Watson * and ap_sx. Note particularly that *both* locks are required to 168efcde1e8SRobert Watson * remove a record from the head of the queue, as an in-progress read 169efcde1e8SRobert Watson * may sleep while copying and therefore cannot hold ap_mtx. 170e257c20eSRobert Watson */ 17109daf1c8SRobert Watson TAILQ_HEAD(, audit_pipe_entry) ap_queue; 17209daf1c8SRobert Watson 173e257c20eSRobert Watson /* 174e257c20eSRobert Watson * Global pipe list. 175e257c20eSRobert Watson */ 17609daf1c8SRobert Watson TAILQ_ENTRY(audit_pipe) ap_list; 17709daf1c8SRobert Watson }; 17809daf1c8SRobert Watson 1795a9d15cdSRobert Watson #define AUDIT_PIPE_LOCK(ap) mtx_lock(&(ap)->ap_mtx) 1805a9d15cdSRobert Watson #define AUDIT_PIPE_LOCK_ASSERT(ap) mtx_assert(&(ap)->ap_mtx, MA_OWNED) 1815a9d15cdSRobert Watson #define AUDIT_PIPE_LOCK_DESTROY(ap) mtx_destroy(&(ap)->ap_mtx) 1825a9d15cdSRobert Watson #define AUDIT_PIPE_LOCK_INIT(ap) mtx_init(&(ap)->ap_mtx, \ 1835a9d15cdSRobert Watson "audit_pipe_mtx", NULL, MTX_DEF) 1845a9d15cdSRobert Watson #define AUDIT_PIPE_UNLOCK(ap) mtx_unlock(&(ap)->ap_mtx) 1855a9d15cdSRobert Watson #define AUDIT_PIPE_MTX(ap) (&(ap)->ap_mtx) 1865a9d15cdSRobert Watson 1875a9d15cdSRobert Watson #define AUDIT_PIPE_SX_LOCK_DESTROY(ap) sx_destroy(&(ap)->ap_sx) 1885a9d15cdSRobert Watson #define AUDIT_PIPE_SX_LOCK_INIT(ap) sx_init(&(ap)->ap_sx, "audit_pipe_sx") 1895a9d15cdSRobert Watson #define AUDIT_PIPE_SX_XLOCK_ASSERT(ap) sx_assert(&(ap)->ap_sx, SA_XLOCKED) 1905a9d15cdSRobert Watson #define AUDIT_PIPE_SX_XLOCK_SIG(ap) sx_xlock_sig(&(ap)->ap_sx) 1915a9d15cdSRobert Watson #define AUDIT_PIPE_SX_XUNLOCK(ap) sx_xunlock(&(ap)->ap_sx) 19209daf1c8SRobert Watson 19309daf1c8SRobert Watson /* 194846f37f1SRobert Watson * Global list of audit pipes, rwlock to protect it. Individual record 195846f37f1SRobert Watson * queues on pipes are protected by per-pipe locks; these locks synchronize 196846f37f1SRobert Watson * between threads walking the list to deliver to individual pipes and add/ 197846f37f1SRobert Watson * remove of pipes, and are mostly acquired for read. 19809daf1c8SRobert Watson */ 199846f37f1SRobert Watson static TAILQ_HEAD(, audit_pipe) audit_pipe_list; 200846f37f1SRobert Watson static struct rwlock audit_pipe_lock; 201846f37f1SRobert Watson 202846f37f1SRobert Watson #define AUDIT_PIPE_LIST_LOCK_INIT() rw_init(&audit_pipe_lock, \ 203846f37f1SRobert Watson "audit_pipe_list_lock") 204b40ea294SDavide Italiano #define AUDIT_PIPE_LIST_LOCK_DESTROY() rw_destroy(&audit_pipe_lock) 205846f37f1SRobert Watson #define AUDIT_PIPE_LIST_RLOCK() rw_rlock(&audit_pipe_lock) 206846f37f1SRobert Watson #define AUDIT_PIPE_LIST_RUNLOCK() rw_runlock(&audit_pipe_lock) 207846f37f1SRobert Watson #define AUDIT_PIPE_LIST_WLOCK() rw_wlock(&audit_pipe_lock) 208846f37f1SRobert Watson #define AUDIT_PIPE_LIST_WLOCK_ASSERT() rw_assert(&audit_pipe_lock, \ 209846f37f1SRobert Watson RA_WLOCKED) 210846f37f1SRobert Watson #define AUDIT_PIPE_LIST_WUNLOCK() rw_wunlock(&audit_pipe_lock) 21109daf1c8SRobert Watson 21209daf1c8SRobert Watson /* 213b40ea294SDavide Italiano * Audit pipe device. 21409daf1c8SRobert Watson */ 215b40ea294SDavide Italiano static struct cdev *audit_pipe_dev; 216b40ea294SDavide Italiano 21709daf1c8SRobert Watson #define AUDIT_PIPE_NAME "auditpipe" 21809daf1c8SRobert Watson 21909daf1c8SRobert Watson /* 22009daf1c8SRobert Watson * Special device methods and definition. 22109daf1c8SRobert Watson */ 22209daf1c8SRobert Watson static d_open_t audit_pipe_open; 22309daf1c8SRobert Watson static d_read_t audit_pipe_read; 22409daf1c8SRobert Watson static d_ioctl_t audit_pipe_ioctl; 22509daf1c8SRobert Watson static d_poll_t audit_pipe_poll; 2260fff4cdeSRobert Watson static d_kqfilter_t audit_pipe_kqfilter; 22709daf1c8SRobert Watson 22809daf1c8SRobert Watson static struct cdevsw audit_pipe_cdevsw = { 22909daf1c8SRobert Watson .d_version = D_VERSION, 23009daf1c8SRobert Watson .d_open = audit_pipe_open, 23109daf1c8SRobert Watson .d_read = audit_pipe_read, 23209daf1c8SRobert Watson .d_ioctl = audit_pipe_ioctl, 23309daf1c8SRobert Watson .d_poll = audit_pipe_poll, 2340fff4cdeSRobert Watson .d_kqfilter = audit_pipe_kqfilter, 23509daf1c8SRobert Watson .d_name = AUDIT_PIPE_NAME, 23609daf1c8SRobert Watson }; 23709daf1c8SRobert Watson 2380fff4cdeSRobert Watson static int audit_pipe_kqread(struct knote *note, long hint); 2390fff4cdeSRobert Watson static void audit_pipe_kqdetach(struct knote *note); 2400fff4cdeSRobert Watson 241*ef9ffb85SMark Johnston static const struct filterops audit_pipe_read_filterops = { 2420fff4cdeSRobert Watson .f_isfd = 1, 2430fff4cdeSRobert Watson .f_attach = NULL, 2440fff4cdeSRobert Watson .f_detach = audit_pipe_kqdetach, 2450fff4cdeSRobert Watson .f_event = audit_pipe_kqread, 2460fff4cdeSRobert Watson }; 2470fff4cdeSRobert Watson 24809daf1c8SRobert Watson /* 24909daf1c8SRobert Watson * Some global statistics on audit pipes. 25009daf1c8SRobert Watson */ 25109daf1c8SRobert Watson static int audit_pipe_count; /* Current number of pipes. */ 25209daf1c8SRobert Watson static u_int64_t audit_pipe_ever; /* Pipes ever allocated. */ 25309daf1c8SRobert Watson static u_int64_t audit_pipe_records; /* Records seen. */ 25409daf1c8SRobert Watson static u_int64_t audit_pipe_drops; /* Global record drop count. */ 25509daf1c8SRobert Watson 25609daf1c8SRobert Watson /* 25709daf1c8SRobert Watson * Free an audit pipe entry. 25809daf1c8SRobert Watson */ 25909daf1c8SRobert Watson static void 26009daf1c8SRobert Watson audit_pipe_entry_free(struct audit_pipe_entry *ape) 26109daf1c8SRobert Watson { 26209daf1c8SRobert Watson 26309daf1c8SRobert Watson free(ape->ape_record, M_AUDIT_PIPE_ENTRY); 26409daf1c8SRobert Watson free(ape, M_AUDIT_PIPE_ENTRY); 26509daf1c8SRobert Watson } 26609daf1c8SRobert Watson 26709daf1c8SRobert Watson /* 268e257c20eSRobert Watson * Find an audit pipe preselection specification for an auid, if any. 269e257c20eSRobert Watson */ 270e257c20eSRobert Watson static struct audit_pipe_preselect * 271e257c20eSRobert Watson audit_pipe_preselect_find(struct audit_pipe *ap, au_id_t auid) 272e257c20eSRobert Watson { 273e257c20eSRobert Watson struct audit_pipe_preselect *app; 274e257c20eSRobert Watson 275846f37f1SRobert Watson AUDIT_PIPE_LOCK_ASSERT(ap); 276e257c20eSRobert Watson 277e257c20eSRobert Watson TAILQ_FOREACH(app, &ap->ap_preselect_list, app_list) { 278e257c20eSRobert Watson if (app->app_auid == auid) 279e257c20eSRobert Watson return (app); 280e257c20eSRobert Watson } 281e257c20eSRobert Watson return (NULL); 282e257c20eSRobert Watson } 283e257c20eSRobert Watson 284e257c20eSRobert Watson /* 285e257c20eSRobert Watson * Query the per-pipe mask for a specific auid. 286e257c20eSRobert Watson */ 287e257c20eSRobert Watson static int 288e257c20eSRobert Watson audit_pipe_preselect_get(struct audit_pipe *ap, au_id_t auid, 289e257c20eSRobert Watson au_mask_t *maskp) 290e257c20eSRobert Watson { 291e257c20eSRobert Watson struct audit_pipe_preselect *app; 292e257c20eSRobert Watson int error; 293e257c20eSRobert Watson 294846f37f1SRobert Watson AUDIT_PIPE_LOCK(ap); 295e257c20eSRobert Watson app = audit_pipe_preselect_find(ap, auid); 296e257c20eSRobert Watson if (app != NULL) { 297e257c20eSRobert Watson *maskp = app->app_mask; 298e257c20eSRobert Watson error = 0; 299e257c20eSRobert Watson } else 300e257c20eSRobert Watson error = ENOENT; 301846f37f1SRobert Watson AUDIT_PIPE_UNLOCK(ap); 302e257c20eSRobert Watson return (error); 303e257c20eSRobert Watson } 304e257c20eSRobert Watson 305e257c20eSRobert Watson /* 306e257c20eSRobert Watson * Set the per-pipe mask for a specific auid. Add a new entry if needed; 307e257c20eSRobert Watson * otherwise, update the current entry. 308e257c20eSRobert Watson */ 309e257c20eSRobert Watson static void 310e257c20eSRobert Watson audit_pipe_preselect_set(struct audit_pipe *ap, au_id_t auid, au_mask_t mask) 311e257c20eSRobert Watson { 312e257c20eSRobert Watson struct audit_pipe_preselect *app, *app_new; 313e257c20eSRobert Watson 314e257c20eSRobert Watson /* 315e257c20eSRobert Watson * Pessimistically assume that the auid doesn't already have a mask 316e257c20eSRobert Watson * set, and allocate. We will free it if it is unneeded. 317e257c20eSRobert Watson */ 318e257c20eSRobert Watson app_new = malloc(sizeof(*app_new), M_AUDIT_PIPE_PRESELECT, M_WAITOK); 319846f37f1SRobert Watson AUDIT_PIPE_LOCK(ap); 320e257c20eSRobert Watson app = audit_pipe_preselect_find(ap, auid); 321e257c20eSRobert Watson if (app == NULL) { 322e257c20eSRobert Watson app = app_new; 323e257c20eSRobert Watson app_new = NULL; 324e257c20eSRobert Watson app->app_auid = auid; 325e257c20eSRobert Watson TAILQ_INSERT_TAIL(&ap->ap_preselect_list, app, app_list); 326e257c20eSRobert Watson } 327e257c20eSRobert Watson app->app_mask = mask; 328846f37f1SRobert Watson AUDIT_PIPE_UNLOCK(ap); 329e257c20eSRobert Watson if (app_new != NULL) 330e257c20eSRobert Watson free(app_new, M_AUDIT_PIPE_PRESELECT); 331e257c20eSRobert Watson } 332e257c20eSRobert Watson 333e257c20eSRobert Watson /* 334e257c20eSRobert Watson * Delete a per-auid mask on an audit pipe. 335e257c20eSRobert Watson */ 336e257c20eSRobert Watson static int 337e257c20eSRobert Watson audit_pipe_preselect_delete(struct audit_pipe *ap, au_id_t auid) 338e257c20eSRobert Watson { 339e257c20eSRobert Watson struct audit_pipe_preselect *app; 340e257c20eSRobert Watson int error; 341e257c20eSRobert Watson 342846f37f1SRobert Watson AUDIT_PIPE_LOCK(ap); 343e257c20eSRobert Watson app = audit_pipe_preselect_find(ap, auid); 344e257c20eSRobert Watson if (app != NULL) { 345e257c20eSRobert Watson TAILQ_REMOVE(&ap->ap_preselect_list, app, app_list); 346e257c20eSRobert Watson error = 0; 347e257c20eSRobert Watson } else 348e257c20eSRobert Watson error = ENOENT; 349846f37f1SRobert Watson AUDIT_PIPE_UNLOCK(ap); 350e257c20eSRobert Watson if (app != NULL) 351e257c20eSRobert Watson free(app, M_AUDIT_PIPE_PRESELECT); 352e257c20eSRobert Watson return (error); 353e257c20eSRobert Watson } 354e257c20eSRobert Watson 355e257c20eSRobert Watson /* 356e257c20eSRobert Watson * Delete all per-auid masks on an audit pipe. 357e257c20eSRobert Watson */ 358e257c20eSRobert Watson static void 359e257c20eSRobert Watson audit_pipe_preselect_flush_locked(struct audit_pipe *ap) 360e257c20eSRobert Watson { 361e257c20eSRobert Watson struct audit_pipe_preselect *app; 362e257c20eSRobert Watson 363846f37f1SRobert Watson AUDIT_PIPE_LOCK_ASSERT(ap); 364e257c20eSRobert Watson 365e257c20eSRobert Watson while ((app = TAILQ_FIRST(&ap->ap_preselect_list)) != NULL) { 366e257c20eSRobert Watson TAILQ_REMOVE(&ap->ap_preselect_list, app, app_list); 367e257c20eSRobert Watson free(app, M_AUDIT_PIPE_PRESELECT); 368e257c20eSRobert Watson } 369e257c20eSRobert Watson } 370e257c20eSRobert Watson 371e257c20eSRobert Watson static void 372e257c20eSRobert Watson audit_pipe_preselect_flush(struct audit_pipe *ap) 373e257c20eSRobert Watson { 374e257c20eSRobert Watson 375846f37f1SRobert Watson AUDIT_PIPE_LOCK(ap); 376e257c20eSRobert Watson audit_pipe_preselect_flush_locked(ap); 377846f37f1SRobert Watson AUDIT_PIPE_UNLOCK(ap); 378e257c20eSRobert Watson } 379e257c20eSRobert Watson 380d8c0f4dcSRobert Watson /*- 381e257c20eSRobert Watson * Determine whether a specific audit pipe matches a record with these 382e257c20eSRobert Watson * properties. Algorithm is as follows: 383e257c20eSRobert Watson * 384e257c20eSRobert Watson * - If the pipe is configured to track the default trail configuration, then 385e257c20eSRobert Watson * use the results of global preselection matching. 386e257c20eSRobert Watson * - If not, search for a specifically configured auid entry matching the 387e257c20eSRobert Watson * event. If an entry is found, use that. 388e257c20eSRobert Watson * - Otherwise, use the default flags or naflags configured for the pipe. 389e257c20eSRobert Watson */ 390e257c20eSRobert Watson static int 391e257c20eSRobert Watson audit_pipe_preselect_check(struct audit_pipe *ap, au_id_t auid, 392e257c20eSRobert Watson au_event_t event, au_class_t class, int sorf, int trail_preselect) 393e257c20eSRobert Watson { 394e257c20eSRobert Watson struct audit_pipe_preselect *app; 395e257c20eSRobert Watson 396846f37f1SRobert Watson AUDIT_PIPE_LOCK_ASSERT(ap); 397e257c20eSRobert Watson 398e257c20eSRobert Watson switch (ap->ap_preselect_mode) { 399e257c20eSRobert Watson case AUDITPIPE_PRESELECT_MODE_TRAIL: 400e257c20eSRobert Watson return (trail_preselect); 401e257c20eSRobert Watson 402e257c20eSRobert Watson case AUDITPIPE_PRESELECT_MODE_LOCAL: 403e257c20eSRobert Watson app = audit_pipe_preselect_find(ap, auid); 404e257c20eSRobert Watson if (app == NULL) { 405e257c20eSRobert Watson if (auid == AU_DEFAUDITID) 406e257c20eSRobert Watson return (au_preselect(event, class, 407e257c20eSRobert Watson &ap->ap_preselect_naflags, sorf)); 408e257c20eSRobert Watson else 409e257c20eSRobert Watson return (au_preselect(event, class, 410e257c20eSRobert Watson &ap->ap_preselect_flags, sorf)); 411e257c20eSRobert Watson } else 412e257c20eSRobert Watson return (au_preselect(event, class, &app->app_mask, 413e257c20eSRobert Watson sorf)); 414e257c20eSRobert Watson 415e257c20eSRobert Watson default: 416e257c20eSRobert Watson panic("audit_pipe_preselect_check: mode %d", 417e257c20eSRobert Watson ap->ap_preselect_mode); 418e257c20eSRobert Watson } 419e257c20eSRobert Watson 420e257c20eSRobert Watson return (0); 421e257c20eSRobert Watson } 422e257c20eSRobert Watson 423e257c20eSRobert Watson /* 424e257c20eSRobert Watson * Determine whether there exists a pipe interested in a record with specific 425e257c20eSRobert Watson * properties. 426e257c20eSRobert Watson */ 427e257c20eSRobert Watson int 428e257c20eSRobert Watson audit_pipe_preselect(au_id_t auid, au_event_t event, au_class_t class, 429e257c20eSRobert Watson int sorf, int trail_preselect) 430e257c20eSRobert Watson { 431e257c20eSRobert Watson struct audit_pipe *ap; 432e257c20eSRobert Watson 433d423f266SRobert Watson /* Lockless read to avoid acquiring the global lock if not needed. */ 434d423f266SRobert Watson if (TAILQ_EMPTY(&audit_pipe_list)) 435d423f266SRobert Watson return (0); 436d423f266SRobert Watson 437846f37f1SRobert Watson AUDIT_PIPE_LIST_RLOCK(); 438e257c20eSRobert Watson TAILQ_FOREACH(ap, &audit_pipe_list, ap_list) { 439846f37f1SRobert Watson AUDIT_PIPE_LOCK(ap); 440e257c20eSRobert Watson if (audit_pipe_preselect_check(ap, auid, event, class, sorf, 441e257c20eSRobert Watson trail_preselect)) { 442846f37f1SRobert Watson AUDIT_PIPE_UNLOCK(ap); 443846f37f1SRobert Watson AUDIT_PIPE_LIST_RUNLOCK(); 444e257c20eSRobert Watson return (1); 445e257c20eSRobert Watson } 446846f37f1SRobert Watson AUDIT_PIPE_UNLOCK(ap); 447e257c20eSRobert Watson } 448846f37f1SRobert Watson AUDIT_PIPE_LIST_RUNLOCK(); 449e257c20eSRobert Watson return (0); 450e257c20eSRobert Watson } 451e257c20eSRobert Watson 452e257c20eSRobert Watson /* 453e257c20eSRobert Watson * Append individual record to a queue -- allocate queue-local buffer, and 4541daa6febSRobert Watson * add to the queue. If the queue is full or we can't allocate memory, drop 4551daa6febSRobert Watson * the newest record. 45609daf1c8SRobert Watson */ 45709daf1c8SRobert Watson static void 45809daf1c8SRobert Watson audit_pipe_append(struct audit_pipe *ap, void *record, u_int record_len) 45909daf1c8SRobert Watson { 4601daa6febSRobert Watson struct audit_pipe_entry *ape; 46109daf1c8SRobert Watson 462846f37f1SRobert Watson AUDIT_PIPE_LOCK_ASSERT(ap); 46309daf1c8SRobert Watson 4641daa6febSRobert Watson if (ap->ap_qlen >= ap->ap_qlimit) { 4651daa6febSRobert Watson ap->ap_drops++; 4661daa6febSRobert Watson audit_pipe_drops++; 4671daa6febSRobert Watson return; 4681daa6febSRobert Watson } 4691daa6febSRobert Watson 47009daf1c8SRobert Watson ape = malloc(sizeof(*ape), M_AUDIT_PIPE_ENTRY, M_NOWAIT | M_ZERO); 47109daf1c8SRobert Watson if (ape == NULL) { 47209daf1c8SRobert Watson ap->ap_drops++; 47369c89e43SRobert Watson audit_pipe_drops++; 47409daf1c8SRobert Watson return; 47509daf1c8SRobert Watson } 47609daf1c8SRobert Watson 47709daf1c8SRobert Watson ape->ape_record = malloc(record_len, M_AUDIT_PIPE_ENTRY, M_NOWAIT); 47809daf1c8SRobert Watson if (ape->ape_record == NULL) { 47909daf1c8SRobert Watson free(ape, M_AUDIT_PIPE_ENTRY); 48009daf1c8SRobert Watson ap->ap_drops++; 48109daf1c8SRobert Watson audit_pipe_drops++; 48209daf1c8SRobert Watson return; 48309daf1c8SRobert Watson } 48409daf1c8SRobert Watson 48509daf1c8SRobert Watson bcopy(record, ape->ape_record, record_len); 48609daf1c8SRobert Watson ape->ape_record_len = record_len; 48709daf1c8SRobert Watson 48809daf1c8SRobert Watson TAILQ_INSERT_TAIL(&ap->ap_queue, ape, ape_queue); 48909daf1c8SRobert Watson ap->ap_inserts++; 49009daf1c8SRobert Watson ap->ap_qlen++; 491cff9c52eSRobert Watson ap->ap_qbyteslen += ape->ape_record_len; 49209daf1c8SRobert Watson selwakeuppri(&ap->ap_selinfo, PSOCK); 4930fff4cdeSRobert Watson KNOTE_LOCKED(&ap->ap_selinfo.si_note, 0); 49409daf1c8SRobert Watson if (ap->ap_flags & AUDIT_PIPE_ASYNC) 49509daf1c8SRobert Watson pgsigio(&ap->ap_sigio, SIGIO, 0); 496846f37f1SRobert Watson cv_broadcast(&ap->ap_cv); 49709daf1c8SRobert Watson } 49809daf1c8SRobert Watson 49909daf1c8SRobert Watson /* 50009daf1c8SRobert Watson * audit_pipe_submit(): audit_worker submits audit records via this 50109daf1c8SRobert Watson * interface, which arranges for them to be delivered to pipe queues. 50209daf1c8SRobert Watson */ 50309daf1c8SRobert Watson void 504e257c20eSRobert Watson audit_pipe_submit(au_id_t auid, au_event_t event, au_class_t class, int sorf, 505e257c20eSRobert Watson int trail_select, void *record, u_int record_len) 506e257c20eSRobert Watson { 507e257c20eSRobert Watson struct audit_pipe *ap; 508e257c20eSRobert Watson 509e257c20eSRobert Watson /* 510846f37f1SRobert Watson * Lockless read to avoid lock overhead if pipes are not in use. 511e257c20eSRobert Watson */ 512e257c20eSRobert Watson if (TAILQ_FIRST(&audit_pipe_list) == NULL) 513e257c20eSRobert Watson return; 514e257c20eSRobert Watson 515846f37f1SRobert Watson AUDIT_PIPE_LIST_RLOCK(); 516e257c20eSRobert Watson TAILQ_FOREACH(ap, &audit_pipe_list, ap_list) { 517846f37f1SRobert Watson AUDIT_PIPE_LOCK(ap); 518e257c20eSRobert Watson if (audit_pipe_preselect_check(ap, auid, event, class, sorf, 519e257c20eSRobert Watson trail_select)) 520e257c20eSRobert Watson audit_pipe_append(ap, record, record_len); 521846f37f1SRobert Watson AUDIT_PIPE_UNLOCK(ap); 522e257c20eSRobert Watson } 523846f37f1SRobert Watson AUDIT_PIPE_LIST_RUNLOCK(); 524846f37f1SRobert Watson 525846f37f1SRobert Watson /* Unlocked increment. */ 526e257c20eSRobert Watson audit_pipe_records++; 527e257c20eSRobert Watson } 528e257c20eSRobert Watson 529e257c20eSRobert Watson /* 530e257c20eSRobert Watson * audit_pipe_submit_user(): the same as audit_pipe_submit(), except that 531e257c20eSRobert Watson * since we don't currently have selection information available, it is 532e257c20eSRobert Watson * delivered to the pipe unconditionally. 533e257c20eSRobert Watson * 534e257c20eSRobert Watson * XXXRW: This is a bug. The BSM check routine for submitting a user record 535e257c20eSRobert Watson * should parse that information and return it. 536e257c20eSRobert Watson */ 537e257c20eSRobert Watson void 538e257c20eSRobert Watson audit_pipe_submit_user(void *record, u_int record_len) 53909daf1c8SRobert Watson { 54009daf1c8SRobert Watson struct audit_pipe *ap; 54109daf1c8SRobert Watson 54209daf1c8SRobert Watson /* 543846f37f1SRobert Watson * Lockless read to avoid lock overhead if pipes are not in use. 54409daf1c8SRobert Watson */ 54509daf1c8SRobert Watson if (TAILQ_FIRST(&audit_pipe_list) == NULL) 54609daf1c8SRobert Watson return; 54709daf1c8SRobert Watson 548846f37f1SRobert Watson AUDIT_PIPE_LIST_RLOCK(); 549846f37f1SRobert Watson TAILQ_FOREACH(ap, &audit_pipe_list, ap_list) { 550846f37f1SRobert Watson AUDIT_PIPE_LOCK(ap); 55109daf1c8SRobert Watson audit_pipe_append(ap, record, record_len); 552846f37f1SRobert Watson AUDIT_PIPE_UNLOCK(ap); 553846f37f1SRobert Watson } 554846f37f1SRobert Watson AUDIT_PIPE_LIST_RUNLOCK(); 555846f37f1SRobert Watson 556846f37f1SRobert Watson /* Unlocked increment. */ 55709daf1c8SRobert Watson audit_pipe_records++; 55809daf1c8SRobert Watson } 55909daf1c8SRobert Watson 56009daf1c8SRobert Watson /* 56109daf1c8SRobert Watson * Allocate a new audit pipe. Connects the pipe, on success, to the global 56209daf1c8SRobert Watson * list and updates statistics. 56309daf1c8SRobert Watson */ 56409daf1c8SRobert Watson static struct audit_pipe * 56509daf1c8SRobert Watson audit_pipe_alloc(void) 56609daf1c8SRobert Watson { 56709daf1c8SRobert Watson struct audit_pipe *ap; 56809daf1c8SRobert Watson 56909daf1c8SRobert Watson ap = malloc(sizeof(*ap), M_AUDIT_PIPE, M_NOWAIT | M_ZERO); 57009daf1c8SRobert Watson if (ap == NULL) 57109daf1c8SRobert Watson return (NULL); 57209daf1c8SRobert Watson ap->ap_qlimit = AUDIT_PIPE_QLIMIT_DEFAULT; 57309daf1c8SRobert Watson TAILQ_INIT(&ap->ap_queue); 574d8b0556cSKonstantin Belousov knlist_init_mtx(&ap->ap_selinfo.si_note, AUDIT_PIPE_MTX(ap)); 575846f37f1SRobert Watson AUDIT_PIPE_LOCK_INIT(ap); 5765a9d15cdSRobert Watson AUDIT_PIPE_SX_LOCK_INIT(ap); 577846f37f1SRobert Watson cv_init(&ap->ap_cv, "audit_pipe"); 578e257c20eSRobert Watson 579e257c20eSRobert Watson /* 580e257c20eSRobert Watson * Default flags, naflags, and auid-specific preselection settings to 581e257c20eSRobert Watson * 0. Initialize the mode to the global trail so that if praudit(1) 582e257c20eSRobert Watson * is run on /dev/auditpipe, it sees events associated with the 583e257c20eSRobert Watson * default trail. Pipe-aware application can clear the flag, set 584e257c20eSRobert Watson * custom masks, and flush the pipe as needed. 585e257c20eSRobert Watson */ 586e257c20eSRobert Watson bzero(&ap->ap_preselect_flags, sizeof(ap->ap_preselect_flags)); 587e257c20eSRobert Watson bzero(&ap->ap_preselect_naflags, sizeof(ap->ap_preselect_naflags)); 588e257c20eSRobert Watson TAILQ_INIT(&ap->ap_preselect_list); 589e257c20eSRobert Watson ap->ap_preselect_mode = AUDITPIPE_PRESELECT_MODE_TRAIL; 590e257c20eSRobert Watson 5910fff4cdeSRobert Watson /* 5920fff4cdeSRobert Watson * Add to global list and update global statistics. 5930fff4cdeSRobert Watson */ 594b40ea294SDavide Italiano AUDIT_PIPE_LIST_WLOCK(); 59509daf1c8SRobert Watson TAILQ_INSERT_HEAD(&audit_pipe_list, ap, ap_list); 59609daf1c8SRobert Watson audit_pipe_count++; 59709daf1c8SRobert Watson audit_pipe_ever++; 598b40ea294SDavide Italiano AUDIT_PIPE_LIST_WUNLOCK(); 599e257c20eSRobert Watson 60009daf1c8SRobert Watson return (ap); 60109daf1c8SRobert Watson } 60209daf1c8SRobert Watson 60309daf1c8SRobert Watson /* 604e257c20eSRobert Watson * Flush all records currently present in an audit pipe; assume mutex is held. 60509daf1c8SRobert Watson */ 60609daf1c8SRobert Watson static void 607e257c20eSRobert Watson audit_pipe_flush(struct audit_pipe *ap) 60809daf1c8SRobert Watson { 60909daf1c8SRobert Watson struct audit_pipe_entry *ape; 61009daf1c8SRobert Watson 611846f37f1SRobert Watson AUDIT_PIPE_LOCK_ASSERT(ap); 61209daf1c8SRobert Watson 61309daf1c8SRobert Watson while ((ape = TAILQ_FIRST(&ap->ap_queue)) != NULL) { 61409daf1c8SRobert Watson TAILQ_REMOVE(&ap->ap_queue, ape, ape_queue); 615cff9c52eSRobert Watson ap->ap_qbyteslen -= ape->ape_record_len; 61609daf1c8SRobert Watson audit_pipe_entry_free(ape); 61709daf1c8SRobert Watson ap->ap_qlen--; 61809daf1c8SRobert Watson } 619cff9c52eSRobert Watson ap->ap_qoffset = 0; 620cff9c52eSRobert Watson 621cff9c52eSRobert Watson KASSERT(ap->ap_qlen == 0, ("audit_pipe_free: ap_qbyteslen")); 622cff9c52eSRobert Watson KASSERT(ap->ap_qbyteslen == 0, ("audit_pipe_flush: ap_qbyteslen")); 623e257c20eSRobert Watson } 624e257c20eSRobert Watson 625e257c20eSRobert Watson /* 626e257c20eSRobert Watson * Free an audit pipe; this means freeing all preselection state and all 627846f37f1SRobert Watson * records in the pipe. Assumes global write lock and pipe mutex are held to 628846f37f1SRobert Watson * prevent any new records from being inserted during the free, and that the 629846f37f1SRobert Watson * audit pipe is still on the global list. 630e257c20eSRobert Watson */ 631e257c20eSRobert Watson static void 632e257c20eSRobert Watson audit_pipe_free(struct audit_pipe *ap) 633e257c20eSRobert Watson { 634e257c20eSRobert Watson 635846f37f1SRobert Watson AUDIT_PIPE_LIST_WLOCK_ASSERT(); 636846f37f1SRobert Watson AUDIT_PIPE_LOCK_ASSERT(ap); 637e257c20eSRobert Watson 638e257c20eSRobert Watson audit_pipe_preselect_flush_locked(ap); 639e257c20eSRobert Watson audit_pipe_flush(ap); 640846f37f1SRobert Watson cv_destroy(&ap->ap_cv); 6415a9d15cdSRobert Watson AUDIT_PIPE_SX_LOCK_DESTROY(ap); 642846f37f1SRobert Watson AUDIT_PIPE_LOCK_DESTROY(ap); 6436aba400aSAttilio Rao seldrain(&ap->ap_selinfo); 6440fff4cdeSRobert Watson knlist_destroy(&ap->ap_selinfo.si_note); 645e257c20eSRobert Watson TAILQ_REMOVE(&audit_pipe_list, ap, ap_list); 64609daf1c8SRobert Watson free(ap, M_AUDIT_PIPE); 64709daf1c8SRobert Watson audit_pipe_count--; 64809daf1c8SRobert Watson } 64909daf1c8SRobert Watson 65009daf1c8SRobert Watson static void 651b40ea294SDavide Italiano audit_pipe_dtor(void *arg) 65209daf1c8SRobert Watson { 653b40ea294SDavide Italiano struct audit_pipe *ap; 65409daf1c8SRobert Watson 655b40ea294SDavide Italiano ap = arg; 656c77f6350SKonstantin Belousov funsetown(&ap->ap_sigio); 657b40ea294SDavide Italiano AUDIT_PIPE_LIST_WLOCK(); 658b40ea294SDavide Italiano AUDIT_PIPE_LOCK(ap); 659b40ea294SDavide Italiano audit_pipe_free(ap); 660b40ea294SDavide Italiano AUDIT_PIPE_LIST_WUNLOCK(); 66109daf1c8SRobert Watson } 66209daf1c8SRobert Watson 66309daf1c8SRobert Watson /* 664acd3428bSRobert Watson * Audit pipe open method. Explicit privilege check isn't used as this 665acd3428bSRobert Watson * allows file permissions on the special device to be used to grant audit 666acd3428bSRobert Watson * review access. Those file permissions should be managed carefully. 66709daf1c8SRobert Watson */ 66809daf1c8SRobert Watson static int 66909daf1c8SRobert Watson audit_pipe_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 67009daf1c8SRobert Watson { 67109daf1c8SRobert Watson struct audit_pipe *ap; 672b40ea294SDavide Italiano int error; 67309daf1c8SRobert Watson 67409daf1c8SRobert Watson ap = audit_pipe_alloc(); 675c77f6350SKonstantin Belousov if (ap == NULL) 67609daf1c8SRobert Watson return (ENOMEM); 67709daf1c8SRobert Watson fsetown(td->td_proc->p_pid, &ap->ap_sigio); 678b40ea294SDavide Italiano error = devfs_set_cdevpriv(ap, audit_pipe_dtor); 679b40ea294SDavide Italiano if (error != 0) 680c77f6350SKonstantin Belousov audit_pipe_dtor(ap); 681b40ea294SDavide Italiano return (error); 68209daf1c8SRobert Watson } 68309daf1c8SRobert Watson 68409daf1c8SRobert Watson /* 685ed708e1fSRobert Watson * Audit pipe ioctl() routine. Handle file descriptor and audit pipe layer 686ed708e1fSRobert Watson * commands. 68709daf1c8SRobert Watson */ 68809daf1c8SRobert Watson static int 68909daf1c8SRobert Watson audit_pipe_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, 69009daf1c8SRobert Watson struct thread *td) 69109daf1c8SRobert Watson { 692e257c20eSRobert Watson struct auditpipe_ioctl_preselect *aip; 69309daf1c8SRobert Watson struct audit_pipe *ap; 694e257c20eSRobert Watson au_mask_t *maskp; 695e257c20eSRobert Watson int error, mode; 696e257c20eSRobert Watson au_id_t auid; 69709daf1c8SRobert Watson 698b40ea294SDavide Italiano error = devfs_get_cdevpriv((void **)&ap); 699b40ea294SDavide Italiano if (error != 0) 700b40ea294SDavide Italiano return (error); 701e257c20eSRobert Watson 702e257c20eSRobert Watson /* 703e257c20eSRobert Watson * Audit pipe ioctls: first come standard device node ioctls, then 704e257c20eSRobert Watson * manipulation of pipe settings, and finally, statistics query 705e257c20eSRobert Watson * ioctls. 706e257c20eSRobert Watson */ 70709daf1c8SRobert Watson switch (cmd) { 70809daf1c8SRobert Watson case FIONBIO: 709846f37f1SRobert Watson AUDIT_PIPE_LOCK(ap); 71009daf1c8SRobert Watson if (*(int *)data) 71109daf1c8SRobert Watson ap->ap_flags |= AUDIT_PIPE_NBIO; 71209daf1c8SRobert Watson else 71309daf1c8SRobert Watson ap->ap_flags &= ~AUDIT_PIPE_NBIO; 714846f37f1SRobert Watson AUDIT_PIPE_UNLOCK(ap); 71509daf1c8SRobert Watson error = 0; 71609daf1c8SRobert Watson break; 71709daf1c8SRobert Watson 71809daf1c8SRobert Watson case FIONREAD: 719846f37f1SRobert Watson AUDIT_PIPE_LOCK(ap); 720cff9c52eSRobert Watson *(int *)data = ap->ap_qbyteslen - ap->ap_qoffset; 721846f37f1SRobert Watson AUDIT_PIPE_UNLOCK(ap); 72209daf1c8SRobert Watson error = 0; 72309daf1c8SRobert Watson break; 72409daf1c8SRobert Watson 72509daf1c8SRobert Watson case FIOASYNC: 726846f37f1SRobert Watson AUDIT_PIPE_LOCK(ap); 72709daf1c8SRobert Watson if (*(int *)data) 72809daf1c8SRobert Watson ap->ap_flags |= AUDIT_PIPE_ASYNC; 72909daf1c8SRobert Watson else 73009daf1c8SRobert Watson ap->ap_flags &= ~AUDIT_PIPE_ASYNC; 731846f37f1SRobert Watson AUDIT_PIPE_UNLOCK(ap); 73209daf1c8SRobert Watson error = 0; 73309daf1c8SRobert Watson break; 73409daf1c8SRobert Watson 73509daf1c8SRobert Watson case FIOSETOWN: 73609daf1c8SRobert Watson error = fsetown(*(int *)data, &ap->ap_sigio); 73709daf1c8SRobert Watson break; 73809daf1c8SRobert Watson 73909daf1c8SRobert Watson case FIOGETOWN: 74009daf1c8SRobert Watson *(int *)data = fgetown(&ap->ap_sigio); 74109daf1c8SRobert Watson error = 0; 742ed708e1fSRobert Watson break; 743ed708e1fSRobert Watson 744ed708e1fSRobert Watson case AUDITPIPE_GET_QLEN: 745ed708e1fSRobert Watson *(u_int *)data = ap->ap_qlen; 746ed708e1fSRobert Watson error = 0; 747ed708e1fSRobert Watson break; 748ed708e1fSRobert Watson 749ed708e1fSRobert Watson case AUDITPIPE_GET_QLIMIT: 750ed708e1fSRobert Watson *(u_int *)data = ap->ap_qlimit; 751ed708e1fSRobert Watson error = 0; 752ed708e1fSRobert Watson break; 753ed708e1fSRobert Watson 754ed708e1fSRobert Watson case AUDITPIPE_SET_QLIMIT: 755ed708e1fSRobert Watson /* Lockless integer write. */ 756dc8240f0SAndriy Gapon if (*(u_int *)data >= AUDIT_PIPE_QLIMIT_MIN && 757ed708e1fSRobert Watson *(u_int *)data <= AUDIT_PIPE_QLIMIT_MAX) { 758ed708e1fSRobert Watson ap->ap_qlimit = *(u_int *)data; 759ed708e1fSRobert Watson error = 0; 760ed708e1fSRobert Watson } else 761ed708e1fSRobert Watson error = EINVAL; 762ed708e1fSRobert Watson break; 763ed708e1fSRobert Watson 764059c6495SRobert Watson case AUDITPIPE_GET_QLIMIT_MIN: 765059c6495SRobert Watson *(u_int *)data = AUDIT_PIPE_QLIMIT_MIN; 766059c6495SRobert Watson error = 0; 767059c6495SRobert Watson break; 768059c6495SRobert Watson 769059c6495SRobert Watson case AUDITPIPE_GET_QLIMIT_MAX: 770059c6495SRobert Watson *(u_int *)data = AUDIT_PIPE_QLIMIT_MAX; 771059c6495SRobert Watson error = 0; 772059c6495SRobert Watson break; 773059c6495SRobert Watson 774e257c20eSRobert Watson case AUDITPIPE_GET_PRESELECT_FLAGS: 775846f37f1SRobert Watson AUDIT_PIPE_LOCK(ap); 776e257c20eSRobert Watson maskp = (au_mask_t *)data; 777e257c20eSRobert Watson *maskp = ap->ap_preselect_flags; 778846f37f1SRobert Watson AUDIT_PIPE_UNLOCK(ap); 779e257c20eSRobert Watson error = 0; 780e257c20eSRobert Watson break; 781e257c20eSRobert Watson 782e257c20eSRobert Watson case AUDITPIPE_SET_PRESELECT_FLAGS: 783846f37f1SRobert Watson AUDIT_PIPE_LOCK(ap); 784e257c20eSRobert Watson maskp = (au_mask_t *)data; 785e257c20eSRobert Watson ap->ap_preselect_flags = *maskp; 786846f37f1SRobert Watson AUDIT_PIPE_UNLOCK(ap); 787e257c20eSRobert Watson error = 0; 788e257c20eSRobert Watson break; 789e257c20eSRobert Watson 790e257c20eSRobert Watson case AUDITPIPE_GET_PRESELECT_NAFLAGS: 791846f37f1SRobert Watson AUDIT_PIPE_LOCK(ap); 792e257c20eSRobert Watson maskp = (au_mask_t *)data; 793e257c20eSRobert Watson *maskp = ap->ap_preselect_naflags; 794846f37f1SRobert Watson AUDIT_PIPE_UNLOCK(ap); 795e257c20eSRobert Watson error = 0; 796e257c20eSRobert Watson break; 797e257c20eSRobert Watson 798e257c20eSRobert Watson case AUDITPIPE_SET_PRESELECT_NAFLAGS: 799846f37f1SRobert Watson AUDIT_PIPE_LOCK(ap); 800e257c20eSRobert Watson maskp = (au_mask_t *)data; 801e257c20eSRobert Watson ap->ap_preselect_naflags = *maskp; 802846f37f1SRobert Watson AUDIT_PIPE_UNLOCK(ap); 803e257c20eSRobert Watson error = 0; 804e257c20eSRobert Watson break; 805e257c20eSRobert Watson 806e257c20eSRobert Watson case AUDITPIPE_GET_PRESELECT_AUID: 807e257c20eSRobert Watson aip = (struct auditpipe_ioctl_preselect *)data; 808e257c20eSRobert Watson error = audit_pipe_preselect_get(ap, aip->aip_auid, 809e257c20eSRobert Watson &aip->aip_mask); 810e257c20eSRobert Watson break; 811e257c20eSRobert Watson 812e257c20eSRobert Watson case AUDITPIPE_SET_PRESELECT_AUID: 813e257c20eSRobert Watson aip = (struct auditpipe_ioctl_preselect *)data; 814e257c20eSRobert Watson audit_pipe_preselect_set(ap, aip->aip_auid, aip->aip_mask); 815e257c20eSRobert Watson error = 0; 816e257c20eSRobert Watson break; 817e257c20eSRobert Watson 818e257c20eSRobert Watson case AUDITPIPE_DELETE_PRESELECT_AUID: 819e257c20eSRobert Watson auid = *(au_id_t *)data; 820e257c20eSRobert Watson error = audit_pipe_preselect_delete(ap, auid); 821e257c20eSRobert Watson break; 822e257c20eSRobert Watson 823e257c20eSRobert Watson case AUDITPIPE_FLUSH_PRESELECT_AUID: 824e257c20eSRobert Watson audit_pipe_preselect_flush(ap); 825e257c20eSRobert Watson error = 0; 826e257c20eSRobert Watson break; 827e257c20eSRobert Watson 828e257c20eSRobert Watson case AUDITPIPE_GET_PRESELECT_MODE: 829846f37f1SRobert Watson AUDIT_PIPE_LOCK(ap); 830e257c20eSRobert Watson *(int *)data = ap->ap_preselect_mode; 831846f37f1SRobert Watson AUDIT_PIPE_UNLOCK(ap); 832e257c20eSRobert Watson error = 0; 833e257c20eSRobert Watson break; 834e257c20eSRobert Watson 835e257c20eSRobert Watson case AUDITPIPE_SET_PRESELECT_MODE: 836e257c20eSRobert Watson mode = *(int *)data; 837e257c20eSRobert Watson switch (mode) { 838e257c20eSRobert Watson case AUDITPIPE_PRESELECT_MODE_TRAIL: 839e257c20eSRobert Watson case AUDITPIPE_PRESELECT_MODE_LOCAL: 840846f37f1SRobert Watson AUDIT_PIPE_LOCK(ap); 841e257c20eSRobert Watson ap->ap_preselect_mode = mode; 842846f37f1SRobert Watson AUDIT_PIPE_UNLOCK(ap); 843e257c20eSRobert Watson error = 0; 844e257c20eSRobert Watson break; 845e257c20eSRobert Watson 846e257c20eSRobert Watson default: 847e257c20eSRobert Watson error = EINVAL; 848e257c20eSRobert Watson } 849e257c20eSRobert Watson break; 850e257c20eSRobert Watson 851e257c20eSRobert Watson case AUDITPIPE_FLUSH: 8525a9d15cdSRobert Watson if (AUDIT_PIPE_SX_XLOCK_SIG(ap) != 0) 8535a9d15cdSRobert Watson return (EINTR); 854846f37f1SRobert Watson AUDIT_PIPE_LOCK(ap); 855e257c20eSRobert Watson audit_pipe_flush(ap); 856846f37f1SRobert Watson AUDIT_PIPE_UNLOCK(ap); 8575a9d15cdSRobert Watson AUDIT_PIPE_SX_XUNLOCK(ap); 858e257c20eSRobert Watson error = 0; 859e257c20eSRobert Watson break; 860e257c20eSRobert Watson 8619fe741b8SRobert Watson case AUDITPIPE_GET_MAXAUDITDATA: 8629fe741b8SRobert Watson *(u_int *)data = MAXAUDITDATA; 8639fe741b8SRobert Watson error = 0; 8649fe741b8SRobert Watson break; 8659fe741b8SRobert Watson 866ed708e1fSRobert Watson case AUDITPIPE_GET_INSERTS: 867ed708e1fSRobert Watson *(u_int *)data = ap->ap_inserts; 868ed708e1fSRobert Watson error = 0; 869ed708e1fSRobert Watson break; 870ed708e1fSRobert Watson 871ed708e1fSRobert Watson case AUDITPIPE_GET_READS: 872ed708e1fSRobert Watson *(u_int *)data = ap->ap_reads; 873ed708e1fSRobert Watson error = 0; 874ed708e1fSRobert Watson break; 875ed708e1fSRobert Watson 876ed708e1fSRobert Watson case AUDITPIPE_GET_DROPS: 877ed708e1fSRobert Watson *(u_int *)data = ap->ap_drops; 878ed708e1fSRobert Watson error = 0; 879ed708e1fSRobert Watson break; 880ed708e1fSRobert Watson 881ed708e1fSRobert Watson case AUDITPIPE_GET_TRUNCATES: 8821a0edb10SRobert Watson *(u_int *)data = 0; 883ed708e1fSRobert Watson error = 0; 884ed708e1fSRobert Watson break; 88509daf1c8SRobert Watson 88609daf1c8SRobert Watson default: 88709daf1c8SRobert Watson error = ENOTTY; 88809daf1c8SRobert Watson } 88909daf1c8SRobert Watson return (error); 89009daf1c8SRobert Watson } 89109daf1c8SRobert Watson 89209daf1c8SRobert Watson /* 893a9275e0bSRobert Watson * Audit pipe read. Read one or more partial or complete records to user 894a9275e0bSRobert Watson * memory. 89509daf1c8SRobert Watson */ 89609daf1c8SRobert Watson static int 89709daf1c8SRobert Watson audit_pipe_read(struct cdev *dev, struct uio *uio, int flag) 89809daf1c8SRobert Watson { 89909daf1c8SRobert Watson struct audit_pipe_entry *ape; 90009daf1c8SRobert Watson struct audit_pipe *ap; 9015a9d15cdSRobert Watson u_int toread; 90209daf1c8SRobert Watson int error; 90309daf1c8SRobert Watson 904b40ea294SDavide Italiano error = devfs_get_cdevpriv((void **)&ap); 905b40ea294SDavide Italiano if (error != 0) 906b40ea294SDavide Italiano return (error); 907846f37f1SRobert Watson 90809daf1c8SRobert Watson /* 9095a9d15cdSRobert Watson * We hold an sx(9) lock over read and flush because we rely on the 9105a9d15cdSRobert Watson * stability of a record in the queue during uiomove(9). 91109daf1c8SRobert Watson */ 9125a9d15cdSRobert Watson if (AUDIT_PIPE_SX_XLOCK_SIG(ap) != 0) 9135a9d15cdSRobert Watson return (EINTR); 9145a9d15cdSRobert Watson AUDIT_PIPE_LOCK(ap); 9155a9d15cdSRobert Watson while (TAILQ_EMPTY(&ap->ap_queue)) { 91609daf1c8SRobert Watson if (ap->ap_flags & AUDIT_PIPE_NBIO) { 917846f37f1SRobert Watson AUDIT_PIPE_UNLOCK(ap); 9185a9d15cdSRobert Watson AUDIT_PIPE_SX_XUNLOCK(ap); 91909daf1c8SRobert Watson return (EAGAIN); 92009daf1c8SRobert Watson } 921846f37f1SRobert Watson error = cv_wait_sig(&ap->ap_cv, AUDIT_PIPE_MTX(ap)); 92209daf1c8SRobert Watson if (error) { 923846f37f1SRobert Watson AUDIT_PIPE_UNLOCK(ap); 9245a9d15cdSRobert Watson AUDIT_PIPE_SX_XUNLOCK(ap); 92509daf1c8SRobert Watson return (error); 92609daf1c8SRobert Watson } 92709daf1c8SRobert Watson } 92809daf1c8SRobert Watson 92909daf1c8SRobert Watson /* 9305a9d15cdSRobert Watson * Copy as many remaining bytes from the current record to userspace 931a9275e0bSRobert Watson * as we can. Keep processing records until we run out of records in 932a9275e0bSRobert Watson * the queue, or until the user buffer runs out of space. 9335a9d15cdSRobert Watson * 9345a9d15cdSRobert Watson * Note: we rely on the SX lock to maintain ape's stability here. 93509daf1c8SRobert Watson */ 9365a9d15cdSRobert Watson ap->ap_reads++; 937a9275e0bSRobert Watson while ((ape = TAILQ_FIRST(&ap->ap_queue)) != NULL && 938a9275e0bSRobert Watson uio->uio_resid > 0) { 939a9275e0bSRobert Watson AUDIT_PIPE_LOCK_ASSERT(ap); 940a9275e0bSRobert Watson 941cff9c52eSRobert Watson KASSERT(ape->ape_record_len > ap->ap_qoffset, 942cff9c52eSRobert Watson ("audit_pipe_read: record_len > qoffset (1)")); 943cff9c52eSRobert Watson toread = MIN(ape->ape_record_len - ap->ap_qoffset, 9445a9d15cdSRobert Watson uio->uio_resid); 9455a9d15cdSRobert Watson AUDIT_PIPE_UNLOCK(ap); 946cff9c52eSRobert Watson error = uiomove((char *)ape->ape_record + ap->ap_qoffset, 947cff9c52eSRobert Watson toread, uio); 9485a9d15cdSRobert Watson if (error) { 9495a9d15cdSRobert Watson AUDIT_PIPE_SX_XUNLOCK(ap); 9505a9d15cdSRobert Watson return (error); 9515a9d15cdSRobert Watson } 9525a9d15cdSRobert Watson 9535a9d15cdSRobert Watson /* 954a9275e0bSRobert Watson * If the copy succeeded, update book-keeping, and if no 955a9275e0bSRobert Watson * bytes remain in the current record, free it. 9565a9d15cdSRobert Watson */ 9575a9d15cdSRobert Watson AUDIT_PIPE_LOCK(ap); 9585a9d15cdSRobert Watson KASSERT(TAILQ_FIRST(&ap->ap_queue) == ape, 9595a9d15cdSRobert Watson ("audit_pipe_read: queue out of sync after uiomove")); 960cff9c52eSRobert Watson ap->ap_qoffset += toread; 961cff9c52eSRobert Watson KASSERT(ape->ape_record_len >= ap->ap_qoffset, 962cff9c52eSRobert Watson ("audit_pipe_read: record_len >= qoffset (2)")); 963cff9c52eSRobert Watson if (ap->ap_qoffset == ape->ape_record_len) { 9645a9d15cdSRobert Watson TAILQ_REMOVE(&ap->ap_queue, ape, ape_queue); 965cff9c52eSRobert Watson ap->ap_qbyteslen -= ape->ape_record_len; 966a9275e0bSRobert Watson audit_pipe_entry_free(ape); 9675a9d15cdSRobert Watson ap->ap_qlen--; 968cff9c52eSRobert Watson ap->ap_qoffset = 0; 969a9275e0bSRobert Watson } 970a9275e0bSRobert Watson } 9715a9d15cdSRobert Watson AUDIT_PIPE_UNLOCK(ap); 9725a9d15cdSRobert Watson AUDIT_PIPE_SX_XUNLOCK(ap); 973a9275e0bSRobert Watson return (0); 97409daf1c8SRobert Watson } 97509daf1c8SRobert Watson 97609daf1c8SRobert Watson /* 97709daf1c8SRobert Watson * Audit pipe poll. 97809daf1c8SRobert Watson */ 97909daf1c8SRobert Watson static int 98009daf1c8SRobert Watson audit_pipe_poll(struct cdev *dev, int events, struct thread *td) 98109daf1c8SRobert Watson { 98209daf1c8SRobert Watson struct audit_pipe *ap; 983b40ea294SDavide Italiano int error, revents; 98409daf1c8SRobert Watson 98509daf1c8SRobert Watson revents = 0; 986b40ea294SDavide Italiano error = devfs_get_cdevpriv((void **)&ap); 987b40ea294SDavide Italiano if (error != 0) 988b40ea294SDavide Italiano return (error); 98909daf1c8SRobert Watson if (events & (POLLIN | POLLRDNORM)) { 990846f37f1SRobert Watson AUDIT_PIPE_LOCK(ap); 99109daf1c8SRobert Watson if (TAILQ_FIRST(&ap->ap_queue) != NULL) 99209daf1c8SRobert Watson revents |= events & (POLLIN | POLLRDNORM); 99309daf1c8SRobert Watson else 99409daf1c8SRobert Watson selrecord(td, &ap->ap_selinfo); 995846f37f1SRobert Watson AUDIT_PIPE_UNLOCK(ap); 99609daf1c8SRobert Watson } 99709daf1c8SRobert Watson return (revents); 99809daf1c8SRobert Watson } 99909daf1c8SRobert Watson 100009daf1c8SRobert Watson /* 10010fff4cdeSRobert Watson * Audit pipe kqfilter. 10020fff4cdeSRobert Watson */ 10030fff4cdeSRobert Watson static int 10040fff4cdeSRobert Watson audit_pipe_kqfilter(struct cdev *dev, struct knote *kn) 10050fff4cdeSRobert Watson { 10060fff4cdeSRobert Watson struct audit_pipe *ap; 1007b40ea294SDavide Italiano int error; 10080fff4cdeSRobert Watson 1009b40ea294SDavide Italiano error = devfs_get_cdevpriv((void **)&ap); 1010b40ea294SDavide Italiano if (error != 0) 1011b40ea294SDavide Italiano return (error); 10120fff4cdeSRobert Watson if (kn->kn_filter != EVFILT_READ) 10130fff4cdeSRobert Watson return (EINVAL); 10140fff4cdeSRobert Watson 10150fff4cdeSRobert Watson kn->kn_fop = &audit_pipe_read_filterops; 10160fff4cdeSRobert Watson kn->kn_hook = ap; 10170fff4cdeSRobert Watson 1018846f37f1SRobert Watson AUDIT_PIPE_LOCK(ap); 10190fff4cdeSRobert Watson knlist_add(&ap->ap_selinfo.si_note, kn, 1); 1020846f37f1SRobert Watson AUDIT_PIPE_UNLOCK(ap); 10210fff4cdeSRobert Watson return (0); 10220fff4cdeSRobert Watson } 10230fff4cdeSRobert Watson 10240fff4cdeSRobert Watson /* 10250fff4cdeSRobert Watson * Return true if there are records available for reading on the pipe. 10260fff4cdeSRobert Watson */ 10270fff4cdeSRobert Watson static int 10280fff4cdeSRobert Watson audit_pipe_kqread(struct knote *kn, long hint) 10290fff4cdeSRobert Watson { 10300fff4cdeSRobert Watson struct audit_pipe *ap; 10310fff4cdeSRobert Watson 10320fff4cdeSRobert Watson ap = (struct audit_pipe *)kn->kn_hook; 1033846f37f1SRobert Watson AUDIT_PIPE_LOCK_ASSERT(ap); 1034846f37f1SRobert Watson 10350fff4cdeSRobert Watson if (ap->ap_qlen != 0) { 1036cff9c52eSRobert Watson kn->kn_data = ap->ap_qbyteslen - ap->ap_qoffset; 10370fff4cdeSRobert Watson return (1); 10380fff4cdeSRobert Watson } else { 10390fff4cdeSRobert Watson kn->kn_data = 0; 10400fff4cdeSRobert Watson return (0); 10410fff4cdeSRobert Watson } 10420fff4cdeSRobert Watson } 10430fff4cdeSRobert Watson 10440fff4cdeSRobert Watson /* 10450fff4cdeSRobert Watson * Detach kqueue state from audit pipe. 10460fff4cdeSRobert Watson */ 10470fff4cdeSRobert Watson static void 10480fff4cdeSRobert Watson audit_pipe_kqdetach(struct knote *kn) 10490fff4cdeSRobert Watson { 10500fff4cdeSRobert Watson struct audit_pipe *ap; 10510fff4cdeSRobert Watson 10520fff4cdeSRobert Watson ap = (struct audit_pipe *)kn->kn_hook; 1053846f37f1SRobert Watson AUDIT_PIPE_LOCK(ap); 10540fff4cdeSRobert Watson knlist_remove(&ap->ap_selinfo.si_note, kn, 1); 1055846f37f1SRobert Watson AUDIT_PIPE_UNLOCK(ap); 10560fff4cdeSRobert Watson } 10570fff4cdeSRobert Watson 10580fff4cdeSRobert Watson /* 105909daf1c8SRobert Watson * Initialize the audit pipe system. 106009daf1c8SRobert Watson */ 106109daf1c8SRobert Watson static void 106209daf1c8SRobert Watson audit_pipe_init(void *unused) 106309daf1c8SRobert Watson { 106409daf1c8SRobert Watson 106509daf1c8SRobert Watson TAILQ_INIT(&audit_pipe_list); 1066846f37f1SRobert Watson AUDIT_PIPE_LIST_LOCK_INIT(); 1067b40ea294SDavide Italiano audit_pipe_dev = make_dev(&audit_pipe_cdevsw, 0, UID_ROOT, 1068b40ea294SDavide Italiano GID_WHEEL, 0600, "%s", AUDIT_PIPE_NAME); 1069b40ea294SDavide Italiano if (audit_pipe_dev == NULL) { 1070b40ea294SDavide Italiano AUDIT_PIPE_LIST_LOCK_DESTROY(); 1071b40ea294SDavide Italiano panic("Can't initialize audit pipe subsystem"); 1072b40ea294SDavide Italiano } 107309daf1c8SRobert Watson } 107409daf1c8SRobert Watson 107509daf1c8SRobert Watson SYSINIT(audit_pipe_init, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, audit_pipe_init, 107609daf1c8SRobert Watson NULL); 1077