Index: head/sys/bsm/audit.h =================================================================== --- head/sys/bsm/audit.h (revision 181052) +++ head/sys/bsm/audit.h (revision 181053) @@ -1,293 +1,293 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. + * Copyright (c) 2005 Apple Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * P4: //depot/projects/trustedbsd/audit3/sys/bsm/audit.h#40 * $FreeBSD$ */ #ifndef _BSM_AUDIT_H #define _BSM_AUDIT_H #include #include #include #define AUDIT_RECORD_MAGIC 0x828a0f1b #define MAX_AUDIT_RECORDS 20 #define MAXAUDITDATA (0x8000 - 1) #define MAX_AUDIT_RECORD_SIZE MAXAUDITDATA #define MIN_AUDIT_FILE_SIZE (512 * 1024) /* * Minimum noumber of free blocks on the filesystem containing the audit * log necessary to avoid a hard log rotation. DO NOT SET THIS VALUE TO 0 * as the kernel does an unsigned compare, plus we want to leave a few blocks * free so userspace can terminate the log, etc. */ #define AUDIT_HARD_LIMIT_FREE_BLOCKS 4 /* * Triggers for the audit daemon. */ #define AUDIT_TRIGGER_MIN 1 #define AUDIT_TRIGGER_LOW_SPACE 1 /* Below low watermark. */ #define AUDIT_TRIGGER_ROTATE_KERNEL 2 /* Kernel requests rotate. */ #define AUDIT_TRIGGER_READ_FILE 3 /* Re-read config file. */ #define AUDIT_TRIGGER_CLOSE_AND_DIE 4 /* Terminate audit. */ #define AUDIT_TRIGGER_NO_SPACE 5 /* Below min free space. */ #define AUDIT_TRIGGER_ROTATE_USER 6 /* User requests roate. */ #define AUDIT_TRIGGER_MAX 6 /* * The special device filename (FreeBSD). */ #define AUDITDEV_FILENAME "audit" #define AUDIT_TRIGGER_FILE ("/dev/" AUDITDEV_FILENAME) /* * Pre-defined audit IDs */ #define AU_DEFAUDITID -1 /* * IPC types. */ #define AT_IPC_MSG ((u_char)1) /* Message IPC id. */ #define AT_IPC_SEM ((u_char)2) /* Semaphore IPC id. */ #define AT_IPC_SHM ((u_char)3) /* Shared mem IPC id. */ /* * Audit conditions. */ #define AUC_UNSET 0 #define AUC_AUDITING 1 #define AUC_NOAUDIT 2 #define AUC_DISABLED -1 /* * auditon(2) commands. */ #define A_GETPOLICY 2 #define A_SETPOLICY 3 #define A_GETKMASK 4 #define A_SETKMASK 5 #define A_GETQCTRL 6 #define A_SETQCTRL 7 #define A_GETCWD 8 #define A_GETCAR 9 #define A_GETSTAT 12 #define A_SETSTAT 13 #define A_SETUMASK 14 #define A_SETSMASK 15 #define A_GETCOND 20 #define A_SETCOND 21 #define A_GETCLASS 22 #define A_SETCLASS 23 #define A_GETPINFO 24 #define A_SETPMASK 25 #define A_SETFSIZE 26 #define A_GETFSIZE 27 #define A_GETPINFO_ADDR 28 #define A_GETKAUDIT 29 #define A_SETKAUDIT 30 #define A_SENDTRIGGER 31 /* * Audit policy controls. */ #define AUDIT_CNT 0x0001 #define AUDIT_AHLT 0x0002 #define AUDIT_ARGV 0x0004 #define AUDIT_ARGE 0x0008 #define AUDIT_SEQ 0x0010 #define AUDIT_WINDATA 0x0020 #define AUDIT_USER 0x0040 #define AUDIT_GROUP 0x0080 #define AUDIT_TRAIL 0x0100 #define AUDIT_PATH 0x0200 #define AUDIT_SCNT 0x0400 #define AUDIT_PUBLIC 0x0800 #define AUDIT_ZONENAME 0x1000 #define AUDIT_PERZONE 0x2000 /* * Default audit queue control parameters. */ #define AQ_HIWATER 100 #define AQ_MAXHIGH 10000 #define AQ_LOWATER 10 #define AQ_BUFSZ MAXAUDITDATA #define AQ_MAXBUFSZ 1048576 /* * Default minimum percentage free space on file system. */ #define AU_FS_MINFREE 20 /* * Type definitions used indicating the length of variable length addresses * in tokens containing addresses, such as header fields. */ #define AU_IPv4 4 #define AU_IPv6 16 __BEGIN_DECLS typedef uid_t au_id_t; typedef pid_t au_asid_t; typedef u_int16_t au_event_t; typedef u_int16_t au_emod_t; typedef u_int32_t au_class_t; struct au_tid { dev_t port; u_int32_t machine; }; typedef struct au_tid au_tid_t; struct au_tid_addr { dev_t at_port; u_int32_t at_type; u_int32_t at_addr[4]; }; typedef struct au_tid_addr au_tid_addr_t; struct au_mask { unsigned int am_success; /* Success bits. */ unsigned int am_failure; /* Failure bits. */ }; typedef struct au_mask au_mask_t; struct auditinfo { au_id_t ai_auid; /* Audit user ID. */ au_mask_t ai_mask; /* Audit masks. */ au_tid_t ai_termid; /* Terminal ID. */ au_asid_t ai_asid; /* Audit session ID. */ }; typedef struct auditinfo auditinfo_t; struct auditinfo_addr { au_id_t ai_auid; /* Audit user ID. */ au_mask_t ai_mask; /* Audit masks. */ au_tid_addr_t ai_termid; /* Terminal ID. */ au_asid_t ai_asid; /* Audit session ID. */ }; typedef struct auditinfo_addr auditinfo_addr_t; struct auditpinfo { pid_t ap_pid; /* ID of target process. */ au_id_t ap_auid; /* Audit user ID. */ au_mask_t ap_mask; /* Audit masks. */ au_tid_t ap_termid; /* Terminal ID. */ au_asid_t ap_asid; /* Audit session ID. */ }; typedef struct auditpinfo auditpinfo_t; struct auditpinfo_addr { pid_t ap_pid; /* ID of target process. */ au_id_t ap_auid; /* Audit user ID. */ au_mask_t ap_mask; /* Audit masks. */ au_tid_addr_t ap_termid; /* Terminal ID. */ au_asid_t ap_asid; /* Audit session ID. */ }; typedef struct auditpinfo_addr auditpinfo_addr_t; /* * Contents of token_t are opaque outside of libbsm. */ typedef struct au_token token_t; /* * Kernel audit queue control parameters. */ struct au_qctrl { size_t aq_hiwater; size_t aq_lowater; size_t aq_bufsz; clock_t aq_delay; int aq_minfree; /* Minimum filesystem percent free space. */ }; typedef struct au_qctrl au_qctrl_t; /* * Structure for the audit statistics. */ struct audit_stat { unsigned int as_version; unsigned int as_numevent; int as_generated; int as_nonattrib; int as_kernel; int as_audit; int as_auditctl; int as_enqueue; int as_written; int as_wblocked; int as_rblocked; int as_dropped; int as_totalsize; unsigned int as_memused; }; typedef struct audit_stat au_stat_t; /* * Structure for the audit file statistics. */ struct audit_fstat { u_quad_t af_filesz; u_quad_t af_currsz; }; typedef struct audit_fstat au_fstat_t; /* * Audit to event class mapping. */ struct au_evclass_map { au_event_t ec_number; au_class_t ec_class; }; typedef struct au_evclass_map au_evclass_map_t; /* * Audit system calls. */ #if !defined(_KERNEL) && !defined(KERNEL) int audit(const void *, int); int auditon(int, void *, int); int auditctl(const char *); int getauid(au_id_t *); int setauid(const au_id_t *); int getaudit(struct auditinfo *); int setaudit(const struct auditinfo *); int getaudit_addr(struct auditinfo_addr *, int); int setaudit_addr(const struct auditinfo_addr *, int); #endif /* defined(_KERNEL) || defined(KERNEL) */ __END_DECLS #endif /* !_BSM_AUDIT_H */ Index: head/sys/bsm/audit_internal.h =================================================================== --- head/sys/bsm/audit_internal.h (revision 181052) +++ head/sys/bsm/audit_internal.h (revision 181053) @@ -1,116 +1,116 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. + * Copyright (c) 2005 Apple Inc. * Copyright (c) 2005 SPARTA, Inc. * All rights reserved. * * This code was developed in part by Robert N. M. Watson, Senior Principal * Scientist, SPARTA, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * P4: //depot/projects/trustedbsd/audit3/sys/bsm/audit_internal.h#18 * $FreeBSD$ */ #ifndef _AUDIT_INTERNAL_H #define _AUDIT_INTERNAL_H #if defined(__linux__) && !defined(__unused) #define __unused #endif /* * audit_internal.h contains private interfaces that are shared by user space * and the kernel for the purposes of assembling audit records. Applications * should not include this file or use the APIs found within, or it may be * broken with future releases of OpenBSM, which may delete, modify, or * otherwise break these interfaces or the assumptions they rely on. */ struct au_token { u_char *t_data; size_t len; TAILQ_ENTRY(au_token) tokens; }; struct au_record { char used; /* Record currently in use? */ int desc; /* Descriptor for record. */ TAILQ_HEAD(, au_token) token_q; /* Queue of BSM tokens. */ u_char *data; size_t len; LIST_ENTRY(au_record) au_rec_q; }; typedef struct au_record au_record_t; /* * We could determined the header and trailer sizes by defining appropriate * structures. We hold off that approach until we have a consistent way of * using structures for all tokens. This is not straightforward since these * token structures may contain pointers of whose contents we do not know the * size (e.g text tokens). */ #define AUDIT_HEADER_SIZE 18 #define AUDIT_TRAILER_SIZE 7 /* * BSM token streams store fields in big endian byte order, so as to be * portable; when encoding and decoding, we must convert byte orders for * typed values. */ #define ADD_U_CHAR(loc, val) \ do { \ *(loc) = (val); \ (loc) += sizeof(u_char); \ } while(0) #define ADD_U_INT16(loc, val) \ do { \ be16enc((loc), (val)); \ (loc) += sizeof(u_int16_t); \ } while(0) #define ADD_U_INT32(loc, val) \ do { \ be32enc((loc), (val)); \ (loc) += sizeof(u_int32_t); \ } while(0) #define ADD_U_INT64(loc, val) \ do { \ be64enc((loc), (val)); \ (loc) += sizeof(u_int64_t); \ } while(0) #define ADD_MEM(loc, data, size) \ do { \ memcpy((loc), (data), (size)); \ (loc) += size; \ } while(0) #define ADD_STRING(loc, data, size) ADD_MEM(loc, data, size) #endif /* !_AUDIT_INTERNAL_H_ */ Index: head/sys/bsm/audit_kevents.h =================================================================== --- head/sys/bsm/audit_kevents.h (revision 181052) +++ head/sys/bsm/audit_kevents.h (revision 181053) @@ -1,683 +1,683 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. + * Copyright (c) 2005 Apple Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * P4: //depot/projects/trustedbsd/audit3/sys/bsm/audit_kevents.h#34 * $FreeBSD$ */ #ifndef _BSM_AUDIT_KEVENTS_H_ #define _BSM_AUDIT_KEVENTS_H_ /* * Values marked as AUE_NULL are not required to be audited as per CAPP. * * Some conflicts exist in the assignment of name to event number mappings * between BSM implementations. In general, we prefer the OpenSolaris * definition as we consider Solaris BSM to be authoritative. _DARWIN_ has * been inserted for the Darwin variants. If necessary, other tags will be * added in the future. */ #define AUE_NULL 0 #define AUE_EXIT 1 #define AUE_FORK 2 #define AUE_FORKALL AUE_FORK /* Solaris-specific. */ #define AUE_OPEN 3 #define AUE_CREAT 4 #define AUE_LINK 5 #define AUE_UNLINK 6 #define AUE_DELETE AUE_UNLINK /* Darwin-specific. */ #define AUE_EXEC 7 #define AUE_CHDIR 8 #define AUE_MKNOD 9 #define AUE_CHMOD 10 #define AUE_CHOWN 11 #define AUE_UMOUNT 12 #define AUE_JUNK 13 /* Solaris-specific. */ #define AUE_ACCESS 14 #define AUE_CHECKUSERACCESS AUE_ACCESS /* Darwin-specific. */ #define AUE_KILL 15 #define AUE_STAT 16 #define AUE_LSTAT 17 #define AUE_ACCT 18 #define AUE_MCTL 19 /* Solaris-specific. */ #define AUE_REBOOT 20 /* XXX: Darwin conflict. */ #define AUE_SYMLINK 21 #define AUE_READLINK 22 #define AUE_EXECVE 23 #define AUE_CHROOT 24 #define AUE_VFORK 25 #define AUE_SETGROUPS 26 #define AUE_SETPGRP 27 #define AUE_SWAPON 28 #define AUE_SETHOSTNAME 29 /* XXX: Darwin conflict. */ #define AUE_FCNTL 30 #define AUE_SETPRIORITY 31 /* XXX: Darwin conflict. */ #define AUE_CONNECT 32 #define AUE_ACCEPT 33 #define AUE_BIND 34 #define AUE_SETSOCKOPT 35 #define AUE_VTRACE 36 /* Solaris-specific. */ #define AUE_SETTIMEOFDAY 37 /* XXX: Darwin conflict. */ #define AUE_FCHOWN 38 #define AUE_FCHMOD 39 #define AUE_SETREUID 40 #define AUE_SETREGID 41 #define AUE_RENAME 42 #define AUE_TRUNCATE 43 /* XXX: Darwin conflict. */ #define AUE_FTRUNCATE 44 /* XXX: Darwin conflict. */ #define AUE_FLOCK 45 /* XXX: Darwin conflict. */ #define AUE_SHUTDOWN 46 #define AUE_MKDIR 47 #define AUE_RMDIR 48 #define AUE_UTIMES 49 #define AUE_ADJTIME 50 #define AUE_SETRLIMIT 51 #define AUE_KILLPG 52 #define AUE_NFS_SVC 53 /* XXX: Darwin conflict. */ #define AUE_STATFS 54 #define AUE_FSTATFS 55 #define AUE_UNMOUNT 56 /* XXX: Darwin conflict. */ #define AUE_ASYNC_DAEMON 57 #define AUE_NFS_GETFH 58 /* XXX: Darwin conflict. */ #define AUE_SETDOMAINNAME 59 #define AUE_QUOTACTL 60 /* XXX: Darwin conflict. */ #define AUE_EXPORTFS 61 #define AUE_MOUNT 62 #define AUE_SEMSYS 63 #define AUE_MSGSYS 64 #define AUE_SHMSYS 65 #define AUE_BSMSYS 66 /* Solaris-specific. */ #define AUE_RFSSYS 67 /* Solaris-specific. */ #define AUE_FCHDIR 68 #define AUE_FCHROOT 69 #define AUE_VPIXSYS 70 /* Solaris-specific. */ #define AUE_PATHCONF 71 #define AUE_OPEN_R 72 #define AUE_OPEN_RC 73 #define AUE_OPEN_RT 74 #define AUE_OPEN_RTC 75 #define AUE_OPEN_W 76 #define AUE_OPEN_WC 77 #define AUE_OPEN_WT 78 #define AUE_OPEN_WTC 79 #define AUE_OPEN_RW 80 #define AUE_OPEN_RWC 81 #define AUE_OPEN_RWT 82 #define AUE_OPEN_RWTC 83 #define AUE_MSGCTL 84 #define AUE_MSGCTL_RMID 85 #define AUE_MSGCTL_SET 86 #define AUE_MSGCTL_STAT 87 #define AUE_MSGGET 88 #define AUE_MSGRCV 89 #define AUE_MSGSND 90 #define AUE_SHMCTL 91 #define AUE_SHMCTL_RMID 92 #define AUE_SHMCTL_SET 93 #define AUE_SHMCTL_STAT 94 #define AUE_SHMGET 95 #define AUE_SHMAT 96 #define AUE_SHMDT 97 #define AUE_SEMCTL 98 #define AUE_SEMCTL_RMID 99 #define AUE_SEMCTL_SET 100 #define AUE_SEMCTL_STAT 101 #define AUE_SEMCTL_GETNCNT 102 #define AUE_SEMCTL_GETPID 103 #define AUE_SEMCTL_GETVAL 104 #define AUE_SEMCTL_GETALL 105 #define AUE_SEMCTL_GETZCNT 106 #define AUE_SEMCTL_SETVAL 107 #define AUE_SEMCTL_SETALL 108 #define AUE_SEMGET 109 #define AUE_SEMOP 110 #define AUE_CORE 111 /* Solaris-specific, currently. */ #define AUE_CLOSE 112 #define AUE_SYSTEMBOOT 113 /* Solaris-specific. */ #define AUE_ASYNC_DAEMON_EXIT 114 /* Solaris-specific. */ #define AUE_NFSSVC_EXIT 115 /* Solaris-specific. */ #define AUE_WRITEL 128 /* Solaris-specific. */ #define AUE_WRITEVL 129 /* Solaris-specific. */ #define AUE_GETAUID 130 #define AUE_SETAUID 131 #define AUE_GETAUDIT 132 #define AUE_SETAUDIT 133 #define AUE_GETUSERAUDIT 134 /* Solaris-specific. */ #define AUE_SETUSERAUDIT 135 /* Solaris-specific. */ #define AUE_AUDITSVC 136 /* Solaris-specific. */ #define AUE_AUDITUSER 137 /* Solaris-specific. */ #define AUE_AUDITON 138 #define AUE_AUDITON_GTERMID 139 /* Solaris-specific. */ #define AUE_AUDITON_STERMID 140 /* Solaris-specific. */ #define AUE_AUDITON_GPOLICY 141 #define AUE_AUDITON_SPOLICY 142 #define AUE_AUDITON_GQCTRL 145 #define AUE_AUDITON_SQCTRL 146 #define AUE_GETKERNSTATE 147 /* Solaris-specific. */ #define AUE_SETKERNSTATE 148 /* Solaris-specific. */ #define AUE_GETPORTAUDIT 149 /* Solaris-specific. */ #define AUE_AUDITSTAT 150 /* Solaris-specific. */ #define AUE_REVOKE 151 #define AUE_MAC 152 /* Solaris-specific. */ #define AUE_ENTERPROM 153 /* Solaris-specific. */ #define AUE_EXITPROM 154 /* Solaris-specific. */ #define AUE_IFLOAT 155 /* Solaris-specific. */ #define AUE_PFLOAT 156 /* Solaris-specific. */ #define AUE_UPRIV 157 /* Solaris-specific. */ #define AUE_IOCTL 158 #define AUE_SOCKET 183 #define AUE_SENDTO 184 #define AUE_PIPE 185 #define AUE_SOCKETPAIR 186 /* XXX: Darwin conflict. */ #define AUE_SEND 187 #define AUE_SENDMSG 188 #define AUE_RECV 189 #define AUE_RECVMSG 190 #define AUE_RECVFROM 191 #define AUE_READ 192 #define AUE_GETDENTS 193 #define AUE_LSEEK 194 #define AUE_WRITE 195 #define AUE_WRITEV 196 #define AUE_NFS 197 /* Solaris-specific. */ #define AUE_READV 198 #define AUE_OSTAT 199 /* Solaris-specific. */ #define AUE_SETUID 200 /* XXXRW: Solaris old setuid? */ #define AUE_STIME 201 /* XXXRW: Solaris old stime? */ #define AUE_UTIME 202 /* XXXRW: Solaris old utime? */ #define AUE_NICE 203 /* XXXRW: Solaris old nice? */ #define AUE_OSETPGRP 204 /* Solaris-specific. */ #define AUE_SETGID 205 #define AUE_READL 206 /* Solaris-specific. */ #define AUE_READVL 207 /* Solaris-specific. */ #define AUE_FSTAT 208 #define AUE_DUP2 209 #define AUE_MMAP 210 #define AUE_AUDIT 211 #define AUE_PRIOCNTLSYS 212 /* Solaris-specific. */ #define AUE_MUNMAP 213 #define AUE_SETEGID 214 #define AUE_SETEUID 215 #define AUE_PUTMSG 216 /* Solaris-specific. */ #define AUE_GETMSG 217 /* Solaris-specific. */ #define AUE_PUTPMSG 218 /* Solaris-specific. */ #define AUE_GETPMSG 219 /* Solaris-specific. */ #define AUE_AUDITSYS 220 /* Solaris-specific. */ #define AUE_AUDITON_GETKMASK 221 #define AUE_AUDITON_SETKMASK 222 #define AUE_AUDITON_GETCWD 223 #define AUE_AUDITON_GETCAR 224 #define AUE_AUDITON_GETSTAT 225 #define AUE_AUDITON_SETSTAT 226 #define AUE_AUDITON_SETUMASK 227 #define AUE_AUDITON_SETSMASK 228 #define AUE_AUDITON_GETCOND 229 #define AUE_AUDITON_SETCOND 230 #define AUE_AUDITON_GETCLASS 231 #define AUE_AUDITON_SETCLASS 232 #define AUE_FUSERS 233 /* Solaris-specific; also UTSSYS? */ #define AUE_STATVFS 234 #define AUE_XSTAT 235 /* Solaris-specific. */ #define AUE_LXSTAT 236 /* Solaris-specific. */ #define AUE_LCHOWN 237 #define AUE_MEMCNTL 238 /* Solaris-specific. */ #define AUE_SYSINFO 239 /* Solaris-specific. */ #define AUE_XMKNOD 240 /* Solaris-specific. */ #define AUE_FORK1 241 #define AUE_MODCTL 242 /* Solaris-specific. */ #define AUE_MODLOAD 243 #define AUE_MODUNLOAD 244 #define AUE_MODCONFIG 245 /* Solaris-specific. */ #define AUE_MODADDMAJ 246 /* Solaris-specific. */ #define AUE_SOCKACCEPT 247 /* Solaris-specific. */ #define AUE_SOCKCONNECT 248 /* Solaris-specific. */ #define AUE_SOCKSEND 249 /* Solaris-specific. */ #define AUE_SOCKRECEIVE 250 /* Solaris-specific. */ #define AUE_ACLSET 251 #define AUE_FACLSET 252 #define AUE_DOORFS 253 /* Solaris-specific. */ #define AUE_DOORFS_DOOR_CALL 254 /* Solaris-specific. */ #define AUE_DOORFS_DOOR_RETURN 255 /* Solaris-specific. */ #define AUE_DOORFS_DOOR_CREATE 256 /* Solaris-specific. */ #define AUE_DOORFS_DOOR_REVOKE 257 /* Solaris-specific. */ #define AUE_DOORFS_DOOR_INFO 258 /* Solaris-specific. */ #define AUE_DOORFS_DOOR_CRED 259 /* Solaris-specific. */ #define AUE_DOORFS_DOOR_BIND 260 /* Solaris-specific. */ #define AUE_DOORFS_DOOR_UNBIND 261 /* Solaris-specific. */ #define AUE_P_ONLINE 262 /* Solaris-specific. */ #define AUE_PROCESSOR_BIND 263 /* Solaris-specific. */ #define AUE_INST_SYNC 264 /* Solaris-specific. */ #define AUE_SOCKCONFIG 265 /* Solaris-specific. */ #define AUE_SETAUDIT_ADDR 266 #define AUE_GETAUDIT_ADDR 267 #define AUE_UMOUNT2 268 /* Solaris-specific. */ #define AUE_FSAT 269 /* Solaris-specific. */ #define AUE_OPENAT_R 270 #define AUE_OPENAT_RC 271 #define AUE_OPENAT_RT 272 #define AUE_OPENAT_RTC 273 #define AUE_OPENAT_W 274 #define AUE_OPENAT_WC 275 #define AUE_OPENAT_WT 276 #define AUE_OPENAT_WTC 277 #define AUE_OPENAT_RW 278 #define AUE_OPENAT_RWC 279 #define AUE_OPENAT_RWT 280 #define AUE_OPENAT_RWTC 281 #define AUE_RENAMEAT 282 #define AUE_FSTATAT 283 #define AUE_FCHOWNAT 284 #define AUE_FUTIMESAT 285 #define AUE_UNLINKAT 286 #define AUE_CLOCK_SETTIME 287 #define AUE_NTP_ADJTIME 288 #define AUE_SETPPRIV 289 /* Solaris-specific. */ #define AUE_MODDEVPLCY 290 /* Solaris-specific. */ #define AUE_MODADDPRIV 291 /* Solaris-specific. */ #define AUE_CRYPTOADM 292 /* Solaris-specific. */ #define AUE_CONFIGKSSL 293 /* Solaris-specific. */ #define AUE_BRANDSYS 294 /* Solaris-specific. */ #define AUE_PF_POLICY_ADDRULE 295 /* Solaris-specific. */ #define AUE_PF_POLICY_DELRULE 296 /* Solaris-specific. */ #define AUE_PF_POLICY_CLONE 297 /* Solaris-specific. */ #define AUE_PF_POLICY_FLIP 298 /* Solaris-specific. */ #define AUE_PF_POLICY_FLUSH 299 /* Solaris-specific. */ #define AUE_PF_POLICY_ALGS 300 /* Solaris-specific. */ /* * Events added for Apple Darwin that potentially collide with future Solaris * BSM events. These are assigned AUE_DARWIN prefixes, and are deprecated in * new trails. Systems generating these events should switch to the new * identifiers that avoid colliding with the Solaris identifier space. */ #define AUE_DARWIN_GETFSSTAT 301 #define AUE_DARWIN_PTRACE 302 #define AUE_DARWIN_CHFLAGS 303 #define AUE_DARWIN_FCHFLAGS 304 #define AUE_DARWIN_PROFILE 305 #define AUE_DARWIN_KTRACE 306 #define AUE_DARWIN_SETLOGIN 307 #define AUE_DARWIN_REBOOT 308 #define AUE_DARWIN_REVOKE 309 #define AUE_DARWIN_UMASK 310 #define AUE_DARWIN_MPROTECT 311 #define AUE_DARWIN_SETPRIORITY 312 #define AUE_DARWIN_SETTIMEOFDAY 313 #define AUE_DARWIN_FLOCK 314 #define AUE_DARWIN_MKFIFO 315 #define AUE_DARWIN_POLL 316 #define AUE_DARWIN_SOCKETPAIR 317 #define AUE_DARWIN_FUTIMES 318 #define AUE_DARWIN_SETSID 319 #define AUE_DARWIN_SETPRIVEXEC 320 /* Darwin-specific. */ #define AUE_DARWIN_NFSSVC 321 #define AUE_DARWIN_GETFH 322 #define AUE_DARWIN_QUOTACTL 323 #define AUE_DARWIN_ADDPROFILE 324 /* Darwin-specific. */ #define AUE_DARWIN_KDEBUGTRACE 325 /* Darwin-specific. */ #define AUE_DARWIN_KDBUGTRACE AUE_KDEBUGTRACE #define AUE_DARWIN_FSTAT 326 #define AUE_DARWIN_FPATHCONF 327 #define AUE_DARWIN_GETDIRENTRIES 328 #define AUE_DARWIN_TRUNCATE 329 #define AUE_DARWIN_FTRUNCATE 330 #define AUE_DARWIN_SYSCTL 331 #define AUE_DARWIN_MLOCK 332 #define AUE_DARWIN_MUNLOCK 333 #define AUE_DARWIN_UNDELETE 334 #define AUE_DARWIN_GETATTRLIST 335 /* Darwin-specific. */ #define AUE_DARWIN_SETATTRLIST 336 /* Darwin-specific. */ #define AUE_DARWIN_GETDIRENTRIESATTR 337 /* Darwin-specific. */ #define AUE_DARWIN_EXCHANGEDATA 338 /* Darwin-specific. */ #define AUE_DARWIN_SEARCHFS 339 /* Darwin-specific. */ #define AUE_DARWIN_MINHERIT 340 #define AUE_DARWIN_SEMCONFIG 341 #define AUE_DARWIN_SEMOPEN 342 #define AUE_DARWIN_SEMCLOSE 343 #define AUE_DARWIN_SEMUNLINK 344 #define AUE_DARWIN_SHMOPEN 345 #define AUE_DARWIN_SHMUNLINK 346 #define AUE_DARWIN_LOADSHFILE 347 /* Darwin-specific. */ #define AUE_DARWIN_RESETSHFILE 348 /* Darwin-specific. */ #define AUE_DARWIN_NEWSYSTEMSHREG 349 /* Darwin-specific. */ #define AUE_DARWIN_PTHREADKILL 350 /* Darwin-specific. */ #define AUE_DARWIN_PTHREADSIGMASK 351 /* Darwin-specific. */ #define AUE_DARWIN_AUDITCTL 352 #define AUE_DARWIN_RFORK 353 #define AUE_DARWIN_LCHMOD 354 #define AUE_DARWIN_SWAPOFF 355 #define AUE_DARWIN_INITPROCESS 356 /* Darwin-specific. */ #define AUE_DARWIN_MAPFD 357 /* Darwin-specific. */ #define AUE_DARWIN_TASKFORPID 358 /* Darwin-specific. */ #define AUE_DARWIN_PIDFORTASK 359 /* Darwin-specific. */ #define AUE_DARWIN_SYSCTL_NONADMIN 360 #define AUE_DARWIN_COPYFILE 361 /* Darwin-specific. */ /* * Audit event identifiers added as part of OpenBSM, generally corresponding * to events in FreeBSD, Darwin, and Linux that were not present in Solaris. * These often duplicate events added to the Solaris set by Darwin, but use * event identifiers in a higher range in order to avoid colliding with * future Solaris additions. * * If an event in this section is later added to Solaris, we prefer the * Solaris event identifier, and add _OPENBSM_ to the OpenBSM-specific * identifier so that old trails can still be processed, but new trails use * the Solaris identifier. */ #define AUE_GETFSSTAT 43001 #define AUE_PTRACE 43002 #define AUE_CHFLAGS 43003 #define AUE_FCHFLAGS 43004 #define AUE_PROFILE 43005 #define AUE_KTRACE 43006 #define AUE_SETLOGIN 43007 #define AUE_OPENBSM_REVOKE 43008 /* Solaris event now preferred. */ #define AUE_UMASK 43009 #define AUE_MPROTECT 43010 #define AUE_MKFIFO 43011 #define AUE_POLL 43012 #define AUE_FUTIMES 43013 #define AUE_SETSID 43014 #define AUE_SETPRIVEXEC 43015 /* Darwin-specific. */ #define AUE_ADDPROFILE 43016 /* Darwin-specific. */ #define AUE_KDEBUGTRACE 43017 /* Darwin-specific. */ #define AUE_KDBUGTRACE AUE_KDEBUGTRACE #define AUE_OPENBSM_FSTAT 43018 /* Solaris event now preferred. */ #define AUE_FPATHCONF 43019 #define AUE_GETDIRENTRIES 43020 #define AUE_SYSCTL 43021 #define AUE_MLOCK 43022 #define AUE_MUNLOCK 43023 #define AUE_UNDELETE 43024 #define AUE_GETATTRLIST 43025 /* Darwin-specific. */ #define AUE_SETATTRLIST 43026 /* Darwin-specific. */ #define AUE_GETDIRENTRIESATTR 43027 /* Darwin-specific. */ #define AUE_EXCHANGEDATA 43028 /* Darwin-specific. */ #define AUE_SEARCHFS 43029 /* Darwin-specific. */ #define AUE_MINHERIT 43030 #define AUE_SEMCONFIG 43031 #define AUE_SEMOPEN 43032 #define AUE_SEMCLOSE 43033 #define AUE_SEMUNLINK 43034 #define AUE_SHMOPEN 43035 #define AUE_SHMUNLINK 43036 #define AUE_LOADSHFILE 43037 /* Darwin-specific. */ #define AUE_RESETSHFILE 43038 /* Darwin-specific. */ #define AUE_NEWSYSTEMSHREG 43039 /* Darwin-specific. */ #define AUE_PTHREADKILL 43040 /* Darwin-specific. */ #define AUE_PTHREADSIGMASK 43041 /* Darwin-specific. */ #define AUE_AUDITCTL 43042 #define AUE_RFORK 43043 #define AUE_LCHMOD 43044 #define AUE_SWAPOFF 43045 #define AUE_INITPROCESS 43046 /* Darwin-specific. */ #define AUE_MAPFD 43047 /* Darwin-specific. */ #define AUE_TASKFORPID 43048 /* Darwin-specific. */ #define AUE_PIDFORTASK 43049 /* Darwin-specific. */ #define AUE_SYSCTL_NONADMIN 43050 #define AUE_COPYFILE 43051 /* Darwin-specific. */ /* * Events added to OpenBSM for FreeBSD and Linux; may also be used by Darwin * in the future. */ #define AUE_LUTIMES 43052 #define AUE_LCHFLAGS 43053 /* FreeBSD-specific. */ #define AUE_SENDFILE 43054 /* BSD/Linux-specific. */ #define AUE_USELIB 43055 /* Linux-specific. */ #define AUE_GETRESUID 43056 #define AUE_SETRESUID 43057 #define AUE_GETRESGID 43058 #define AUE_SETRESGID 43059 #define AUE_WAIT4 43060 /* FreeBSD-specific. */ #define AUE_LGETFH 43061 /* FreeBSD-specific. */ #define AUE_FHSTATFS 43062 /* FreeBSD-specific. */ #define AUE_FHOPEN 43063 /* FreeBSD-specific. */ #define AUE_FHSTAT 43064 /* FreeBSD-specific. */ #define AUE_JAIL 43065 /* FreeBSD-specific. */ #define AUE_EACCESS 43066 /* FreeBSD-specific. */ #define AUE_KQUEUE 43067 /* FreeBSD-specific. */ #define AUE_KEVENT 43068 /* FreeBSD-specific. */ #define AUE_FSYNC 43069 #define AUE_NMOUNT 43070 /* FreeBSD-specific. */ #define AUE_BDFLUSH 43071 /* Linux-specific. */ #define AUE_SETFSUID 43072 /* Linux-specific. */ #define AUE_SETFSGID 43073 /* Linux-specific. */ #define AUE_PERSONALITY 43074 /* Linux-specific. */ #define AUE_SCHED_GETSCHEDULER 43075 /* POSIX.1b. */ #define AUE_SCHED_SETSCHEDULER 43076 /* POSIX.1b. */ #define AUE_PRCTL 43077 /* Linux-specific. */ #define AUE_GETCWD 43078 /* FreeBSD/Linux-specific. */ #define AUE_CAPGET 43079 /* Linux-specific. */ #define AUE_CAPSET 43080 /* Linux-specific. */ #define AUE_PIVOT_ROOT 43081 /* Linux-specific. */ #define AUE_RTPRIO 43082 /* FreeBSD-specific. */ #define AUE_SCHED_GETPARAM 43083 /* POSIX.1b. */ #define AUE_SCHED_SETPARAM 43084 /* POSIX.1b. */ #define AUE_SCHED_GET_PRIORITY_MAX 43085 /* POSIX.1b. */ #define AUE_SCHED_GET_PRIORITY_MIN 43086 /* POSIX.1b. */ #define AUE_SCHED_RR_GET_INTERVAL 43087 /* POSIX.1b. */ #define AUE_ACL_GET_FILE 43088 /* FreeBSD. */ #define AUE_ACL_SET_FILE 43089 /* FreeBSD. */ #define AUE_ACL_GET_FD 43090 /* FreeBSD. */ #define AUE_ACL_SET_FD 43091 /* FreeBSD. */ #define AUE_ACL_DELETE_FILE 43092 /* FreeBSD. */ #define AUE_ACL_DELETE_FD 43093 /* FreeBSD. */ #define AUE_ACL_CHECK_FILE 43094 /* FreeBSD. */ #define AUE_ACL_CHECK_FD 43095 /* FreeBSD. */ #define AUE_ACL_GET_LINK 43096 /* FreeBSD. */ #define AUE_ACL_SET_LINK 43097 /* FreeBSD. */ #define AUE_ACL_DELETE_LINK 43098 /* FreeBSD. */ #define AUE_ACL_CHECK_LINK 43099 /* FreeBSD. */ #define AUE_SYSARCH 43100 /* FreeBSD. */ #define AUE_EXTATTRCTL 43101 /* FreeBSD. */ #define AUE_EXTATTR_GET_FILE 43102 /* FreeBSD. */ #define AUE_EXTATTR_SET_FILE 43103 /* FreeBSD. */ #define AUE_EXTATTR_LIST_FILE 43104 /* FreeBSD. */ #define AUE_EXTATTR_DELETE_FILE 43105 /* FreeBSD. */ #define AUE_EXTATTR_GET_FD 43106 /* FreeBSD. */ #define AUE_EXTATTR_SET_FD 43107 /* FreeBSD. */ #define AUE_EXTATTR_LIST_FD 43108 /* FreeBSD. */ #define AUE_EXTATTR_DELETE_FD 43109 /* FreeBSD. */ #define AUE_EXTATTR_GET_LINK 43110 /* FreeBSD. */ #define AUE_EXTATTR_SET_LINK 43111 /* FreeBSD. */ #define AUE_EXTATTR_LIST_LINK 43112 /* FreeBSD. */ #define AUE_EXTATTR_DELETE_LINK 43113 /* FreeBSD. */ #define AUE_KENV 43114 /* FreeBSD. */ #define AUE_JAIL_ATTACH 43115 /* FreeBSD. */ #define AUE_SYSCTL_WRITE 43116 /* FreeBSD. */ #define AUE_IOPERM 43117 /* Linux. */ #define AUE_READDIR 43118 /* Linux. */ #define AUE_IOPL 43119 /* Linux. */ #define AUE_VM86 43120 /* Linux. */ #define AUE_MAC_GET_PROC 43121 /* FreeBSD. */ #define AUE_MAC_SET_PROC 43122 /* FreeBSD. */ #define AUE_MAC_GET_FD 43123 /* FreeBSD. */ #define AUE_MAC_GET_FILE 43124 /* FreeBSD. */ #define AUE_MAC_SET_FD 43125 /* FreeBSD. */ #define AUE_MAC_SET_FILE 43126 /* FreeBSD. */ #define AUE_MAC_SYSCALL 43127 /* FreeBSD. */ #define AUE_MAC_GET_PID 43128 /* FreeBSD. */ #define AUE_MAC_GET_LINK 43129 /* FreeBSD. */ #define AUE_MAC_SET_LINK 43130 /* FreeBSD. */ #define AUE_MAC_EXECVE 43131 /* FreeBSD. */ #define AUE_GETPATH_FROMFD 43132 /* FreeBSD. */ #define AUE_GETPATH_FROMADDR 43133 /* FreeBSD. */ #define AUE_MQ_OPEN 43134 /* FreeBSD. */ #define AUE_MQ_SETATTR 43135 /* FreeBSD. */ #define AUE_MQ_TIMEDRECEIVE 43136 /* FreeBSD. */ #define AUE_MQ_TIMEDSEND 43137 /* FreeBSD. */ #define AUE_MQ_NOTIFY 43138 /* FreeBSD. */ #define AUE_MQ_UNLINK 43139 /* FreeBSD. */ #define AUE_LISTEN 43140 /* FreeBSD/Darwin/Linux. */ #define AUE_MLOCKALL 43141 /* FreeBSD. */ #define AUE_MUNLOCKALL 43142 /* FreeBSD. */ #define AUE_CLOSEFROM 43143 /* FreeBSD. */ #define AUE_FEXECVE 43144 /* FreeBSD. */ #define AUE_FACCESSAT 43145 /* FreeBSD. */ #define AUE_FCHMODAT 43146 /* FreeBSD. */ #define AUE_LINKAT 43147 /* FreeBSD. */ #define AUE_MKDIRAT 43148 /* FreeBSD. */ #define AUE_MKFIFOAT 43149 /* FreeBSD. */ #define AUE_MKNODAT 43150 /* FreeBSD. */ #define AUE_READLINKAT 43151 /* FreeBSD. */ #define AUE_SYMLINKAT 43152 /* FreeBSD. */ /* * Darwin BSM uses a number of AUE_O_* definitions, which are aliased to the * normal Solaris BSM identifiers. _O_ refers to it being an old, or compat * interface. In most cases, Darwin has never implemented these system calls * but picked up the fields in their system call table from their FreeBSD * import. Happily, these have different names than the AUE_O* definitions * in Solaris BSM. */ #define AUE_O_CREAT AUE_OPEN_RWTC /* Darwin */ #define AUE_O_EXECVE AUE_NULL /* Darwin */ #define AUE_O_SBREAK AUE_NULL /* Darwin */ #define AUE_O_LSEEK AUE_NULL /* Darwin */ #define AUE_O_MOUNT AUE_NULL /* Darwin */ #define AUE_O_UMOUNT AUE_NULL /* Darwin */ #define AUE_O_STAT AUE_STAT /* Darwin */ #define AUE_O_LSTAT AUE_LSTAT /* Darwin */ #define AUE_O_FSTAT AUE_FSTAT /* Darwin */ #define AUE_O_GETPAGESIZE AUE_NULL /* Darwin */ #define AUE_O_VREAD AUE_NULL /* Darwin */ #define AUE_O_VWRITE AUE_NULL /* Darwin */ #define AUE_O_MMAP AUE_MMAP /* Darwin */ #define AUE_O_VADVISE AUE_NULL /* Darwin */ #define AUE_O_VHANGUP AUE_NULL /* Darwin */ #define AUE_O_VLIMIT AUE_NULL /* Darwin */ #define AUE_O_WAIT AUE_NULL /* Darwin */ #define AUE_O_GETHOSTNAME AUE_NULL /* Darwin */ #define AUE_O_SETHOSTNAME AUE_SYSCTL /* Darwin */ #define AUE_O_GETDOPT AUE_NULL /* Darwin */ #define AUE_O_SETDOPT AUE_NULL /* Darwin */ #define AUE_O_ACCEPT AUE_NULL /* Darwin */ #define AUE_O_SEND AUE_SENDMSG /* Darwin */ #define AUE_O_RECV AUE_RECVMSG /* Darwin */ #define AUE_O_VTIMES AUE_NULL /* Darwin */ #define AUE_O_SIGVEC AUE_NULL /* Darwin */ #define AUE_O_SIGBLOCK AUE_NULL /* Darwin */ #define AUE_O_SIGSETMASK AUE_NULL /* Darwin */ #define AUE_O_SIGSTACK AUE_NULL /* Darwin */ #define AUE_O_RECVMSG AUE_RECVMSG /* Darwin */ #define AUE_O_SENDMSG AUE_SENDMSG /* Darwin */ #define AUE_O_VTRACE AUE_NULL /* Darwin */ #define AUE_O_RESUBA AUE_NULL /* Darwin */ #define AUE_O_RECVFROM AUE_RECVFROM /* Darwin */ #define AUE_O_SETREUID AUE_SETREUID /* Darwin */ #define AUE_O_SETREGID AUE_SETREGID /* Darwin */ #define AUE_O_GETDIRENTRIES AUE_GETDIRENTRIES /* Darwin */ #define AUE_O_TRUNCATE AUE_TRUNCATE /* Darwin */ #define AUE_O_FTRUNCATE AUE_FTRUNCATE /* Darwin */ #define AUE_O_GETPEERNAME AUE_NULL /* Darwin */ #define AUE_O_GETHOSTID AUE_NULL /* Darwin */ #define AUE_O_SETHOSTID AUE_NULL /* Darwin */ #define AUE_O_GETRLIMIT AUE_NULL /* Darwin */ #define AUE_O_SETRLIMIT AUE_SETRLIMIT /* Darwin */ #define AUE_O_KILLPG AUE_KILL /* Darwin */ #define AUE_O_SETQUOTA AUE_NULL /* Darwin */ #define AUE_O_QUOTA AUE_NULL /* Darwin */ #define AUE_O_GETSOCKNAME AUE_NULL /* Darwin */ #define AUE_O_GETDIREENTRIES AUE_GETDIREENTRIES /* Darwin */ #define AUE_O_ASYNCDAEMON AUE_NULL /* Darwin */ #define AUE_O_GETDOMAINNAME AUE_NULL /* Darwin */ #define AUE_O_SETDOMAINNAME AUE_SYSCTL /* Darwin */ #define AUE_O_PCFS_MOUNT AUE_NULL /* Darwin */ #define AUE_O_EXPORTFS AUE_NULL /* Darwin */ #define AUE_O_USTATE AUE_NULL /* Darwin */ #define AUE_O_WAIT3 AUE_NULL /* Darwin */ #define AUE_O_RPAUSE AUE_NULL /* Darwin */ #define AUE_O_GETDENTS AUE_NULL /* Darwin */ /* * Possible desired future values based on review of BSD/Darwin system calls. */ #define AUE_DUP AUE_NULL #define AUE_FSCTL AUE_NULL #define AUE_FSTATV AUE_NULL #define AUE_GCCONTROL AUE_NULL #define AUE_GETDTABLESIZE AUE_NULL #define AUE_GETEGID AUE_NULL #define AUE_GETEUID AUE_NULL #define AUE_GETGID AUE_NULL #define AUE_GETGROUPS AUE_NULL #define AUE_GETITIMER AUE_NULL #define AUE_GETLOGIN AUE_NULL #define AUE_GETPEERNAME AUE_NULL #define AUE_GETPGID AUE_NULL #define AUE_GETPGRP AUE_NULL #define AUE_GETPID AUE_NULL #define AUE_GETPPID AUE_NULL #define AUE_GETPRIORITY AUE_NULL #define AUE_GETRLIMIT AUE_NULL #define AUE_GETRUSAGE AUE_NULL #define AUE_GETSID AUE_NULL #define AUE_GETSOCKNAME AUE_NULL #define AUE_GETTIMEOFDAY AUE_NULL #define AUE_GETUID AUE_NULL #define AUE_GETSOCKOPT AUE_NULL #define AUE_GTSOCKOPT AUE_GETSOCKOPT /* XXX: Typo in Darwin. */ #define AUE_ISSETUGID AUE_NULL #define AUE_LSTATV AUE_NULL #define AUE_MADVISE AUE_NULL #define AUE_MINCORE AUE_NULL #define AUE_MKCOMPLEX AUE_NULL #define AUE_MODWATCH AUE_NULL #define AUE_MSGCL AUE_NULL #define AUE_MSYNC AUE_NULL #define AUE_PREAD AUE_NULL #define AUE_PWRITE AUE_NULL #define AUE_PREADV AUE_NULL #define AUE_PWRITEV AUE_NULL #define AUE_SBRK AUE_NULL #define AUE_SELECT AUE_NULL #define AUE_SEMDESTROY AUE_NULL #define AUE_SEMGETVALUE AUE_NULL #define AUE_SEMINIT AUE_NULL #define AUE_SEMPOST AUE_NULL #define AUE_SEMTRYWAIT AUE_NULL #define AUE_SEMWAIT AUE_NULL #define AUE_SETITIMER AUE_NULL #define AUE_SIGACTION AUE_NULL #define AUE_SIGALTSTACK AUE_NULL #define AUE_SIGPENDING AUE_NULL #define AUE_SIGPROCMASK AUE_NULL #define AUE_SIGRETURN AUE_NULL #define AUE_SIGSUSPEND AUE_NULL #define AUE_SIGWAIT AUE_NULL #define AUE_SSTK AUE_NULL #define AUE_STATV AUE_NULL #define AUE_SYNC AUE_NULL #define AUE_SYSCALL AUE_NULL #define AUE_TABLE AUE_NULL #define AUE_WAITEVENT AUE_NULL #define AUE_WATCHEVENT AUE_NULL #endif /* !_BSM_AUDIT_KEVENTS_H_ */ Index: head/sys/bsm/audit_record.h =================================================================== --- head/sys/bsm/audit_record.h (revision 181052) +++ head/sys/bsm/audit_record.h (revision 181053) @@ -1,335 +1,335 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. + * Copyright (c) 2005 Apple Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * P4: //depot/projects/trustedbsd/audit3/sys/bsm/audit_record.h#26 * $FreeBSD$ */ #ifndef _BSM_AUDIT_RECORD_H_ #define _BSM_AUDIT_RECORD_H_ #include /* struct timeval */ /* * Token type identifiers. */ #define AUT_INVALID 0x00 #define AUT_OTHER_FILE32 0x11 #define AUT_OHEADER 0x12 #define AUT_TRAILER 0x13 #define AUT_HEADER32 0x14 #define AUT_HEADER32_EX 0x15 #define AUT_DATA 0x21 #define AUT_IPC 0x22 #define AUT_PATH 0x23 #define AUT_SUBJECT32 0x24 #define AUT_SERVER32 0x25 #define AUT_PROCESS32 0x26 #define AUT_RETURN32 0x27 #define AUT_TEXT 0x28 #define AUT_OPAQUE 0x29 #define AUT_IN_ADDR 0x2a #define AUT_IP 0x2b #define AUT_IPORT 0x2c #define AUT_ARG32 0x2d #define AUT_SOCKET 0x2e #define AUT_SEQ 0x2f #define AUT_ACL 0x30 #define AUT_ATTR 0x31 #define AUT_IPC_PERM 0x32 #define AUT_LABEL 0x33 #define AUT_GROUPS 0x34 #define AUT_ILABEL 0x35 #define AUT_SLABEL 0x36 #define AUT_CLEAR 0x37 #define AUT_PRIV 0x38 #define AUT_UPRIV 0x39 #define AUT_LIAISON 0x3a #define AUT_NEWGROUPS 0x3b #define AUT_EXEC_ARGS 0x3c #define AUT_EXEC_ENV 0x3d #define AUT_ATTR32 0x3e /* #define AUT_???? 0x3f */ #define AUT_XATOM 0x40 #define AUT_XOBJ 0x41 #define AUT_XPROTO 0x42 #define AUT_XSELECT 0x43 /* XXXRW: Additional X11 tokens not defined? */ #define AUT_CMD 0x51 #define AUT_EXIT 0x52 #define AUT_ZONENAME 0x60 /* XXXRW: OpenBSM AUT_HOST 0x70? */ #define AUT_ARG64 0x71 #define AUT_RETURN64 0x72 #define AUT_ATTR64 0x73 #define AUT_HEADER64 0x74 #define AUT_SUBJECT64 0x75 #define AUT_SERVER64 0x76 #define AUT_PROCESS64 0x77 #define AUT_OTHER_FILE64 0x78 #define AUT_HEADER64_EX 0x79 #define AUT_SUBJECT32_EX 0x7a #define AUT_PROCESS32_EX 0x7b #define AUT_SUBJECT64_EX 0x7c #define AUT_PROCESS64_EX 0x7d #define AUT_IN_ADDR_EX 0x7e #define AUT_SOCKET_EX 0x7f /* * Pre-64-bit BSM, 32-bit tokens weren't explicitly named as '32'. We have * compatibility defines. */ #define AUT_HEADER AUT_HEADER32 #define AUT_ARG AUT_ARG32 #define AUT_RETURN AUT_RETURN32 #define AUT_SUBJECT AUT_SUBJECT32 #define AUT_SERVER AUT_SERVER32 #define AUT_PROCESS AUT_PROCESS32 #define AUT_OTHER_FILE AUT_OTHER_FILE32 /* * Darwin's bsm distribution uses the following non-BSM token name defines. * We provide them for a single OpenBSM release for compatibility reasons. */ #define AU_FILE_TOKEN AUT_OTHER_FILE32 #define AU_TRAILER_TOKEN AUT_TRAILER #define AU_HEADER_32_TOKEN AUT_HEADER32 #define AU_DATA_TOKEN AUT_DATA #define AU_ARB_TOKEN AUT_DATA #define AU_IPC_TOKEN AUT_IPC #define AU_PATH_TOKEN AUT_PATH #define AU_SUBJECT_32_TOKEN AUT_SUBJECT32 #define AU_PROCESS_32_TOKEN AUT_PROCESS32 #define AU_RETURN_32_TOKEN AUT_RETURN32 #define AU_TEXT_TOKEN AUT_TEXT #define AU_OPAQUE_TOKEN AUT_OPAQUE #define AU_IN_ADDR_TOKEN AUT_IN_ADDR #define AU_IP_TOKEN AUT_IP #define AU_IPORT_TOKEN AUT_IPORT #define AU_ARG32_TOKEN AUT_ARG32 #define AU_SOCK_TOKEN AUT_SOCKET #define AU_SEQ_TOKEN AUT_SEQ #define AU_ATTR_TOKEN AUT_ATTR #define AU_IPCPERM_TOKEN AUT_IPC_PERM #define AU_NEWGROUPS_TOKEN AUT_NEWGROUPS #define AU_EXEC_ARG_TOKEN AUT_EXEC_ARGS #define AU_EXEC_ENV_TOKEN AUT_EXEC_ENV #define AU_ATTR32_TOKEN AUT_ATTR32 #define AU_CMD_TOKEN AUT_CMD #define AU_EXIT_TOKEN AUT_EXIT #define AU_ARG64_TOKEN AUT_ARG64 #define AU_RETURN_64_TOKEN AUT_RETURN64 #define AU_ATTR64_TOKEN AUT_ATTR64 #define AU_HEADER_64_TOKEN AUT_HEADER64 #define AU_SUBJECT_64_TOKEN AUT_SUBJECT64 #define AU_PROCESS_64_TOKEN AUT_PROCESS64 #define AU_HEADER_64_EX_TOKEN AUT_HEADER64_EX #define AU_SUBJECT_32_EX_TOKEN AUT_SUBJECT32_EX #define AU_PROCESS_32_EX_TOKEN AUT_PROCESS32_EX #define AU_SUBJECT_64_EX_TOKEN AUT_SUBJECT64_EX #define AU_PROCESS_64_EX_TOKEN AUT_PROCESS64_EX #define AU_IN_ADDR_EX_TOKEN AUT_IN_ADDR_EX #define AU_SOCK_32_EX_TOKEN AUT_SOCKET_EX /* * The values for the following token ids are not defined by BSM. * * XXXRW: Not sure how to handle these in OpenBSM yet, but I'll give them * names more consistent with Sun's BSM. These originally came from Apple's * BSM. */ #define AUT_SOCKINET32 0x80 /* XXX */ #define AUT_SOCKINET128 0x81 /* XXX */ #define AUT_SOCKUNIX 0x82 /* XXX */ #define AU_SOCK_INET_32_TOKEN AUT_SOCKINET32 #define AU_SOCK_INET_128_TOKEN AUT_SOCKINET128 #define AU_SOCK_UNIX_TOKEN AUT_SOCKUNIX /* print values for the arbitrary token */ #define AUP_BINARY 0 #define AUP_OCTAL 1 #define AUP_DECIMAL 2 #define AUP_HEX 3 #define AUP_STRING 4 /* data-types for the arbitrary token */ #define AUR_BYTE 0 #define AUR_CHAR AUR_BYTE #define AUR_SHORT 1 #define AUR_INT32 2 #define AUR_INT AUR_INT32 #define AUR_INT64 3 /* ... and their sizes */ #define AUR_BYTE_SIZE sizeof(u_char) #define AUR_CHAR_SIZE AUR_BYTE_SIZE #define AUR_SHORT_SIZE sizeof(uint16_t) #define AUR_INT32_SIZE sizeof(uint32_t) #define AUR_INT_SIZE AUR_INT32_SIZE #define AUR_INT64_SIZE sizeof(uint64_t) /* Modifiers for the header token */ #define PAD_NOTATTR 0x4000 /* nonattributable event */ #define PAD_FAILURE 0x8000 /* fail audit event */ #define AUDIT_MAX_GROUPS 16 /* * A number of BSM versions are floating around and defined. Here are * constants for them. OpenBSM uses the same token types, etc, used in the * Solaris BSM version, but has a separate version number in order to * identify a potentially different event identifier name space. */ #define AUDIT_HEADER_VERSION_OLDDARWIN 1 /* In retrospect, a mistake. */ #define AUDIT_HEADER_VERSION_SOLARIS 2 #define AUDIT_HEADER_VERSION_TSOL25 3 #define AUDIT_HEADER_VERSION_TSOL 4 #define AUDIT_HEADER_VERSION_OPENBSM 10 /* * BSM define is AUT_TRAILER_MAGIC; Apple BSM define is TRAILER_PAD_MAGIC; we * split the difference, will remove the Apple define for the next release. */ #define AUT_TRAILER_MAGIC 0xb105 #define TRAILER_PAD_MAGIC AUT_TRAILER_MAGIC /* BSM library calls */ __BEGIN_DECLS struct in_addr; struct in6_addr; struct ip; struct ipc_perm; struct kevent; struct sockaddr_in; struct sockaddr_in6; struct sockaddr_un; #if defined(_KERNEL) || defined(KERNEL) struct vnode_au_info; #endif int au_open(void); int au_write(int d, token_t *m); int au_close(int d, int keep, short event); int au_close_buffer(int d, short event, u_char *buffer, size_t *buflen); int au_close_token(token_t *tok, u_char *buffer, size_t *buflen); token_t *au_to_file(char *file, struct timeval tm); token_t *au_to_header32_tm(int rec_size, au_event_t e_type, au_emod_t e_mod, struct timeval tm); token_t *au_to_header64_tm(int rec_size, au_event_t e_type, au_emod_t e_mod, struct timeval tm); #if !defined(KERNEL) && !defined(_KERNEL) token_t *au_to_header(int rec_size, au_event_t e_type, au_emod_t e_mod); token_t *au_to_header32(int rec_size, au_event_t e_type, au_emod_t e_mod); token_t *au_to_header64(int rec_size, au_event_t e_type, au_emod_t e_mod); #endif token_t *au_to_me(void); token_t *au_to_arg(char n, char *text, uint32_t v); token_t *au_to_arg32(char n, char *text, uint32_t v); token_t *au_to_arg64(char n, char *text, uint64_t v); #if defined(_KERNEL) || defined(KERNEL) token_t *au_to_attr(struct vnode_au_info *vni); token_t *au_to_attr32(struct vnode_au_info *vni); token_t *au_to_attr64(struct vnode_au_info *vni); #endif token_t *au_to_data(char unit_print, char unit_type, char unit_count, char *p); token_t *au_to_exit(int retval, int err); token_t *au_to_groups(int *groups); token_t *au_to_newgroups(uint16_t n, gid_t *groups); token_t *au_to_in_addr(struct in_addr *internet_addr); token_t *au_to_in_addr_ex(struct in6_addr *internet_addr); token_t *au_to_ip(struct ip *ip); token_t *au_to_ipc(char type, int id); token_t *au_to_ipc_perm(struct ipc_perm *perm); token_t *au_to_iport(uint16_t iport); token_t *au_to_opaque(char *data, uint16_t bytes); token_t *au_to_path(char *path); token_t *au_to_process(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid, au_tid_t *tid); token_t *au_to_process32(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid, au_tid_t *tid); token_t *au_to_process64(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid, au_tid_t *tid); token_t *au_to_process_ex(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid, au_tid_addr_t *tid); token_t *au_to_process32_ex(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid, au_tid_addr_t *tid); token_t *au_to_process64_ex(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid, au_tid_addr_t *tid); token_t *au_to_return(char status, uint32_t ret); token_t *au_to_return32(char status, uint32_t ret); token_t *au_to_return64(char status, uint64_t ret); token_t *au_to_seq(long audit_count); #if defined(_KERNEL) || defined(KERNEL) token_t *au_to_socket(struct socket *so); token_t *au_to_socket_ex_32(uint16_t lp, uint16_t rp, struct sockaddr *la, struct sockaddr *ta); token_t *au_to_socket_ex_128(uint16_t lp, uint16_t rp, struct sockaddr *la, struct sockaddr *ta); #endif token_t *au_to_sock_inet(struct sockaddr_in *so); token_t *au_to_sock_inet32(struct sockaddr_in *so); token_t *au_to_sock_inet128(struct sockaddr_in6 *so); token_t *au_to_sock_unix(struct sockaddr_un *so); token_t *au_to_subject(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid, au_tid_t *tid); token_t *au_to_subject32(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid, au_tid_t *tid); token_t *au_to_subject64(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid, au_tid_t *tid); token_t *au_to_subject_ex(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid, au_tid_addr_t *tid); token_t *au_to_subject32_ex(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid, au_tid_addr_t *tid); token_t *au_to_subject64_ex(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid, au_tid_addr_t *tid); #if defined(_KERNEL) || defined(KERNEL) token_t *au_to_exec_args(char *args, int argc); token_t *au_to_exec_env(char *envs, int envc); #else token_t *au_to_exec_args(char **argv); token_t *au_to_exec_env(char **envp); #endif token_t *au_to_text(char *text); token_t *au_to_kevent(struct kevent *kev); token_t *au_to_trailer(int rec_size); token_t *au_to_zonename(char *zonename); __END_DECLS #endif /* ! _BSM_AUDIT_RECORD_H_ */ Index: head/sys/security/audit/audit.c =================================================================== --- head/sys/security/audit/audit.c (revision 181052) +++ head/sys/security/audit/audit.c (revision 181053) @@ -1,631 +1,631 @@ -/* +/*- * Copyright (c) 1999-2005 Apple Inc. * Copyright (c) 2006-2007 Robert N. M. Watson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static uma_zone_t audit_record_zone; static MALLOC_DEFINE(M_AUDITCRED, "audit_cred", "Audit cred storage"); MALLOC_DEFINE(M_AUDITDATA, "audit_data", "Audit data storage"); MALLOC_DEFINE(M_AUDITPATH, "audit_path", "Audit path storage"); MALLOC_DEFINE(M_AUDITTEXT, "audit_text", "Audit text storage"); SYSCTL_NODE(_security, OID_AUTO, audit, CTLFLAG_RW, 0, "TrustedBSD audit controls"); /* * Audit control settings that are set/read by system calls and are hence * non-static. * * Define the audit control flags. */ int audit_enabled; int audit_suspended; /* * 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? */ int audit_panic_on_write_fail; int audit_fail_stop; int audit_argv; int audit_arge; /* * Are we currently "failing stop" due to out of disk space? */ int audit_in_failure; /* * Global audit statistics. */ struct audit_fstat audit_fstat; /* * Preselection mask for non-attributable events. */ struct au_mask audit_nae_mask; /* * Mutex to protect global variables shared between various threads and * processes. */ struct mtx audit_mtx; /* * Queue of audit records ready for delivery to disk. We insert new records * at the tail, and remove records from the head. Also, a count of the * number of records used for checking queue depth. In addition, a counter * of records that we have allocated but are not yet in the queue, which is * needed to estimate the total size of the combined set of records * outstanding in the system. */ struct kaudit_queue audit_q; int audit_q_len; int audit_pre_q_len; /* * Audit queue control settings (minimum free, low/high water marks, etc.) */ struct au_qctrl audit_qctrl; /* * 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. */ struct cv audit_worker_cv; /* * 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_watermark_cv; /* * Condition variable for auditing threads wait on when in fail-stop mode. * Threads wait on this CV forever (and ever), never seeing the light of day * again. */ static struct cv audit_fail_cv; /* * Construct an audit record for the passed thread. */ static int audit_record_ctor(void *mem, int size, void *arg, int flags) { struct kaudit_record *ar; struct thread *td; KASSERT(sizeof(*ar) == size, ("audit_record_ctor: wrong size")); td = arg; ar = mem; bzero(ar, sizeof(*ar)); ar->k_ar.ar_magic = AUDIT_RECORD_MAGIC; nanotime(&ar->k_ar.ar_starttime); /* * Export the subject credential. */ cru2x(td->td_ucred, &ar->k_ar.ar_subj_cred); ar->k_ar.ar_subj_ruid = td->td_ucred->cr_ruid; ar->k_ar.ar_subj_rgid = td->td_ucred->cr_rgid; ar->k_ar.ar_subj_egid = td->td_ucred->cr_groups[0]; ar->k_ar.ar_subj_auid = td->td_ucred->cr_audit.ai_auid; ar->k_ar.ar_subj_asid = td->td_ucred->cr_audit.ai_asid; ar->k_ar.ar_subj_pid = td->td_proc->p_pid; ar->k_ar.ar_subj_amask = td->td_ucred->cr_audit.ai_mask; ar->k_ar.ar_subj_term_addr = td->td_ucred->cr_audit.ai_termid; return (0); } static void audit_record_dtor(void *mem, int size, void *arg) { struct kaudit_record *ar; KASSERT(sizeof(*ar) == size, ("audit_record_dtor: wrong size")); ar = mem; if (ar->k_ar.ar_arg_upath1 != NULL) free(ar->k_ar.ar_arg_upath1, M_AUDITPATH); if (ar->k_ar.ar_arg_upath2 != NULL) free(ar->k_ar.ar_arg_upath2, M_AUDITPATH); if (ar->k_ar.ar_arg_text != NULL) free(ar->k_ar.ar_arg_text, M_AUDITTEXT); if (ar->k_udata != NULL) free(ar->k_udata, M_AUDITDATA); if (ar->k_ar.ar_arg_argv != NULL) free(ar->k_ar.ar_arg_argv, M_AUDITTEXT); if (ar->k_ar.ar_arg_envv != NULL) free(ar->k_ar.ar_arg_envv, M_AUDITTEXT); } /* * Initialize the Audit subsystem: configuration state, work queue, * synchronization primitives, worker thread, and trigger device node. Also * call into the BSM assembly code to initialize it. */ static void audit_init(void) { audit_enabled = 0; audit_suspended = 0; audit_panic_on_write_fail = 0; audit_fail_stop = 0; audit_in_failure = 0; audit_argv = 0; audit_arge = 0; audit_fstat.af_filesz = 0; /* '0' means unset, unbounded. */ audit_fstat.af_currsz = 0; audit_nae_mask.am_success = 0; audit_nae_mask.am_failure = 0; TAILQ_INIT(&audit_q); audit_q_len = 0; audit_pre_q_len = 0; audit_qctrl.aq_hiwater = AQ_HIWATER; audit_qctrl.aq_lowater = AQ_LOWATER; audit_qctrl.aq_bufsz = AQ_BUFSZ; audit_qctrl.aq_minfree = AU_FS_MINFREE; mtx_init(&audit_mtx, "audit_mtx", NULL, MTX_DEF); 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", sizeof(struct kaudit_record), audit_record_ctor, audit_record_dtor, NULL, NULL, UMA_ALIGN_PTR, 0); /* Initialize the BSM audit subsystem. */ kau_init(); audit_trigger_init(); /* Register shutdown handler. */ EVENTHANDLER_REGISTER(shutdown_pre_sync, audit_shutdown, NULL, SHUTDOWN_PRI_FIRST); /* Start audit worker thread. */ audit_worker_init(); } SYSINIT(audit_init, SI_SUB_AUDIT, SI_ORDER_FIRST, audit_init, NULL); /* * Drain the audit queue and close the log at shutdown. Note that this can * be called both from the system shutdown path and also from audit * configuration syscalls, so 'arg' and 'howto' are ignored. * * XXXRW: In FreeBSD 7.x and 8.x, this fails to wait for the record queue to * drain before returning, which could lead to lost records on shutdown. */ void audit_shutdown(void *arg, int howto) { audit_rotate_vnode(NULL, NULL); } /* * Return the current thread's audit record, if any. */ struct kaudit_record * currecord(void) { return (curthread->td_ar); } /* * XXXAUDIT: There are a number of races present in the code below due to * release and re-grab of the mutex. The code should be revised to become * slightly less racy. * * XXXAUDIT: Shouldn't there be logic here to sleep waiting on available * pre_q space, suspending the system call until there is room? */ struct kaudit_record * audit_new(int event, struct thread *td) { struct kaudit_record *ar; int no_record; mtx_lock(&audit_mtx); no_record = (audit_suspended || !audit_enabled); mtx_unlock(&audit_mtx); if (no_record) return (NULL); /* * Note: the number of outstanding uncommitted audit records is * limited to the number of concurrent threads servicing system calls * in the kernel. */ ar = uma_zalloc_arg(audit_record_zone, td, M_WAITOK); ar->k_ar.ar_event = event; mtx_lock(&audit_mtx); audit_pre_q_len++; mtx_unlock(&audit_mtx); return (ar); } void audit_free(struct kaudit_record *ar) { uma_zfree(audit_record_zone, ar); } 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; if (ar == NULL) return; /* * Decide whether to commit the audit record by checking the error * value from the system call and using the appropriate audit mask. */ if (ar->k_ar.ar_subj_auid == AU_DEFAUDITID) aumask = &audit_nae_mask; else aumask = &ar->k_ar.ar_subj_amask; if (error) sorf = AU_PRS_FAILURE; else sorf = AU_PRS_SUCCESS; switch(ar->k_ar.ar_event) { case AUE_OPEN_RWTC: /* * The open syscall always writes a AUE_OPEN_RWTC event; * change it to the proper type of event based on the flags * and the error value. */ ar->k_ar.ar_event = audit_flags_and_error_to_openevent( ar->k_ar.ar_arg_fflags, error); break; case AUE_SYSCTL: ar->k_ar.ar_event = audit_ctlname_to_sysctlevent( ar->k_ar.ar_arg_ctlname, ar->k_ar.ar_valid_arg); break; case AUE_AUDITON: /* Convert the auditon() command to an event. */ ar->k_ar.ar_event = auditon_command_event(ar->k_ar.ar_arg_cmd); break; } auid = ar->k_ar.ar_subj_auid; event = ar->k_ar.ar_event; class = au_event_class(event); 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 | AR_PRESELECT_USER_TRAIL | AR_PRESELECT_USER_PIPE)) == 0) { mtx_lock(&audit_mtx); audit_pre_q_len--; mtx_unlock(&audit_mtx); audit_free(ar); return; } ar->k_ar.ar_errno = error; ar->k_ar.ar_retval = retval; nanotime(&ar->k_ar.ar_endtime); /* * Note: it could be that some records initiated while audit was * enabled should still be committed? */ mtx_lock(&audit_mtx); if (audit_suspended || !audit_enabled) { audit_pre_q_len--; mtx_unlock(&audit_mtx); audit_free(ar); return; } /* * Constrain the number of committed audit records based on the * configurable parameter. */ while (audit_q_len >= audit_qctrl.aq_hiwater) cv_wait(&audit_watermark_cv, &audit_mtx); TAILQ_INSERT_TAIL(&audit_q, ar, k_q); audit_q_len++; audit_pre_q_len--; cv_signal(&audit_worker_cv); mtx_unlock(&audit_mtx); } /* * audit_syscall_enter() is called on entry to each system call. It is * responsible for deciding whether or not to audit the call (preselection), * and if so, allocating a per-thread audit record. audit_new() will fill in * basic thread/credential properties. */ void audit_syscall_enter(unsigned short code, struct thread *td) { 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")); /* * In FreeBSD, each ABI has its own system call table, and hence * mapping of system call codes to audit events. Convert the code to * an audit event identifier using the process system call table * reference. In Darwin, there's only one, so we use the global * symbol for the system call table. No audit record is generated * for bad system calls, as no operation has been performed. */ if (code >= td->td_proc->p_sysent->sv_size) return; 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. */ auid = td->td_ucred->cr_audit.ai_auid; if (auid == AU_DEFAUDITID) aumask = &audit_nae_mask; else aumask = &td->td_ucred->cr_audit.ai_mask; /* * Allocate an audit record, if preselection allows it, and store in * the thread for later use. */ 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 * another audit record. * * Note: we might wish to be able to continue here in the * future, if the system recovers. That should be possible * by means of checking the condition in a loop around * cv_wait(). It might be desirable to reevaluate whether an * audit record is still required for this event by * re-calling au_preselect(). */ if (audit_in_failure && priv_check(td, PRIV_AUDIT_FAILSTOP) != 0) { cv_wait(&audit_fail_cv, &audit_mtx); panic("audit_failing_stop: thread continued"); } 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; } /* * audit_syscall_exit() is called from the return of every system call, or in * the event of exit1(), during the execution of exit1(). It is responsible * for committing the audit record, if any, along with return condition. */ void audit_syscall_exit(int error, struct thread *td) { int retval; /* * Commit the audit record as desired; once we pass the record into * audit_commit(), the memory is owned by the audit subsystem. The * return value from the system call is stored on the user thread. * If there was an error, the return value is set to -1, imitating * the behavior of the cerror routine. */ if (error) retval = -1; else retval = td->td_retval[0]; audit_commit(td->td_ar, error, retval); td->td_ar = NULL; } void audit_cred_copy(struct ucred *src, struct ucred *dest) { bcopy(&src->cr_audit, &dest->cr_audit, sizeof(dest->cr_audit)); } void audit_cred_destroy(struct ucred *cred) { } void audit_cred_init(struct ucred *cred) { bzero(&cred->cr_audit, sizeof(cred->cr_audit)); } /* * Initialize audit information for the first kernel process (proc 0) and for * the first user process (init). */ void audit_cred_kproc0(struct ucred *cred) { cred->cr_audit.ai_auid = AU_DEFAUDITID; cred->cr_audit.ai_termid.at_type = AU_IPv4; } void audit_cred_proc1(struct ucred *cred) { cred->cr_audit.ai_auid = AU_DEFAUDITID; cred->cr_audit.ai_termid.at_type = AU_IPv4; } void audit_thread_alloc(struct thread *td) { td->td_ar = NULL; } void audit_thread_free(struct thread *td) { KASSERT(td->td_ar == NULL, ("audit_thread_free: td_ar != NULL")); } void audit_proc_coredump(struct thread *td, char *path, int errcode) { struct kaudit_record *ar; struct au_mask *aumask; au_class_t class; int ret, sorf; char **pathp; au_id_t auid; ret = 0; /* * Make sure we are using the correct preselection mask. */ auid = td->td_ucred->cr_audit.ai_auid; if (auid == AU_DEFAUDITID) aumask = &audit_nae_mask; else aumask = &td->td_ucred->cr_audit.ai_mask; /* * It's possible for coredump(9) generation to fail. Make sure that * we handle this case correctly for preselection. */ if (errcode != 0) sorf = AU_PRS_FAILURE; else sorf = AU_PRS_SUCCESS; class = au_event_class(AUE_CORE); if (au_preselect(AUE_CORE, class, aumask, sorf) == 0) return; /* * If we are interested in seeing this audit record, allocate it. * Where possible coredump records should contain a pathname and arg32 * (signal) tokens. */ ar = audit_new(AUE_CORE, td); if (path != NULL) { pathp = &ar->k_ar.ar_arg_upath1; *pathp = malloc(MAXPATHLEN, M_AUDITPATH, M_WAITOK); audit_canon_path(td, path, *pathp); ARG_SET_VALID(ar, ARG_UPATH1); } ar->k_ar.ar_arg_signum = td->td_proc->p_sig; ARG_SET_VALID(ar, ARG_SIGNUM); if (errcode != 0) ret = 1; audit_commit(ar, errcode, ret); } Index: head/sys/security/audit/audit.h =================================================================== --- head/sys/security/audit/audit.h (revision 181052) +++ head/sys/security/audit/audit.h (revision 181053) @@ -1,233 +1,233 @@ -/* +/*- * Copyright (c) 1999-2005 Apple Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ /* * This header includes function prototypes and type definitions that are * necessary for the kernel as a whole to interact with the audit subsystem. */ #ifndef _SECURITY_AUDIT_KERNEL_H_ #define _SECURITY_AUDIT_KERNEL_H_ #ifndef _KERNEL #error "no user-serviceable parts inside" #endif #include #include #include /* * Audit subsystem condition flags. The audit_enabled flag is set and * removed automatically as a result of configuring log files, and can be * observed but should not be directly manipulated. The audit suspension * flag permits audit to be temporarily disabled without reconfiguring the * audit target. */ extern int audit_enabled; extern int audit_suspended; /* * Define the masks for the audited arguments. * * XXXRW: These need to remain in audit.h for now because our vnode and name * lookup audit calls rely on passing in flags to indicate which name or * vnode is being logged. These should move to audit_private.h when that is * fixed. */ #define ARG_EUID 0x0000000000000001ULL #define ARG_RUID 0x0000000000000002ULL #define ARG_SUID 0x0000000000000004ULL #define ARG_EGID 0x0000000000000008ULL #define ARG_RGID 0x0000000000000010ULL #define ARG_SGID 0x0000000000000020ULL #define ARG_PID 0x0000000000000040ULL #define ARG_UID 0x0000000000000080ULL #define ARG_AUID 0x0000000000000100ULL #define ARG_GID 0x0000000000000200ULL #define ARG_FD 0x0000000000000400ULL #define ARG_POSIX_IPC_PERM 0x0000000000000800ULL #define ARG_FFLAGS 0x0000000000001000ULL #define ARG_MODE 0x0000000000002000ULL #define ARG_DEV 0x0000000000004000ULL #define ARG_ADDR 0x0000000000008000ULL #define ARG_LEN 0x0000000000010000ULL #define ARG_MASK 0x0000000000020000ULL #define ARG_SIGNUM 0x0000000000040000ULL #define ARG_LOGIN 0x0000000000080000ULL #define ARG_SADDRINET 0x0000000000100000ULL #define ARG_SADDRINET6 0x0000000000200000ULL #define ARG_SADDRUNIX 0x0000000000400000ULL #define ARG_TERMID_ADDR 0x0000000000400000ULL #define ARG_UNUSED2 0x0000000001000000ULL #define ARG_UPATH1 0x0000000002000000ULL #define ARG_UPATH2 0x0000000004000000ULL #define ARG_TEXT 0x0000000008000000ULL #define ARG_VNODE1 0x0000000010000000ULL #define ARG_VNODE2 0x0000000020000000ULL #define ARG_SVIPC_CMD 0x0000000040000000ULL #define ARG_SVIPC_PERM 0x0000000080000000ULL #define ARG_SVIPC_ID 0x0000000100000000ULL #define ARG_SVIPC_ADDR 0x0000000200000000ULL #define ARG_GROUPSET 0x0000000400000000ULL #define ARG_CMD 0x0000000800000000ULL #define ARG_SOCKINFO 0x0000001000000000ULL #define ARG_ASID 0x0000002000000000ULL #define ARG_TERMID 0x0000004000000000ULL #define ARG_AUDITON 0x0000008000000000ULL #define ARG_VALUE 0x0000010000000000ULL #define ARG_AMASK 0x0000020000000000ULL #define ARG_CTLNAME 0x0000040000000000ULL #define ARG_PROCESS 0x0000080000000000ULL #define ARG_MACHPORT1 0x0000100000000000ULL #define ARG_MACHPORT2 0x0000200000000000ULL #define ARG_EXIT 0x0000400000000000ULL #define ARG_IOVECSTR 0x0000800000000000ULL #define ARG_ARGV 0x0001000000000000ULL #define ARG_ENVV 0x0002000000000000ULL #define ARG_NONE 0x0000000000000000ULL #define ARG_ALL 0xFFFFFFFFFFFFFFFFULL void audit_syscall_enter(unsigned short code, struct thread *td); void audit_syscall_exit(int error, struct thread *td); /* * The remaining kernel functions are conditionally compiled in as they are * wrapped by a macro, and the macro should be the only place in the source * tree where these functions are referenced. */ #ifdef AUDIT struct ipc_perm; struct sockaddr; union auditon_udata; void audit_arg_addr(void * addr); void audit_arg_exit(int status, int retval); void audit_arg_len(int len); void audit_arg_fd(int fd); void audit_arg_fflags(int fflags); void audit_arg_gid(gid_t gid); void audit_arg_uid(uid_t uid); void audit_arg_egid(gid_t egid); void audit_arg_euid(uid_t euid); void audit_arg_rgid(gid_t rgid); void audit_arg_ruid(uid_t ruid); void audit_arg_sgid(gid_t sgid); void audit_arg_suid(uid_t suid); void audit_arg_groupset(gid_t *gidset, u_int gidset_size); void audit_arg_login(char *login); void audit_arg_ctlname(int *name, int namelen); void audit_arg_mask(int mask); void audit_arg_mode(mode_t mode); void audit_arg_dev(int dev); void audit_arg_value(long value); void audit_arg_owner(uid_t uid, gid_t gid); void audit_arg_pid(pid_t pid); void audit_arg_process(struct proc *p); void audit_arg_signum(u_int signum); void audit_arg_socket(int sodomain, int sotype, int soprotocol); void audit_arg_sockaddr(struct thread *td, struct sockaddr *sa); void audit_arg_auid(uid_t auid); void audit_arg_auditinfo(struct auditinfo *au_info); void audit_arg_auditinfo_addr(struct auditinfo_addr *au_info); void audit_arg_upath(struct thread *td, char *upath, u_int64_t flags); void audit_arg_vnode(struct vnode *vp, u_int64_t flags); void audit_arg_text(char *text); void audit_arg_cmd(int cmd); void audit_arg_svipc_cmd(int cmd); void audit_arg_svipc_perm(struct ipc_perm *perm); void audit_arg_svipc_id(int id); void audit_arg_svipc_addr(void *addr); void audit_arg_posix_ipc_perm(uid_t uid, gid_t gid, mode_t mode); void audit_arg_auditon(union auditon_udata *udata); void audit_arg_file(struct proc *p, struct file *fp); void audit_arg_argv(char *argv, int argc, int length); void audit_arg_envv(char *envv, int envc, int length); void audit_sysclose(struct thread *td, int fd); void audit_cred_copy(struct ucred *src, struct ucred *dest); void audit_cred_destroy(struct ucred *cred); void audit_cred_init(struct ucred *cred); void audit_cred_kproc0(struct ucred *cred); void audit_cred_proc1(struct ucred *cred); void audit_proc_coredump(struct thread *td, char *path, int errcode); void audit_thread_alloc(struct thread *td); void audit_thread_free(struct thread *td); /* * Define a macro to wrap the audit_arg_* calls by checking the global * audit_enabled flag before performing the actual call. */ #define AUDIT_ARG(op, args...) do { \ if (td->td_ar != NULL) \ audit_arg_ ## op (args); \ } while (0) #define AUDIT_SYSCALL_ENTER(code, td) do { \ if (audit_enabled) { \ audit_syscall_enter(code, td); \ } \ } while (0) /* * Wrap the audit_syscall_exit() function so that it is called only when * auditing is enabled, or we have a audit record on the thread. It is * possible that an audit record was begun before auditing was turned off. */ #define AUDIT_SYSCALL_EXIT(error, td) do { \ if (audit_enabled || (td->td_ar != NULL)) \ audit_syscall_exit(error, td); \ } while (0) /* * A Macro to wrap the audit_sysclose() function. */ #define AUDIT_SYSCLOSE(td, fd) do { \ if (audit_enabled) \ audit_sysclose(td, fd); \ } while (0) #else /* !AUDIT */ #define AUDIT_ARG(op, args...) do { \ } while (0) #define AUDIT_SYSCALL_ENTER(code, td) do { \ } while (0) #define AUDIT_SYSCALL_EXIT(error, td) do { \ } while (0) #define AUDIT_SYSCLOSE(p, fd) do { \ } while (0) #endif /* AUDIT */ #endif /* !_SECURITY_AUDIT_KERNEL_H_ */ Index: head/sys/security/audit/audit_arg.c =================================================================== --- head/sys/security/audit/audit_arg.c (revision 181052) +++ head/sys/security/audit/audit_arg.c (revision 181053) @@ -1,857 +1,857 @@ -/* +/*- * Copyright (c) 1999-2005 Apple Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * Calls to manipulate elements of the audit record structure from system * call code. Macro wrappers will prevent this functions from being entered * if auditing is disabled, avoiding the function call cost. We check the * thread audit record pointer anyway, as the audit condition could change, * and pre-selection may not have allocated an audit record for this event. * * XXXAUDIT: Should we assert, in each case, that this field of the record * hasn't already been filled in? */ void audit_arg_addr(void *addr) { struct kaudit_record *ar; ar = currecord(); if (ar == NULL) return; ar->k_ar.ar_arg_addr = addr; ARG_SET_VALID(ar, ARG_ADDR); } void audit_arg_exit(int status, int retval) { struct kaudit_record *ar; ar = currecord(); if (ar == NULL) return; ar->k_ar.ar_arg_exitstatus = status; ar->k_ar.ar_arg_exitretval = retval; ARG_SET_VALID(ar, ARG_EXIT); } void audit_arg_len(int len) { struct kaudit_record *ar; ar = currecord(); if (ar == NULL) return; ar->k_ar.ar_arg_len = len; ARG_SET_VALID(ar, ARG_LEN); } void audit_arg_fd(int fd) { struct kaudit_record *ar; ar = currecord(); if (ar == NULL) return; ar->k_ar.ar_arg_fd = fd; ARG_SET_VALID(ar, ARG_FD); } void audit_arg_fflags(int fflags) { struct kaudit_record *ar; ar = currecord(); if (ar == NULL) return; ar->k_ar.ar_arg_fflags = fflags; ARG_SET_VALID(ar, ARG_FFLAGS); } void audit_arg_gid(gid_t gid) { struct kaudit_record *ar; ar = currecord(); if (ar == NULL) return; ar->k_ar.ar_arg_gid = gid; ARG_SET_VALID(ar, ARG_GID); } void audit_arg_uid(uid_t uid) { struct kaudit_record *ar; ar = currecord(); if (ar == NULL) return; ar->k_ar.ar_arg_uid = uid; ARG_SET_VALID(ar, ARG_UID); } void audit_arg_egid(gid_t egid) { struct kaudit_record *ar; ar = currecord(); if (ar == NULL) return; ar->k_ar.ar_arg_egid = egid; ARG_SET_VALID(ar, ARG_EGID); } void audit_arg_euid(uid_t euid) { struct kaudit_record *ar; ar = currecord(); if (ar == NULL) return; ar->k_ar.ar_arg_euid = euid; ARG_SET_VALID(ar, ARG_EUID); } void audit_arg_rgid(gid_t rgid) { struct kaudit_record *ar; ar = currecord(); if (ar == NULL) return; ar->k_ar.ar_arg_rgid = rgid; ARG_SET_VALID(ar, ARG_RGID); } void audit_arg_ruid(uid_t ruid) { struct kaudit_record *ar; ar = currecord(); if (ar == NULL) return; ar->k_ar.ar_arg_ruid = ruid; ARG_SET_VALID(ar, ARG_RUID); } void audit_arg_sgid(gid_t sgid) { struct kaudit_record *ar; ar = currecord(); if (ar == NULL) return; ar->k_ar.ar_arg_sgid = sgid; ARG_SET_VALID(ar, ARG_SGID); } void audit_arg_suid(uid_t suid) { struct kaudit_record *ar; ar = currecord(); if (ar == NULL) return; ar->k_ar.ar_arg_suid = suid; ARG_SET_VALID(ar, ARG_SUID); } void audit_arg_groupset(gid_t *gidset, u_int gidset_size) { u_int i; struct kaudit_record *ar; ar = currecord(); if (ar == NULL) return; for (i = 0; i < gidset_size; i++) ar->k_ar.ar_arg_groups.gidset[i] = gidset[i]; ar->k_ar.ar_arg_groups.gidset_size = gidset_size; ARG_SET_VALID(ar, ARG_GROUPSET); } void audit_arg_login(char *login) { struct kaudit_record *ar; ar = currecord(); if (ar == NULL) return; strlcpy(ar->k_ar.ar_arg_login, login, MAXLOGNAME); ARG_SET_VALID(ar, ARG_LOGIN); } void audit_arg_ctlname(int *name, int namelen) { struct kaudit_record *ar; ar = currecord(); if (ar == NULL) return; bcopy(name, &ar->k_ar.ar_arg_ctlname, namelen * sizeof(int)); ar->k_ar.ar_arg_len = namelen; ARG_SET_VALID(ar, ARG_CTLNAME | ARG_LEN); } void audit_arg_mask(int mask) { struct kaudit_record *ar; ar = currecord(); if (ar == NULL) return; ar->k_ar.ar_arg_mask = mask; ARG_SET_VALID(ar, ARG_MASK); } void audit_arg_mode(mode_t mode) { struct kaudit_record *ar; ar = currecord(); if (ar == NULL) return; ar->k_ar.ar_arg_mode = mode; ARG_SET_VALID(ar, ARG_MODE); } void audit_arg_dev(int dev) { struct kaudit_record *ar; ar = currecord(); if (ar == NULL) return; ar->k_ar.ar_arg_dev = dev; ARG_SET_VALID(ar, ARG_DEV); } void audit_arg_value(long value) { struct kaudit_record *ar; ar = currecord(); if (ar == NULL) return; ar->k_ar.ar_arg_value = value; ARG_SET_VALID(ar, ARG_VALUE); } void audit_arg_owner(uid_t uid, gid_t gid) { struct kaudit_record *ar; ar = currecord(); if (ar == NULL) return; ar->k_ar.ar_arg_uid = uid; ar->k_ar.ar_arg_gid = gid; ARG_SET_VALID(ar, ARG_UID | ARG_GID); } void audit_arg_pid(pid_t pid) { struct kaudit_record *ar; ar = currecord(); if (ar == NULL) return; ar->k_ar.ar_arg_pid = pid; ARG_SET_VALID(ar, ARG_PID); } void audit_arg_process(struct proc *p) { struct kaudit_record *ar; KASSERT(p != NULL, ("audit_arg_process: p == NULL")); PROC_LOCK_ASSERT(p, MA_OWNED); ar = currecord(); if (ar == NULL) return; ar->k_ar.ar_arg_auid = p->p_ucred->cr_audit.ai_auid; ar->k_ar.ar_arg_euid = p->p_ucred->cr_uid; ar->k_ar.ar_arg_egid = p->p_ucred->cr_groups[0]; ar->k_ar.ar_arg_ruid = p->p_ucred->cr_ruid; ar->k_ar.ar_arg_rgid = p->p_ucred->cr_rgid; ar->k_ar.ar_arg_asid = p->p_ucred->cr_audit.ai_asid; ar->k_ar.ar_arg_termid_addr = p->p_ucred->cr_audit.ai_termid; ar->k_ar.ar_arg_pid = p->p_pid; ARG_SET_VALID(ar, ARG_AUID | ARG_EUID | ARG_EGID | ARG_RUID | ARG_RGID | ARG_ASID | ARG_TERMID_ADDR | ARG_PID | ARG_PROCESS); } void audit_arg_signum(u_int signum) { struct kaudit_record *ar; ar = currecord(); if (ar == NULL) return; ar->k_ar.ar_arg_signum = signum; ARG_SET_VALID(ar, ARG_SIGNUM); } void audit_arg_socket(int sodomain, int sotype, int soprotocol) { struct kaudit_record *ar; ar = currecord(); if (ar == NULL) return; ar->k_ar.ar_arg_sockinfo.so_domain = sodomain; ar->k_ar.ar_arg_sockinfo.so_type = sotype; ar->k_ar.ar_arg_sockinfo.so_protocol = soprotocol; ARG_SET_VALID(ar, ARG_SOCKINFO); } void audit_arg_sockaddr(struct thread *td, struct sockaddr *sa) { struct kaudit_record *ar; KASSERT(td != NULL, ("audit_arg_sockaddr: td == NULL")); KASSERT(sa != NULL, ("audit_arg_sockaddr: sa == NULL")); ar = currecord(); if (ar == NULL) return; bcopy(sa, &ar->k_ar.ar_arg_sockaddr, sa->sa_len); switch (sa->sa_family) { case AF_INET: ARG_SET_VALID(ar, ARG_SADDRINET); break; case AF_INET6: ARG_SET_VALID(ar, ARG_SADDRINET6); break; case AF_UNIX: audit_arg_upath(td, ((struct sockaddr_un *)sa)->sun_path, ARG_UPATH1); ARG_SET_VALID(ar, ARG_SADDRUNIX); break; /* XXXAUDIT: default:? */ } } void audit_arg_auid(uid_t auid) { struct kaudit_record *ar; ar = currecord(); if (ar == NULL) return; ar->k_ar.ar_arg_auid = auid; ARG_SET_VALID(ar, ARG_AUID); } void audit_arg_auditinfo(struct auditinfo *au_info) { struct kaudit_record *ar; ar = currecord(); if (ar == NULL) return; ar->k_ar.ar_arg_auid = au_info->ai_auid; ar->k_ar.ar_arg_asid = au_info->ai_asid; ar->k_ar.ar_arg_amask.am_success = au_info->ai_mask.am_success; ar->k_ar.ar_arg_amask.am_failure = au_info->ai_mask.am_failure; ar->k_ar.ar_arg_termid.port = au_info->ai_termid.port; ar->k_ar.ar_arg_termid.machine = au_info->ai_termid.machine; ARG_SET_VALID(ar, ARG_AUID | ARG_ASID | ARG_AMASK | ARG_TERMID); } void audit_arg_auditinfo_addr(struct auditinfo_addr *au_info) { struct kaudit_record *ar; ar = currecord(); if (ar == NULL) return; ar->k_ar.ar_arg_auid = au_info->ai_auid; ar->k_ar.ar_arg_asid = au_info->ai_asid; ar->k_ar.ar_arg_amask.am_success = au_info->ai_mask.am_success; ar->k_ar.ar_arg_amask.am_failure = au_info->ai_mask.am_failure; ar->k_ar.ar_arg_termid_addr.at_type = au_info->ai_termid.at_type; ar->k_ar.ar_arg_termid_addr.at_port = au_info->ai_termid.at_port; ar->k_ar.ar_arg_termid_addr.at_addr[0] = au_info->ai_termid.at_addr[0]; ar->k_ar.ar_arg_termid_addr.at_addr[1] = au_info->ai_termid.at_addr[1]; ar->k_ar.ar_arg_termid_addr.at_addr[2] = au_info->ai_termid.at_addr[2]; ar->k_ar.ar_arg_termid_addr.at_addr[3] = au_info->ai_termid.at_addr[3]; ARG_SET_VALID(ar, ARG_AUID | ARG_ASID | ARG_AMASK | ARG_TERMID_ADDR); } void audit_arg_text(char *text) { struct kaudit_record *ar; KASSERT(text != NULL, ("audit_arg_text: text == NULL")); ar = currecord(); if (ar == NULL) return; /* Invalidate the text string */ ar->k_ar.ar_valid_arg &= (ARG_ALL ^ ARG_TEXT); if (ar->k_ar.ar_arg_text == NULL) ar->k_ar.ar_arg_text = malloc(MAXPATHLEN, M_AUDITTEXT, M_WAITOK); strncpy(ar->k_ar.ar_arg_text, text, MAXPATHLEN); ARG_SET_VALID(ar, ARG_TEXT); } void audit_arg_cmd(int cmd) { struct kaudit_record *ar; ar = currecord(); if (ar == NULL) return; ar->k_ar.ar_arg_cmd = cmd; ARG_SET_VALID(ar, ARG_CMD); } void audit_arg_svipc_cmd(int cmd) { struct kaudit_record *ar; ar = currecord(); if (ar == NULL) return; ar->k_ar.ar_arg_svipc_cmd = cmd; ARG_SET_VALID(ar, ARG_SVIPC_CMD); } void audit_arg_svipc_perm(struct ipc_perm *perm) { struct kaudit_record *ar; ar = currecord(); if (ar == NULL) return; bcopy(perm, &ar->k_ar.ar_arg_svipc_perm, sizeof(ar->k_ar.ar_arg_svipc_perm)); ARG_SET_VALID(ar, ARG_SVIPC_PERM); } void audit_arg_svipc_id(int id) { struct kaudit_record *ar; ar = currecord(); if (ar == NULL) return; ar->k_ar.ar_arg_svipc_id = id; ARG_SET_VALID(ar, ARG_SVIPC_ID); } void audit_arg_svipc_addr(void * addr) { struct kaudit_record *ar; ar = currecord(); if (ar == NULL) return; ar->k_ar.ar_arg_svipc_addr = addr; ARG_SET_VALID(ar, ARG_SVIPC_ADDR); } void audit_arg_posix_ipc_perm(uid_t uid, gid_t gid, mode_t mode) { struct kaudit_record *ar; ar = currecord(); if (ar == NULL) return; ar->k_ar.ar_arg_pipc_perm.pipc_uid = uid; ar->k_ar.ar_arg_pipc_perm.pipc_gid = gid; ar->k_ar.ar_arg_pipc_perm.pipc_mode = mode; ARG_SET_VALID(ar, ARG_POSIX_IPC_PERM); } void audit_arg_auditon(union auditon_udata *udata) { struct kaudit_record *ar; ar = currecord(); if (ar == NULL) return; bcopy((void *)udata, &ar->k_ar.ar_arg_auditon, sizeof(ar->k_ar.ar_arg_auditon)); ARG_SET_VALID(ar, ARG_AUDITON); } /* * Audit information about a file, either the file's vnode info, or its * socket address info. */ void audit_arg_file(struct proc *p, struct file *fp) { struct kaudit_record *ar; struct socket *so; struct inpcb *pcb; struct vnode *vp; int vfslocked; ar = currecord(); if (ar == NULL) return; switch (fp->f_type) { case DTYPE_VNODE: case DTYPE_FIFO: /* * XXXAUDIT: Only possibly to record as first vnode? */ vp = fp->f_vnode; vfslocked = VFS_LOCK_GIANT(vp->v_mount); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); audit_arg_vnode(vp, ARG_VNODE1); VOP_UNLOCK(vp, 0); VFS_UNLOCK_GIANT(vfslocked); break; case DTYPE_SOCKET: so = (struct socket *)fp->f_data; if (INP_CHECK_SOCKAF(so, PF_INET)) { SOCK_LOCK(so); ar->k_ar.ar_arg_sockinfo.so_type = so->so_type; ar->k_ar.ar_arg_sockinfo.so_domain = INP_SOCKAF(so); ar->k_ar.ar_arg_sockinfo.so_protocol = so->so_proto->pr_protocol; SOCK_UNLOCK(so); pcb = (struct inpcb *)so->so_pcb; INP_RLOCK(pcb); ar->k_ar.ar_arg_sockinfo.so_raddr = pcb->inp_faddr.s_addr; ar->k_ar.ar_arg_sockinfo.so_laddr = pcb->inp_laddr.s_addr; ar->k_ar.ar_arg_sockinfo.so_rport = pcb->inp_fport; ar->k_ar.ar_arg_sockinfo.so_lport = pcb->inp_lport; INP_RUNLOCK(pcb); ARG_SET_VALID(ar, ARG_SOCKINFO); } break; default: /* XXXAUDIT: else? */ break; } } /* * Store a path as given by the user process for auditing into the audit * record stored on the user thread. This function will allocate the memory * to store the path info if not already available. This memory will be * freed when the audit record is freed. * * XXXAUDIT: Possibly assert that the memory isn't already allocated? */ void audit_arg_upath(struct thread *td, char *upath, u_int64_t flag) { struct kaudit_record *ar; char **pathp; KASSERT(td != NULL, ("audit_arg_upath: td == NULL")); KASSERT(upath != NULL, ("audit_arg_upath: upath == NULL")); ar = currecord(); if (ar == NULL) return; KASSERT((flag == ARG_UPATH1) || (flag == ARG_UPATH2), ("audit_arg_upath: flag %llu", (unsigned long long)flag)); KASSERT((flag != ARG_UPATH1) || (flag != ARG_UPATH2), ("audit_arg_upath: flag %llu", (unsigned long long)flag)); if (flag == ARG_UPATH1) pathp = &ar->k_ar.ar_arg_upath1; else pathp = &ar->k_ar.ar_arg_upath2; if (*pathp == NULL) *pathp = malloc(MAXPATHLEN, M_AUDITPATH, M_WAITOK); audit_canon_path(td, upath, *pathp); ARG_SET_VALID(ar, flag); } /* * Function to save the path and vnode attr information into the audit * record. * * It is assumed that the caller will hold any vnode locks necessary to * perform a VOP_GETATTR() on the passed vnode. * * XXX: The attr code is very similar to vfs_vnops.c:vn_stat(), but always * provides access to the generation number as we need that to construct the * BSM file ID. * * XXX: We should accept the process argument from the caller, since it's * very likely they already have a reference. * * XXX: Error handling in this function is poor. * * XXXAUDIT: Possibly KASSERT the path pointer is NULL? */ void audit_arg_vnode(struct vnode *vp, u_int64_t flags) { struct kaudit_record *ar; struct vattr vattr; int error; struct vnode_au_info *vnp; KASSERT(vp != NULL, ("audit_arg_vnode: vp == NULL")); KASSERT((flags == ARG_VNODE1) || (flags == ARG_VNODE2), ("audit_arg_vnode: flags %jd", (intmax_t)flags)); /* * Assume that if the caller is calling audit_arg_vnode() on a * non-MPSAFE vnode, then it will have acquired Giant. */ VFS_ASSERT_GIANT(vp->v_mount); ASSERT_VOP_LOCKED(vp, "audit_arg_vnode"); ar = currecord(); if (ar == NULL) return; /* * XXXAUDIT: The below clears, and then resets the flags for valid * arguments. Ideally, either the new vnode is used, or the old one * would be. */ if (flags & ARG_VNODE1) { ar->k_ar.ar_valid_arg &= (ARG_ALL ^ ARG_VNODE1); vnp = &ar->k_ar.ar_arg_vnode1; } else { ar->k_ar.ar_valid_arg &= (ARG_ALL ^ ARG_VNODE2); vnp = &ar->k_ar.ar_arg_vnode2; } error = VOP_GETATTR(vp, &vattr, curthread->td_ucred, curthread); if (error) { /* XXX: How to handle this case? */ return; } vnp->vn_mode = vattr.va_mode; vnp->vn_uid = vattr.va_uid; vnp->vn_gid = vattr.va_gid; vnp->vn_dev = vattr.va_rdev; vnp->vn_fsid = vattr.va_fsid; vnp->vn_fileid = vattr.va_fileid; vnp->vn_gen = vattr.va_gen; if (flags & ARG_VNODE1) ARG_SET_VALID(ar, ARG_VNODE1); else ARG_SET_VALID(ar, ARG_VNODE2); } /* * Audit the argument strings passed to exec. */ void audit_arg_argv(char *argv, int argc, int length) { struct kaudit_record *ar; if (audit_argv == 0) return; ar = currecord(); if (ar == NULL) return; ar->k_ar.ar_arg_argv = malloc(length, M_AUDITTEXT, M_WAITOK); bcopy(argv, ar->k_ar.ar_arg_argv, length); ar->k_ar.ar_arg_argc = argc; ARG_SET_VALID(ar, ARG_ARGV); } /* * Audit the environment strings passed to exec. */ void audit_arg_envv(char *envv, int envc, int length) { struct kaudit_record *ar; if (audit_arge == 0) return; ar = currecord(); if (ar == NULL) return; ar->k_ar.ar_arg_envv = malloc(length, M_AUDITTEXT, M_WAITOK); bcopy(envv, ar->k_ar.ar_arg_envv, length); ar->k_ar.ar_arg_envc = envc; ARG_SET_VALID(ar, ARG_ENVV); } /* * The close() system call uses it's own audit call to capture the path/vnode * information because those pieces are not easily obtained within the system * call itself. */ void audit_sysclose(struct thread *td, int fd) { struct kaudit_record *ar; struct vnode *vp; struct file *fp; int vfslocked; KASSERT(td != NULL, ("audit_sysclose: td == NULL")); ar = currecord(); if (ar == NULL) return; audit_arg_fd(fd); if (getvnode(td->td_proc->p_fd, fd, &fp) != 0) return; vp = fp->f_vnode; vfslocked = VFS_LOCK_GIANT(vp->v_mount); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); audit_arg_vnode(vp, ARG_VNODE1); VOP_UNLOCK(vp, 0); VFS_UNLOCK_GIANT(vfslocked); fdrop(fp, td); } Index: head/sys/security/audit/audit_bsm_klib.c =================================================================== --- head/sys/security/audit/audit_bsm_klib.c (revision 181052) +++ head/sys/security/audit/audit_bsm_klib.c (revision 181053) @@ -1,548 +1,548 @@ /* * Copyright (c) 1999-2005 Apple Inc. * Copyright (c) 2005 Robert N. M. Watson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * Hash table functions for the audit event number to event class mask * mapping. */ #define EVCLASSMAP_HASH_TABLE_SIZE 251 struct evclass_elem { au_event_t event; au_class_t class; LIST_ENTRY(evclass_elem) entry; }; struct evclass_list { LIST_HEAD(, evclass_elem) head; }; static MALLOC_DEFINE(M_AUDITEVCLASS, "audit_evclass", "Audit event class"); static struct mtx evclass_mtx; static struct evclass_list evclass_hash[EVCLASSMAP_HASH_TABLE_SIZE]; /* * Look up the class for an audit event in the class mapping table. */ au_class_t au_event_class(au_event_t event) { struct evclass_list *evcl; struct evclass_elem *evc; au_class_t class; mtx_lock(&evclass_mtx); evcl = &evclass_hash[event % EVCLASSMAP_HASH_TABLE_SIZE]; class = 0; LIST_FOREACH(evc, &evcl->head, entry) { if (evc->event == event) { class = evc->class; goto out; } } out: mtx_unlock(&evclass_mtx); return (class); } /* * Insert a event to class mapping. If the event already exists in the * mapping, then replace the mapping with the new one. * * XXX There is currently no constraints placed on the number of mappings. * May want to either limit to a number, or in terms of memory usage. */ void au_evclassmap_insert(au_event_t event, au_class_t class) { struct evclass_list *evcl; struct evclass_elem *evc, *evc_new; /* * Pessimistically, always allocate storage before acquiring mutex. * Free if there is already a mapping for this event. */ evc_new = malloc(sizeof(*evc), M_AUDITEVCLASS, M_WAITOK); mtx_lock(&evclass_mtx); evcl = &evclass_hash[event % EVCLASSMAP_HASH_TABLE_SIZE]; LIST_FOREACH(evc, &evcl->head, entry) { if (evc->event == event) { evc->class = class; mtx_unlock(&evclass_mtx); free(evc_new, M_AUDITEVCLASS); return; } } evc = evc_new; evc->event = event; evc->class = class; LIST_INSERT_HEAD(&evcl->head, evc, entry); mtx_unlock(&evclass_mtx); } void au_evclassmap_init(void) { int i; mtx_init(&evclass_mtx, "evclass_mtx", NULL, MTX_DEF); for (i = 0; i < EVCLASSMAP_HASH_TABLE_SIZE; i++) LIST_INIT(&evclass_hash[i].head); /* * Set up the initial event to class mapping for system calls. * * XXXRW: Really, this should walk all possible audit events, not all * native ABI system calls, as there may be audit events reachable * only through non-native system calls. It also seems a shame to * frob the mutex this early. */ for (i = 0; i < SYS_MAXSYSCALL; i++) { if (sysent[i].sy_auevent != AUE_NULL) au_evclassmap_insert(sysent[i].sy_auevent, 0); } } /* * Check whether an event is aditable by comparing the mask of classes this * event is part of against the given mask. */ int au_preselect(au_event_t event, au_class_t class, au_mask_t *mask_p, int sorf) { au_class_t effmask = 0; if (mask_p == NULL) return (-1); /* * Perform the actual check of the masks against the event. */ if (sorf & AU_PRS_SUCCESS) effmask |= (mask_p->am_success & class); if (sorf & AU_PRS_FAILURE) effmask |= (mask_p->am_failure & class); if (effmask) return (1); else return (0); } /* * Convert sysctl names and present arguments to events. */ au_event_t audit_ctlname_to_sysctlevent(int name[], uint64_t valid_arg) { /* can't parse it - so return the worst case */ if ((valid_arg & (ARG_CTLNAME | ARG_LEN)) != (ARG_CTLNAME | ARG_LEN)) return (AUE_SYSCTL); switch (name[0]) { /* non-admin "lookups" treat them special */ case KERN_OSTYPE: case KERN_OSRELEASE: case KERN_OSREV: case KERN_VERSION: case KERN_ARGMAX: case KERN_CLOCKRATE: case KERN_BOOTTIME: case KERN_POSIX1: case KERN_NGROUPS: case KERN_JOB_CONTROL: case KERN_SAVED_IDS: case KERN_OSRELDATE: case KERN_DUMMY: return (AUE_SYSCTL_NONADMIN); /* only treat the changeable controls as admin */ case KERN_MAXVNODES: case KERN_MAXPROC: case KERN_MAXFILES: case KERN_MAXPROCPERUID: case KERN_MAXFILESPERPROC: case KERN_HOSTID: case KERN_SECURELVL: case KERN_HOSTNAME: case KERN_VNODE: case KERN_PROC: case KERN_FILE: case KERN_PROF: case KERN_NISDOMAINNAME: case KERN_UPDATEINTERVAL: case KERN_NTP_PLL: case KERN_BOOTFILE: case KERN_DUMPDEV: case KERN_IPC: case KERN_PS_STRINGS: case KERN_USRSTACK: case KERN_LOGSIGEXIT: case KERN_IOV_MAX: case KERN_MAXID: return ((valid_arg & ARG_VALUE) ? - AUE_SYSCTL : AUE_SYSCTL_NONADMIN); + AUE_SYSCTL : AUE_SYSCTL_NONADMIN); default: return (AUE_SYSCTL); } /* NOTREACHED */ } /* * Convert an open flags specifier into a specific type of open event for * auditing purposes. */ au_event_t audit_flags_and_error_to_openevent(int oflags, int error) { au_event_t aevent; /* * Need to check only those flags we care about. */ oflags = oflags & (O_RDONLY | O_CREAT | O_TRUNC | O_RDWR | O_WRONLY); /* * These checks determine what flags are on with the condition that * ONLY that combination is on, and no other flags are on. */ switch (oflags) { case O_RDONLY: aevent = AUE_OPEN_R; break; case (O_RDONLY | O_CREAT): aevent = AUE_OPEN_RC; break; case (O_RDONLY | O_CREAT | O_TRUNC): aevent = AUE_OPEN_RTC; break; case (O_RDONLY | O_TRUNC): aevent = AUE_OPEN_RT; break; case O_RDWR: aevent = AUE_OPEN_RW; break; case (O_RDWR | O_CREAT): aevent = AUE_OPEN_RWC; break; case (O_RDWR | O_CREAT | O_TRUNC): aevent = AUE_OPEN_RWTC; break; case (O_RDWR | O_TRUNC): aevent = AUE_OPEN_RWT; break; case O_WRONLY: aevent = AUE_OPEN_W; break; case (O_WRONLY | O_CREAT): aevent = AUE_OPEN_WC; break; case (O_WRONLY | O_CREAT | O_TRUNC): aevent = AUE_OPEN_WTC; break; case (O_WRONLY | O_TRUNC): aevent = AUE_OPEN_WT; break; default: aevent = AUE_OPEN; break; } #if 0 /* * Convert chatty errors to better matching events. Failures to * find a file are really just attribute events -- so recast them as * such. * * XXXAUDIT: Solaris defines that AUE_OPEN will never be returned, it * is just a placeholder. However, in Darwin we return that in * preference to other events. For now, comment this out as we don't * have a BSM conversion routine for AUE_OPEN. */ switch (aevent) { case AUE_OPEN_R: case AUE_OPEN_RT: case AUE_OPEN_RW: case AUE_OPEN_RWT: case AUE_OPEN_W: case AUE_OPEN_WT: if (error == ENOENT) aevent = AUE_OPEN; } #endif return (aevent); } /* * Convert a MSGCTL command to a specific event. */ int audit_msgctl_to_event(int cmd) { switch (cmd) { case IPC_RMID: return (AUE_MSGCTL_RMID); case IPC_SET: return (AUE_MSGCTL_SET); case IPC_STAT: return (AUE_MSGCTL_STAT); default: /* We will audit a bad command. */ return (AUE_MSGCTL); } } /* * Convert a SEMCTL command to a specific event. */ int audit_semctl_to_event(int cmd) { switch (cmd) { case GETALL: return (AUE_SEMCTL_GETALL); case GETNCNT: return (AUE_SEMCTL_GETNCNT); case GETPID: return (AUE_SEMCTL_GETPID); case GETVAL: return (AUE_SEMCTL_GETVAL); case GETZCNT: return (AUE_SEMCTL_GETZCNT); case IPC_RMID: return (AUE_SEMCTL_RMID); case IPC_SET: return (AUE_SEMCTL_SET); case SETALL: return (AUE_SEMCTL_SETALL); case SETVAL: return (AUE_SEMCTL_SETVAL); case IPC_STAT: return (AUE_SEMCTL_STAT); default: - /* We will audit a bad command */ + /* We will audit a bad command. */ return (AUE_SEMCTL); } } /* * Convert a command for the auditon() system call to a audit event. */ int auditon_command_event(int cmd) { switch(cmd) { case A_GETPOLICY: return (AUE_AUDITON_GPOLICY); case A_SETPOLICY: return (AUE_AUDITON_SPOLICY); case A_GETKMASK: return (AUE_AUDITON_GETKMASK); case A_SETKMASK: return (AUE_AUDITON_SETKMASK); case A_GETQCTRL: return (AUE_AUDITON_GQCTRL); case A_SETQCTRL: return (AUE_AUDITON_SQCTRL); case A_GETCWD: return (AUE_AUDITON_GETCWD); case A_GETCAR: return (AUE_AUDITON_GETCAR); case A_GETSTAT: return (AUE_AUDITON_GETSTAT); case A_SETSTAT: return (AUE_AUDITON_SETSTAT); case A_SETUMASK: return (AUE_AUDITON_SETUMASK); case A_SETSMASK: return (AUE_AUDITON_SETSMASK); case A_GETCOND: return (AUE_AUDITON_GETCOND); case A_SETCOND: return (AUE_AUDITON_SETCOND); case A_GETCLASS: return (AUE_AUDITON_GETCLASS); case A_SETCLASS: return (AUE_AUDITON_SETCLASS); case A_GETPINFO: case A_SETPMASK: case A_SETFSIZE: case A_GETFSIZE: case A_GETPINFO_ADDR: case A_GETKAUDIT: case A_SETKAUDIT: default: return (AUE_AUDITON); /* No special record */ } } /* * Create a canonical path from given path by prefixing either the root * directory, or the current working directory. If the process working * directory is NULL, we could use 'rootvnode' to obtain the root directory, * but this results in a volfs name written to the audit log. So we will * leave the filename starting with '/' in the audit log in this case. * * XXXRW: Since we combine two paths here, ideally a buffer of size * MAXPATHLEN * 2 would be passed in. */ void audit_canon_path(struct thread *td, char *path, char *cpath) { char *bufp; char *retbuf, *freebuf; struct vnode *vnp; struct filedesc *fdp; int cisr, error, vfslocked; WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "audit_canon_path() at %s:%d", __FILE__, __LINE__); fdp = td->td_proc->p_fd; bufp = path; cisr = 0; FILEDESC_SLOCK(fdp); if (*(path) == '/') { while (*(bufp) == '/') bufp++; /* Skip leading '/'s. */ /* * If no process root, or it is the same as the system root, * audit the path as passed in with a single '/'. */ if ((fdp->fd_rdir == NULL) || (fdp->fd_rdir == rootvnode)) { vnp = NULL; bufp--; /* Restore one '/'. */ } else { vnp = fdp->fd_rdir; /* Use process root. */ vref(vnp); } } else { vnp = fdp->fd_cdir; /* Prepend the current dir. */ cisr = (fdp->fd_rdir == fdp->fd_cdir); vref(vnp); bufp = path; } FILEDESC_SUNLOCK(fdp); if (vnp != NULL) { /* * XXX: vn_fullpath() on FreeBSD is "less reliable" than * vn_getpath() on Darwin, so this will need more attention * in the future. Also, the question and string bounding * here seems a bit questionable and will also require * attention. */ vfslocked = VFS_LOCK_GIANT(vnp->v_mount); vn_lock(vnp, LK_EXCLUSIVE | LK_RETRY); error = vn_fullpath(td, vnp, &retbuf, &freebuf); if (error == 0) { /* Copy and free buffer allocated by vn_fullpath(). * If the current working directory was the same as * the root directory, and the path was a relative * pathname, do not separate the two components with * the '/' character. */ snprintf(cpath, MAXPATHLEN, "%s%s%s", retbuf, cisr ? "" : "/", bufp); free(freebuf, M_TEMP); } else cpath[0] = '\0'; vput(vnp); VFS_UNLOCK_GIANT(vfslocked); } else strlcpy(cpath, bufp, MAXPATHLEN); } Index: head/sys/security/audit/audit_bsm_token.c =================================================================== --- head/sys/security/audit/audit_bsm_token.c (revision 181052) +++ head/sys/security/audit/audit_bsm_token.c (revision 181053) @@ -1,1371 +1,1371 @@ -/* +/*- * Copyright (c) 2004 Apple Inc. * Copyright (c) 2005 SPARTA, Inc. * All rights reserved. * * This code was developed in part by Robert N. M. Watson, Senior Principal * Scientist, SPARTA, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define GET_TOKEN_AREA(t, dptr, length) do { \ t = malloc(sizeof(token_t), M_AUDITBSM, M_WAITOK); \ t->t_data = malloc(length, M_AUDITBSM, M_WAITOK | M_ZERO); \ t->len = length; \ dptr = t->t_data; \ } while (0) /* * token ID 1 byte * argument # 1 byte * argument value 4 bytes/8 bytes (32-bit/64-bit value) * text length 2 bytes * text N bytes + 1 terminating NULL byte */ token_t * au_to_arg32(char n, char *text, u_int32_t v) { token_t *t; u_char *dptr = NULL; u_int16_t textlen; textlen = strlen(text); textlen += 1; GET_TOKEN_AREA(t, dptr, 2 * sizeof(u_char) + sizeof(u_int32_t) + sizeof(u_int16_t) + textlen); ADD_U_CHAR(dptr, AUT_ARG32); ADD_U_CHAR(dptr, n); ADD_U_INT32(dptr, v); ADD_U_INT16(dptr, textlen); ADD_STRING(dptr, text, textlen); return (t); } token_t * au_to_arg64(char n, char *text, u_int64_t v) { token_t *t; u_char *dptr = NULL; u_int16_t textlen; textlen = strlen(text); textlen += 1; GET_TOKEN_AREA(t, dptr, 2 * sizeof(u_char) + sizeof(u_int64_t) + sizeof(u_int16_t) + textlen); ADD_U_CHAR(dptr, AUT_ARG64); ADD_U_CHAR(dptr, n); ADD_U_INT64(dptr, v); ADD_U_INT16(dptr, textlen); ADD_STRING(dptr, text, textlen); return (t); } token_t * au_to_arg(char n, char *text, u_int32_t v) { return (au_to_arg32(n, text, v)); } #if defined(_KERNEL) || defined(KERNEL) /* * token ID 1 byte * file access mode 4 bytes * owner user ID 4 bytes * owner group ID 4 bytes * file system ID 4 bytes * node ID 8 bytes * device 4 bytes/8 bytes (32-bit/64-bit) */ token_t * au_to_attr32(struct vnode_au_info *vni) { token_t *t; u_char *dptr = NULL; u_int16_t pad0_16 = 0; u_int16_t pad0_32 = 0; GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 2 * sizeof(u_int16_t) + 3 * sizeof(u_int32_t) + sizeof(u_int64_t) + sizeof(u_int32_t)); ADD_U_CHAR(dptr, AUT_ATTR32); /* * Darwin defines the size for the file mode * as 2 bytes; BSM defines 4 so pad with 0 */ ADD_U_INT16(dptr, pad0_16); ADD_U_INT16(dptr, vni->vn_mode); ADD_U_INT32(dptr, vni->vn_uid); ADD_U_INT32(dptr, vni->vn_gid); ADD_U_INT32(dptr, vni->vn_fsid); /* - * Some systems use 32-bit file ID's, other's use 64-bit file IDs. + * Some systems use 32-bit file ID's, others use 64-bit file IDs. * Attempt to handle both, and let the compiler sort it out. If we * could pick this out at compile-time, it would be better, so as to * avoid the else case below. */ if (sizeof(vni->vn_fileid) == sizeof(uint32_t)) { ADD_U_INT32(dptr, pad0_32); ADD_U_INT32(dptr, vni->vn_fileid); } else if (sizeof(vni->vn_fileid) == sizeof(uint64_t)) ADD_U_INT64(dptr, vni->vn_fileid); else ADD_U_INT64(dptr, 0LL); ADD_U_INT32(dptr, vni->vn_dev); return (t); } token_t * au_to_attr64(struct vnode_au_info *vni) { token_t *t; u_char *dptr = NULL; u_int16_t pad0_16 = 0; u_int16_t pad0_32 = 0; GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 2 * sizeof(u_int16_t) + 3 * sizeof(u_int32_t) + sizeof(u_int64_t) * 2); ADD_U_CHAR(dptr, AUT_ATTR64); /* * Darwin defines the size for the file mode * as 2 bytes; BSM defines 4 so pad with 0 */ ADD_U_INT16(dptr, pad0_16); ADD_U_INT16(dptr, vni->vn_mode); ADD_U_INT32(dptr, vni->vn_uid); ADD_U_INT32(dptr, vni->vn_gid); ADD_U_INT32(dptr, vni->vn_fsid); /* * Some systems use 32-bit file ID's, other's use 64-bit file IDs. * Attempt to handle both, and let the compiler sort it out. If we * could pick this out at compile-time, it would be better, so as to * avoid the else case below. */ if (sizeof(vni->vn_fileid) == sizeof(uint32_t)) { ADD_U_INT32(dptr, pad0_32); ADD_U_INT32(dptr, vni->vn_fileid); } else if (sizeof(vni->vn_fileid) == sizeof(uint64_t)) ADD_U_INT64(dptr, vni->vn_fileid); else ADD_U_INT64(dptr, 0LL); ADD_U_INT64(dptr, vni->vn_dev); return (t); } token_t * au_to_attr(struct vnode_au_info *vni) { return (au_to_attr32(vni)); } #endif /* !(defined(_KERNEL) || defined(KERNEL) */ /* * token ID 1 byte * how to print 1 byte * basic unit 1 byte * unit count 1 byte * data items (depends on basic unit) */ token_t * au_to_data(char unit_print, char unit_type, char unit_count, char *p) { token_t *t; u_char *dptr = NULL; size_t datasize, totdata; /* Determine the size of the basic unit. */ switch (unit_type) { case AUR_BYTE: /* case AUR_CHAR: */ datasize = AUR_BYTE_SIZE; break; case AUR_SHORT: datasize = AUR_SHORT_SIZE; break; case AUR_INT32: /* case AUR_INT: */ datasize = AUR_INT32_SIZE; break; case AUR_INT64: datasize = AUR_INT64_SIZE; break; default: return (NULL); } totdata = datasize * unit_count; GET_TOKEN_AREA(t, dptr, 4 * sizeof(u_char) + totdata); ADD_U_CHAR(dptr, AUT_DATA); ADD_U_CHAR(dptr, unit_print); ADD_U_CHAR(dptr, unit_type); ADD_U_CHAR(dptr, unit_count); ADD_MEM(dptr, p, totdata); return (t); } /* * token ID 1 byte * status 4 bytes * return value 4 bytes */ token_t * au_to_exit(int retval, int err) { token_t *t; u_char *dptr = NULL; GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 2 * sizeof(u_int32_t)); ADD_U_CHAR(dptr, AUT_EXIT); ADD_U_INT32(dptr, err); ADD_U_INT32(dptr, retval); return (t); } /* */ token_t * au_to_groups(int *groups) { return (au_to_newgroups(AUDIT_MAX_GROUPS, (gid_t*)groups)); } /* * token ID 1 byte * number groups 2 bytes * group list count * 4 bytes */ token_t * au_to_newgroups(u_int16_t n, gid_t *groups) { token_t *t; u_char *dptr = NULL; int i; GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int16_t) + n * sizeof(u_int32_t)); ADD_U_CHAR(dptr, AUT_NEWGROUPS); ADD_U_INT16(dptr, n); for (i = 0; i < n; i++) ADD_U_INT32(dptr, groups[i]); return (t); } /* * token ID 1 byte * internet address 4 bytes */ token_t * au_to_in_addr(struct in_addr *internet_addr) { token_t *t; u_char *dptr = NULL; GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(uint32_t)); ADD_U_CHAR(dptr, AUT_IN_ADDR); ADD_MEM(dptr, &internet_addr->s_addr, sizeof(uint32_t)); return (t); } /* * token ID 1 byte * address type/length 4 bytes * Address 16 bytes */ token_t * au_to_in_addr_ex(struct in6_addr *internet_addr) { token_t *t; u_char *dptr = NULL; u_int32_t type = AU_IPv6; GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 5 * sizeof(uint32_t)); ADD_U_CHAR(dptr, AUT_IN_ADDR_EX); ADD_U_INT32(dptr, type); ADD_MEM(dptr, internet_addr, 4 * sizeof(uint32_t)); return (t); } /* * token ID 1 byte * ip header 20 bytes * * The IP header should be submitted in network byte order. */ token_t * au_to_ip(struct ip *ip) { token_t *t; u_char *dptr = NULL; GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(struct ip)); ADD_U_CHAR(dptr, AUT_IP); ADD_MEM(dptr, ip, sizeof(struct ip)); return (t); } /* * token ID 1 byte * object ID type 1 byte * object ID 4 bytes */ token_t * au_to_ipc(char type, int id) { token_t *t; u_char *dptr = NULL; GET_TOKEN_AREA(t, dptr, 2 * sizeof(u_char) + sizeof(u_int32_t)); ADD_U_CHAR(dptr, AUT_IPC); ADD_U_CHAR(dptr, type); ADD_U_INT32(dptr, id); return (t); } /* * token ID 1 byte * owner user ID 4 bytes * owner group ID 4 bytes * creator user ID 4 bytes * creator group ID 4 bytes * access mode 4 bytes * slot sequence # 4 bytes * key 4 bytes */ token_t * au_to_ipc_perm(struct ipc_perm *perm) { token_t *t; u_char *dptr = NULL; u_int16_t pad0 = 0; GET_TOKEN_AREA(t, dptr, 12 * sizeof(u_int16_t) + sizeof(u_int32_t)); ADD_U_CHAR(dptr, AUT_IPC_PERM); /* * Darwin defines the sizes for ipc_perm members * as 2 bytes; BSM defines 4 so pad with 0 */ ADD_U_INT16(dptr, pad0); ADD_U_INT16(dptr, perm->uid); ADD_U_INT16(dptr, pad0); ADD_U_INT16(dptr, perm->gid); ADD_U_INT16(dptr, pad0); ADD_U_INT16(dptr, perm->cuid); ADD_U_INT16(dptr, pad0); ADD_U_INT16(dptr, perm->cgid); ADD_U_INT16(dptr, pad0); ADD_U_INT16(dptr, perm->mode); ADD_U_INT16(dptr, pad0); ADD_U_INT16(dptr, perm->seq); ADD_U_INT32(dptr, perm->key); return (t); } /* * token ID 1 byte * port IP address 2 bytes */ token_t * au_to_iport(u_int16_t iport) { token_t *t; u_char *dptr = NULL; GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int16_t)); ADD_U_CHAR(dptr, AUT_IPORT); ADD_U_INT16(dptr, iport); return (t); } /* * token ID 1 byte * size 2 bytes * data size bytes */ token_t * au_to_opaque(char *data, u_int16_t bytes) { token_t *t; u_char *dptr = NULL; GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int16_t) + bytes); ADD_U_CHAR(dptr, AUT_OPAQUE); ADD_U_INT16(dptr, bytes); ADD_MEM(dptr, data, bytes); return (t); } /* * token ID 1 byte * seconds of time 4 bytes * milliseconds of time 4 bytes * file name len 2 bytes * file pathname N bytes + 1 terminating NULL byte */ token_t * au_to_file(char *file, struct timeval tm) { token_t *t; u_char *dptr = NULL; u_int16_t filelen; u_int32_t timems; filelen = strlen(file); filelen += 1; GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 2 * sizeof(u_int32_t) + sizeof(u_int16_t) + filelen); timems = tm.tv_usec/1000; ADD_U_CHAR(dptr, AUT_OTHER_FILE32); ADD_U_INT32(dptr, tm.tv_sec); ADD_U_INT32(dptr, timems); /* We need time in ms. */ ADD_U_INT16(dptr, filelen); ADD_STRING(dptr, file, filelen); return (t); } /* * token ID 1 byte * text length 2 bytes * text N bytes + 1 terminating NULL byte */ token_t * au_to_text(char *text) { token_t *t; u_char *dptr = NULL; u_int16_t textlen; textlen = strlen(text); textlen += 1; GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int16_t) + textlen); ADD_U_CHAR(dptr, AUT_TEXT); ADD_U_INT16(dptr, textlen); ADD_STRING(dptr, text, textlen); return (t); } /* * token ID 1 byte * path length 2 bytes * path N bytes + 1 terminating NULL byte */ token_t * au_to_path(char *text) { token_t *t; u_char *dptr = NULL; u_int16_t textlen; textlen = strlen(text); textlen += 1; GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int16_t) + textlen); ADD_U_CHAR(dptr, AUT_PATH); ADD_U_INT16(dptr, textlen); ADD_STRING(dptr, text, textlen); return (t); } /* * token ID 1 byte * audit ID 4 bytes * effective user ID 4 bytes * effective group ID 4 bytes * real user ID 4 bytes * real group ID 4 bytes * process ID 4 bytes * session ID 4 bytes * terminal ID * port ID 4 bytes/8 bytes (32-bit/64-bit value) * machine address 4 bytes */ token_t * au_to_process32(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid, au_tid_t *tid) { token_t *t; u_char *dptr = NULL; GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 9 * sizeof(u_int32_t)); ADD_U_CHAR(dptr, AUT_PROCESS32); ADD_U_INT32(dptr, auid); ADD_U_INT32(dptr, euid); ADD_U_INT32(dptr, egid); ADD_U_INT32(dptr, ruid); ADD_U_INT32(dptr, rgid); ADD_U_INT32(dptr, pid); ADD_U_INT32(dptr, sid); ADD_U_INT32(dptr, tid->port); ADD_MEM(dptr, &tid->machine, sizeof(u_int32_t)); return (t); } token_t * au_to_process64(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid, au_tid_t *tid) { token_t *t; u_char *dptr = NULL; GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 8 * sizeof(u_int32_t) + sizeof(u_int64_t)); ADD_U_CHAR(dptr, AUT_PROCESS64); ADD_U_INT32(dptr, auid); ADD_U_INT32(dptr, euid); ADD_U_INT32(dptr, egid); ADD_U_INT32(dptr, ruid); ADD_U_INT32(dptr, rgid); ADD_U_INT32(dptr, pid); ADD_U_INT32(dptr, sid); ADD_U_INT64(dptr, tid->port); ADD_MEM(dptr, &tid->machine, sizeof(u_int32_t)); return (t); } token_t * au_to_process(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid, au_tid_t *tid) { return (au_to_process32(auid, euid, egid, ruid, rgid, pid, sid, tid)); } /* * token ID 1 byte * audit ID 4 bytes * effective user ID 4 bytes * effective group ID 4 bytes * real user ID 4 bytes * real group ID 4 bytes * process ID 4 bytes * session ID 4 bytes * terminal ID * port ID 4 bytes/8 bytes (32-bit/64-bit value) * address type-len 4 bytes * machine address 4/16 bytes */ token_t * au_to_process32_ex(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid, au_tid_addr_t *tid) { token_t *t; u_char *dptr = NULL; KASSERT((tid->at_type == AU_IPv4) || (tid->at_type == AU_IPv6), ("au_to_process32_ex: type %u", (unsigned int)tid->at_type)); if (tid->at_type == AU_IPv6) GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 13 * sizeof(u_int32_t)); else GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 10 * sizeof(u_int32_t)); ADD_U_CHAR(dptr, AUT_PROCESS32_EX); ADD_U_INT32(dptr, auid); ADD_U_INT32(dptr, euid); ADD_U_INT32(dptr, egid); ADD_U_INT32(dptr, ruid); ADD_U_INT32(dptr, rgid); ADD_U_INT32(dptr, pid); ADD_U_INT32(dptr, sid); ADD_U_INT32(dptr, tid->at_port); ADD_U_INT32(dptr, tid->at_type); if (tid->at_type == AU_IPv6) ADD_MEM(dptr, &tid->at_addr[0], 4 * sizeof(u_int32_t)); else ADD_MEM(dptr, &tid->at_addr[0], sizeof(u_int32_t)); return (t); } token_t * au_to_process64_ex(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid, au_tid_addr_t *tid) { token_t *t; u_char *dptr = NULL; if (tid->at_type == AU_IPv4) GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 7 * sizeof(u_int32_t) + sizeof(u_int64_t) + 2 * sizeof(u_int32_t)); else if (tid->at_type == AU_IPv6) GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 7 * sizeof(u_int32_t) + sizeof(u_int64_t) + 5 * sizeof(u_int32_t)); else panic("au_to_process64_ex: invalidate at_type (%d)", tid->at_type); ADD_U_CHAR(dptr, AUT_PROCESS64_EX); ADD_U_INT32(dptr, auid); ADD_U_INT32(dptr, euid); ADD_U_INT32(dptr, egid); ADD_U_INT32(dptr, ruid); ADD_U_INT32(dptr, rgid); ADD_U_INT32(dptr, pid); ADD_U_INT32(dptr, sid); ADD_U_INT64(dptr, tid->at_port); ADD_U_INT32(dptr, tid->at_type); ADD_MEM(dptr, &tid->at_addr[0], sizeof(u_int32_t)); if (tid->at_type == AU_IPv6) { ADD_MEM(dptr, &tid->at_addr[1], sizeof(u_int32_t)); ADD_MEM(dptr, &tid->at_addr[2], sizeof(u_int32_t)); ADD_MEM(dptr, &tid->at_addr[3], sizeof(u_int32_t)); } return (t); } token_t * au_to_process_ex(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid, au_tid_addr_t *tid) { return (au_to_process32_ex(auid, euid, egid, ruid, rgid, pid, sid, tid)); } /* * token ID 1 byte * error status 1 byte * return value 4 bytes/8 bytes (32-bit/64-bit value) */ token_t * au_to_return32(char status, u_int32_t ret) { token_t *t; u_char *dptr = NULL; GET_TOKEN_AREA(t, dptr, 2 * sizeof(u_char) + sizeof(u_int32_t)); ADD_U_CHAR(dptr, AUT_RETURN32); ADD_U_CHAR(dptr, status); ADD_U_INT32(dptr, ret); return (t); } token_t * au_to_return64(char status, u_int64_t ret) { token_t *t; u_char *dptr = NULL; GET_TOKEN_AREA(t, dptr, 2 * sizeof(u_char) + sizeof(u_int64_t)); ADD_U_CHAR(dptr, AUT_RETURN64); ADD_U_CHAR(dptr, status); ADD_U_INT64(dptr, ret); return (t); } token_t * au_to_return(char status, u_int32_t ret) { return (au_to_return32(status, ret)); } /* * token ID 1 byte * sequence number 4 bytes */ token_t * au_to_seq(long audit_count) { token_t *t; u_char *dptr = NULL; GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int32_t)); ADD_U_CHAR(dptr, AUT_SEQ); ADD_U_INT32(dptr, audit_count); return (t); } /* * token ID 1 byte * socket type 2 bytes * local port 2 bytes * local Internet address 4 bytes * remote port 2 bytes * remote Internet address 4 bytes */ token_t * au_to_socket(struct socket *so) { /* XXXRW ... */ return (NULL); } /* * Kernel-specific version of the above function. */ #ifdef _KERNEL token_t * kau_to_socket(struct socket_au_info *soi) { token_t *t; u_char *dptr; u_int16_t so_type; GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 2 * sizeof(u_int16_t) + sizeof(u_int32_t) + sizeof(u_int16_t) + sizeof(u_int32_t)); ADD_U_CHAR(dptr, AU_SOCK_TOKEN); /* Coerce the socket type into a short value */ so_type = soi->so_type; ADD_U_INT16(dptr, so_type); ADD_U_INT16(dptr, soi->so_lport); ADD_U_INT32(dptr, soi->so_laddr); ADD_U_INT16(dptr, soi->so_rport); ADD_U_INT32(dptr, soi->so_raddr); return (t); } #endif /* * token ID 1 byte * socket type 2 bytes * local port 2 bytes * address type/length 4 bytes * local Internet address 4 bytes/16 bytes (IPv4/IPv6 address) * remote port 4 bytes * address type/length 4 bytes * remote Internet address 4 bytes/16 bytes (IPv4/IPv6 address) */ token_t * au_to_socket_ex_32(u_int16_t lp, u_int16_t rp, struct sockaddr *la, struct sockaddr *ra) { return (NULL); } token_t * au_to_socket_ex_128(u_int16_t lp, u_int16_t rp, struct sockaddr *la, struct sockaddr *ra) { return (NULL); } /* * token ID 1 byte * socket family 2 bytes * path 104 bytes */ token_t * au_to_sock_unix(struct sockaddr_un *so) { token_t *t; u_char *dptr; GET_TOKEN_AREA(t, dptr, 3 * sizeof(u_char) + strlen(so->sun_path) + 1); ADD_U_CHAR(dptr, AU_SOCK_UNIX_TOKEN); /* BSM token has two bytes for family */ ADD_U_CHAR(dptr, 0); ADD_U_CHAR(dptr, so->sun_family); ADD_STRING(dptr, so->sun_path, strlen(so->sun_path) + 1); return (t); } /* * token ID 1 byte * socket family 2 bytes * local port 2 bytes * socket address 4 bytes */ token_t * au_to_sock_inet32(struct sockaddr_in *so) { token_t *t; u_char *dptr = NULL; uint16_t family; GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 2 * sizeof(uint16_t) + sizeof(uint32_t)); ADD_U_CHAR(dptr, AUT_SOCKINET32); /* * BSM defines the family field as 16 bits, but many operating * systems have an 8-bit sin_family field. Extend to 16 bits before * writing into the token. Assume that both the port and the address * in the sockaddr_in are already in network byte order, but family * is in local byte order. * * XXXRW: Should a name space conversion be taking place on the value * of sin_family? */ family = so->sin_family; ADD_U_INT16(dptr, family); ADD_MEM(dptr, &so->sin_port, sizeof(uint16_t)); ADD_MEM(dptr, &so->sin_addr.s_addr, sizeof(uint32_t)); return (t); } token_t * au_to_sock_inet128(struct sockaddr_in6 *so) { token_t *t; u_char *dptr = NULL; GET_TOKEN_AREA(t, dptr, 3 * sizeof(u_char) + sizeof(u_int16_t) + 4 * sizeof(u_int32_t)); ADD_U_CHAR(dptr, AUT_SOCKINET128); /* * In Darwin, sin6_family is one octet, but BSM defines the token * to store two. So we copy in a 0 first. */ ADD_U_CHAR(dptr, 0); ADD_U_CHAR(dptr, so->sin6_family); ADD_U_INT16(dptr, so->sin6_port); ADD_MEM(dptr, &so->sin6_addr, 4 * sizeof(uint32_t)); return (t); } token_t * au_to_sock_inet(struct sockaddr_in *so) { return (au_to_sock_inet32(so)); } /* * token ID 1 byte * audit ID 4 bytes * effective user ID 4 bytes * effective group ID 4 bytes * real user ID 4 bytes * real group ID 4 bytes * process ID 4 bytes * session ID 4 bytes * terminal ID * port ID 4 bytes/8 bytes (32-bit/64-bit value) * machine address 4 bytes */ token_t * au_to_subject32(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid, au_tid_t *tid) { token_t *t; u_char *dptr = NULL; GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 9 * sizeof(u_int32_t)); ADD_U_CHAR(dptr, AUT_SUBJECT32); ADD_U_INT32(dptr, auid); ADD_U_INT32(dptr, euid); ADD_U_INT32(dptr, egid); ADD_U_INT32(dptr, ruid); ADD_U_INT32(dptr, rgid); ADD_U_INT32(dptr, pid); ADD_U_INT32(dptr, sid); ADD_U_INT32(dptr, tid->port); ADD_MEM(dptr, &tid->machine, sizeof(u_int32_t)); return (t); } token_t * au_to_subject64(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid, au_tid_t *tid) { token_t *t; u_char *dptr = NULL; GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 7 * sizeof(u_int32_t) + sizeof(u_int64_t) + sizeof(u_int32_t)); ADD_U_CHAR(dptr, AUT_SUBJECT64); ADD_U_INT32(dptr, auid); ADD_U_INT32(dptr, euid); ADD_U_INT32(dptr, egid); ADD_U_INT32(dptr, ruid); ADD_U_INT32(dptr, rgid); ADD_U_INT32(dptr, pid); ADD_U_INT32(dptr, sid); ADD_U_INT64(dptr, tid->port); ADD_MEM(dptr, &tid->machine, sizeof(u_int32_t)); return (t); } token_t * au_to_subject(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid, au_tid_t *tid) { return (au_to_subject32(auid, euid, egid, ruid, rgid, pid, sid, tid)); } /* * token ID 1 byte * audit ID 4 bytes * effective user ID 4 bytes * effective group ID 4 bytes * real user ID 4 bytes * real group ID 4 bytes * process ID 4 bytes * session ID 4 bytes * terminal ID * port ID 4 bytes/8 bytes (32-bit/64-bit value) * address type/length 4 bytes * machine address 4/16 bytes */ token_t * au_to_subject32_ex(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid, au_tid_addr_t *tid) { token_t *t; u_char *dptr = NULL; KASSERT((tid->at_type == AU_IPv4) || (tid->at_type == AU_IPv6), ("au_to_subject32_ex: type %u", (unsigned int)tid->at_type)); if (tid->at_type == AU_IPv6) GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 13 * sizeof(u_int32_t)); else GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 10 * sizeof(u_int32_t)); ADD_U_CHAR(dptr, AUT_SUBJECT32_EX); ADD_U_INT32(dptr, auid); ADD_U_INT32(dptr, euid); ADD_U_INT32(dptr, egid); ADD_U_INT32(dptr, ruid); ADD_U_INT32(dptr, rgid); ADD_U_INT32(dptr, pid); ADD_U_INT32(dptr, sid); ADD_U_INT32(dptr, tid->at_port); ADD_U_INT32(dptr, tid->at_type); if (tid->at_type == AU_IPv6) ADD_MEM(dptr, &tid->at_addr[0], 4 * sizeof(u_int32_t)); else ADD_MEM(dptr, &tid->at_addr[0], sizeof(u_int32_t)); return (t); } token_t * au_to_subject64_ex(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid, au_tid_addr_t *tid) { token_t *t; u_char *dptr = NULL; if (tid->at_type == AU_IPv4) GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 7 * sizeof(u_int32_t) + sizeof(u_int64_t) + 2 * sizeof(u_int32_t)); else if (tid->at_type == AU_IPv6) GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 7 * sizeof(u_int32_t) + sizeof(u_int64_t) + 5 * sizeof(u_int32_t)); else panic("au_to_subject64_ex: invalid at_type (%d)", tid->at_type); ADD_U_CHAR(dptr, AUT_SUBJECT64_EX); ADD_U_INT32(dptr, auid); ADD_U_INT32(dptr, euid); ADD_U_INT32(dptr, egid); ADD_U_INT32(dptr, ruid); ADD_U_INT32(dptr, rgid); ADD_U_INT32(dptr, pid); ADD_U_INT32(dptr, sid); ADD_U_INT64(dptr, tid->at_port); ADD_U_INT32(dptr, tid->at_type); if (tid->at_type == AU_IPv6) ADD_MEM(dptr, &tid->at_addr[0], 4 * sizeof(u_int32_t)); else ADD_MEM(dptr, &tid->at_addr[0], sizeof(u_int32_t)); return (t); } token_t * au_to_subject_ex(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid, au_tid_addr_t *tid) { return (au_to_subject32_ex(auid, euid, egid, ruid, rgid, pid, sid, tid)); } #if !defined(_KERNEL) && !defined(KERNEL) && defined(HAVE_AUDIT_SYSCALLS) /* * Collects audit information for the current process * and creates a subject token from it */ token_t * au_to_me(void) { auditinfo_t auinfo; if (getaudit(&auinfo) != 0) return (NULL); return (au_to_subject32(auinfo.ai_auid, geteuid(), getegid(), getuid(), getgid(), getpid(), auinfo.ai_asid, &auinfo.ai_termid)); } #endif #if defined(_KERNEL) || defined(KERNEL) static token_t * au_to_exec_strings(char *strs, int count, u_char type) { token_t *t; u_char *dptr = NULL; u_int32_t totlen; int ctr; char *p; totlen = 0; ctr = count; p = strs; while (ctr-- > 0) { totlen += strlen(p) + 1; p = strs + totlen; } GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int32_t) + totlen); ADD_U_CHAR(dptr, type); ADD_U_INT32(dptr, count); ADD_STRING(dptr, strs, totlen); return (t); } /* * token ID 1 byte * count 4 bytes * text count null-terminated strings */ token_t * au_to_exec_args(char *args, int argc) { return (au_to_exec_strings(args, argc, AUT_EXEC_ARGS)); } /* * token ID 1 byte * count 4 bytes * text count null-terminated strings */ token_t * au_to_exec_env(char *envs, int envc) { return (au_to_exec_strings(envs, envc, AUT_EXEC_ENV)); } #else /* * token ID 1 byte * count 4 bytes * text count null-terminated strings */ token_t * au_to_exec_args(char **argv) { token_t *t; u_char *dptr = NULL; const char *nextarg; int i, count = 0; size_t totlen = 0; nextarg = *argv; while (nextarg != NULL) { int nextlen; nextlen = strlen(nextarg); totlen += nextlen + 1; count++; nextarg = *(argv + count); } totlen += count * sizeof(char); /* nul terminations. */ GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int32_t) + totlen); ADD_U_CHAR(dptr, AUT_EXEC_ARGS); ADD_U_INT32(dptr, count); for (i = 0; i < count; i++) { nextarg = *(argv + i); ADD_MEM(dptr, nextarg, strlen(nextarg) + 1); } return (t); } /* * token ID 1 byte * zonename length 2 bytes * zonename N bytes + 1 terminating NULL byte */ token_t * au_to_zonename(char *zonename) { u_char *dptr = NULL; u_int16_t textlen; token_t *t; textlen = strlen(zonename); textlen += 1; GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int16_t) + textlen); ADD_U_CHAR(dptr, AUT_ZONENAME); ADD_U_INT16(dptr, textlen); ADD_STRING(dptr, zonename, textlen); return (t); } /* * token ID 1 byte * count 4 bytes * text count null-terminated strings */ token_t * au_to_exec_env(char **envp) { token_t *t; u_char *dptr = NULL; int i, count = 0; size_t totlen = 0; const char *nextenv; nextenv = *envp; while (nextenv != NULL) { int nextlen; nextlen = strlen(nextenv); totlen += nextlen + 1; count++; nextenv = *(envp + count); } totlen += sizeof(char) * count; GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int32_t) + totlen); ADD_U_CHAR(dptr, AUT_EXEC_ENV); ADD_U_INT32(dptr, count); for (i = 0; i < count; i++) { nextenv = *(envp + i); ADD_MEM(dptr, nextenv, strlen(nextenv) + 1); } return (t); } #endif /* * token ID 1 byte * record byte count 4 bytes * version # 1 byte [2] * event type 2 bytes * event modifier 2 bytes * seconds of time 4 bytes/8 bytes (32-bit/64-bit value) * milliseconds of time 4 bytes/8 bytes (32-bit/64-bit value) */ token_t * au_to_header32_tm(int rec_size, au_event_t e_type, au_emod_t e_mod, struct timeval tm) { token_t *t; u_char *dptr = NULL; u_int32_t timems; GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int32_t) + sizeof(u_char) + 2 * sizeof(u_int16_t) + 2 * sizeof(u_int32_t)); ADD_U_CHAR(dptr, AUT_HEADER32); ADD_U_INT32(dptr, rec_size); ADD_U_CHAR(dptr, AUDIT_HEADER_VERSION_OPENBSM); ADD_U_INT16(dptr, e_type); ADD_U_INT16(dptr, e_mod); timems = tm.tv_usec/1000; /* Add the timestamp */ ADD_U_INT32(dptr, tm.tv_sec); ADD_U_INT32(dptr, timems); /* We need time in ms. */ return (t); } token_t * au_to_header64_tm(int rec_size, au_event_t e_type, au_emod_t e_mod, struct timeval tm) { token_t *t; u_char *dptr = NULL; u_int32_t timems; GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int32_t) + sizeof(u_char) + 2 * sizeof(u_int16_t) + 2 * sizeof(u_int64_t)); ADD_U_CHAR(dptr, AUT_HEADER64); ADD_U_INT32(dptr, rec_size); ADD_U_CHAR(dptr, AUDIT_HEADER_VERSION_OPENBSM); ADD_U_INT16(dptr, e_type); ADD_U_INT16(dptr, e_mod); timems = tm.tv_usec/1000; /* Add the timestamp */ ADD_U_INT64(dptr, tm.tv_sec); ADD_U_INT64(dptr, timems); /* We need time in ms. */ return (t); } /* * token ID 1 byte * trailer magic number 2 bytes * record byte count 4 bytes */ token_t * au_to_trailer(int rec_size) { token_t *t; u_char *dptr = NULL; u_int16_t magic = TRAILER_PAD_MAGIC; GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int16_t) + sizeof(u_int32_t)); ADD_U_CHAR(dptr, AUT_TRAILER); ADD_U_INT16(dptr, magic); ADD_U_INT32(dptr, rec_size); return (t); } Index: head/sys/security/audit/audit_pipe.c =================================================================== --- head/sys/security/audit/audit_pipe.c (revision 181052) +++ head/sys/security/audit/audit_pipe.c (revision 181053) @@ -1,1058 +1,1057 @@ /*- * Copyright (c) 2006 Robert N. M. Watson * All rights reserved. * * This software was developed by Robert Watson for the TrustedBSD Project. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * 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. Consumers may * express interest via a set of preselection ioctls. */ /* * Memory types. */ 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_presel", "Audit pipe preselection structure"); /* * Audit pipe buffer parameters. */ #define AUDIT_PIPE_QLIMIT_DEFAULT (128) #define AUDIT_PIPE_QLIMIT_MIN (0) #define AUDIT_PIPE_QLIMIT_MAX (1024) /* * Description of an entry in an audit_pipe. */ struct audit_pipe_entry { void *ape_record; u_int ape_record_len; TAILQ_ENTRY(audit_pipe_entry) ape_queue; }; /* * 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. */ #define AUDIT_PIPE_ASYNC 0x00000001 #define AUDIT_PIPE_NBIO 0x00000002 struct audit_pipe { int ap_open; /* Device open? */ u_int ap_flags; struct selinfo ap_selinfo; struct sigio *ap_sigio; u_int ap_qlen; u_int ap_qlimit; u_int64_t ap_inserts; /* Records added. */ u_int64_t ap_reads; /* Records read. */ 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. 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 might * be per-pipe to avoid unnecessary wakeups when several pipes with different * preselection masks are present. */ static struct cv audit_pipe_cv; /* * Cloning related variables and constants. */ #define AUDIT_PIPE_NAME "auditpipe" static eventhandler_tag audit_pipe_eh_tag; static struct clonedevs *audit_pipe_clones; /* * Special device methods and definition. */ static d_open_t audit_pipe_open; static d_close_t audit_pipe_close; static d_read_t audit_pipe_read; static d_ioctl_t audit_pipe_ioctl; static d_poll_t audit_pipe_poll; static d_kqfilter_t audit_pipe_kqfilter; static struct cdevsw audit_pipe_cdevsw = { .d_version = D_VERSION, .d_flags = D_PSEUDO | D_NEEDGIANT | D_NEEDMINOR, .d_open = audit_pipe_open, .d_close = audit_pipe_close, .d_read = audit_pipe_read, .d_ioctl = audit_pipe_ioctl, .d_poll = audit_pipe_poll, .d_kqfilter = audit_pipe_kqfilter, .d_name = AUDIT_PIPE_NAME, }; static int audit_pipe_kqread(struct knote *note, long hint); static void audit_pipe_kqdetach(struct knote *note); static struct filterops audit_pipe_read_filterops = { .f_isfd = 1, .f_attach = NULL, .f_detach = audit_pipe_kqdetach, .f_event = audit_pipe_kqread, }; /* * Some global statistics on audit pipes. */ static int audit_pipe_count; /* Current number of pipes. */ static u_int64_t audit_pipe_ever; /* Pipes ever allocated. */ static u_int64_t audit_pipe_records; /* Records seen. */ static u_int64_t audit_pipe_drops; /* Global record drop count. */ /* * Free an audit pipe entry. */ static void audit_pipe_entry_free(struct audit_pipe_entry *ape) { free(ape->ape_record, M_AUDIT_PIPE_ENTRY); free(ape, M_AUDIT_PIPE_ENTRY); } /* * 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. */ static void audit_pipe_append(struct audit_pipe *ap, void *record, u_int record_len) { struct audit_pipe_entry *ape, *ape_remove; mtx_assert(&audit_pipe_mtx, MA_OWNED); ape = malloc(sizeof(*ape), M_AUDIT_PIPE_ENTRY, M_NOWAIT | M_ZERO); if (ape == NULL) { ap->ap_drops++; audit_pipe_drops++; return; } ape->ape_record = malloc(record_len, M_AUDIT_PIPE_ENTRY, M_NOWAIT); if (ape->ape_record == NULL) { free(ape, M_AUDIT_PIPE_ENTRY); ap->ap_drops++; audit_pipe_drops++; return; } bcopy(record, ape->ape_record, record_len); ape->ape_record_len = record_len; if (ap->ap_qlen >= ap->ap_qlimit) { ape_remove = TAILQ_FIRST(&ap->ap_queue); TAILQ_REMOVE(&ap->ap_queue, ape_remove, ape_queue); audit_pipe_entry_free(ape_remove); ap->ap_qlen--; ap->ap_drops++; audit_pipe_drops++; } TAILQ_INSERT_TAIL(&ap->ap_queue, ape, ape_queue); ap->ap_inserts++; ap->ap_qlen++; selwakeuppri(&ap->ap_selinfo, PSOCK); KNOTE_LOCKED(&ap->ap_selinfo.si_note, 0); if (ap->ap_flags & AUDIT_PIPE_ASYNC) pgsigio(&ap->ap_sigio, SIGIO, 0); } /* * audit_pipe_submit(): audit_worker submits audit records via this * interface, which arranges for them to be delivered to pipe queues. */ void 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_broadcastpri(&audit_pipe_cv, PSOCK); } /* * 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 * should parse that information and return it. */ void audit_pipe_submit_user(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) audit_pipe_append(ap, record, record_len); audit_pipe_records++; mtx_unlock(&audit_pipe_mtx); cv_broadcastpri(&audit_pipe_cv, PSOCK); } - /* * Pop the next record off of an audit pipe. */ static struct audit_pipe_entry * audit_pipe_pop(struct audit_pipe *ap) { struct audit_pipe_entry *ape; mtx_assert(&audit_pipe_mtx, MA_OWNED); ape = TAILQ_FIRST(&ap->ap_queue); KASSERT((ape == NULL && ap->ap_qlen == 0) || (ape != NULL && ap->ap_qlen != 0), ("audit_pipe_pop: qlen")); if (ape == NULL) return (NULL); TAILQ_REMOVE(&ap->ap_queue, ape, ape_queue); ap->ap_qlen--; return (ape); } /* * Allocate a new audit pipe. Connects the pipe, on success, to the global * list and updates statistics. */ static struct audit_pipe * audit_pipe_alloc(void) { struct audit_pipe *ap; mtx_assert(&audit_pipe_mtx, MA_OWNED); ap = malloc(sizeof(*ap), M_AUDIT_PIPE, M_NOWAIT | M_ZERO); if (ap == NULL) return (NULL); ap->ap_qlimit = AUDIT_PIPE_QLIMIT_DEFAULT; TAILQ_INIT(&ap->ap_queue); knlist_init(&ap->ap_selinfo.si_note, &audit_pipe_mtx, NULL, NULL, NULL); /* * Default flags, naflags, and auid-specific preselection settings to * 0. Initialize the mode to the global trail so that if praudit(1) * is run on /dev/auditpipe, it sees events associated with the * default trail. Pipe-aware application can clear the flag, set * custom masks, and flush the pipe as needed. */ bzero(&ap->ap_preselect_flags, sizeof(ap->ap_preselect_flags)); bzero(&ap->ap_preselect_naflags, sizeof(ap->ap_preselect_naflags)); TAILQ_INIT(&ap->ap_preselect_list); ap->ap_preselect_mode = AUDITPIPE_PRESELECT_MODE_TRAIL; /* * Add to global list and update global statistics. */ TAILQ_INSERT_HEAD(&audit_pipe_list, ap, ap_list); audit_pipe_count++; audit_pipe_ever++; return (ap); } /* * Flush all records currently present in an audit pipe; assume mutex is held. */ static void audit_pipe_flush(struct audit_pipe *ap) { struct audit_pipe_entry *ape; mtx_assert(&audit_pipe_mtx, MA_OWNED); while ((ape = TAILQ_FIRST(&ap->ap_queue)) != NULL) { TAILQ_REMOVE(&ap->ap_queue, ape, ape_queue); audit_pipe_entry_free(ape); ap->ap_qlen--; } KASSERT(ap->ap_qlen == 0, ("audit_pipe_free: ap_qlen")); } /* * Free an audit pipe; this means freeing all preselection state and all * records in the pipe. Assumes mutex is held to prevent any new records * from being inserted during the free, and that the audit pipe is still on * the global list. */ static void audit_pipe_free(struct audit_pipe *ap) { mtx_assert(&audit_pipe_mtx, MA_OWNED); audit_pipe_preselect_flush_locked(ap); audit_pipe_flush(ap); knlist_destroy(&ap->ap_selinfo.si_note); TAILQ_REMOVE(&audit_pipe_list, ap, ap_list); free(ap, M_AUDIT_PIPE); 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 audit_pipe_clone(void *arg, struct ucred *cred, char *name, int namelen, struct cdev **dev) { int i, u; if (*dev != NULL) return; if (strcmp(name, AUDIT_PIPE_NAME) == 0) u = -1; else if (dev_stdclone(name, NULL, AUDIT_PIPE_NAME, &u) != 1) return; i = clone_create(&audit_pipe_clones, &audit_pipe_cdevsw, &u, dev, 0); if (i) { *dev = make_dev(&audit_pipe_cdevsw, unit2minor(u), UID_ROOT, GID_WHEEL, 0600, "%s%d", AUDIT_PIPE_NAME, u); if (*dev != NULL) { dev_ref(*dev); (*dev)->si_flags |= SI_CHEAPCLONE; } } } /* * 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 * review access. Those file permissions should be managed carefully. */ static int audit_pipe_open(struct cdev *dev, int oflags, int devtype, struct thread *td) { struct audit_pipe *ap; mtx_lock(&audit_pipe_mtx); ap = dev->si_drv1; if (ap == NULL) { ap = audit_pipe_alloc(); if (ap == NULL) { mtx_unlock(&audit_pipe_mtx); return (ENOMEM); } dev->si_drv1 = ap; } else { KASSERT(ap->ap_open, ("audit_pipe_open: ap && !ap_open")); mtx_unlock(&audit_pipe_mtx); return (EBUSY); } ap->ap_open = 1; mtx_unlock(&audit_pipe_mtx); fsetown(td->td_proc->p_pid, &ap->ap_sigio); return (0); } /* * Close audit pipe, tear down all records, etc. */ static int audit_pipe_close(struct cdev *dev, int fflag, int devtype, struct thread *td) { struct audit_pipe *ap; ap = dev->si_drv1; KASSERT(ap != NULL, ("audit_pipe_close: ap == NULL")); KASSERT(ap->ap_open, ("audit_pipe_close: !ap_open")); funsetown(&ap->ap_sigio); mtx_lock(&audit_pipe_mtx); ap->ap_open = 0; audit_pipe_free(ap); dev->si_drv1 = NULL; mtx_unlock(&audit_pipe_mtx); return (0); } /* * Audit pipe ioctl() routine. Handle file descriptor and audit pipe layer * commands. * * Would be desirable to support filtering, although perhaps something simple * like an event mask, as opposed to something complicated like BPF. */ static int audit_pipe_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) { struct auditpipe_ioctl_preselect *aip; struct audit_pipe *ap; au_mask_t *maskp; int error, mode; au_id_t auid; ap = dev->si_drv1; KASSERT(ap != NULL, ("audit_pipe_ioctl: ap == NULL")); /* * Audit pipe ioctls: first come standard device node ioctls, then * manipulation of pipe settings, and finally, statistics query * ioctls. */ switch (cmd) { case FIONBIO: mtx_lock(&audit_pipe_mtx); if (*(int *)data) ap->ap_flags |= AUDIT_PIPE_NBIO; else ap->ap_flags &= ~AUDIT_PIPE_NBIO; mtx_unlock(&audit_pipe_mtx); error = 0; break; case FIONREAD: mtx_lock(&audit_pipe_mtx); if (TAILQ_FIRST(&ap->ap_queue) != NULL) *(int *)data = TAILQ_FIRST(&ap->ap_queue)->ape_record_len; else *(int *)data = 0; mtx_unlock(&audit_pipe_mtx); error = 0; break; case FIOASYNC: mtx_lock(&audit_pipe_mtx); if (*(int *)data) ap->ap_flags |= AUDIT_PIPE_ASYNC; else ap->ap_flags &= ~AUDIT_PIPE_ASYNC; mtx_unlock(&audit_pipe_mtx); error = 0; break; case FIOSETOWN: error = fsetown(*(int *)data, &ap->ap_sigio); break; case FIOGETOWN: *(int *)data = fgetown(&ap->ap_sigio); error = 0; break; case AUDITPIPE_GET_QLEN: *(u_int *)data = ap->ap_qlen; error = 0; break; case AUDITPIPE_GET_QLIMIT: *(u_int *)data = ap->ap_qlimit; error = 0; break; case AUDITPIPE_SET_QLIMIT: /* Lockless integer write. */ if (*(u_int *)data >= AUDIT_PIPE_QLIMIT_MIN || *(u_int *)data <= AUDIT_PIPE_QLIMIT_MAX) { ap->ap_qlimit = *(u_int *)data; error = 0; } else error = EINVAL; break; case AUDITPIPE_GET_QLIMIT_MIN: *(u_int *)data = AUDIT_PIPE_QLIMIT_MIN; error = 0; break; case AUDITPIPE_GET_QLIMIT_MAX: *(u_int *)data = AUDIT_PIPE_QLIMIT_MAX; error = 0; break; case AUDITPIPE_GET_PRESELECT_FLAGS: mtx_lock(&audit_pipe_mtx); maskp = (au_mask_t *)data; *maskp = ap->ap_preselect_flags; mtx_unlock(&audit_pipe_mtx); error = 0; break; case AUDITPIPE_SET_PRESELECT_FLAGS: mtx_lock(&audit_pipe_mtx); maskp = (au_mask_t *)data; ap->ap_preselect_flags = *maskp; mtx_unlock(&audit_pipe_mtx); error = 0; break; case AUDITPIPE_GET_PRESELECT_NAFLAGS: mtx_lock(&audit_pipe_mtx); maskp = (au_mask_t *)data; *maskp = ap->ap_preselect_naflags; mtx_unlock(&audit_pipe_mtx); error = 0; break; case AUDITPIPE_SET_PRESELECT_NAFLAGS: mtx_lock(&audit_pipe_mtx); maskp = (au_mask_t *)data; ap->ap_preselect_naflags = *maskp; mtx_unlock(&audit_pipe_mtx); error = 0; break; case AUDITPIPE_GET_PRESELECT_AUID: aip = (struct auditpipe_ioctl_preselect *)data; error = audit_pipe_preselect_get(ap, aip->aip_auid, &aip->aip_mask); break; case AUDITPIPE_SET_PRESELECT_AUID: aip = (struct auditpipe_ioctl_preselect *)data; audit_pipe_preselect_set(ap, aip->aip_auid, aip->aip_mask); error = 0; break; case AUDITPIPE_DELETE_PRESELECT_AUID: auid = *(au_id_t *)data; error = audit_pipe_preselect_delete(ap, auid); break; case AUDITPIPE_FLUSH_PRESELECT_AUID: audit_pipe_preselect_flush(ap); error = 0; break; case AUDITPIPE_GET_PRESELECT_MODE: mtx_lock(&audit_pipe_mtx); *(int *)data = ap->ap_preselect_mode; mtx_unlock(&audit_pipe_mtx); error = 0; break; case AUDITPIPE_SET_PRESELECT_MODE: mode = *(int *)data; switch (mode) { case AUDITPIPE_PRESELECT_MODE_TRAIL: case AUDITPIPE_PRESELECT_MODE_LOCAL: mtx_lock(&audit_pipe_mtx); ap->ap_preselect_mode = mode; mtx_unlock(&audit_pipe_mtx); error = 0; break; default: error = EINVAL; } break; case AUDITPIPE_FLUSH: mtx_lock(&audit_pipe_mtx); audit_pipe_flush(ap); mtx_unlock(&audit_pipe_mtx); error = 0; break; case AUDITPIPE_GET_MAXAUDITDATA: *(u_int *)data = MAXAUDITDATA; error = 0; break; case AUDITPIPE_GET_INSERTS: *(u_int *)data = ap->ap_inserts; error = 0; break; case AUDITPIPE_GET_READS: *(u_int *)data = ap->ap_reads; error = 0; break; case AUDITPIPE_GET_DROPS: *(u_int *)data = ap->ap_drops; error = 0; break; case AUDITPIPE_GET_TRUNCATES: *(u_int *)data = ap->ap_truncates; error = 0; break; default: error = ENOTTY; } return (error); } /* * Audit pipe read. Pull one record off the queue and copy to user space. * On error, the record is dropped. * * Providing more sophisticated behavior, such as partial reads, is tricky * due to the potential for parallel I/O. If partial read support is * required, it will require a per-pipe "current record being read" along * with an offset into that trecord which has already been read. Threads * performing partial reads will need to allocate per-thread copies of the * data so that if another thread completes the read of the record, it can be * freed without adding reference count logic. If this is added, a flag to * indicate that only atomic record reads are desired would be useful, as if * different threads are all waiting for records on the pipe, they will want * independent record reads, which is currently the behavior. */ static int audit_pipe_read(struct cdev *dev, struct uio *uio, int flag) { struct audit_pipe_entry *ape; struct audit_pipe *ap; int error; ap = dev->si_drv1; KASSERT(ap != NULL, ("audit_pipe_read: ap == NULL")); mtx_lock(&audit_pipe_mtx); do { /* * Wait for a record that fits into the read buffer, dropping * records that would be truncated if actually passed to the * process. This helps maintain the discreet record read * interface. */ while ((ape = audit_pipe_pop(ap)) == NULL) { if (ap->ap_flags & AUDIT_PIPE_NBIO) { mtx_unlock(&audit_pipe_mtx); return (EAGAIN); } error = cv_wait_sig(&audit_pipe_cv, &audit_pipe_mtx); if (error) { mtx_unlock(&audit_pipe_mtx); return (error); } } if (ape->ape_record_len <= uio->uio_resid) break; audit_pipe_entry_free(ape); ap->ap_truncates++; } while (1); ap->ap_reads++; mtx_unlock(&audit_pipe_mtx); /* * Now read record to user space memory. Even if the read is short, * we abandon the remainder of the record, supporting only discreet * record reads. */ error = uiomove(ape->ape_record, ape->ape_record_len, uio); audit_pipe_entry_free(ape); return (error); } /* * Audit pipe poll. */ static int audit_pipe_poll(struct cdev *dev, int events, struct thread *td) { struct audit_pipe *ap; int revents; revents = 0; ap = dev->si_drv1; KASSERT(ap != NULL, ("audit_pipe_poll: ap == NULL")); if (events & (POLLIN | POLLRDNORM)) { mtx_lock(&audit_pipe_mtx); if (TAILQ_FIRST(&ap->ap_queue) != NULL) revents |= events & (POLLIN | POLLRDNORM); else selrecord(td, &ap->ap_selinfo); mtx_unlock(&audit_pipe_mtx); } return (revents); } /* * Audit pipe kqfilter. */ static int audit_pipe_kqfilter(struct cdev *dev, struct knote *kn) { struct audit_pipe *ap; ap = dev->si_drv1; KASSERT(ap != NULL, ("audit_pipe_kqfilter: ap == NULL")); if (kn->kn_filter != EVFILT_READ) return (EINVAL); kn->kn_fop = &audit_pipe_read_filterops; kn->kn_hook = ap; mtx_lock(&audit_pipe_mtx); knlist_add(&ap->ap_selinfo.si_note, kn, 1); mtx_unlock(&audit_pipe_mtx); return (0); } /* * Return true if there are records available for reading on the pipe. */ static int audit_pipe_kqread(struct knote *kn, long hint) { struct audit_pipe_entry *ape; struct audit_pipe *ap; mtx_assert(&audit_pipe_mtx, MA_OWNED); ap = (struct audit_pipe *)kn->kn_hook; KASSERT(ap != NULL, ("audit_pipe_kqread: ap == NULL")); if (ap->ap_qlen != 0) { ape = TAILQ_FIRST(&ap->ap_queue); KASSERT(ape != NULL, ("audit_pipe_kqread: ape == NULL")); kn->kn_data = ape->ape_record_len; return (1); } else { kn->kn_data = 0; return (0); } } /* * Detach kqueue state from audit pipe. */ static void audit_pipe_kqdetach(struct knote *kn) { struct audit_pipe *ap; ap = (struct audit_pipe *)kn->kn_hook; KASSERT(ap != NULL, ("audit_pipe_kqdetach: ap == NULL")); mtx_lock(&audit_pipe_mtx); knlist_remove(&ap->ap_selinfo.si_note, kn, 1); mtx_unlock(&audit_pipe_mtx); } /* * Initialize the audit pipe system. */ static void audit_pipe_init(void *unused) { TAILQ_INIT(&audit_pipe_list); mtx_init(&audit_pipe_mtx, "audit_pipe_mtx", NULL, MTX_DEF); cv_init(&audit_pipe_cv, "audit_pipe_cv"); clone_setup(&audit_pipe_clones); audit_pipe_eh_tag = EVENTHANDLER_REGISTER(dev_clone, audit_pipe_clone, 0, 1000); if (audit_pipe_eh_tag == NULL) panic("audit_pipe_init: EVENTHANDLER_REGISTER"); } SYSINIT(audit_pipe_init, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, audit_pipe_init, NULL); Index: head/sys/security/audit/audit_private.h =================================================================== --- head/sys/security/audit/audit_private.h (revision 181052) +++ head/sys/security/audit/audit_private.h (revision 181053) @@ -1,339 +1,339 @@ -/* +/*- * Copyright (c) 1999-2005 Apple Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ /* * This include file contains function prototypes and type definitions used * within the audit implementation. */ #ifndef _SECURITY_AUDIT_PRIVATE_H_ #define _SECURITY_AUDIT_PRIVATE_H_ #ifndef _KERNEL #error "no user-serviceable parts inside" #endif #include #include #include #ifdef MALLOC_DECLARE MALLOC_DECLARE(M_AUDITBSM); MALLOC_DECLARE(M_AUDITDATA); MALLOC_DECLARE(M_AUDITPATH); MALLOC_DECLARE(M_AUDITTEXT); #endif /* * Audit control variables that are usually set/read via system calls and * used to control various aspects of auditing. */ extern struct au_qctrl audit_qctrl; extern struct audit_fstat audit_fstat; extern struct au_mask audit_nae_mask; extern int audit_panic_on_write_fail; extern int audit_fail_stop; extern int audit_argv; extern int audit_arge; /* * Success/failure conditions for the conversion of a kernel audit record to * BSM format. */ #define BSM_SUCCESS 0 #define BSM_FAILURE 1 #define BSM_NOAUDIT 2 /* * Defines for the kernel audit record k_ar_commit field. Flags are set to * indicate what sort of record it is, and which preselection mechanism * selected it. */ #define AR_COMMIT_KERNEL 0x00000001U #define AR_COMMIT_USER 0x00000010U #define AR_PRESELECT_TRAIL 0x00001000U #define AR_PRESELECT_PIPE 0x00002000U #define AR_PRESELECT_USER_TRAIL 0x00004000U #define AR_PRESELECT_USER_PIPE 0x00008000U /* * Audit data is generated as a stream of struct audit_record structures, * linked by struct kaudit_record, and contain storage for possible audit so * that it will not need to be allocated during the processing of a system * call, both improving efficiency and avoiding sleeping at untimely moments. * This structure is converted to BSM format before being written to disk. */ struct vnode_au_info { mode_t vn_mode; uid_t vn_uid; gid_t vn_gid; dev_t vn_dev; long vn_fsid; long vn_fileid; long vn_gen; }; struct groupset { gid_t gidset[NGROUPS]; u_int gidset_size; }; struct socket_au_info { int so_domain; int so_type; int so_protocol; in_addr_t so_raddr; /* Remote address if INET socket. */ in_addr_t so_laddr; /* Local address if INET socket. */ u_short so_rport; /* Remote port. */ u_short so_lport; /* Local port. */ }; union auditon_udata { char *au_path; long au_cond; long au_flags; long au_policy; int au_trigger; au_evclass_map_t au_evclass; au_mask_t au_mask; auditinfo_t au_auinfo; auditpinfo_t au_aupinfo; auditpinfo_addr_t au_aupinfo_addr; au_qctrl_t au_qctrl; au_stat_t au_stat; au_fstat_t au_fstat; }; struct posix_ipc_perm { uid_t pipc_uid; gid_t pipc_gid; mode_t pipc_mode; }; struct audit_record { /* Audit record header. */ u_int32_t ar_magic; int ar_event; int ar_retval; /* value returned to the process */ int ar_errno; /* return status of system call */ struct timespec ar_starttime; struct timespec ar_endtime; u_int64_t ar_valid_arg; /* Bitmask of valid arguments */ /* Audit subject information. */ struct xucred ar_subj_cred; uid_t ar_subj_ruid; gid_t ar_subj_rgid; gid_t ar_subj_egid; uid_t ar_subj_auid; /* Audit user ID */ pid_t ar_subj_asid; /* Audit session ID */ pid_t ar_subj_pid; struct au_tid ar_subj_term; struct au_tid_addr ar_subj_term_addr; struct au_mask ar_subj_amask; /* Operation arguments. */ uid_t ar_arg_euid; uid_t ar_arg_ruid; uid_t ar_arg_suid; gid_t ar_arg_egid; gid_t ar_arg_rgid; gid_t ar_arg_sgid; pid_t ar_arg_pid; pid_t ar_arg_asid; struct au_tid ar_arg_termid; struct au_tid_addr ar_arg_termid_addr; uid_t ar_arg_uid; uid_t ar_arg_auid; gid_t ar_arg_gid; struct groupset ar_arg_groups; int ar_arg_fd; int ar_arg_fflags; mode_t ar_arg_mode; int ar_arg_dev; long ar_arg_value; void * ar_arg_addr; int ar_arg_len; int ar_arg_mask; u_int ar_arg_signum; char ar_arg_login[MAXLOGNAME]; int ar_arg_ctlname[CTL_MAXNAME]; struct socket_au_info ar_arg_sockinfo; char *ar_arg_upath1; char *ar_arg_upath2; char *ar_arg_text; struct au_mask ar_arg_amask; struct vnode_au_info ar_arg_vnode1; struct vnode_au_info ar_arg_vnode2; int ar_arg_cmd; int ar_arg_svipc_cmd; struct ipc_perm ar_arg_svipc_perm; int ar_arg_svipc_id; void * ar_arg_svipc_addr; struct posix_ipc_perm ar_arg_pipc_perm; union auditon_udata ar_arg_auditon; char *ar_arg_argv; int ar_arg_argc; char *ar_arg_envv; int ar_arg_envc; int ar_arg_exitstatus; int ar_arg_exitretval; struct sockaddr_storage ar_arg_sockaddr; }; /* * Arguments in the audit record are initially not defined; flags are set to * indicate if they are present so they can be included in the audit log * stream only if defined. */ #define ARG_IS_VALID(kar, arg) ((kar)->k_ar.ar_valid_arg & (arg)) #define ARG_SET_VALID(kar, arg) do { \ (kar)->k_ar.ar_valid_arg |= (arg); \ } while (0) /* * In-kernel version of audit record; the basic record plus queue meta-data. * This record can also have a pointer set to some opaque data that will be * passed through to the audit writing mechanism. */ struct kaudit_record { struct audit_record k_ar; u_int32_t k_ar_commit; void *k_udata; /* User data. */ u_int k_ulen; /* User data length. */ struct uthread *k_uthread; /* Audited thread. */ TAILQ_ENTRY(kaudit_record) k_q; }; TAILQ_HEAD(kaudit_queue, kaudit_record); /* * Functions to manage the allocation, release, and commit of kernel audit * records. */ void audit_abort(struct kaudit_record *ar); void audit_commit(struct kaudit_record *ar, int error, int retval); struct kaudit_record *audit_new(int event, struct thread *td); /* * Functions relating to the conversion of internal kernel audit records to * the BSM file format. */ struct au_record; int kaudit_to_bsm(struct kaudit_record *kar, struct au_record **pau); int bsm_rec_verify(void *rec); /* * Kernel versions of the libbsm audit record functions. */ void kau_free(struct au_record *rec); void kau_init(void); /* * Return values for pre-selection and post-selection decisions. */ #define AU_PRS_SUCCESS 1 #define AU_PRS_FAILURE 2 #define AU_PRS_BOTH (AU_PRS_SUCCESS|AU_PRS_FAILURE) /* * Data structures relating to the kernel audit queue. Ideally, these might * be abstracted so that only accessor methods are exposed. */ extern struct mtx audit_mtx; extern struct cv audit_watermark_cv; extern struct cv audit_worker_cv; extern struct kaudit_queue audit_q; extern int audit_q_len; extern int audit_pre_q_len; extern int audit_in_failure; /* * Flags to use on audit files when opening and closing. */ #define AUDIT_OPEN_FLAGS (FWRITE | O_APPEND) #define AUDIT_CLOSE_FLAGS (FWRITE | O_APPEND) #include #include #include /* * Some of the BSM tokenizer functions take different parameters in the * kernel implementations in order to save the copying of large kernel data * structures. The prototypes of these functions are declared here. */ token_t *kau_to_socket(struct socket_au_info *soi); /* * audit_klib prototypes */ int au_preselect(au_event_t event, au_class_t class, au_mask_t *mask_p, int sorf); void au_evclassmap_init(void); void au_evclassmap_insert(au_event_t event, au_class_t class); au_class_t au_event_class(au_event_t event); au_event_t audit_ctlname_to_sysctlevent(int name[], uint64_t valid_arg); au_event_t audit_flags_and_error_to_openevent(int oflags, int error); int audit_msgctl_to_event(int cmd); int audit_semctl_to_event(int cmr); void audit_canon_path(struct thread *td, char *path, char *cpath); int auditon_command_event(int cmd); /* * Audit trigger events notify user space of kernel audit conditions * asynchronously. */ void audit_trigger_init(void); int audit_send_trigger(unsigned int trigger); /* * General audit related functions. */ struct kaudit_record *currecord(void); void audit_free(struct kaudit_record *ar); void audit_shutdown(void *arg, int howto); void audit_rotate_vnode(struct ucred *cred, struct vnode *vp); void audit_worker_init(void); /* * Audit pipe functions. */ int audit_pipe_preselect(au_id_t auid, au_event_t event, au_class_t class, int sorf, int trail_select); void 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); void audit_pipe_submit_user(void *record, u_int record_len); #endif /* ! _SECURITY_AUDIT_PRIVATE_H_ */ Index: head/sys/security/audit/audit_syscalls.c =================================================================== --- head/sys/security/audit/audit_syscalls.c (revision 181052) +++ head/sys/security/audit/audit_syscalls.c (revision 181053) @@ -1,757 +1,757 @@ -/* +/*- * Copyright (c) 1999-2005 Apple Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_mac.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef AUDIT /* * System call to allow a user space application to submit a BSM audit record * to the kernel for inclusion in the audit log. This function does little * verification on the audit record that is submitted. * * XXXAUDIT: Audit preselection for user records does not currently work, * since we pre-select only based on the AUE_audit event type, not the event * type submitted as part of the user audit data. */ /* ARGSUSED */ int audit(struct thread *td, struct audit_args *uap) { int error; void * rec; struct kaudit_record *ar; if (jailed(td->td_ucred)) return (ENOSYS); error = priv_check(td, PRIV_AUDIT_SUBMIT); if (error) return (error); if ((uap->length <= 0) || (uap->length > audit_qctrl.aq_bufsz)) return (EINVAL); ar = currecord(); /* * If there's no current audit record (audit() itself not audited) * commit the user audit record. */ if (ar == NULL) { /* * This is not very efficient; we're required to allocate a * complete kernel audit record just so the user record can * tag along. * * XXXAUDIT: Maybe AUE_AUDIT in the system call context and * special pre-select handling? */ td->td_ar = audit_new(AUE_NULL, td); if (td->td_ar == NULL) return (ENOTSUP); ar = td->td_ar; } if (uap->length > MAX_AUDIT_RECORD_SIZE) return (EINVAL); rec = malloc(uap->length, M_AUDITDATA, M_WAITOK); error = copyin(uap->record, rec, uap->length); if (error) goto free_out; /* Verify the record. */ if (bsm_rec_verify(rec) == 0) { error = EINVAL; goto free_out; } #ifdef MAC error = mac_system_check_audit(td->td_ucred, rec, uap->length); if (error) goto free_out; #endif /* * Attach the user audit record to the kernel audit record. Because * this system call is an auditable event, we will write the user * record along with the record for this audit event. * * XXXAUDIT: KASSERT appropriate starting values of k_udata, k_ulen, * k_ar_commit & AR_COMMIT_USER? */ ar->k_udata = rec; ar->k_ulen = uap->length; ar->k_ar_commit |= AR_COMMIT_USER; /* * Currently we assume that all preselection has been performed in * userspace. We unconditionally set these masks so that the records * get committed both to the trail and pipe. In the future we will * want to setup kernel based preselection. */ ar->k_ar_commit |= (AR_PRESELECT_USER_TRAIL | AR_PRESELECT_USER_PIPE); return (0); free_out: /* * audit_syscall_exit() will free the audit record on the thread even * if we allocated it above. */ free(rec, M_AUDITDATA); return (error); } /* * System call to manipulate auditing. */ /* ARGSUSED */ int auditon(struct thread *td, struct auditon_args *uap) { struct ucred *newcred, *oldcred; int error; union auditon_udata udata; struct proc *tp; if (jailed(td->td_ucred)) return (ENOSYS); AUDIT_ARG(cmd, uap->cmd); #ifdef MAC error = mac_system_check_auditon(td->td_ucred, uap->cmd); if (error) return (error); #endif error = priv_check(td, PRIV_AUDIT_CONTROL); if (error) return (error); if ((uap->length <= 0) || (uap->length > sizeof(union auditon_udata))) return (EINVAL); memset((void *)&udata, 0, sizeof(udata)); /* * Some of the GET commands use the arguments too. */ switch (uap->cmd) { case A_SETPOLICY: case A_SETKMASK: case A_SETQCTRL: case A_SETSTAT: case A_SETUMASK: case A_SETSMASK: case A_SETCOND: case A_SETCLASS: case A_SETPMASK: case A_SETFSIZE: case A_SETKAUDIT: case A_GETCLASS: case A_GETPINFO: case A_GETPINFO_ADDR: case A_SENDTRIGGER: error = copyin(uap->data, (void *)&udata, uap->length); if (error) return (error); AUDIT_ARG(auditon, &udata); break; } /* * XXXAUDIT: Locking? */ switch (uap->cmd) { case A_GETPOLICY: if (!audit_fail_stop) udata.au_policy |= AUDIT_CNT; if (audit_panic_on_write_fail) udata.au_policy |= AUDIT_AHLT; if (audit_argv) udata.au_policy |= AUDIT_ARGV; if (audit_arge) udata.au_policy |= AUDIT_ARGE; break; case A_SETPOLICY: if (udata.au_policy & ~(AUDIT_CNT|AUDIT_AHLT|AUDIT_ARGV| AUDIT_ARGE)) return (EINVAL); /* * XXX - Need to wake up waiters if the policy relaxes? */ audit_fail_stop = ((udata.au_policy & AUDIT_CNT) == 0); audit_panic_on_write_fail = (udata.au_policy & AUDIT_AHLT); audit_argv = (udata.au_policy & AUDIT_ARGV); audit_arge = (udata.au_policy & AUDIT_ARGE); break; case A_GETKMASK: udata.au_mask = audit_nae_mask; break; case A_SETKMASK: audit_nae_mask = udata.au_mask; break; case A_GETQCTRL: udata.au_qctrl = audit_qctrl; break; case A_SETQCTRL: if ((udata.au_qctrl.aq_hiwater > AQ_MAXHIGH) || (udata.au_qctrl.aq_lowater >= udata.au_qctrl.aq_hiwater) || (udata.au_qctrl.aq_bufsz > AQ_MAXBUFSZ) || (udata.au_qctrl.aq_minfree < 0) || (udata.au_qctrl.aq_minfree > 100)) return (EINVAL); audit_qctrl = udata.au_qctrl; /* XXX The queue delay value isn't used with the kernel. */ audit_qctrl.aq_delay = -1; break; case A_GETCWD: return (ENOSYS); break; case A_GETCAR: return (ENOSYS); break; case A_GETSTAT: return (ENOSYS); break; case A_SETSTAT: return (ENOSYS); break; case A_SETUMASK: return (ENOSYS); break; case A_SETSMASK: return (ENOSYS); break; case A_GETCOND: if (audit_enabled && !audit_suspended) udata.au_cond = AUC_AUDITING; else udata.au_cond = AUC_NOAUDIT; break; case A_SETCOND: if (udata.au_cond == AUC_NOAUDIT) audit_suspended = 1; if (udata.au_cond == AUC_AUDITING) audit_suspended = 0; if (udata.au_cond == AUC_DISABLED) { audit_suspended = 1; audit_shutdown(NULL, 0); } break; case A_GETCLASS: udata.au_evclass.ec_class = au_event_class( udata.au_evclass.ec_number); break; case A_SETCLASS: au_evclassmap_insert(udata.au_evclass.ec_number, udata.au_evclass.ec_class); break; case A_GETPINFO: if (udata.au_aupinfo.ap_pid < 1) return (EINVAL); if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL) return (EINVAL); if (p_cansee(td, tp) != 0) { PROC_UNLOCK(tp); return (EINVAL); } if (tp->p_ucred->cr_audit.ai_termid.at_type == AU_IPv6) { PROC_UNLOCK(tp); return (EINVAL); } udata.au_aupinfo.ap_auid = tp->p_ucred->cr_audit.ai_auid; udata.au_aupinfo.ap_mask.am_success = tp->p_ucred->cr_audit.ai_mask.am_success; udata.au_aupinfo.ap_mask.am_failure = tp->p_ucred->cr_audit.ai_mask.am_failure; udata.au_aupinfo.ap_termid.machine = tp->p_ucred->cr_audit.ai_termid.at_addr[0]; udata.au_aupinfo.ap_termid.port = (dev_t)tp->p_ucred->cr_audit.ai_termid.at_port; udata.au_aupinfo.ap_asid = tp->p_ucred->cr_audit.ai_asid; PROC_UNLOCK(tp); break; case A_SETPMASK: if (udata.au_aupinfo.ap_pid < 1) return (EINVAL); newcred = crget(); if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL) { crfree(newcred); return (EINVAL); } if (p_cansee(td, tp) != 0) { PROC_UNLOCK(tp); crfree(newcred); return (EINVAL); } oldcred = tp->p_ucred; crcopy(newcred, oldcred); newcred->cr_audit.ai_mask.am_success = udata.au_aupinfo.ap_mask.am_success; newcred->cr_audit.ai_mask.am_failure = udata.au_aupinfo.ap_mask.am_failure; td->td_proc->p_ucred = newcred; PROC_UNLOCK(tp); crfree(oldcred); break; case A_SETFSIZE: if ((udata.au_fstat.af_filesz != 0) && (udata.au_fstat.af_filesz < MIN_AUDIT_FILE_SIZE)) return (EINVAL); audit_fstat.af_filesz = udata.au_fstat.af_filesz; break; case A_GETFSIZE: udata.au_fstat.af_filesz = audit_fstat.af_filesz; udata.au_fstat.af_currsz = audit_fstat.af_currsz; break; case A_GETPINFO_ADDR: if (udata.au_aupinfo_addr.ap_pid < 1) return (EINVAL); if ((tp = pfind(udata.au_aupinfo_addr.ap_pid)) == NULL) return (EINVAL); udata.au_aupinfo_addr.ap_auid = tp->p_ucred->cr_audit.ai_auid; udata.au_aupinfo_addr.ap_mask.am_success = tp->p_ucred->cr_audit.ai_mask.am_success; udata.au_aupinfo_addr.ap_mask.am_failure = tp->p_ucred->cr_audit.ai_mask.am_failure; udata.au_aupinfo_addr.ap_termid = tp->p_ucred->cr_audit.ai_termid; udata.au_aupinfo_addr.ap_asid = tp->p_ucred->cr_audit.ai_asid; PROC_UNLOCK(tp); break; case A_GETKAUDIT: return (ENOSYS); break; case A_SETKAUDIT: return (ENOSYS); break; case A_SENDTRIGGER: if ((udata.au_trigger < AUDIT_TRIGGER_MIN) || (udata.au_trigger > AUDIT_TRIGGER_MAX)) return (EINVAL); return (audit_send_trigger(udata.au_trigger)); default: return (EINVAL); } /* * Copy data back to userspace for the GET comands. */ switch (uap->cmd) { case A_GETPOLICY: case A_GETKMASK: case A_GETQCTRL: case A_GETCWD: case A_GETCAR: case A_GETSTAT: case A_GETCOND: case A_GETCLASS: case A_GETPINFO: case A_GETFSIZE: case A_GETPINFO_ADDR: case A_GETKAUDIT: error = copyout((void *)&udata, uap->data, uap->length); if (error) return (error); break; } return (0); } /* * System calls to manage the user audit information. */ /* ARGSUSED */ int getauid(struct thread *td, struct getauid_args *uap) { int error; if (jailed(td->td_ucred)) return (ENOSYS); error = priv_check(td, PRIV_AUDIT_GETAUDIT); if (error) return (error); return (copyout(&td->td_ucred->cr_audit.ai_auid, uap->auid, sizeof(td->td_ucred->cr_audit.ai_auid))); } /* ARGSUSED */ int setauid(struct thread *td, struct setauid_args *uap) { struct ucred *newcred, *oldcred; au_id_t id; int error; if (jailed(td->td_ucred)) return (ENOSYS); error = copyin(uap->auid, &id, sizeof(id)); if (error) return (error); audit_arg_auid(id); newcred = crget(); PROC_LOCK(td->td_proc); oldcred = td->td_proc->p_ucred; crcopy(newcred, oldcred); #ifdef MAC error = mac_proc_check_setauid(oldcred, id); if (error) goto fail; #endif error = priv_check_cred(oldcred, PRIV_AUDIT_SETAUDIT, 0); if (error) goto fail; newcred->cr_audit.ai_auid = id; td->td_proc->p_ucred = newcred; PROC_UNLOCK(td->td_proc); crfree(oldcred); return (0); fail: PROC_UNLOCK(td->td_proc); crfree(newcred); return (error); } /* * System calls to get and set process audit information. */ /* ARGSUSED */ int getaudit(struct thread *td, struct getaudit_args *uap) { struct auditinfo ai; int error; if (jailed(td->td_ucred)) return (ENOSYS); error = priv_check(td, PRIV_AUDIT_GETAUDIT); if (error) return (error); if (td->td_ucred->cr_audit.ai_termid.at_type == AU_IPv6) return (E2BIG); bzero(&ai, sizeof(ai)); ai.ai_auid = td->td_ucred->cr_audit.ai_auid; ai.ai_mask = td->td_ucred->cr_audit.ai_mask; ai.ai_asid = td->td_ucred->cr_audit.ai_asid; ai.ai_termid.machine = td->td_ucred->cr_audit.ai_termid.at_addr[0]; ai.ai_termid.port = td->td_ucred->cr_audit.ai_termid.at_port; return (copyout(&ai, uap->auditinfo, sizeof(ai))); } /* ARGSUSED */ int setaudit(struct thread *td, struct setaudit_args *uap) { struct ucred *newcred, *oldcred; struct auditinfo ai; int error; if (jailed(td->td_ucred)) return (ENOSYS); error = copyin(uap->auditinfo, &ai, sizeof(ai)); if (error) return (error); audit_arg_auditinfo(&ai); newcred = crget(); PROC_LOCK(td->td_proc); oldcred = td->td_proc->p_ucred; crcopy(newcred, oldcred); #ifdef MAC error = mac_proc_check_setaudit(oldcred, &ai); if (error) goto fail; #endif error = priv_check_cred(oldcred, PRIV_AUDIT_SETAUDIT, 0); if (error) goto fail; bzero(&newcred->cr_audit, sizeof(newcred->cr_audit)); newcred->cr_audit.ai_auid = ai.ai_auid; newcred->cr_audit.ai_mask = ai.ai_mask; newcred->cr_audit.ai_asid = ai.ai_asid; newcred->cr_audit.ai_termid.at_addr[0] = ai.ai_termid.machine; newcred->cr_audit.ai_termid.at_port = ai.ai_termid.port; newcred->cr_audit.ai_termid.at_type = AU_IPv4; td->td_proc->p_ucred = newcred; PROC_UNLOCK(td->td_proc); crfree(oldcred); return (0); fail: PROC_UNLOCK(td->td_proc); crfree(newcred); return (error); } /* ARGSUSED */ int getaudit_addr(struct thread *td, struct getaudit_addr_args *uap) { int error; if (jailed(td->td_ucred)) return (ENOSYS); if (uap->length < sizeof(*uap->auditinfo_addr)) return (EOVERFLOW); error = priv_check(td, PRIV_AUDIT_GETAUDIT); if (error) return (error); return (copyout(&td->td_ucred->cr_audit, uap->auditinfo_addr, sizeof(*uap->auditinfo_addr))); } /* ARGSUSED */ int setaudit_addr(struct thread *td, struct setaudit_addr_args *uap) { struct ucred *newcred, *oldcred; struct auditinfo_addr aia; int error; if (jailed(td->td_ucred)) return (ENOSYS); error = copyin(uap->auditinfo_addr, &aia, sizeof(aia)); if (error) return (error); audit_arg_auditinfo_addr(&aia); if (aia.ai_termid.at_type != AU_IPv6 && aia.ai_termid.at_type != AU_IPv4) return (EINVAL); newcred = crget(); PROC_LOCK(td->td_proc); oldcred = td->td_proc->p_ucred; crcopy(newcred, oldcred); #ifdef MAC error = mac_proc_check_setaudit_addr(oldcred, &aia); if (error) goto fail; #endif error = priv_check_cred(oldcred, PRIV_AUDIT_SETAUDIT, 0); if (error) goto fail; newcred->cr_audit = aia; td->td_proc->p_ucred = newcred; PROC_UNLOCK(td->td_proc); crfree(oldcred); return (0); fail: PROC_UNLOCK(td->td_proc); crfree(newcred); return (error); } /* * Syscall to manage audit files. */ /* ARGSUSED */ int auditctl(struct thread *td, struct auditctl_args *uap) { struct nameidata nd; struct ucred *cred; struct vnode *vp; int error = 0; int flags, vfslocked; if (jailed(td->td_ucred)) return (ENOSYS); error = priv_check(td, PRIV_AUDIT_CONTROL); if (error) return (error); vp = NULL; cred = NULL; /* * If a path is specified, open the replacement vnode, perform * validity checks, and grab another reference to the current * credential. * * On Darwin, a NULL path argument is also used to disable audit. */ if (uap->path == NULL) return (EINVAL); NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1, UIO_USERSPACE, uap->path, td); flags = AUDIT_OPEN_FLAGS; error = vn_open(&nd, &flags, 0, NULL); if (error) return (error); vfslocked = NDHASGIANT(&nd); vp = nd.ni_vp; #ifdef MAC error = mac_system_check_auditctl(td->td_ucred, vp); VOP_UNLOCK(vp, 0); if (error) { vn_close(vp, AUDIT_CLOSE_FLAGS, td->td_ucred, td); VFS_UNLOCK_GIANT(vfslocked); return (error); } #else VOP_UNLOCK(vp, 0); #endif NDFREE(&nd, NDF_ONLY_PNBUF); if (vp->v_type != VREG) { vn_close(vp, AUDIT_CLOSE_FLAGS, td->td_ucred, td); VFS_UNLOCK_GIANT(vfslocked); return (EINVAL); } VFS_UNLOCK_GIANT(vfslocked); cred = td->td_ucred; crhold(cred); /* * XXXAUDIT: Should audit_suspended actually be cleared by * audit_worker? */ audit_suspended = 0; audit_rotate_vnode(cred, vp); return (error); } #else /* !AUDIT */ int audit(struct thread *td, struct audit_args *uap) { return (ENOSYS); } int auditon(struct thread *td, struct auditon_args *uap) { return (ENOSYS); } int getauid(struct thread *td, struct getauid_args *uap) { return (ENOSYS); } int setauid(struct thread *td, struct setauid_args *uap) { return (ENOSYS); } int getaudit(struct thread *td, struct getaudit_args *uap) { return (ENOSYS); } int setaudit(struct thread *td, struct setaudit_args *uap) { return (ENOSYS); } int getaudit_addr(struct thread *td, struct getaudit_addr_args *uap) { return (ENOSYS); } int setaudit_addr(struct thread *td, struct setaudit_addr_args *uap) { return (ENOSYS); } int auditctl(struct thread *td, struct auditctl_args *uap) { return (ENOSYS); } #endif /* AUDIT */ Index: head/sys/security/audit/audit_worker.c =================================================================== --- head/sys/security/audit/audit_worker.c (revision 181052) +++ head/sys/security/audit/audit_worker.c (revision 181053) @@ -1,487 +1,487 @@ -/* +/*- * Copyright (c) 1999-2005 Apple Inc. * Copyright (c) 2006-2008 Robert N. M. Watson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * Worker thread that will schedule disk I/O, etc. */ static struct proc *audit_thread; /* * audit_cred and audit_vp are the stored credential and vnode to use for * active audit trail. They are protected by audit_worker_sx, which will be * held across all I/O and all rotation to prevent them from being replaced * (rotated) while in use. The audit_file_rotate_wait flag is set when the * kernel has delivered a trigger to auditd to rotate the trail, and is * cleared when the next rotation takes place. It is also protected by * audit_worker_sx. */ static int audit_file_rotate_wait; static struct sx audit_worker_sx; static struct ucred *audit_cred; static struct vnode *audit_vp; /* * Write an audit record to a file, performed as the last stage after both * preselection and BSM conversion. Both space management and write failures * are handled in this function. * * No attempt is made to deal with possible failure to deliver a trigger to * the audit daemon, since the message is asynchronous anyway. */ static void audit_record_write(struct vnode *vp, struct ucred *cred, void *data, size_t len) { static struct timeval last_lowspace_trigger; static struct timeval last_fail; static int cur_lowspace_trigger; struct statfs *mnt_stat; int error, vfslocked; static int cur_fail; struct vattr vattr; long temp; sx_assert(&audit_worker_sx, SA_LOCKED); /* audit_file_rotate_wait. */ if (vp == NULL) return; mnt_stat = &vp->v_mount->mnt_stat; vfslocked = VFS_LOCK_GIANT(vp->v_mount); /* * First, gather statistics on the audit log file and file system so * that we know how we're doing on space. Consider failure of these * operations to indicate a future inability to write to the file. */ error = VFS_STATFS(vp->v_mount, mnt_stat, curthread); if (error) goto fail; vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); error = VOP_GETATTR(vp, &vattr, cred, curthread); VOP_UNLOCK(vp, 0); if (error) goto fail; audit_fstat.af_currsz = vattr.va_size; /* * We handle four different space-related limits: * * - A fixed (hard) limit on the minimum free blocks we require on * the file system, and results in record loss, a trigger, and * possible fail stop due to violating invariants. * * - An administrative (soft) limit, which when fallen below, results * in the kernel notifying the audit daemon of low space. * * - An audit trail size limit, which when gone above, results in the * kernel notifying the audit daemon that rotation is desired. * * - The total depth of the kernel audit record exceeding free space, * which can lead to possible fail stop (with drain), in order to * prevent violating invariants. Failure here doesn't halt * immediately, but prevents new records from being generated. * * Possibly, the last of these should be handled differently, always * allowing a full queue to be lost, rather than trying to prevent * loss. * * First, handle the hard limit, which generates a trigger and may * fail stop. This is handled in the same manner as ENOSPC from * VOP_WRITE, and results in record loss. */ if (mnt_stat->f_bfree < AUDIT_HARD_LIMIT_FREE_BLOCKS) { error = ENOSPC; goto fail_enospc; } /* * Second, handle falling below the soft limit, if defined; we send * the daemon a trigger and continue processing the record. Triggers * are limited to 1/sec. */ if (audit_qctrl.aq_minfree != 0) { temp = mnt_stat->f_blocks / (100 / audit_qctrl.aq_minfree); if (mnt_stat->f_bfree < temp) { if (ppsratecheck(&last_lowspace_trigger, &cur_lowspace_trigger, 1)) { (void)audit_send_trigger( AUDIT_TRIGGER_LOW_SPACE); printf("Warning: disk space low (< %d%% free) " "on audit log file-system\n", audit_qctrl.aq_minfree); } } } /* * If the current file is getting full, generate a rotation trigger * to the daemon. This is only approximate, which is fine as more * records may be generated before the daemon rotates the file. */ if ((audit_fstat.af_filesz != 0) && (audit_file_rotate_wait == 0) && (vattr.va_size >= audit_fstat.af_filesz)) { sx_assert(&audit_worker_sx, SA_XLOCKED); audit_file_rotate_wait = 1; (void)audit_send_trigger(AUDIT_TRIGGER_ROTATE_KERNEL); } /* * If the estimated amount of audit data in the audit event queue * (plus records allocated but not yet queued) has reached the amount * of free space on the disk, then we need to go into an audit fail * stop state, in which we do not permit the allocation/committing of * any new audit records. We continue to process records but don't * allow any activities that might generate new records. In the * future, we might want to detect when space is available again and * allow operation to continue, but this behavior is sufficient to * meet fail stop requirements in CAPP. */ if (audit_fail_stop) { if ((unsigned long)((audit_q_len + audit_pre_q_len + 1) * MAX_AUDIT_RECORD_SIZE) / mnt_stat->f_bsize >= (unsigned long)(mnt_stat->f_bfree)) { if (ppsratecheck(&last_fail, &cur_fail, 1)) printf("audit_record_write: free space " "below size of audit queue, failing " "stop\n"); audit_in_failure = 1; } else if (audit_in_failure) { /* * Note: if we want to handle recovery, this is the * spot to do it: unset audit_in_failure, and issue a * wakeup on the cv. */ } } error = vn_rdwr(UIO_WRITE, vp, data, len, (off_t)0, UIO_SYSSPACE, IO_APPEND|IO_UNIT, cred, NULL, NULL, curthread); if (error == ENOSPC) goto fail_enospc; else if (error) goto fail; /* * Catch completion of a queue drain here; if we're draining and the * queue is now empty, fail stop. That audit_fail_stop is implicitly * true, since audit_in_failure can only be set of audit_fail_stop is * set. * * Note: if we handle recovery from audit_in_failure, then we need to * make panic here conditional. */ if (audit_in_failure) { if (audit_q_len == 0 && audit_pre_q_len == 0) { VOP_LOCK(vp, LK_EXCLUSIVE | LK_RETRY); (void)VOP_FSYNC(vp, MNT_WAIT, curthread); VOP_UNLOCK(vp, 0); panic("Audit store overflow; record queue drained."); } } VFS_UNLOCK_GIANT(vfslocked); return; fail_enospc: /* * ENOSPC is considered a special case with respect to failures, as * this can reflect either our preemptive detection of insufficient * space, or ENOSPC returned by the vnode write call. */ if (audit_fail_stop) { VOP_LOCK(vp, LK_EXCLUSIVE | LK_RETRY); (void)VOP_FSYNC(vp, MNT_WAIT, curthread); VOP_UNLOCK(vp, 0); panic("Audit log space exhausted and fail-stop set."); } (void)audit_send_trigger(AUDIT_TRIGGER_NO_SPACE); audit_suspended = 1; /* FALLTHROUGH */ fail: /* * We have failed to write to the file, so the current record is * lost, which may require an immediate system halt. */ if (audit_panic_on_write_fail) { VOP_LOCK(vp, LK_EXCLUSIVE | LK_RETRY); (void)VOP_FSYNC(vp, MNT_WAIT, curthread); VOP_UNLOCK(vp, 0); panic("audit_worker: write error %d\n", error); } else if (ppsratecheck(&last_fail, &cur_fail, 1)) printf("audit_worker: write error %d\n", error); VFS_UNLOCK_GIANT(vfslocked); } /* * Given a kernel audit record, process as required. Kernel audit records * are converted to one, or possibly two, BSM records, depending on whether * there is a user audit record present also. Kernel records need be * converted to BSM before they can be written out. Both types will be * written to disk, and audit pipes. */ static void audit_worker_process_record(struct kaudit_record *ar) { struct au_record *bsm; au_class_t class; au_event_t event; au_id_t auid; int error, sorf; int trail_locked; /* * We hold the audit_worker_sx lock over both writes, if there are * two, so that the two records won't be split across a rotation and * end up in two different trail files. */ if (((ar->k_ar_commit & AR_COMMIT_USER) && (ar->k_ar_commit & AR_PRESELECT_USER_TRAIL)) || (ar->k_ar_commit & AR_PRESELECT_TRAIL)) { sx_xlock(&audit_worker_sx); trail_locked = 1; } else trail_locked = 0; /* * First, handle the user record, if any: commit to the system trail * and audit pipes as selected. */ if ((ar->k_ar_commit & AR_COMMIT_USER) && (ar->k_ar_commit & AR_PRESELECT_USER_TRAIL)) { sx_assert(&audit_worker_sx, SA_XLOCKED); audit_record_write(audit_vp, audit_cred, ar->k_udata, ar->k_ulen); } if ((ar->k_ar_commit & AR_COMMIT_USER) && (ar->k_ar_commit & AR_PRESELECT_USER_PIPE)) audit_pipe_submit_user(ar->k_udata, ar->k_ulen); if (!(ar->k_ar_commit & AR_COMMIT_KERNEL) || ((ar->k_ar_commit & AR_PRESELECT_PIPE) == 0 && (ar->k_ar_commit & AR_PRESELECT_TRAIL) == 0)) goto out; auid = ar->k_ar.ar_subj_auid; event = ar->k_ar.ar_event; class = au_event_class(event); if (ar->k_ar.ar_errno == 0) sorf = AU_PRS_SUCCESS; else sorf = AU_PRS_FAILURE; error = kaudit_to_bsm(ar, &bsm); switch (error) { case BSM_NOAUDIT: goto out; case BSM_FAILURE: printf("audit_worker_process_record: BSM_FAILURE\n"); goto out; case BSM_SUCCESS: break; default: panic("kaudit_to_bsm returned %d", error); } if (ar->k_ar_commit & AR_PRESELECT_TRAIL) { sx_assert(&audit_worker_sx, SA_XLOCKED); audit_record_write(audit_vp, audit_cred, bsm->data, bsm->len); } if (ar->k_ar_commit & AR_PRESELECT_PIPE) audit_pipe_submit(auid, event, class, sorf, ar->k_ar_commit & AR_PRESELECT_TRAIL, bsm->data, bsm->len); kau_free(bsm); out: if (trail_locked) sx_xunlock(&audit_worker_sx); } /* * The audit_worker thread is responsible for watching the event queue, * dequeueing records, converting them to BSM format, and committing them to * disk. In order to minimize lock thrashing, records are dequeued in sets * to a thread-local work queue. * * Note: this means that the effect bound on the size of the pending record * queue is 2x the length of the global queue. */ static void audit_worker(void *arg) { struct kaudit_queue ar_worklist; struct kaudit_record *ar; int lowater_signal; TAILQ_INIT(&ar_worklist); mtx_lock(&audit_mtx); while (1) { mtx_assert(&audit_mtx, MA_OWNED); /* * Wait for a record. */ while (TAILQ_EMPTY(&audit_q)) cv_wait(&audit_worker_cv, &audit_mtx); /* * If there are records in the global audit record queue, * transfer them to a thread-local queue and process them * one by one. If we cross the low watermark threshold, * signal any waiting processes that they may wake up and * continue generating records. */ lowater_signal = 0; while ((ar = TAILQ_FIRST(&audit_q))) { TAILQ_REMOVE(&audit_q, ar, k_q); audit_q_len--; if (audit_q_len == audit_qctrl.aq_lowater) lowater_signal++; TAILQ_INSERT_TAIL(&ar_worklist, ar, k_q); } if (lowater_signal) cv_broadcast(&audit_watermark_cv); mtx_unlock(&audit_mtx); while ((ar = TAILQ_FIRST(&ar_worklist))) { TAILQ_REMOVE(&ar_worklist, ar, k_q); audit_worker_process_record(ar); audit_free(ar); } mtx_lock(&audit_mtx); } } /* * audit_rotate_vnode() is called by a user or kernel thread to configure or * de-configure auditing on a vnode. The arguments are the replacement * credential (referenced) and vnode (referenced and opened) to substitute * for the current credential and vnode, if any. If either is set to NULL, * both should be NULL, and this is used to indicate that audit is being * disabled. Any previous cred/vnode will be closed and freed. We re-enable * generating rotation requests to auditd. */ void audit_rotate_vnode(struct ucred *cred, struct vnode *vp) { struct ucred *old_audit_cred; struct vnode *old_audit_vp; int vfslocked; KASSERT((cred != NULL && vp != NULL) || (cred == NULL && vp == NULL), ("audit_rotate_vnode: cred %p vp %p", cred, vp)); /* * Rotate the vnode/cred, and clear the rotate flag so that we will * send a rotate trigger if the new file fills. */ sx_xlock(&audit_worker_sx); old_audit_cred = audit_cred; old_audit_vp = audit_vp; audit_cred = cred; audit_vp = vp; audit_file_rotate_wait = 0; audit_enabled = (audit_vp != NULL); sx_xunlock(&audit_worker_sx); /* * If there was an old vnode/credential, close and free. */ if (old_audit_vp != NULL) { vfslocked = VFS_LOCK_GIANT(old_audit_vp->v_mount); vn_close(old_audit_vp, AUDIT_CLOSE_FLAGS, old_audit_cred, curthread); VFS_UNLOCK_GIANT(vfslocked); crfree(old_audit_cred); } } void audit_worker_init(void) { int error; sx_init(&audit_worker_sx, "audit_worker_sx"); error = kproc_create(audit_worker, NULL, &audit_thread, RFHIGHPID, 0, "audit"); if (error) panic("audit_worker_init: kproc_create returned %d", error); }