1 /* 2 * Copyright (c) 1999-2009 Apple Inc. 3 * Copyright (c) 2005, 2016-2017 Robert N. M. Watson 4 * All rights reserved. 5 * 6 * Portions of this software were developed by BAE Systems, the University of 7 * Cambridge Computer Laboratory, and Memorial University under DARPA/AFRL 8 * contract FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent 9 * Computing (TC) research program. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of Apple Inc. ("Apple") nor the names of 20 * its contributors may be used to endorse or promote products derived 21 * from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR 27 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 31 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 32 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 * POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 __FBSDID("$FreeBSD$"); 38 39 #include <sys/param.h> 40 #include <sys/capsicum.h> 41 #include <sys/fcntl.h> 42 #include <sys/filedesc.h> 43 #include <sys/libkern.h> 44 #include <sys/malloc.h> 45 #include <sys/mount.h> 46 #include <sys/proc.h> 47 #include <sys/rwlock.h> 48 #include <sys/sem.h> 49 #include <sys/sbuf.h> 50 #include <sys/sx.h> 51 #include <sys/syscall.h> 52 #include <sys/sysctl.h> 53 #include <sys/sysent.h> 54 #include <sys/vnode.h> 55 56 #include <bsm/audit.h> 57 #include <bsm/audit_kevents.h> 58 #include <security/audit/audit.h> 59 #include <security/audit/audit_private.h> 60 61 /* 62 * Hash table functions for the audit event number to event class mask 63 * mapping. 64 */ 65 #define EVCLASSMAP_HASH_TABLE_SIZE 251 66 struct evclass_elem { 67 au_event_t event; 68 au_class_t class; 69 LIST_ENTRY(evclass_elem) entry; 70 }; 71 struct evclass_list { 72 LIST_HEAD(, evclass_elem) head; 73 }; 74 75 static MALLOC_DEFINE(M_AUDITEVCLASS, "audit_evclass", "Audit event class"); 76 static struct rwlock evclass_lock; 77 static struct evclass_list evclass_hash[EVCLASSMAP_HASH_TABLE_SIZE]; 78 79 #define EVCLASS_LOCK_INIT() rw_init(&evclass_lock, "evclass_lock") 80 #define EVCLASS_RLOCK() rw_rlock(&evclass_lock) 81 #define EVCLASS_RUNLOCK() rw_runlock(&evclass_lock) 82 #define EVCLASS_WLOCK() rw_wlock(&evclass_lock) 83 #define EVCLASS_WUNLOCK() rw_wunlock(&evclass_lock) 84 85 /* 86 * Hash table maintaining a mapping from audit event numbers to audit event 87 * names. For now, used only by DTrace, but present always so that userspace 88 * tools can register and inspect fields consistently even if DTrace is not 89 * present. 90 * 91 * struct evname_elem is defined in audit_private.h so that audit_dtrace.c can 92 * use the definition. 93 */ 94 #define EVNAMEMAP_HASH_TABLE_SIZE 251 95 struct evname_list { 96 LIST_HEAD(, evname_elem) enl_head; 97 }; 98 99 static MALLOC_DEFINE(M_AUDITEVNAME, "audit_evname", "Audit event name"); 100 static struct sx evnamemap_lock; 101 static struct evname_list evnamemap_hash[EVNAMEMAP_HASH_TABLE_SIZE]; 102 103 #define EVNAMEMAP_LOCK_INIT() sx_init(&evnamemap_lock, "evnamemap_lock"); 104 #define EVNAMEMAP_RLOCK() sx_slock(&evnamemap_lock) 105 #define EVNAMEMAP_RUNLOCK() sx_sunlock(&evnamemap_lock) 106 #define EVNAMEMAP_WLOCK() sx_xlock(&evnamemap_lock) 107 #define EVNAMEMAP_WUNLOCK() sx_xunlock(&evnamemap_lock) 108 109 /* 110 * Look up the class for an audit event in the class mapping table. 111 */ 112 au_class_t 113 au_event_class(au_event_t event) 114 { 115 struct evclass_list *evcl; 116 struct evclass_elem *evc; 117 au_class_t class; 118 119 EVCLASS_RLOCK(); 120 evcl = &evclass_hash[event % EVCLASSMAP_HASH_TABLE_SIZE]; 121 class = 0; 122 LIST_FOREACH(evc, &evcl->head, entry) { 123 if (evc->event == event) { 124 class = evc->class; 125 goto out; 126 } 127 } 128 out: 129 EVCLASS_RUNLOCK(); 130 return (class); 131 } 132 133 /* 134 * Insert a event to class mapping. If the event already exists in the 135 * mapping, then replace the mapping with the new one. 136 * 137 * XXX There is currently no constraints placed on the number of mappings. 138 * May want to either limit to a number, or in terms of memory usage. 139 */ 140 void 141 au_evclassmap_insert(au_event_t event, au_class_t class) 142 { 143 struct evclass_list *evcl; 144 struct evclass_elem *evc, *evc_new; 145 146 /* 147 * Pessimistically, always allocate storage before acquiring mutex. 148 * Free if there is already a mapping for this event. 149 */ 150 evc_new = malloc(sizeof(*evc), M_AUDITEVCLASS, M_WAITOK); 151 152 EVCLASS_WLOCK(); 153 evcl = &evclass_hash[event % EVCLASSMAP_HASH_TABLE_SIZE]; 154 LIST_FOREACH(evc, &evcl->head, entry) { 155 if (evc->event == event) { 156 evc->class = class; 157 EVCLASS_WUNLOCK(); 158 free(evc_new, M_AUDITEVCLASS); 159 return; 160 } 161 } 162 evc = evc_new; 163 evc->event = event; 164 evc->class = class; 165 LIST_INSERT_HEAD(&evcl->head, evc, entry); 166 EVCLASS_WUNLOCK(); 167 } 168 169 void 170 au_evclassmap_init(void) 171 { 172 int i; 173 174 EVCLASS_LOCK_INIT(); 175 for (i = 0; i < EVCLASSMAP_HASH_TABLE_SIZE; i++) 176 LIST_INIT(&evclass_hash[i].head); 177 178 /* 179 * Set up the initial event to class mapping for system calls. 180 * 181 * XXXRW: Really, this should walk all possible audit events, not all 182 * native ABI system calls, as there may be audit events reachable 183 * only through non-native system calls. It also seems a shame to 184 * frob the mutex this early. 185 */ 186 for (i = 0; i < SYS_MAXSYSCALL; i++) { 187 if (sysent[i].sy_auevent != AUE_NULL) 188 au_evclassmap_insert(sysent[i].sy_auevent, 0); 189 } 190 } 191 192 /* 193 * Look up the name for an audit event in the event-to-name mapping table. 194 */ 195 int 196 au_event_name(au_event_t event, char *name) 197 { 198 struct evname_list *enl; 199 struct evname_elem *ene; 200 int error; 201 202 error = ENOENT; 203 EVNAMEMAP_RLOCK(); 204 enl = &evnamemap_hash[event % EVNAMEMAP_HASH_TABLE_SIZE]; 205 LIST_FOREACH(ene, &enl->enl_head, ene_entry) { 206 if (ene->ene_event == event) { 207 strlcpy(name, ene->ene_name, EVNAMEMAP_NAME_SIZE); 208 error = 0; 209 goto out; 210 } 211 } 212 out: 213 EVNAMEMAP_RUNLOCK(); 214 return (error); 215 } 216 217 /* 218 * Insert a event-to-name mapping. If the event already exists in the 219 * mapping, then replace the mapping with the new one. 220 * 221 * XXX There is currently no constraints placed on the number of mappings. 222 * May want to either limit to a number, or in terms of memory usage. 223 * 224 * XXXRW: Accepts truncated name -- but perhaps should return failure instead? 225 * 226 * XXXRW: It could be we need a way to remove existing names...? 227 * 228 * XXXRW: We handle collisions between numbers, but I wonder if we also need a 229 * way to handle name collisions, for DTrace, where probe names must be 230 * unique? 231 */ 232 void 233 au_evnamemap_insert(au_event_t event, const char *name) 234 { 235 struct evname_list *enl; 236 struct evname_elem *ene, *ene_new; 237 238 /* 239 * Pessimistically, always allocate storage before acquiring lock. 240 * Free if there is already a mapping for this event. 241 */ 242 ene_new = malloc(sizeof(*ene_new), M_AUDITEVNAME, M_WAITOK | M_ZERO); 243 EVNAMEMAP_WLOCK(); 244 enl = &evnamemap_hash[event % EVNAMEMAP_HASH_TABLE_SIZE]; 245 LIST_FOREACH(ene, &enl->enl_head, ene_entry) { 246 if (ene->ene_event == event) { 247 EVNAME_LOCK(ene); 248 (void)strlcpy(ene->ene_name, name, 249 sizeof(ene->ene_name)); 250 EVNAME_UNLOCK(ene); 251 EVNAMEMAP_WUNLOCK(); 252 free(ene_new, M_AUDITEVNAME); 253 return; 254 } 255 } 256 ene = ene_new; 257 mtx_init(&ene->ene_lock, "au_evnamemap", NULL, MTX_DEF); 258 ene->ene_event = event; 259 (void)strlcpy(ene->ene_name, name, sizeof(ene->ene_name)); 260 LIST_INSERT_HEAD(&enl->enl_head, ene, ene_entry); 261 EVNAMEMAP_WUNLOCK(); 262 } 263 264 void 265 au_evnamemap_init(void) 266 { 267 int i; 268 269 EVNAMEMAP_LOCK_INIT(); 270 for (i = 0; i < EVNAMEMAP_HASH_TABLE_SIZE; i++) 271 LIST_INIT(&evnamemap_hash[i].enl_head); 272 273 /* 274 * XXXRW: Unlike the event-to-class mapping, we don't attempt to 275 * pre-populate the list. Perhaps we should...? But not sure we 276 * really want to duplicate /etc/security/audit_event in the kernel 277 * -- and we'd need a way to remove names? 278 */ 279 } 280 281 /* 282 * The DTrace audit provider occasionally needs to walk the entries in the 283 * event-to-name mapping table, and uses this public interface to do so. A 284 * write lock is acquired so that the provider can safely update its fields in 285 * table entries. 286 */ 287 void 288 au_evnamemap_foreach(au_evnamemap_callback_t callback) 289 { 290 struct evname_list *enl; 291 struct evname_elem *ene; 292 int i; 293 294 EVNAMEMAP_WLOCK(); 295 for (i = 0; i < EVNAMEMAP_HASH_TABLE_SIZE; i++) { 296 enl = &evnamemap_hash[i]; 297 LIST_FOREACH(ene, &enl->enl_head, ene_entry) 298 callback(ene); 299 } 300 EVNAMEMAP_WUNLOCK(); 301 } 302 303 #ifdef KDTRACE_HOOKS 304 /* 305 * Look up an event-to-name mapping table entry by event number. As evname 306 * elements are stable in memory, we can return the pointer without the table 307 * lock held -- but the caller will need to lock the element mutex before 308 * accessing element fields. 309 * 310 * NB: the event identifier in elements is stable and can be read without 311 * holding the evname_elem lock. 312 */ 313 struct evname_elem * 314 au_evnamemap_lookup(au_event_t event) 315 { 316 struct evname_list *enl; 317 struct evname_elem *ene; 318 319 EVNAMEMAP_RLOCK(); 320 enl = &evnamemap_hash[event % EVNAMEMAP_HASH_TABLE_SIZE]; 321 LIST_FOREACH(ene, &enl->enl_head, ene_entry) { 322 if (ene->ene_event == event) 323 goto out; 324 } 325 ene = NULL; 326 out: 327 EVNAMEMAP_RUNLOCK(); 328 return (ene); 329 } 330 #endif /* !KDTRACE_HOOKS */ 331