Date: Sat, 22 Jan 2005 15:16:00 GMT From: Wayne Salamon <wsalamon@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 69473 for review Message-ID: <200501221516.j0MFG0I0070576@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=69473 Change 69473 by wsalamon@rickenbacker on 2005/01/22 15:15:35 Change the IPC mechanism between kernel and userspace to use a /dev entry. Triggers from the kernel are sent via this path, as well as triggers from userspace. auditctl() now takes three commands: Set the audit log filename, shut down auditing, and send a trigger. (Note that the auditon() syscall also has a shutdown command). Therefore, no longer will userspace send a NULL path pointer to indicate that auditing is done. Change auditd, the audit and auditon commands to use the new auditctl() form. Affected files ... .. //depot/projects/trustedbsd/audit3/contrib/audit_supt/audit/audit.c#4 edit .. //depot/projects/trustedbsd/audit3/contrib/audit_supt/auditd/auditd.c#8 edit .. //depot/projects/trustedbsd/audit3/sys/bsm/audit.h#10 edit .. //depot/projects/trustedbsd/audit3/sys/bsm/audit_kernel.h#12 edit .. //depot/projects/trustedbsd/audit3/sys/kern/init_sysent.c#11 edit .. //depot/projects/trustedbsd/audit3/sys/kern/syscalls.master#11 edit .. //depot/projects/trustedbsd/audit3/sys/security/audit/kern_audit.c#16 edit .. //depot/projects/trustedbsd/audit3/sys/sys/sysproto.h#10 edit .. //depot/projects/trustedbsd/audit3/usr.sbin/auditon/auditon.c#4 edit Differences ... ==== //depot/projects/trustedbsd/audit3/contrib/audit_supt/audit/audit.c#4 (text+ko) ==== @@ -14,7 +14,11 @@ #include <sys/types.h> #include <sys/uio.h> -void process(int flags); +void usage() +{ + (void)fprintf(stderr, "Usage: audit -n | -s | -t \n"); + exit(-1); +} /* * Main routine to process command line options. @@ -22,49 +26,37 @@ int main(int argc, char **argv) { char ch; - int flags = 0; + unsigned int trigger = 0; + + if (argc != 2) + usage(); + while ((ch = getopt(argc, argv, "nst")) != -1) { switch(ch) { case 'n': - flags = AUDITD_TRIGGER_OPEN_NEW; + trigger = AUDITD_TRIGGER_OPEN_NEW; break; case 's': - flags = AUDITD_TRIGGER_READ_FILE; + trigger = AUDITD_TRIGGER_READ_FILE; break; case 't': - flags = AUDITD_TRIGGER_CLOSE_AND_DIE; + trigger = AUDITD_TRIGGER_CLOSE_AND_DIE; break; case '?': default: - (void)fprintf(stderr, - "usage: audit -n | -s | -t \n"); - exit(1); + usage(); + break; } } - process(flags); - return 0; -} - -/* - * Do all the real work. - * Send a message to the audit daemon and check the return code. - */ -void process(int flags) -{ - int fd; - - fd = open(AUDITD_CTL_FILE, O_RDWR); - if (fd == -1) { - perror("error opening auditd control file"); - exit(1); - } - if (write(fd, &flags, sizeof(flags)) == -1) { - perror("error doing write: "); + if (auditctl(AC_SENDTRIGGER, &trigger, sizeof(trigger)) < 0) { + perror("Error sending trigger"); exit(-1); + } else { + printf("Trigger sent.\n"); + exit (0); } - printf("Client call successful\n"); } ==== //depot/projects/trustedbsd/audit3/contrib/audit_supt/auditd/auditd.c#8 (text+ko) ==== @@ -50,7 +50,7 @@ static char *lastfile = NULL; static int allhardcount = 0; -static int controlfd = 0; +static int triggerfd = 0; TAILQ_HEAD(, dir_ent) dir_q; @@ -186,7 +186,7 @@ if (open(fn, O_RDONLY | O_CREAT, S_IRUSR | S_IRGRP) < 0) { perror("File open"); } - else if (auditctl(AC_SETLOGFILE, fn) != 0) { + else if (auditctl(AC_SETLOGFILE, &fn, sizeof(fn)) != 0) { syslog(LOG_ERR, "auditctl failed setting log file! : %s\n", strerror(errno)); @@ -304,7 +304,7 @@ } /* flush contents */ - err_ret = auditctl(AC_SETLOGFILE, NULL); + err_ret = auditctl(AC_SHUTDOWN, NULL, 0); if (err_ret != 0) { syslog(LOG_ERR, "auditctl failed! : %s\n", strerror(errno)); @@ -324,7 +324,7 @@ } endac(); - if(close(controlfd) != 0) { + if(close(triggerfd) != 0) { syslog(LOG_ERR, "Error closing control file\n"); } syslog(LOG_INFO, "Finished.\n"); @@ -389,24 +389,31 @@ } /* - * Signal handler for the SIGIO signal for events on the auditd control file. + * Read the control file for triggers and handle appropriately. */ -static void sigio_handler(int sig) +int wait_for_triggers() { int num; - int trigger; + unsigned int trigger; - num = read(controlfd, &trigger, sizeof(trigger)); - if ((num == -1) && (errno != EINTR)) { - syslog(LOG_ERR, "sigio_handler(): error %d\n", errno); - return; + for (;;) { + num = read(triggerfd, &trigger, sizeof(trigger)); + if ((num == -1) && (errno != EINTR)) { + syslog(LOG_ERR, "%s: error %d\n", __FUNCTION__, errno); + return (-1); + } + if (num == 0) { + syslog(LOG_INFO, "%s: read EOF\n", __FUNCTION__); + return (-1); + } + syslog(LOG_INFO, "%s: read %d\n", __FUNCTION__, trigger); + if (trigger == AUDITD_TRIGGER_CLOSE_AND_DIE) + break; + else + handle_auditd_trigger(trigger); } - if (num == 0) { - syslog(LOG_INFO, "sigio_handler(): read EOF\n"); - return; - } - syslog(LOG_INFO, "sigio_handler(): read %d\n", trigger); - handle_auditd_trigger(trigger); + syslog(LOG_INFO, "auditd exiting.\n"); + return(close_all()); } /* @@ -500,12 +507,6 @@ } break; - case AUDITD_TRIGGER_CLOSE_AND_DIE : - syslog(LOG_INFO, "Got close and die trigger\n"); - rc = close_all(); - exit (rc); - break; - default : break; } @@ -604,68 +605,16 @@ return 0; } -/* - * Configure the IPC mechanism for receiving messages from the kernel - * concerning audit control events. - */ -int config_auditd_ipc() -{ - int rc; - struct stat sb; - - rc = mkfifo(AUDITD_CTL_FILE, S_IRUSR | S_IWUSR); - if ((rc != 0) && (errno != EEXIST)) { - syslog(LOG_ERR, - "config_auditd_ipc() : error creating FIFO\n"); - return rc; - } - - rc = stat(AUDITD_CTL_FILE, &sb); - if ((rc != 0) || ((sb.st_mode & S_IFIFO) == 0)) { - syslog(LOG_ERR, - "config_auditd_ipc() : error stat of FIFO\n"); - return rc; - } - - /* Set up the signal hander */ - if (signal(SIGIO, sigio_handler) == SIG_ERR) { - syslog(LOG_ERR, - "config_auditd_ipc() : error setting up signal handler\n"); - return -1; - } - - controlfd = open(AUDITD_CTL_FILE, O_RDONLY | O_NONBLOCK); - if (controlfd < 0) { - syslog(LOG_ERR, - "config_auditd_ipc() : error opening control file\n"); - return -1; - } - if (fcntl(controlfd, F_SETOWN, getpid())) { - syslog(LOG_ERR, - "config_auditd_ipc() : error setting file ownership\n"); - return -1; - } - - if (fcntl(controlfd, F_SETFL, O_ASYNC)) { - syslog(LOG_ERR, - "config_auditd_ipc() : error setting file ASYNC\n"); - return -1; - } - /* Tell the kernel the name of the auditd control file */ - if (auditctl(AC_SETCTLFILE, AUDITD_CTL_FILE) != 0) { - syslog(LOG_ERR, - "config_auditd_ipc() : failed sending control file " - "name to the kernel: %s\n", - strerror(errno)); - } - return 0; -} - void setup(long flags) { int aufd; token_t *tok; + if ((triggerfd = open(AUDITD_TRIGGER_FILE, O_RDONLY, 0)) < 0) { + syslog(LOG_ERR, "Error opening trigger file\n"); + fail_exit(); + } + TAILQ_INIT(&dir_q); if(read_control_file() == -1) { @@ -692,10 +641,6 @@ else syslog(LOG_INFO, "Audit controls init failed\n"); - if (config_auditd_ipc() == 0) - syslog(LOG_INFO, "auditd control created\n"); - else - syslog(LOG_ERR, "auditd control not created\n"); } int main(int argc, char **argv) @@ -703,6 +648,7 @@ char ch; long flags = AUDIT_CNT; int debug = 0; + int rc; while ((ch = getopt(argc, argv, "dhs")) != -1) { switch(ch) { @@ -744,10 +690,8 @@ } setup(flags); - while(1) - sleep(32768); + + rc = wait_for_triggers(); - syslog(LOG_INFO, "exiting.\n"); - - exit(1); + exit (rc); } ==== //depot/projects/trustedbsd/audit3/sys/bsm/audit.h#10 (text+ko) ==== @@ -36,10 +36,13 @@ #define MAX_AUDIT_RECORD_SIZE 4096 #define MIN_AUDIT_FILE_SIZE 512 * 1024 +/* The special device filename */ +#define AUDITDEV_FILENAME "audit" + /* - * Control FIFO for the audit daemon + * File that will be read for trigger events from the kerenl */ -#define AUDITD_CTL_FILE "/etc/security/auditd_control" +#define AUDITD_TRIGGER_FILE "/dev/audit" /* * Triggers for the audit daemon @@ -164,7 +167,8 @@ * auditctl(2) commands */ #define AC_SETLOGFILE 1 -#define AC_SETCTLFILE 2 +#define AC_SHUTDOWN 2 +#define AC_SENDTRIGGER 3 __BEGIN_DECLS @@ -301,7 +305,7 @@ int audit (const void *, int); int auditon (int, void *, int); -int auditctl (int, const char *); +int auditctl (int, const void *, u_int); int getauid (au_id_t *); int setauid (const au_id_t *); int getaudit (struct auditinfo *); ==== //depot/projects/trustedbsd/audit3/sys/bsm/audit_kernel.h#12 (text+ko) ==== @@ -132,12 +132,12 @@ }; union auditctl_udata { - char ac_path[MAXPATHLEN]; - int ac_fd; + char *ac_path; + unsigned int ac_trigger; }; union auditon_udata { - char au_path[MAXPATHLEN]; + char *au_path; long au_cond; long au_flags; long au_policy; ==== //depot/projects/trustedbsd/audit3/sys/kern/init_sysent.c#11 (text+ko) ==== ==== //depot/projects/trustedbsd/audit3/sys/kern/syscalls.master#11 (text+ko) ==== @@ -705,6 +705,6 @@ *auditinfo_addr, u_int length); } AUE_GETAUDIT_ADDR 452 MSTD { int setaudit_addr(struct auditinfo_addr \ *auditinfo_addr, u_int length); } AUE_SETAUDIT_ADDR -453 MSTD { int auditctl(int cmd, char *path); } AUE_AUDITCTL +453 MSTD { int auditctl(int cmd, void *data, u_int length); } AUE_AUDITCTL ; Please copy any additions and changes to the following compatability tables: ; sys/compat/freebsd32/syscalls.master ==== //depot/projects/trustedbsd/audit3/sys/security/audit/kern_audit.c#16 (text+ko) ==== @@ -22,6 +22,7 @@ #include <sys/param.h> #include <sys/condvar.h> +#include <sys/conf.h> #include <sys/file.h> #include <sys/filedesc.h> #include <sys/fcntl.h> @@ -178,10 +179,6 @@ static int audit_file_rotate_wait; /* - * vnode for the audit daemon control file - */ -static struct vnode *auditd_ctl_vp; -/* * Flags controlling behavior in low storage situations. * Should we panic if a write fails? Should we fail stop * if we're out of disk space? Are we currently "failing @@ -191,6 +188,112 @@ static int audit_fail_stop; static int audit_in_failure; +/* + * Structures and operations to support the basic character special device + * used to communicate with userland. + */ +struct trigger_info { + unsigned int trigger; + TAILQ_ENTRY(trigger_info) list; +}; +static struct cdev *audit_dev; +static int audit_isopen = 0; +static TAILQ_HEAD(, trigger_info) trigger_list; + +static int +audit_open(struct cdev *dev, int oflags, int devtype, struct thread *td) +{ + int error; + + // Only one process may open the device at a time + mtx_lock(&audit_mtx); + if (!audit_isopen) { + error = 0; + audit_isopen = 1; + } else { + error = EOPNOTSUPP; + } + mtx_unlock(&audit_mtx); + + return (error); +} + +static int +audit_close(struct cdev *dev, int fflag, int devtype, struct thread *td) +{ + struct trigger_info *ti; + + /* Drain the queue of pending trigger events */ + mtx_lock(&audit_mtx); + audit_isopen = 0; + while (!TAILQ_EMPTY(&trigger_list)) { + ti = TAILQ_FIRST(&trigger_list); + TAILQ_REMOVE(&trigger_list, ti, list); + free(ti, M_AUDIT); + } + mtx_unlock(&audit_mtx); + return (0); +} + +static int +audit_read(struct cdev *dev, struct uio *uio, int ioflag) +{ + int error = 0; + struct trigger_info *ti = NULL; + + mtx_lock(&audit_mtx); + while (TAILQ_EMPTY(&trigger_list)) { + error = msleep(&trigger_list, &audit_mtx, PSOCK | PCATCH, + "auditd", 0); + if (error) + break; + } + if (!error) { + ti = TAILQ_FIRST(&trigger_list); + TAILQ_REMOVE(&trigger_list, ti, list); + } + mtx_unlock(&audit_mtx); + if (!error) { + error = uiomove(ti, sizeof *ti, uio); + free(ti, M_AUDIT); + } + return error; +} + +static int +audit_write(struct cdev *dev, struct uio *uio, int ioflag) +{ + /* Communication is kernel->userspace only */ + return EOPNOTSUPP; +} + +static int +send_trigger(unsigned int trigger) +{ + struct trigger_info *ti; + + /* If nobody's listening, we ain't talking */ + if (!audit_isopen) + return 0; + + ti = malloc(sizeof *ti, M_AUDIT, M_WAITOK); + mtx_lock(&audit_mtx); + ti->trigger = trigger; + TAILQ_INSERT_TAIL(&trigger_list, ti, list); + wakeup(&trigger_list); + mtx_unlock(&audit_mtx); + return 0; +} + +static struct cdevsw audit_cdevsw = { + .d_version = D_VERSION, + .d_open = audit_open, + .d_close = audit_close, + .d_read = audit_read, + .d_write = audit_write, + .d_name = "audit" +}; + static void audit_free(struct kaudit_record *ar) { @@ -216,11 +319,12 @@ } static int -audit_write(struct vnode *vp, struct kaudit_record *ar, struct ucred *cred, - struct thread *td) +audit_record_write(struct vnode *vp, struct kaudit_record *ar, + struct ucred *cred, struct thread *td) { int ret; int trigger; + long temp; struct au_record *bsm; struct vattr vattr; struct statfs *mnt_stat = &vp->v_mount->mnt_stat; @@ -251,50 +355,41 @@ * XXX Need to decide what to do if the trigger to the audit daemon * fails. */ - if (auditd_ctl_vp != NULL) { - long temp; - /* - * If we fall below percent free blocks, then trigger the - * audit daemon to do something about it. - */ - if (audit_qctrl.aq_minfree != 0) { - temp = mnt_stat->f_blocks / (100 / audit_qctrl.aq_minfree); - if (mnt_stat->f_bfree < temp) { - trigger = AUDITD_TRIGGER_LOW_SPACE; - ret = vn_rdwr(UIO_WRITE, auditd_ctl_vp, - (void *)&trigger, sizeof(trigger), - (off_t)0, UIO_SYSSPACE, IO_APPEND|IO_UNIT, - cred, NULL, NULL, td); - if (ret != 0) { - printf( + /* + * If we fall below percent free blocks, then trigger the + * audit daemon to do something about it. + */ + if (audit_qctrl.aq_minfree != 0) { + temp = mnt_stat->f_blocks / (100 / audit_qctrl.aq_minfree); + if (mnt_stat->f_bfree < temp) { + trigger = AUDITD_TRIGGER_LOW_SPACE; + ret = send_trigger(AUDITD_TRIGGER_LOW_SPACE); + if (ret != 0) { + printf( "Failed audit_triggers(AUDIT_TRIGGER_LOW_SPACE): %d\n", ret); - /* - * XXX: What to do here? Disable auditing? - * panic? - */ - } + /* + * XXX: What to do here? Disable auditing? + * panic? + */ } } - /* Check if the current log file is full; if so, call for - * a log rotate. This is not an exact comparison; we may - * write some records over the limit. If that's not - * acceptable, then add a fudge factor here. - */ - if ((audit_fstat.af_filesz != 0) && - (audit_file_rotate_wait == 0) && - (vattr.va_size >= audit_fstat.af_filesz)) { - audit_file_rotate_wait = 1; - trigger = AUDITD_TRIGGER_OPEN_NEW; - ret = vn_rdwr(UIO_WRITE, auditd_ctl_vp, - (void *)&trigger, sizeof(trigger), - (off_t)0, UIO_SYSSPACE, IO_APPEND|IO_UNIT, - cred, NULL, NULL, td); - if (ret != 0) { - printf( + } + /* Check if the current log file is full; if so, call for + * a log rotate. This is not an exact comparison; we may + * write some records over the limit. If that's not + * acceptable, then add a fudge factor here. + */ + if ((audit_fstat.af_filesz != 0) && + (audit_file_rotate_wait == 0) && + (vattr.va_size >= audit_fstat.af_filesz)) { + audit_file_rotate_wait = 1; + trigger = AUDITD_TRIGGER_OPEN_NEW; + ret = send_trigger(AUDITD_TRIGGER_OPEN_NEW); + if (ret != 0) { + printf( "Failed audit_triggers(AUDITD_TRIGGER_OPEN_NEW): %d\n", ret); - /* XXX what to do here? */ - } + /* XXX what to do here? */ } } @@ -557,8 +652,8 @@ } VOP_LEASE(audit_vp, audit_td, audit_cred, LEASE_WRITE); - error = audit_write(audit_vp, ar, audit_cred, - audit_td); + error = audit_record_write(audit_vp, ar, + audit_cred, audit_td); if (error && audit_panic_on_write_fail) panic("audit_worker: write error %d\n", error); @@ -589,7 +684,6 @@ audit_replacement_flag = 0; audit_file_rotate_wait = 0; audit_replacement_vp = NULL; - auditd_ctl_vp = NULL; audit_fstat.af_filesz = 0; /* '0' means unset, unbounded */ audit_fstat.af_currsz = 0; audit_qctrl.aq_hiwater = AQ_HIWATER; @@ -610,6 +704,11 @@ 0, "audit_worker"); if (error != 0) panic("audit_init: kthread_create returned %d", error); + + TAILQ_INIT(&trigger_list); + /* Create the special device file */ + audit_dev = make_dev(&audit_cdevsw, 0, UID_ROOT, GID_KMEM, 0600, + AUDITDEV_FILENAME); } SYSINIT(audit_init, SI_SUB_AUDIT, SI_ORDER_FIRST, audit_init, NULL) @@ -1090,15 +1189,31 @@ int auditctl(struct thread *td, struct auditctl_args *uap) { + char *fn = NULL; struct nameidata nd; struct ucred *cred; struct vnode *vp; - int error, flags; + union auditctl_udata udata; + int error = 0; + int flags; error = suser(td); if (error) return (error); + /* Some commands don't have associated data; only copy in data if + * it is there. + */ + if (uap->data != NULL) { + if ((uap->length <= 0) || + (uap->length > sizeof(union auditctl_udata))) + return (EINVAL); + + error = copyin(uap->data, (void *)&udata, uap->length); + if (error) + return error; + } + vp = NULL; cred = NULL; @@ -1109,59 +1224,52 @@ * validity checks, and grab another reference to the current * credential. */ - if (uap->path != NULL) { + if (udata.ac_path == NULL) + return (EINVAL); + + fn = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); + error = copyinstr(udata.ac_path, fn, MAXPATHLEN, NULL); + if (error != 0) + goto err_out; - mtx_lock(&Giant); - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, - uap->path, td); - flags = audit_open_flags; - error = vn_open(&nd, &flags, 0, -1); - if (error) { - mtx_unlock(&Giant); - return (error); - } - VOP_UNLOCK(nd.ni_vp, 0, td); - vp = nd.ni_vp; - if (vp->v_type != VREG) { - vn_close(vp, audit_close_flags, - td->td_ucred, td); - mtx_unlock(&Giant); - return (EINVAL); - } - cred = td->td_ucred; - crhold(cred); - audit_suspended = 0; + mtx_lock(&Giant); + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, fn, td); + flags = audit_open_flags; + error = vn_open(&nd, &flags, 0, -1); + if (error) { + mtx_unlock(&Giant); + goto err_out; + } + VOP_UNLOCK(nd.ni_vp, 0, td); + vp = nd.ni_vp; + if (vp->v_type != VREG) { + vn_close(vp, audit_close_flags, + td->td_ucred, td); mtx_unlock(&Giant); + error = EINVAL; + goto err_out; } + cred = td->td_ucred; + crhold(cred); + audit_suspended = 0; + mtx_unlock(&Giant); audit_rotate_vnode(cred, vp); break; - case AC_SETCTLFILE: /* Set auditd control file */ - if (uap->path != NULL) { - mtx_lock(&Giant); - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, - uap->path, td); - flags = FWRITE | O_NONBLOCK; - error = vn_open(&nd, &flags, 0, -1); - if (error) { - mtx_unlock(&Giant); - return (error); - } - VOP_UNLOCK(nd.ni_vp, 0, td); - vp = nd.ni_vp; - if (vp->v_type != VFIFO) { - vn_close(vp, audit_close_flags, - td->td_ucred, td); - mtx_unlock(&Giant); - return (EINVAL); - } - auditd_ctl_vp = vp; - mtx_unlock(&Giant); - } + case AC_SHUTDOWN: + audit_shutdown(); + break; + + case AC_SENDTRIGGER: + error = send_trigger(udata.ac_trigger); break; } - return (0); + +err_out: + if (fn) + free(fn, M_TEMP); + return (error); } /********************************** ==== //depot/projects/trustedbsd/audit3/sys/sys/sysproto.h#10 (text+ko) ==== @@ -1337,7 +1337,8 @@ }; struct auditctl_args { char cmd_l_[PADL_(int)]; int cmd; char cmd_r_[PADR_(int)]; - char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; + char data_l_[PADL_(void *)]; void * data; char data_r_[PADR_(void *)]; + char length_l_[PADL_(u_int)]; u_int length; char length_r_[PADR_(u_int)]; }; int nosys(struct thread *, struct nosys_args *); void sys_exit(struct thread *, struct sys_exit_args *); ==== //depot/projects/trustedbsd/audit3/usr.sbin/auditon/auditon.c#4 (text+ko) ==== @@ -55,11 +55,13 @@ if (argc != 2) usage(); - if (strcmp(argv[1], "off") == 0) - path = NULL; - else + if (strcmp(argv[1], "off") == 0) { + if (auditctl(AC_SHUTDOWN, NULL, 0) != 0) + errx(-1, "Shutdown %s", strerror(errno)); + } else { path = argv[1]; - if (auditctl(AC_SETLOGFILE, path) == -1) - errx(-1, "%s: %s", path, strerror(errno)); + if (auditctl(AC_SETLOGFILE, &path, sizeof(path)) != 0) + errx(-1, "%s: %s", path, strerror(errno)); + } exit(0); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200501221516.j0MFG0I0070576>