audit_bsm_db.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. /*
  2. * Copyright (c) 1999-2009 Apple Inc.
  3. * Copyright (c) 2005, 2016-2018 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. #include <sys/param.h>
  36. #include <sys/capsicum.h>
  37. #include <sys/fcntl.h>
  38. #include <sys/filedesc.h>
  39. #include <sys/libkern.h>
  40. #include <sys/linker.h>
  41. #include <sys/malloc.h>
  42. #include <sys/mount.h>
  43. #include <sys/proc.h>
  44. #include <sys/rwlock.h>
  45. #include <sys/sem.h>
  46. #include <sys/sbuf.h>
  47. #include <sys/sx.h>
  48. #include <sys/syscall.h>
  49. #include <sys/sysctl.h>
  50. #include <sys/sysent.h>
  51. #include <sys/vnode.h>
  52. #include <bsm/audit.h>
  53. #include <bsm/audit_kevents.h>
  54. #include <security/audit/audit.h>
  55. #include <security/audit/audit_private.h>
  56. /*
  57. * Hash table functions for the audit event number to event class mask
  58. * mapping.
  59. */
  60. #define EVCLASSMAP_HASH_TABLE_SIZE 251
  61. struct evclass_elem {
  62. au_event_t event;
  63. au_class_t class;
  64. LIST_ENTRY(evclass_elem) entry;
  65. };
  66. struct evclass_list {
  67. LIST_HEAD(, evclass_elem) head;
  68. };
  69. static MALLOC_DEFINE(M_AUDITEVCLASS, "audit_evclass", "Audit event class");
  70. static struct rwlock evclass_lock;
  71. static struct evclass_list evclass_hash[EVCLASSMAP_HASH_TABLE_SIZE];
  72. #define EVCLASS_LOCK_INIT() rw_init(&evclass_lock, "evclass_lock")
  73. #define EVCLASS_RLOCK() rw_rlock(&evclass_lock)
  74. #define EVCLASS_RUNLOCK() rw_runlock(&evclass_lock)
  75. #define EVCLASS_WLOCK() rw_wlock(&evclass_lock)
  76. #define EVCLASS_WUNLOCK() rw_wunlock(&evclass_lock)
  77. /*
  78. * Hash table maintaining a mapping from audit event numbers to audit event
  79. * names. For now, used only by DTrace, but present always so that userspace
  80. * tools can register and inspect fields consistently even if DTrace is not
  81. * present.
  82. *
  83. * struct evname_elem is defined in audit_private.h so that audit_dtrace.c can
  84. * use the definition.
  85. */
  86. #define EVNAMEMAP_HASH_TABLE_MODULE "etc_security_audit_event"
  87. #define EVNAMEMAP_HASH_TABLE_SIZE 251
  88. struct evname_list {
  89. LIST_HEAD(, evname_elem) enl_head;
  90. };
  91. static MALLOC_DEFINE(M_AUDITEVNAME, "audit_evname", "Audit event name");
  92. static struct sx evnamemap_lock;
  93. static struct evname_list evnamemap_hash[EVNAMEMAP_HASH_TABLE_SIZE];
  94. #define EVNAMEMAP_LOCK_INIT() sx_init(&evnamemap_lock, "evnamemap_lock");
  95. #define EVNAMEMAP_RLOCK() sx_slock(&evnamemap_lock)
  96. #define EVNAMEMAP_RUNLOCK() sx_sunlock(&evnamemap_lock)
  97. #define EVNAMEMAP_WLOCK() sx_xlock(&evnamemap_lock)
  98. #define EVNAMEMAP_WUNLOCK() sx_xunlock(&evnamemap_lock)
  99. /*
  100. * Look up the class for an audit event in the class mapping table.
  101. */
  102. au_class_t
  103. au_event_class(au_event_t event)
  104. {
  105. struct evclass_list *evcl;
  106. struct evclass_elem *evc;
  107. au_class_t class;
  108. EVCLASS_RLOCK();
  109. evcl = &evclass_hash[event % EVCLASSMAP_HASH_TABLE_SIZE];
  110. class = 0;
  111. LIST_FOREACH(evc, &evcl->head, entry) {
  112. if (evc->event == event) {
  113. class = evc->class;
  114. goto out;
  115. }
  116. }
  117. out:
  118. EVCLASS_RUNLOCK();
  119. return (class);
  120. }
  121. /*
  122. * Insert a event to class mapping. If the event already exists in the
  123. * mapping, then replace the mapping with the new one.
  124. *
  125. * XXX There is currently no constraints placed on the number of mappings.
  126. * May want to either limit to a number, or in terms of memory usage.
  127. */
  128. void
  129. au_evclassmap_insert(au_event_t event, au_class_t class)
  130. {
  131. struct evclass_list *evcl;
  132. struct evclass_elem *evc, *evc_new;
  133. /*
  134. * Pessimistically, always allocate storage before acquiring mutex.
  135. * Free if there is already a mapping for this event.
  136. */
  137. evc_new = malloc(sizeof(*evc), M_AUDITEVCLASS, M_WAITOK);
  138. EVCLASS_WLOCK();
  139. evcl = &evclass_hash[event % EVCLASSMAP_HASH_TABLE_SIZE];
  140. LIST_FOREACH(evc, &evcl->head, entry) {
  141. if (evc->event == event) {
  142. evc->class = class;
  143. EVCLASS_WUNLOCK();
  144. free(evc_new, M_AUDITEVCLASS);
  145. return;
  146. }
  147. }
  148. evc = evc_new;
  149. evc->event = event;
  150. evc->class = class;
  151. LIST_INSERT_HEAD(&evcl->head, evc, entry);
  152. EVCLASS_WUNLOCK();
  153. }
  154. void
  155. au_evclassmap_init(void)
  156. {
  157. int i;
  158. EVCLASS_LOCK_INIT();
  159. for (i = 0; i < EVCLASSMAP_HASH_TABLE_SIZE; i++)
  160. LIST_INIT(&evclass_hash[i].head);
  161. /*
  162. * Set up the initial event to class mapping for system calls.
  163. *
  164. * XXXRW: Really, this should walk all possible audit events, not all
  165. * native ABI system calls, as there may be audit events reachable
  166. * only through non-native system calls. It also seems a shame to
  167. * frob the mutex this early.
  168. */
  169. for (i = 0; i < SYS_MAXSYSCALL; i++) {
  170. if (sysent[i].sy_auevent != AUE_NULL)
  171. au_evclassmap_insert(sysent[i].sy_auevent, 0);
  172. }
  173. }
  174. /*
  175. * Look up the name for an audit event in the event-to-name mapping table.
  176. */
  177. int
  178. au_event_name(au_event_t event, char *name)
  179. {
  180. struct evname_list *enl;
  181. struct evname_elem *ene;
  182. int error;
  183. error = ENOENT;
  184. EVNAMEMAP_RLOCK();
  185. enl = &evnamemap_hash[event % EVNAMEMAP_HASH_TABLE_SIZE];
  186. LIST_FOREACH(ene, &enl->enl_head, ene_entry) {
  187. if (ene->ene_event == event) {
  188. strlcpy(name, ene->ene_name, EVNAMEMAP_NAME_SIZE);
  189. error = 0;
  190. goto out;
  191. }
  192. }
  193. out:
  194. EVNAMEMAP_RUNLOCK();
  195. return (error);
  196. }
  197. /*
  198. * Insert a event-to-name mapping. If the event already exists in the
  199. * mapping, then replace the mapping with the new one.
  200. *
  201. * XXX There is currently no constraints placed on the number of mappings.
  202. * May want to either limit to a number, or in terms of memory usage.
  203. *
  204. * XXXRW: Accepts truncated name -- but perhaps should return failure instead?
  205. *
  206. * XXXRW: It could be we need a way to remove existing names...?
  207. *
  208. * XXXRW: We handle collisions between numbers, but I wonder if we also need a
  209. * way to handle name collisions, for DTrace, where probe names must be
  210. * unique?
  211. */
  212. void
  213. au_evnamemap_insert(au_event_t event, const char *name)
  214. {
  215. struct evname_list *enl;
  216. struct evname_elem *ene, *ene_new;
  217. /*
  218. * Pessimistically, always allocate storage before acquiring lock.
  219. * Free if there is already a mapping for this event.
  220. */
  221. ene_new = malloc(sizeof(*ene_new), M_AUDITEVNAME, M_WAITOK | M_ZERO);
  222. EVNAMEMAP_WLOCK();
  223. enl = &evnamemap_hash[event % EVNAMEMAP_HASH_TABLE_SIZE];
  224. LIST_FOREACH(ene, &enl->enl_head, ene_entry) {
  225. if (ene->ene_event == event) {
  226. EVNAME_LOCK(ene);
  227. (void)strlcpy(ene->ene_name, name,
  228. sizeof(ene->ene_name));
  229. EVNAME_UNLOCK(ene);
  230. EVNAMEMAP_WUNLOCK();
  231. free(ene_new, M_AUDITEVNAME);
  232. return;
  233. }
  234. }
  235. ene = ene_new;
  236. mtx_init(&ene->ene_lock, "au_evnamemap", NULL, MTX_DEF);
  237. ene->ene_event = event;
  238. (void)strlcpy(ene->ene_name, name, sizeof(ene->ene_name));
  239. LIST_INSERT_HEAD(&enl->enl_head, ene, ene_entry);
  240. EVNAMEMAP_WUNLOCK();
  241. }
  242. /*
  243. * If /etc/security/audit_event has been preloaded by the boot loader, parse
  244. * it to build an initial set of event number<->name mappings.
  245. */
  246. static void
  247. au_evnamemap_init_preload(void)
  248. {
  249. caddr_t kmdp;
  250. char *endptr, *line, *nextline, *ptr;
  251. const char *evnum_str, *evname;
  252. size_t size;
  253. long evnum;
  254. u_int lineno;
  255. kmdp = preload_search_by_type(EVNAMEMAP_HASH_TABLE_MODULE);
  256. if (kmdp == NULL)
  257. return;
  258. ptr = preload_fetch_addr(kmdp);
  259. size = preload_fetch_size(kmdp);
  260. /*
  261. * Parse preloaded configuration file "in place". Assume that the
  262. * last character is a new line, meaning that we can replace it with a
  263. * nul byte safely. We can then use strsep(3) to process the full
  264. * buffer.
  265. */
  266. ptr[size - 1] = '\0';
  267. /*
  268. * Process line by line.
  269. */
  270. nextline = ptr;
  271. lineno = 0;
  272. while ((line = strsep(&nextline, "\n")) != NULL) {
  273. /*
  274. * Skip any leading white space.
  275. */
  276. while (line[0] == ' ' || line[0] == '\t')
  277. line++;
  278. /*
  279. * Skip blank lines and comment lines.
  280. */
  281. if (line[0] == '\0' || line[0] == '#') {
  282. lineno++;
  283. continue;
  284. }
  285. /*
  286. * Parse each line -- ":"-separated tuple of event number,
  287. * event name, and other material we are less interested in.
  288. */
  289. evnum_str = strsep(&line, ":");
  290. if (evnum_str == NULL || *evnum_str == '\0') {
  291. printf("%s: Invalid line %u - evnum strsep\n",
  292. __func__, lineno);
  293. lineno++;
  294. continue;
  295. }
  296. evnum = strtol(evnum_str, &endptr, 10);
  297. if (*evnum_str == '\0' || *endptr != '\0' ||
  298. evnum <= 0 || evnum > UINT16_MAX) {
  299. printf("%s: Invalid line %u - evnum strtol\n",
  300. __func__, lineno);
  301. lineno++;
  302. continue;
  303. }
  304. evname = strsep(&line, ":");
  305. if (evname == NULL || *evname == '\0') {
  306. printf("%s: Invalid line %u - evname strsp\n",
  307. __func__, lineno);
  308. lineno++;
  309. continue;
  310. }
  311. au_evnamemap_insert(evnum, evname);
  312. lineno++;
  313. }
  314. }
  315. void
  316. au_evnamemap_init(void)
  317. {
  318. int i;
  319. EVNAMEMAP_LOCK_INIT();
  320. for (i = 0; i < EVNAMEMAP_HASH_TABLE_SIZE; i++)
  321. LIST_INIT(&evnamemap_hash[i].enl_head);
  322. au_evnamemap_init_preload();
  323. }
  324. /*
  325. * The DTrace audit provider occasionally needs to walk the entries in the
  326. * event-to-name mapping table, and uses this public interface to do so. A
  327. * write lock is acquired so that the provider can safely update its fields in
  328. * table entries.
  329. */
  330. void
  331. au_evnamemap_foreach(au_evnamemap_callback_t callback)
  332. {
  333. struct evname_list *enl;
  334. struct evname_elem *ene;
  335. int i;
  336. EVNAMEMAP_WLOCK();
  337. for (i = 0; i < EVNAMEMAP_HASH_TABLE_SIZE; i++) {
  338. enl = &evnamemap_hash[i];
  339. LIST_FOREACH(ene, &enl->enl_head, ene_entry)
  340. callback(ene);
  341. }
  342. EVNAMEMAP_WUNLOCK();
  343. }
  344. #ifdef KDTRACE_HOOKS
  345. /*
  346. * Look up an event-to-name mapping table entry by event number. As evname
  347. * elements are stable in memory, we can return the pointer without the table
  348. * lock held -- but the caller will need to lock the element mutex before
  349. * accessing element fields.
  350. *
  351. * NB: the event identifier in elements is stable and can be read without
  352. * holding the evname_elem lock.
  353. */
  354. struct evname_elem *
  355. au_evnamemap_lookup(au_event_t event)
  356. {
  357. struct evname_list *enl;
  358. struct evname_elem *ene;
  359. EVNAMEMAP_RLOCK();
  360. enl = &evnamemap_hash[event % EVNAMEMAP_HASH_TABLE_SIZE];
  361. LIST_FOREACH(ene, &enl->enl_head, ene_entry) {
  362. if (ene->ene_event == event)
  363. goto out;
  364. }
  365. ene = NULL;
  366. out:
  367. EVNAMEMAP_RUNLOCK();
  368. return (ene);
  369. }
  370. #endif /* !KDTRACE_HOOKS */