Changeset View
Changeset View
Standalone View
Standalone View
sys/security/audit/audit_pipe.c
Show First 20 Lines • Show All 199 Lines • ▼ Show 20 Lines | |||||
* between threads walking the list to deliver to individual pipes and add/ | * between threads walking the list to deliver to individual pipes and add/ | ||||
* remove of pipes, and are mostly acquired for read. | * remove of pipes, and are mostly acquired for read. | ||||
*/ | */ | ||||
static TAILQ_HEAD(, audit_pipe) audit_pipe_list; | static TAILQ_HEAD(, audit_pipe) audit_pipe_list; | ||||
static struct rwlock audit_pipe_lock; | static struct rwlock audit_pipe_lock; | ||||
#define AUDIT_PIPE_LIST_LOCK_INIT() rw_init(&audit_pipe_lock, \ | #define AUDIT_PIPE_LIST_LOCK_INIT() rw_init(&audit_pipe_lock, \ | ||||
"audit_pipe_list_lock") | "audit_pipe_list_lock") | ||||
#define AUDIT_PIPE_LIST_LOCK_DESTROY() rw_destroy(&audit_pipe_lock) | |||||
#define AUDIT_PIPE_LIST_RLOCK() rw_rlock(&audit_pipe_lock) | #define AUDIT_PIPE_LIST_RLOCK() rw_rlock(&audit_pipe_lock) | ||||
#define AUDIT_PIPE_LIST_RUNLOCK() rw_runlock(&audit_pipe_lock) | #define AUDIT_PIPE_LIST_RUNLOCK() rw_runlock(&audit_pipe_lock) | ||||
#define AUDIT_PIPE_LIST_WLOCK() rw_wlock(&audit_pipe_lock) | #define AUDIT_PIPE_LIST_WLOCK() rw_wlock(&audit_pipe_lock) | ||||
#define AUDIT_PIPE_LIST_WLOCK_ASSERT() rw_assert(&audit_pipe_lock, \ | #define AUDIT_PIPE_LIST_WLOCK_ASSERT() rw_assert(&audit_pipe_lock, \ | ||||
RA_WLOCKED) | RA_WLOCKED) | ||||
#define AUDIT_PIPE_LIST_WUNLOCK() rw_wunlock(&audit_pipe_lock) | #define AUDIT_PIPE_LIST_WUNLOCK() rw_wunlock(&audit_pipe_lock) | ||||
/* | /* | ||||
* Cloning related variables and constants. | * Audit pipe device. | ||||
*/ | */ | ||||
static struct cdev *audit_pipe_dev; | |||||
#define AUDIT_PIPE_NAME "auditpipe" | #define AUDIT_PIPE_NAME "auditpipe" | ||||
static eventhandler_tag audit_pipe_eh_tag; | |||||
static struct clonedevs *audit_pipe_clones; | |||||
/* | /* | ||||
* Special device methods and definition. | * Special device methods and definition. | ||||
*/ | */ | ||||
static d_open_t audit_pipe_open; | static d_open_t audit_pipe_open; | ||||
static d_close_t audit_pipe_close; | static d_close_t audit_pipe_close; | ||||
static d_read_t audit_pipe_read; | static d_read_t audit_pipe_read; | ||||
static d_ioctl_t audit_pipe_ioctl; | static d_ioctl_t audit_pipe_ioctl; | ||||
static d_poll_t audit_pipe_poll; | static d_poll_t audit_pipe_poll; | ||||
static d_kqfilter_t audit_pipe_kqfilter; | static d_kqfilter_t audit_pipe_kqfilter; | ||||
static struct cdevsw audit_pipe_cdevsw = { | static struct cdevsw audit_pipe_cdevsw = { | ||||
.d_version = D_VERSION, | .d_version = D_VERSION, | ||||
.d_flags = D_NEEDMINOR, | |||||
.d_open = audit_pipe_open, | .d_open = audit_pipe_open, | ||||
.d_close = audit_pipe_close, | .d_close = audit_pipe_close, | ||||
.d_read = audit_pipe_read, | .d_read = audit_pipe_read, | ||||
.d_ioctl = audit_pipe_ioctl, | .d_ioctl = audit_pipe_ioctl, | ||||
.d_poll = audit_pipe_poll, | .d_poll = audit_pipe_poll, | ||||
.d_kqfilter = audit_pipe_kqfilter, | .d_kqfilter = audit_pipe_kqfilter, | ||||
.d_name = AUDIT_PIPE_NAME, | .d_name = AUDIT_PIPE_NAME, | ||||
}; | }; | ||||
▲ Show 20 Lines • Show All 324 Lines • ▼ Show 20 Lines | |||||
* Allocate a new audit pipe. Connects the pipe, on success, to the global | * Allocate a new audit pipe. Connects the pipe, on success, to the global | ||||
* list and updates statistics. | * list and updates statistics. | ||||
*/ | */ | ||||
static struct audit_pipe * | static struct audit_pipe * | ||||
audit_pipe_alloc(void) | audit_pipe_alloc(void) | ||||
{ | { | ||||
struct audit_pipe *ap; | struct audit_pipe *ap; | ||||
AUDIT_PIPE_LIST_WLOCK_ASSERT(); | |||||
ap = malloc(sizeof(*ap), M_AUDIT_PIPE, M_NOWAIT | M_ZERO); | ap = malloc(sizeof(*ap), M_AUDIT_PIPE, M_NOWAIT | M_ZERO); | ||||
if (ap == NULL) | if (ap == NULL) | ||||
return (NULL); | return (NULL); | ||||
ap->ap_qlimit = AUDIT_PIPE_QLIMIT_DEFAULT; | ap->ap_qlimit = AUDIT_PIPE_QLIMIT_DEFAULT; | ||||
TAILQ_INIT(&ap->ap_queue); | TAILQ_INIT(&ap->ap_queue); | ||||
knlist_init_mtx(&ap->ap_selinfo.si_note, AUDIT_PIPE_MTX(ap)); | knlist_init_mtx(&ap->ap_selinfo.si_note, AUDIT_PIPE_MTX(ap)); | ||||
AUDIT_PIPE_LOCK_INIT(ap); | AUDIT_PIPE_LOCK_INIT(ap); | ||||
AUDIT_PIPE_SX_LOCK_INIT(ap); | AUDIT_PIPE_SX_LOCK_INIT(ap); | ||||
Show All 9 Lines | audit_pipe_alloc(void) | ||||
bzero(&ap->ap_preselect_flags, sizeof(ap->ap_preselect_flags)); | bzero(&ap->ap_preselect_flags, sizeof(ap->ap_preselect_flags)); | ||||
bzero(&ap->ap_preselect_naflags, sizeof(ap->ap_preselect_naflags)); | bzero(&ap->ap_preselect_naflags, sizeof(ap->ap_preselect_naflags)); | ||||
TAILQ_INIT(&ap->ap_preselect_list); | TAILQ_INIT(&ap->ap_preselect_list); | ||||
ap->ap_preselect_mode = AUDITPIPE_PRESELECT_MODE_TRAIL; | ap->ap_preselect_mode = AUDITPIPE_PRESELECT_MODE_TRAIL; | ||||
/* | /* | ||||
* Add to global list and update global statistics. | * Add to global list and update global statistics. | ||||
*/ | */ | ||||
AUDIT_PIPE_LIST_WLOCK(); | |||||
TAILQ_INSERT_HEAD(&audit_pipe_list, ap, ap_list); | TAILQ_INSERT_HEAD(&audit_pipe_list, ap, ap_list); | ||||
audit_pipe_count++; | audit_pipe_count++; | ||||
audit_pipe_ever++; | audit_pipe_ever++; | ||||
AUDIT_PIPE_LIST_WUNLOCK(); | |||||
return (ap); | return (ap); | ||||
} | } | ||||
/* | /* | ||||
* Flush all records currently present in an audit pipe; assume mutex is held. | * Flush all records currently present in an audit pipe; assume mutex is held. | ||||
*/ | */ | ||||
static void | static void | ||||
Show All 35 Lines | audit_pipe_free(struct audit_pipe *ap) | ||||
AUDIT_PIPE_LOCK_DESTROY(ap); | AUDIT_PIPE_LOCK_DESTROY(ap); | ||||
seldrain(&ap->ap_selinfo); | seldrain(&ap->ap_selinfo); | ||||
knlist_destroy(&ap->ap_selinfo.si_note); | knlist_destroy(&ap->ap_selinfo.si_note); | ||||
TAILQ_REMOVE(&audit_pipe_list, ap, ap_list); | TAILQ_REMOVE(&audit_pipe_list, ap, ap_list); | ||||
free(ap, M_AUDIT_PIPE); | free(ap, M_AUDIT_PIPE); | ||||
audit_pipe_count--; | audit_pipe_count--; | ||||
} | } | ||||
/* | |||||
* Audit pipe clone routine -- provide specific requested audit pipe, or a | |||||
* fresh one if a specific one is not requested. | |||||
*/ | |||||
static void | static void | ||||
audit_pipe_clone(void *arg, struct ucred *cred, char *name, int namelen, | audit_pipe_dtor(void *arg) | ||||
struct cdev **dev) | |||||
{ | { | ||||
int i, u; | struct audit_pipe *ap; | ||||
if (*dev != NULL) | ap = arg; | ||||
return; | AUDIT_PIPE_LIST_WLOCK(); | ||||
AUDIT_PIPE_LOCK(ap); | |||||
if (strcmp(name, AUDIT_PIPE_NAME) == 0) | ap->ap_open = 0; | ||||
u = -1; | audit_pipe_free(ap); | ||||
else if (dev_stdclone(name, NULL, AUDIT_PIPE_NAME, &u) != 1) | AUDIT_PIPE_LIST_WUNLOCK(); | ||||
return; | |||||
i = clone_create(&audit_pipe_clones, &audit_pipe_cdevsw, &u, dev, 0); | |||||
if (i) | |||||
*dev = make_dev_credf(MAKEDEV_REF, &audit_pipe_cdevsw, u, cred, | |||||
UID_ROOT, GID_WHEEL, 0600, "%s%d", AUDIT_PIPE_NAME, u); | |||||
} | } | ||||
/* | /* | ||||
* Audit pipe open method. Explicit privilege check isn't used as this | * Audit pipe open method. Explicit privilege check isn't used as this | ||||
* allows file permissions on the special device to be used to grant audit | * allows file permissions on the special device to be used to grant audit | ||||
* review access. Those file permissions should be managed carefully. | * review access. Those file permissions should be managed carefully. | ||||
*/ | */ | ||||
static int | static int | ||||
audit_pipe_open(struct cdev *dev, int oflags, int devtype, struct thread *td) | audit_pipe_open(struct cdev *dev, int oflags, int devtype, struct thread *td) | ||||
{ | { | ||||
struct audit_pipe *ap; | struct audit_pipe *ap; | ||||
int error; | |||||
AUDIT_PIPE_LIST_WLOCK(); | |||||
ap = dev->si_drv1; | |||||
if (ap == NULL) { | |||||
ap = audit_pipe_alloc(); | ap = audit_pipe_alloc(); | ||||
if (ap == NULL) { | if (ap == NULL) { | ||||
AUDIT_PIPE_LIST_WUNLOCK(); | |||||
return (ENOMEM); | return (ENOMEM); | ||||
} | } | ||||
dev->si_drv1 = ap; | dev->si_drv1 = ap; | ||||
} else { | |||||
KASSERT(ap->ap_open, ("audit_pipe_open: ap && !ap_open")); | |||||
AUDIT_PIPE_LIST_WUNLOCK(); | |||||
return (EBUSY); | |||||
} | |||||
ap->ap_open = 1; /* No lock required yet. */ | ap->ap_open = 1; /* No lock required yet. */ | ||||
AUDIT_PIPE_LIST_WUNLOCK(); | |||||
fsetown(td->td_proc->p_pid, &ap->ap_sigio); | fsetown(td->td_proc->p_pid, &ap->ap_sigio); | ||||
error = devfs_set_cdevpriv(ap, audit_pipe_dtor); | |||||
if (error != 0) { | |||||
AUDIT_PIPE_LIST_WLOCK(); | |||||
audit_pipe_free(ap); | |||||
AUDIT_PIPE_LIST_WUNLOCK(); | |||||
} | |||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Close audit pipe, tear down all records, etc. | * Close audit pipe, tear down all records, etc. | ||||
*/ | */ | ||||
static int | static int | ||||
audit_pipe_close(struct cdev *dev, int fflag, int devtype, struct thread *td) | audit_pipe_close(struct cdev *dev, int fflag, int devtype, struct thread *td) | ||||
{ | { | ||||
struct audit_pipe *ap; | struct audit_pipe *ap; | ||||
int error; | |||||
ap = dev->si_drv1; | error = devfs_get_cdevpriv((void **)&ap); | ||||
if (error != 0) | |||||
return (error); | |||||
KASSERT(ap != NULL, ("audit_pipe_close: ap == NULL")); | KASSERT(ap != NULL, ("audit_pipe_close: ap == NULL")); | ||||
KASSERT(ap->ap_open, ("audit_pipe_close: !ap_open")); | KASSERT(ap->ap_open, ("audit_pipe_close: !ap_open")); | ||||
funsetown(&ap->ap_sigio); | funsetown(&ap->ap_sigio); | ||||
AUDIT_PIPE_LIST_WLOCK(); | |||||
AUDIT_PIPE_LOCK(ap); | |||||
ap->ap_open = 0; | |||||
audit_pipe_free(ap); | |||||
dev->si_drv1 = NULL; | dev->si_drv1 = NULL; | ||||
kib: Why is this assignment left ? | |||||
AUDIT_PIPE_LIST_WUNLOCK(); | |||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Audit pipe ioctl() routine. Handle file descriptor and audit pipe layer | * Audit pipe ioctl() routine. Handle file descriptor and audit pipe layer | ||||
* commands. | * commands. | ||||
*/ | */ | ||||
static int | static int | ||||
audit_pipe_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, | audit_pipe_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, | ||||
struct thread *td) | struct thread *td) | ||||
{ | { | ||||
struct auditpipe_ioctl_preselect *aip; | struct auditpipe_ioctl_preselect *aip; | ||||
struct audit_pipe *ap; | struct audit_pipe *ap; | ||||
au_mask_t *maskp; | au_mask_t *maskp; | ||||
int error, mode; | int error, mode; | ||||
au_id_t auid; | au_id_t auid; | ||||
ap = dev->si_drv1; | error = devfs_get_cdevpriv((void **)&ap); | ||||
if (error != 0) | |||||
return (error); | |||||
KASSERT(ap != NULL, ("audit_pipe_ioctl: ap == NULL")); | KASSERT(ap != NULL, ("audit_pipe_ioctl: ap == NULL")); | ||||
/* | /* | ||||
* Audit pipe ioctls: first come standard device node ioctls, then | * Audit pipe ioctls: first come standard device node ioctls, then | ||||
* manipulation of pipe settings, and finally, statistics query | * manipulation of pipe settings, and finally, statistics query | ||||
* ioctls. | * ioctls. | ||||
*/ | */ | ||||
switch (cmd) { | switch (cmd) { | ||||
▲ Show 20 Lines • Show All 188 Lines • ▼ Show 20 Lines | |||||
static int | static int | ||||
audit_pipe_read(struct cdev *dev, struct uio *uio, int flag) | audit_pipe_read(struct cdev *dev, struct uio *uio, int flag) | ||||
{ | { | ||||
struct audit_pipe_entry *ape; | struct audit_pipe_entry *ape; | ||||
struct audit_pipe *ap; | struct audit_pipe *ap; | ||||
u_int toread; | u_int toread; | ||||
int error; | int error; | ||||
ap = dev->si_drv1; | error = devfs_get_cdevpriv((void **)&ap); | ||||
if (error != 0) | |||||
return (error); | |||||
KASSERT(ap != NULL, ("audit_pipe_read: ap == NULL")); | KASSERT(ap != NULL, ("audit_pipe_read: ap == NULL")); | ||||
/* | /* | ||||
* We hold an sx(9) lock over read and flush because we rely on the | * We hold an sx(9) lock over read and flush because we rely on the | ||||
* stability of a record in the queue during uiomove(9). | * stability of a record in the queue during uiomove(9). | ||||
*/ | */ | ||||
if (AUDIT_PIPE_SX_XLOCK_SIG(ap) != 0) | if (AUDIT_PIPE_SX_XLOCK_SIG(ap) != 0) | ||||
return (EINTR); | return (EINTR); | ||||
▲ Show 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Audit pipe poll. | * Audit pipe poll. | ||||
*/ | */ | ||||
static int | static int | ||||
audit_pipe_poll(struct cdev *dev, int events, struct thread *td) | audit_pipe_poll(struct cdev *dev, int events, struct thread *td) | ||||
{ | { | ||||
struct audit_pipe *ap; | struct audit_pipe *ap; | ||||
int revents; | int error, revents; | ||||
revents = 0; | revents = 0; | ||||
ap = dev->si_drv1; | error = devfs_get_cdevpriv((void **)&ap); | ||||
if (error != 0) | |||||
return (error); | |||||
KASSERT(ap != NULL, ("audit_pipe_poll: ap == NULL")); | KASSERT(ap != NULL, ("audit_pipe_poll: ap == NULL")); | ||||
if (events & (POLLIN | POLLRDNORM)) { | if (events & (POLLIN | POLLRDNORM)) { | ||||
AUDIT_PIPE_LOCK(ap); | AUDIT_PIPE_LOCK(ap); | ||||
if (TAILQ_FIRST(&ap->ap_queue) != NULL) | if (TAILQ_FIRST(&ap->ap_queue) != NULL) | ||||
revents |= events & (POLLIN | POLLRDNORM); | revents |= events & (POLLIN | POLLRDNORM); | ||||
else | else | ||||
selrecord(td, &ap->ap_selinfo); | selrecord(td, &ap->ap_selinfo); | ||||
AUDIT_PIPE_UNLOCK(ap); | AUDIT_PIPE_UNLOCK(ap); | ||||
} | } | ||||
return (revents); | return (revents); | ||||
} | } | ||||
/* | /* | ||||
* Audit pipe kqfilter. | * Audit pipe kqfilter. | ||||
*/ | */ | ||||
static int | static int | ||||
audit_pipe_kqfilter(struct cdev *dev, struct knote *kn) | audit_pipe_kqfilter(struct cdev *dev, struct knote *kn) | ||||
{ | { | ||||
struct audit_pipe *ap; | struct audit_pipe *ap; | ||||
int error; | |||||
ap = dev->si_drv1; | error = devfs_get_cdevpriv((void **)&ap); | ||||
if (error != 0) | |||||
return (error); | |||||
KASSERT(ap != NULL, ("audit_pipe_kqfilter: ap == NULL")); | KASSERT(ap != NULL, ("audit_pipe_kqfilter: ap == NULL")); | ||||
if (kn->kn_filter != EVFILT_READ) | if (kn->kn_filter != EVFILT_READ) | ||||
return (EINVAL); | return (EINVAL); | ||||
kn->kn_fop = &audit_pipe_read_filterops; | kn->kn_fop = &audit_pipe_read_filterops; | ||||
kn->kn_hook = ap; | kn->kn_hook = ap; | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | |||||
* Initialize the audit pipe system. | * Initialize the audit pipe system. | ||||
*/ | */ | ||||
static void | static void | ||||
audit_pipe_init(void *unused) | audit_pipe_init(void *unused) | ||||
{ | { | ||||
TAILQ_INIT(&audit_pipe_list); | TAILQ_INIT(&audit_pipe_list); | ||||
AUDIT_PIPE_LIST_LOCK_INIT(); | AUDIT_PIPE_LIST_LOCK_INIT(); | ||||
/* XXXDAVIDE: credentials */ | |||||
clone_setup(&audit_pipe_clones); | audit_pipe_dev = make_dev(&audit_pipe_cdevsw, 0, UID_ROOT, | ||||
audit_pipe_eh_tag = EVENTHANDLER_REGISTER(dev_clone, | GID_WHEEL, 0600, "%s", AUDIT_PIPE_NAME); | ||||
audit_pipe_clone, 0, 1000); | if (audit_pipe_dev == NULL) { | ||||
if (audit_pipe_eh_tag == NULL) | AUDIT_PIPE_LIST_LOCK_DESTROY(); | ||||
panic("audit_pipe_init: EVENTHANDLER_REGISTER"); | panic("Can't initialize audit pipe subsystem"); | ||||
} | |||||
} | } | ||||
SYSINIT(audit_pipe_init, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, audit_pipe_init, | SYSINIT(audit_pipe_init, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, audit_pipe_init, | ||||
NULL); | NULL); |
Why is this assignment left ?