xref: /xnu-10002.1.13/bsd/security/audit/audit_bsm_klib.c (revision 1031c584a5e37aff177559b9f69dbd3c8c3fd30a)
1 /*-
2  * Copyright (c) 1999-2009 Apple Inc.
3  * Copyright (c) 2005 Robert N. M. Watson
4  * All rights reserved.
5  *
6  * @APPLE_BSD_LICENSE_HEADER_START@
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1.  Redistributions of source code must retain the above copyright
12  *     notice, this list of conditions and the following disclaimer.
13  * 2.  Redistributions in binary form must reproduce the above copyright
14  *     notice, this list of conditions and the following disclaimer in the
15  *     documentation and/or other materials provided with the distribution.
16  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
17  *     its contributors may be used to endorse or promote products derived
18  *     from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
24  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  *
32  * @APPLE_BSD_LICENSE_HEADER_END@
33  */
34 /*
35  * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
36  * support for mandatory and extensible security protections.  This notice
37  * is included in support of clause 2.2 (b) of the Apple Public License,
38  * Version 2.0.
39  */
40 
41 #include <sys/systm.h>
42 #include <sys/sysent.h>
43 #include <sys/types.h>
44 #include <sys/proc_internal.h>
45 #include <sys/vnode_internal.h>
46 #include <sys/fcntl.h>
47 #include <sys/filedesc.h>
48 #include <sys/sem.h>
49 #include <sys/syscall.h>
50 
51 #include <bsm/audit.h>
52 #include <bsm/audit_kevents.h>
53 #include <security/audit/audit.h>
54 #include <security/audit/audit_bsd.h>
55 #include <security/audit/audit_private.h>
56 #include <IOKit/IOBSD.h>
57 
58 #if CONFIG_AUDIT
59 /*
60  * Hash table functions for the audit event number to event class mask
61  * mapping.
62  */
63 #define EVCLASSMAP_HASH_TABLE_SIZE      251
64 struct evclass_elem {
65 	au_event_t event;
66 	au_class_t class;
67 	LIST_ENTRY(evclass_elem) entry;
68 };
69 struct evclass_list {
70 	LIST_HEAD(, evclass_elem) head;
71 };
72 
73 static MALLOC_DEFINE(M_AUDITEVCLASS, "audit_evclass", "Audit event class");
74 static struct rwlock            evclass_lock;
75 static struct evclass_list      evclass_hash[EVCLASSMAP_HASH_TABLE_SIZE];
76 
77 #define EVCLASS_LOCK_INIT()     rw_init(&evclass_lock, "evclass_lock")
78 #define EVCLASS_RLOCK()         rw_rlock(&evclass_lock)
79 #define EVCLASS_RUNLOCK()       rw_runlock(&evclass_lock)
80 #define EVCLASS_WLOCK()         rw_wlock(&evclass_lock)
81 #define EVCLASS_WUNLOCK()       rw_wunlock(&evclass_lock)
82 
83 /*
84  * Look up the class for an audit event in the class mapping table.
85  */
86 au_class_t
au_event_class(au_event_t event)87 au_event_class(au_event_t event)
88 {
89 	struct evclass_list *evcl;
90 	struct evclass_elem *evc;
91 	au_class_t class;
92 
93 	EVCLASS_RLOCK();
94 	evcl = &evclass_hash[event % EVCLASSMAP_HASH_TABLE_SIZE];
95 	class = 0;
96 	LIST_FOREACH(evc, &evcl->head, entry) {
97 		if (evc->event == event) {
98 			class = evc->class;
99 			goto out;
100 		}
101 	}
102 out:
103 	EVCLASS_RUNLOCK();
104 	return class;
105 }
106 
107 /*
108  * Return a new class mask that allows changing the reserved class bit
109  * only if the current task is entitled to do so or if this is being done
110  * from the kernel task. If the current task is not allowed to make the
111  * change, the reserved bit is reverted to its previous state and the rest
112  * of the mask is left intact.
113  */
114 static au_class_t
au_class_protect(au_class_t old_class,au_class_t new_class)115 au_class_protect(au_class_t old_class, au_class_t new_class)
116 {
117 	au_class_t result = new_class;
118 
119 	/* Check if the reserved class bit has been flipped */
120 	if ((old_class & AU_CLASS_MASK_RESERVED) !=
121 	    (new_class & AU_CLASS_MASK_RESERVED)) {
122 		task_t task = current_task();
123 		if (task != kernel_task &&
124 		    !IOCurrentTaskHasEntitlement(AU_CLASS_RESERVED_ENTITLEMENT)) {
125 			/*
126 			 * If the caller isn't entitled, revert the class bit:
127 			 * - First remove the reserved bit from the new_class mask
128 			 * - Next get the state of the old_class mask's reserved bit
129 			 * - Finally, OR the result from the first two operations
130 			 */
131 			result = (new_class & ~AU_CLASS_MASK_RESERVED) |
132 			    (old_class & AU_CLASS_MASK_RESERVED);
133 		}
134 	}
135 
136 	return result;
137 }
138 
139 /*
140  * Insert a event to class mapping. If the event already exists in the
141  * mapping, then replace the mapping with the new one.
142  *
143  * IMPORTANT: This function should only be called from the kernel during
144  * initialization (e.g. during au_evclassmap_init). Calling afterwards can
145  * have adverse effects on other system components that rely on event/class
146  * map state.
147  *
148  * XXX There is currently no constraints placed on the number of mappings.
149  * May want to either limit to a number, or in terms of memory usage.
150  */
151 void
au_evclassmap_insert(au_event_t event,au_class_t class)152 au_evclassmap_insert(au_event_t event, au_class_t class)
153 {
154 	struct evclass_list *evcl;
155 	struct evclass_elem *evc, *evc_new;
156 
157 	/*
158 	 * If this event requires auditing a system call then add it to  our
159 	 * audit kernel event mask.  We use audit_kevent_mask to check to see
160 	 * if the audit syscalls flag needs to be set when preselection masks
161 	 * are set.
162 	 */
163 	if (AUE_IS_A_KEVENT(event)) {
164 		audit_kevent_mask |= class;
165 	}
166 
167 	/*
168 	 * Pessimistically, always allocate storage before acquiring mutex.
169 	 * Free if there is already a mapping for this event.
170 	 */
171 	evc_new = kalloc_type(struct evclass_elem, Z_WAITOK | Z_ZERO | Z_NOFAIL);
172 
173 	EVCLASS_WLOCK();
174 	evcl = &evclass_hash[event % EVCLASSMAP_HASH_TABLE_SIZE];
175 	LIST_FOREACH(evc, &evcl->head, entry) {
176 		if (evc->event == event) {
177 			evc->class = au_class_protect(evc->class, class);
178 			EVCLASS_WUNLOCK();
179 			kfree_type(struct evclass_elem, evc_new);
180 			return;
181 		}
182 	}
183 	evc = evc_new;
184 	evc->event = event;
185 	/*
186 	 * Mappings that require a new element must use 0 as the "old_class" since
187 	 * there is no previous state.
188 	 */
189 	evc->class = au_class_protect(0, class);
190 	LIST_INSERT_HEAD(&evcl->head, evc, entry);
191 	EVCLASS_WUNLOCK();
192 }
193 
194 void
au_evclassmap_init(void)195 au_evclassmap_init(void)
196 {
197 	unsigned int i;
198 
199 	EVCLASS_LOCK_INIT();
200 	for (i = 0; i < EVCLASSMAP_HASH_TABLE_SIZE; i++) {
201 		LIST_INIT(&evclass_hash[i].head);
202 	}
203 
204 	/*
205 	 * Set up the initial event to class mapping for system calls.
206 	 */
207 	for (i = 0; i < nsysent; i++) {
208 		if (sys_au_event[i] != AUE_NULL) {
209 			au_evclassmap_insert(sys_au_event[i], 0);
210 		}
211 	}
212 
213 	/*
214 	 *  Add the Mach system call events. These are not in sys_au_event[].
215 	 */
216 	au_evclassmap_insert(AUE_TASKFORPID, 0);
217 	au_evclassmap_insert(AUE_PIDFORTASK, 0);
218 	au_evclassmap_insert(AUE_SWAPON, 0);
219 	au_evclassmap_insert(AUE_SWAPOFF, 0);
220 	au_evclassmap_insert(AUE_MAPFD, 0);
221 	au_evclassmap_insert(AUE_INITPROCESS, 0);
222 }
223 
224 /*
225  * Check whether an event is aditable by comparing the mask of classes this
226  * event is part of against the given mask.
227  */
228 int
au_preselect(__unused au_event_t event,au_class_t class,au_mask_t * mask_p,int sorf)229 au_preselect(__unused au_event_t event, au_class_t class, au_mask_t *mask_p,
230     int sorf)
231 {
232 	au_class_t effmask = 0;
233 
234 	if (mask_p == NULL) {
235 		return -1;
236 	}
237 
238 	/*
239 	 * Perform the actual check of the masks against the event.
240 	 */
241 	if (sorf & AU_PRS_SUCCESS) {
242 		effmask |= (mask_p->am_success & class);
243 	}
244 
245 	if (sorf & AU_PRS_FAILURE) {
246 		effmask |= (mask_p->am_failure & class);
247 	}
248 
249 	if (effmask) {
250 		return 1;
251 	} else {
252 		return 0;
253 	}
254 }
255 
256 /*
257  * Convert sysctl names and present arguments to events.
258  */
259 au_event_t
audit_ctlname_to_sysctlevent(int name[],uint64_t valid_arg)260 audit_ctlname_to_sysctlevent(int name[], uint64_t valid_arg)
261 {
262 	/* can't parse it - so return the worst case */
263 	if ((valid_arg & (ARG_CTLNAME | ARG_LEN)) != (ARG_CTLNAME | ARG_LEN)) {
264 		return AUE_SYSCTL;
265 	}
266 
267 	switch (name[0]) {
268 	/* non-admin "lookups" treat them special */
269 	case KERN_OSTYPE:
270 	case KERN_OSRELEASE:
271 	case KERN_OSREV:
272 	case KERN_VERSION:
273 	case KERN_ARGMAX:
274 	case KERN_CLOCKRATE:
275 	case KERN_BOOTTIME:
276 	case KERN_POSIX1:
277 	case KERN_NGROUPS:
278 	case KERN_JOB_CONTROL:
279 	case KERN_SAVED_IDS:
280 	case KERN_OSRELDATE:
281 	case KERN_NETBOOT:
282 	case KERN_SYMFILE:
283 	case KERN_SHREG_PRIVATIZABLE:
284 	case KERN_OSVERSION:
285 		return AUE_SYSCTL_NONADMIN;
286 
287 	/* only treat the changeable controls as admin */
288 	case KERN_MAXVNODES:
289 	case KERN_MAXPROC:
290 	case KERN_MAXFILES:
291 	case KERN_MAXPROCPERUID:
292 	case KERN_MAXFILESPERPROC:
293 	case KERN_HOSTID:
294 	case KERN_AIOMAX:
295 	case KERN_AIOPROCMAX:
296 	case KERN_AIOTHREADS:
297 	case KERN_COREDUMP:
298 	case KERN_SUGID_COREDUMP:
299 	case KERN_NX_PROTECTION:
300 		return (valid_arg & ARG_VALUE32) ?
301 		       AUE_SYSCTL : AUE_SYSCTL_NONADMIN;
302 
303 	default:
304 		return AUE_SYSCTL;
305 	}
306 	/* NOTREACHED */
307 }
308 
309 /*
310  * Convert an open flags specifier into a specific type of open event for
311  * auditing purposes.
312  */
313 au_event_t
audit_flags_and_error_to_openevent(int oflags,int error)314 audit_flags_and_error_to_openevent(int oflags, int error)
315 {
316 	au_event_t aevent;
317 
318 	/*
319 	 * Need to check only those flags we care about.
320 	 */
321 	oflags = oflags & (O_RDONLY | O_CREAT | O_TRUNC | O_RDWR | O_WRONLY);
322 
323 	/*
324 	 * These checks determine what flags are on with the condition that
325 	 * ONLY that combination is on, and no other flags are on.
326 	 */
327 	switch (oflags) {
328 	case O_RDONLY:
329 		aevent = AUE_OPEN_R;
330 		break;
331 
332 	case (O_RDONLY | O_CREAT):
333 		aevent = AUE_OPEN_RC;
334 		break;
335 
336 	case (O_RDONLY | O_CREAT | O_TRUNC):
337 		aevent = AUE_OPEN_RTC;
338 		break;
339 
340 	case (O_RDONLY | O_TRUNC):
341 		aevent = AUE_OPEN_RT;
342 		break;
343 
344 	case O_RDWR:
345 		aevent = AUE_OPEN_RW;
346 		break;
347 
348 	case (O_RDWR | O_CREAT):
349 		aevent = AUE_OPEN_RWC;
350 		break;
351 
352 	case (O_RDWR | O_CREAT | O_TRUNC):
353 		aevent = AUE_OPEN_RWTC;
354 		break;
355 
356 	case (O_RDWR | O_TRUNC):
357 		aevent = AUE_OPEN_RWT;
358 		break;
359 
360 	case O_WRONLY:
361 		aevent = AUE_OPEN_W;
362 		break;
363 
364 	case (O_WRONLY | O_CREAT):
365 		aevent = AUE_OPEN_WC;
366 		break;
367 
368 	case (O_WRONLY | O_CREAT | O_TRUNC):
369 		aevent = AUE_OPEN_WTC;
370 		break;
371 
372 	case (O_WRONLY | O_TRUNC):
373 		aevent = AUE_OPEN_WT;
374 		break;
375 
376 	default:
377 		aevent = AUE_OPEN;
378 		break;
379 	}
380 
381 	/*
382 	 * Convert chatty errors to better matching events.  Failures to
383 	 * find a file are really just attribute events -- so recast them as
384 	 * such.
385 	 *
386 	 * XXXAUDIT: Solaris defines that AUE_OPEN will never be returned, it
387 	 * is just a placeholder.  However, in Darwin we return that in
388 	 * preference to other events.
389 	 *
390 	 * XXXRW: This behavior differs from FreeBSD, so possibly revise this
391 	 * code or this comment.
392 	 */
393 	switch (aevent) {
394 	case AUE_OPEN_R:
395 	case AUE_OPEN_RT:
396 	case AUE_OPEN_RW:
397 	case AUE_OPEN_RWT:
398 	case AUE_OPEN_W:
399 	case AUE_OPEN_WT:
400 		if (error == ENOENT) {
401 			aevent = AUE_OPEN;
402 		}
403 	}
404 	return aevent;
405 }
406 
407 /*
408  * Convert an open flags specifier into a specific type of open_extended event
409  * for auditing purposes.
410  */
411 au_event_t
audit_flags_and_error_to_openextendedevent(int oflags,int error)412 audit_flags_and_error_to_openextendedevent(int oflags, int error)
413 {
414 	au_event_t aevent;
415 
416 	/*
417 	 * Need to check only those flags we care about.
418 	 */
419 	oflags = oflags & (O_RDONLY | O_CREAT | O_TRUNC | O_RDWR | O_WRONLY);
420 
421 	/*
422 	 * These checks determine what flags are on with the condition that
423 	 * ONLY that combination is on, and no other flags are on.
424 	 */
425 	switch (oflags) {
426 	case O_RDONLY:
427 		aevent = AUE_OPEN_EXTENDED_R;
428 		break;
429 
430 	case (O_RDONLY | O_CREAT):
431 		aevent = AUE_OPEN_EXTENDED_RC;
432 		break;
433 
434 	case (O_RDONLY | O_CREAT | O_TRUNC):
435 		aevent = AUE_OPEN_EXTENDED_RTC;
436 		break;
437 
438 	case (O_RDONLY | O_TRUNC):
439 		aevent = AUE_OPEN_EXTENDED_RT;
440 		break;
441 
442 	case O_RDWR:
443 		aevent = AUE_OPEN_EXTENDED_RW;
444 		break;
445 
446 	case (O_RDWR | O_CREAT):
447 		aevent = AUE_OPEN_EXTENDED_RWC;
448 		break;
449 
450 	case (O_RDWR | O_CREAT | O_TRUNC):
451 		aevent = AUE_OPEN_EXTENDED_RWTC;
452 		break;
453 
454 	case (O_RDWR | O_TRUNC):
455 		aevent = AUE_OPEN_EXTENDED_RWT;
456 		break;
457 
458 	case O_WRONLY:
459 		aevent = AUE_OPEN_EXTENDED_W;
460 		break;
461 
462 	case (O_WRONLY | O_CREAT):
463 		aevent = AUE_OPEN_EXTENDED_WC;
464 		break;
465 
466 	case (O_WRONLY | O_CREAT | O_TRUNC):
467 		aevent = AUE_OPEN_EXTENDED_WTC;
468 		break;
469 
470 	case (O_WRONLY | O_TRUNC):
471 		aevent = AUE_OPEN_EXTENDED_WT;
472 		break;
473 
474 	default:
475 		aevent = AUE_OPEN_EXTENDED;
476 		break;
477 	}
478 
479 	/*
480 	 * Convert chatty errors to better matching events.  Failures to
481 	 * find a file are really just attribute events -- so recast them as
482 	 * such.
483 	 *
484 	 * XXXAUDIT: Solaris defines that AUE_OPEN will never be returned, it
485 	 * is just a placeholder.  However, in Darwin we return that in
486 	 * preference to other events.
487 	 *
488 	 * XXXRW: This behavior differs from FreeBSD, so possibly revise this
489 	 * code or this comment.
490 	 */
491 	switch (aevent) {
492 	case AUE_OPEN_EXTENDED_R:
493 	case AUE_OPEN_EXTENDED_RT:
494 	case AUE_OPEN_EXTENDED_RW:
495 	case AUE_OPEN_EXTENDED_RWT:
496 	case AUE_OPEN_EXTENDED_W:
497 	case AUE_OPEN_EXTENDED_WT:
498 		if (error == ENOENT) {
499 			aevent = AUE_OPEN_EXTENDED;
500 		}
501 	}
502 	return aevent;
503 }
504 
505 /*
506  * Convert an open flags specifier into a specific type of open_extended event
507  * for auditing purposes.
508  */
509 au_event_t
audit_flags_and_error_to_openatevent(int oflags,int error)510 audit_flags_and_error_to_openatevent(int oflags, int error)
511 {
512 	au_event_t aevent;
513 
514 	/*
515 	 * Need to check only those flags we care about.
516 	 */
517 	oflags = oflags & (O_RDONLY | O_CREAT | O_TRUNC | O_RDWR | O_WRONLY);
518 
519 	/*
520 	 * These checks determine what flags are on with the condition that
521 	 * ONLY that combination is on, and no other flags are on.
522 	 */
523 	switch (oflags) {
524 	case O_RDONLY:
525 		aevent = AUE_OPENAT_R;
526 		break;
527 
528 	case (O_RDONLY | O_CREAT):
529 		aevent = AUE_OPENAT_RC;
530 		break;
531 
532 	case (O_RDONLY | O_CREAT | O_TRUNC):
533 		aevent = AUE_OPENAT_RTC;
534 		break;
535 
536 	case (O_RDONLY | O_TRUNC):
537 		aevent = AUE_OPENAT_RT;
538 		break;
539 
540 	case O_RDWR:
541 		aevent = AUE_OPENAT_RW;
542 		break;
543 
544 	case (O_RDWR | O_CREAT):
545 		aevent = AUE_OPENAT_RWC;
546 		break;
547 
548 	case (O_RDWR | O_CREAT | O_TRUNC):
549 		aevent = AUE_OPENAT_RWTC;
550 		break;
551 
552 	case (O_RDWR | O_TRUNC):
553 		aevent = AUE_OPENAT_RWT;
554 		break;
555 
556 	case O_WRONLY:
557 		aevent = AUE_OPENAT_W;
558 		break;
559 
560 	case (O_WRONLY | O_CREAT):
561 		aevent = AUE_OPENAT_WC;
562 		break;
563 
564 	case (O_WRONLY | O_CREAT | O_TRUNC):
565 		aevent = AUE_OPENAT_WTC;
566 		break;
567 
568 	case (O_WRONLY | O_TRUNC):
569 		aevent = AUE_OPENAT_WT;
570 		break;
571 
572 	default:
573 		aevent = AUE_OPENAT;
574 		break;
575 	}
576 
577 	/*
578 	 * Convert chatty errors to better matching events.  Failures to
579 	 * find a file are really just attribute events -- so recast them as
580 	 * such.
581 	 *
582 	 * XXXAUDIT: Solaris defines that AUE_OPENAT will never be returned, it
583 	 * is just a placeholder.  However, in Darwin we return that in
584 	 * preference to other events.
585 	 *
586 	 * XXXRW: This behavior differs from FreeBSD, so possibly revise this
587 	 * code or this comment.
588 	 */
589 	switch (aevent) {
590 	case AUE_OPENAT_R:
591 	case AUE_OPENAT_RT:
592 	case AUE_OPENAT_RW:
593 	case AUE_OPENAT_RWT:
594 	case AUE_OPENAT_W:
595 	case AUE_OPENAT_WT:
596 		if (error == ENOENT) {
597 			aevent = AUE_OPENAT;
598 		}
599 	}
600 	return aevent;
601 }
602 
603 /*
604  * Convert an open flags specifier into a specific type of openbyid event
605  * for auditing purposes.
606  */
607 au_event_t
audit_flags_and_error_to_openbyidevent(int oflags,int error)608 audit_flags_and_error_to_openbyidevent(int oflags, int error)
609 {
610 	au_event_t aevent;
611 
612 	/*
613 	 * Need to check only those flags we care about.
614 	 */
615 	oflags = oflags & (O_RDONLY | O_TRUNC | O_RDWR | O_WRONLY);
616 
617 	/*
618 	 * These checks determine what flags are on with the condition that
619 	 * ONLY that combination is on, and no other flags are on.
620 	 */
621 	switch (oflags) {
622 	case O_RDONLY:
623 		aevent = AUE_OPENBYID_R;
624 		break;
625 
626 	case (O_RDONLY | O_TRUNC):
627 		aevent = AUE_OPENBYID_RT;
628 		break;
629 
630 	case O_RDWR:
631 		aevent = AUE_OPENBYID_RW;
632 		break;
633 
634 	case (O_RDWR | O_TRUNC):
635 		aevent = AUE_OPENBYID_RWT;
636 		break;
637 
638 	case O_WRONLY:
639 		aevent = AUE_OPENBYID_W;
640 		break;
641 
642 	case (O_WRONLY | O_TRUNC):
643 		aevent = AUE_OPENBYID_WT;
644 		break;
645 
646 	default:
647 		aevent = AUE_OPENBYID;
648 		break;
649 	}
650 
651 	/*
652 	 * Convert chatty errors to better matching events.  Failures to
653 	 * find a file are really just attribute events -- so recast them as
654 	 * such.
655 	 */
656 	switch (aevent) {
657 	case AUE_OPENBYID_R:
658 	case AUE_OPENBYID_RT:
659 	case AUE_OPENBYID_RW:
660 	case AUE_OPENBYID_RWT:
661 	case AUE_OPENBYID_W:
662 	case AUE_OPENBYID_WT:
663 		if (error == ENOENT) {
664 			aevent = AUE_OPENBYID;
665 		}
666 	}
667 	return aevent;
668 }
669 
670 /*
671  * Convert a MSGCTL command to a specific event.
672  */
673 au_event_t
audit_msgctl_to_event(int cmd)674 audit_msgctl_to_event(int cmd)
675 {
676 	switch (cmd) {
677 	case IPC_RMID:
678 		return AUE_MSGCTL_RMID;
679 
680 	case IPC_SET:
681 		return AUE_MSGCTL_SET;
682 
683 	case IPC_STAT:
684 		return AUE_MSGCTL_STAT;
685 
686 	default:
687 		/* We will audit a bad command. */
688 		return AUE_MSGCTL;
689 	}
690 }
691 
692 /*
693  * Convert a SEMCTL command to a specific event.
694  */
695 au_event_t
audit_semctl_to_event(int cmd)696 audit_semctl_to_event(int cmd)
697 {
698 	switch (cmd) {
699 	case GETALL:
700 		return AUE_SEMCTL_GETALL;
701 
702 	case GETNCNT:
703 		return AUE_SEMCTL_GETNCNT;
704 
705 	case GETPID:
706 		return AUE_SEMCTL_GETPID;
707 
708 	case GETVAL:
709 		return AUE_SEMCTL_GETVAL;
710 
711 	case GETZCNT:
712 		return AUE_SEMCTL_GETZCNT;
713 
714 	case IPC_RMID:
715 		return AUE_SEMCTL_RMID;
716 
717 	case IPC_SET:
718 		return AUE_SEMCTL_SET;
719 
720 	case SETALL:
721 		return AUE_SEMCTL_SETALL;
722 
723 	case SETVAL:
724 		return AUE_SEMCTL_SETVAL;
725 
726 	case IPC_STAT:
727 		return AUE_SEMCTL_STAT;
728 
729 	default:
730 		/* We will audit a bad command. */
731 		return AUE_SEMCTL;
732 	}
733 }
734 
735 /*
736  * Convert a command for the auditon() system call to a audit event.
737  */
738 au_event_t
auditon_command_event(int cmd)739 auditon_command_event(int cmd)
740 {
741 	switch (cmd) {
742 	case A_GETPOLICY:
743 		return AUE_AUDITON_GPOLICY;
744 
745 	case A_SETPOLICY:
746 		return AUE_AUDITON_SPOLICY;
747 
748 	case A_GETKMASK:
749 		return AUE_AUDITON_GETKMASK;
750 
751 	case A_SETKMASK:
752 		return AUE_AUDITON_SETKMASK;
753 
754 	case A_GETQCTRL:
755 		return AUE_AUDITON_GQCTRL;
756 
757 	case A_SETQCTRL:
758 		return AUE_AUDITON_SQCTRL;
759 
760 	case A_GETCWD:
761 		return AUE_AUDITON_GETCWD;
762 
763 	case A_GETCAR:
764 		return AUE_AUDITON_GETCAR;
765 
766 	case A_GETSTAT:
767 		return AUE_AUDITON_GETSTAT;
768 
769 	case A_SETSTAT:
770 		return AUE_AUDITON_SETSTAT;
771 
772 	case A_SETUMASK:
773 		return AUE_AUDITON_SETUMASK;
774 
775 	case A_SETSMASK:
776 		return AUE_AUDITON_SETSMASK;
777 
778 	case A_GETCOND:
779 		return AUE_AUDITON_GETCOND;
780 
781 	case A_SETCOND:
782 		return AUE_AUDITON_SETCOND;
783 
784 	case A_GETCLASS:
785 		return AUE_AUDITON_GETCLASS;
786 
787 	case A_SETCLASS:
788 		return AUE_AUDITON_SETCLASS;
789 
790 	case A_GETPINFO:
791 	case A_SETPMASK:
792 	case A_SETFSIZE:
793 	case A_GETFSIZE:
794 	case A_GETPINFO_ADDR:
795 	case A_GETKAUDIT:
796 	case A_SETKAUDIT:
797 	case A_GETSINFO_ADDR:
798 	default:
799 		return AUE_AUDITON;   /* No special record */
800 	}
801 }
802 
803 /*
804  * For darwin we rewrite events generated by fcntl(F_OPENFROM,...) and
805  * fcntl(F_UNLINKFROM,...) system calls to AUE_OPENAT_* and AUE_UNLINKAT audit
806  * events.
807  */
808 au_event_t
audit_fcntl_command_event(int cmd,int oflags,int error)809 audit_fcntl_command_event(int cmd, int oflags, int error)
810 {
811 	switch (cmd) {
812 	case F_OPENFROM:
813 		return audit_flags_and_error_to_openatevent(oflags, error);
814 
815 	case F_UNLINKFROM:
816 		return AUE_UNLINKAT;
817 
818 	default:
819 		return AUE_FCNTL;   /* Don't change from AUE_FCNTL. */
820 	}
821 }
822 
823 /*
824  * Create a canonical path from given path by prefixing either the root
825  * directory, or the current working directory.
826  */
827 int
audit_canon_path(struct vnode * cwd_vp,const char * path,char * cpath)828 audit_canon_path(struct vnode *cwd_vp, const char *path, char *cpath)
829 {
830 	int len;
831 	int ret;
832 	const char *bufp = path;
833 
834 	/*
835 	 * Convert multiple leading '/' into a single '/' if the cwd_vp is
836 	 * NULL (i.e. an absolute path), and strip them entirely if the
837 	 * cwd_vp represents a chroot directory (i.e. the caller checked for
838 	 * an initial '/' character itself, saw one, and passed fdp->fd_rdir).
839 	 * Somewhat complicated, but it places the onus for locking structs
840 	 * involved on the caller, and makes proxy operations explicit rather
841 	 * than implicit.
842 	 */
843 	if (*(path) == '/') {
844 		while (*(bufp) == '/') {
845 			bufp++;         /* skip leading '/'s */
846 		}
847 		if (cwd_vp == NULL) {
848 			bufp--;         /* restore one '/' */
849 		}
850 	}
851 	if (cwd_vp != NULL) {
852 		len = MAXPATHLEN;
853 		ret = vn_getpath(cwd_vp, cpath, &len);
854 		if (ret != 0) {
855 			cpath[0] = '\0';
856 			return ret;
857 		}
858 		if (len < MAXPATHLEN) {
859 			cpath[len - 1] = '/';
860 		}
861 		strlcpy(cpath + len, bufp, MAXPATHLEN - len);
862 	} else {
863 		strlcpy(cpath, bufp, MAXPATHLEN);
864 	}
865 	return 0;
866 }
867 #endif /* CONFIG_AUDIT */
868