Deleted Added
full compact
audit_bsm_klib.c (181053) audit_bsm_klib.c (181060)
1/*
2 * Copyright (c) 1999-2005 Apple Inc.
3 * Copyright (c) 2005 Robert N. M. Watson
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
22 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <sys/cdefs.h>
1/*
2 * Copyright (c) 1999-2005 Apple Inc.
3 * Copyright (c) 2005 Robert N. M. Watson
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
22 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD: head/sys/security/audit/audit_bsm_klib.c 181053 2008-07-31 09:54:35Z rwatson $");
32__FBSDID("$FreeBSD: head/sys/security/audit/audit_bsm_klib.c 181060 2008-07-31 16:57:41Z csjp $");
33
34#include <sys/param.h>
35#include <sys/fcntl.h>
36#include <sys/filedesc.h>
37#include <sys/libkern.h>
38#include <sys/malloc.h>
39#include <sys/mount.h>
40#include <sys/proc.h>
41#include <sys/sem.h>
33
34#include <sys/param.h>
35#include <sys/fcntl.h>
36#include <sys/filedesc.h>
37#include <sys/libkern.h>
38#include <sys/malloc.h>
39#include <sys/mount.h>
40#include <sys/proc.h>
41#include <sys/sem.h>
42#include <sys/sbuf.h>
42#include <sys/syscall.h>
43#include <sys/sysctl.h>
44#include <sys/sysent.h>
45#include <sys/vnode.h>
46
47#include <bsm/audit.h>
48#include <bsm/audit_kevents.h>
49#include <security/audit/audit.h>
50#include <security/audit/audit_private.h>
51
52/*
53 * Hash table functions for the audit event number to event class mask
54 * mapping.
55 */
56#define EVCLASSMAP_HASH_TABLE_SIZE 251
57struct evclass_elem {
58 au_event_t event;
59 au_class_t class;
60 LIST_ENTRY(evclass_elem) entry;
61};
62struct evclass_list {
63 LIST_HEAD(, evclass_elem) head;
64};
65
66static MALLOC_DEFINE(M_AUDITEVCLASS, "audit_evclass", "Audit event class");
67static struct mtx evclass_mtx;
68static struct evclass_list evclass_hash[EVCLASSMAP_HASH_TABLE_SIZE];
69
70/*
71 * Look up the class for an audit event in the class mapping table.
72 */
73au_class_t
74au_event_class(au_event_t event)
75{
76 struct evclass_list *evcl;
77 struct evclass_elem *evc;
78 au_class_t class;
79
80 mtx_lock(&evclass_mtx);
81 evcl = &evclass_hash[event % EVCLASSMAP_HASH_TABLE_SIZE];
82 class = 0;
83 LIST_FOREACH(evc, &evcl->head, entry) {
84 if (evc->event == event) {
85 class = evc->class;
86 goto out;
87 }
88 }
89out:
90 mtx_unlock(&evclass_mtx);
91 return (class);
92}
93
94/*
95 * Insert a event to class mapping. If the event already exists in the
96 * mapping, then replace the mapping with the new one.
97 *
98 * XXX There is currently no constraints placed on the number of mappings.
99 * May want to either limit to a number, or in terms of memory usage.
100 */
101void
102au_evclassmap_insert(au_event_t event, au_class_t class)
103{
104 struct evclass_list *evcl;
105 struct evclass_elem *evc, *evc_new;
106
107 /*
108 * Pessimistically, always allocate storage before acquiring mutex.
109 * Free if there is already a mapping for this event.
110 */
111 evc_new = malloc(sizeof(*evc), M_AUDITEVCLASS, M_WAITOK);
112
113 mtx_lock(&evclass_mtx);
114 evcl = &evclass_hash[event % EVCLASSMAP_HASH_TABLE_SIZE];
115 LIST_FOREACH(evc, &evcl->head, entry) {
116 if (evc->event == event) {
117 evc->class = class;
118 mtx_unlock(&evclass_mtx);
119 free(evc_new, M_AUDITEVCLASS);
120 return;
121 }
122 }
123 evc = evc_new;
124 evc->event = event;
125 evc->class = class;
126 LIST_INSERT_HEAD(&evcl->head, evc, entry);
127 mtx_unlock(&evclass_mtx);
128}
129
130void
131au_evclassmap_init(void)
132{
133 int i;
134
135 mtx_init(&evclass_mtx, "evclass_mtx", NULL, MTX_DEF);
136 for (i = 0; i < EVCLASSMAP_HASH_TABLE_SIZE; i++)
137 LIST_INIT(&evclass_hash[i].head);
138
139 /*
140 * Set up the initial event to class mapping for system calls.
141 *
142 * XXXRW: Really, this should walk all possible audit events, not all
143 * native ABI system calls, as there may be audit events reachable
144 * only through non-native system calls. It also seems a shame to
145 * frob the mutex this early.
146 */
147 for (i = 0; i < SYS_MAXSYSCALL; i++) {
148 if (sysent[i].sy_auevent != AUE_NULL)
149 au_evclassmap_insert(sysent[i].sy_auevent, 0);
150 }
151}
152
153/*
154 * Check whether an event is aditable by comparing the mask of classes this
155 * event is part of against the given mask.
156 */
157int
158au_preselect(au_event_t event, au_class_t class, au_mask_t *mask_p, int sorf)
159{
160 au_class_t effmask = 0;
161
162 if (mask_p == NULL)
163 return (-1);
164
165 /*
166 * Perform the actual check of the masks against the event.
167 */
168 if (sorf & AU_PRS_SUCCESS)
169 effmask |= (mask_p->am_success & class);
170
171 if (sorf & AU_PRS_FAILURE)
172 effmask |= (mask_p->am_failure & class);
173
174 if (effmask)
175 return (1);
176 else
177 return (0);
178}
179
180/*
181 * Convert sysctl names and present arguments to events.
182 */
183au_event_t
184audit_ctlname_to_sysctlevent(int name[], uint64_t valid_arg)
185{
186
187 /* can't parse it - so return the worst case */
188 if ((valid_arg & (ARG_CTLNAME | ARG_LEN)) != (ARG_CTLNAME | ARG_LEN))
189 return (AUE_SYSCTL);
190
191 switch (name[0]) {
192 /* non-admin "lookups" treat them special */
193 case KERN_OSTYPE:
194 case KERN_OSRELEASE:
195 case KERN_OSREV:
196 case KERN_VERSION:
197 case KERN_ARGMAX:
198 case KERN_CLOCKRATE:
199 case KERN_BOOTTIME:
200 case KERN_POSIX1:
201 case KERN_NGROUPS:
202 case KERN_JOB_CONTROL:
203 case KERN_SAVED_IDS:
204 case KERN_OSRELDATE:
205 case KERN_DUMMY:
206 return (AUE_SYSCTL_NONADMIN);
207
208 /* only treat the changeable controls as admin */
209 case KERN_MAXVNODES:
210 case KERN_MAXPROC:
211 case KERN_MAXFILES:
212 case KERN_MAXPROCPERUID:
213 case KERN_MAXFILESPERPROC:
214 case KERN_HOSTID:
215 case KERN_SECURELVL:
216 case KERN_HOSTNAME:
217 case KERN_VNODE:
218 case KERN_PROC:
219 case KERN_FILE:
220 case KERN_PROF:
221 case KERN_NISDOMAINNAME:
222 case KERN_UPDATEINTERVAL:
223 case KERN_NTP_PLL:
224 case KERN_BOOTFILE:
225 case KERN_DUMPDEV:
226 case KERN_IPC:
227 case KERN_PS_STRINGS:
228 case KERN_USRSTACK:
229 case KERN_LOGSIGEXIT:
230 case KERN_IOV_MAX:
231 case KERN_MAXID:
232 return ((valid_arg & ARG_VALUE) ?
233 AUE_SYSCTL : AUE_SYSCTL_NONADMIN);
234
235 default:
236 return (AUE_SYSCTL);
237 }
238 /* NOTREACHED */
239}
240
241/*
242 * Convert an open flags specifier into a specific type of open event for
243 * auditing purposes.
244 */
245au_event_t
246audit_flags_and_error_to_openevent(int oflags, int error)
247{
248 au_event_t aevent;
249
250 /*
251 * Need to check only those flags we care about.
252 */
253 oflags = oflags & (O_RDONLY | O_CREAT | O_TRUNC | O_RDWR | O_WRONLY);
254
255 /*
256 * These checks determine what flags are on with the condition that
257 * ONLY that combination is on, and no other flags are on.
258 */
259 switch (oflags) {
260 case O_RDONLY:
261 aevent = AUE_OPEN_R;
262 break;
263
264 case (O_RDONLY | O_CREAT):
265 aevent = AUE_OPEN_RC;
266 break;
267
268 case (O_RDONLY | O_CREAT | O_TRUNC):
269 aevent = AUE_OPEN_RTC;
270 break;
271
272 case (O_RDONLY | O_TRUNC):
273 aevent = AUE_OPEN_RT;
274 break;
275
276 case O_RDWR:
277 aevent = AUE_OPEN_RW;
278 break;
279
280 case (O_RDWR | O_CREAT):
281 aevent = AUE_OPEN_RWC;
282 break;
283
284 case (O_RDWR | O_CREAT | O_TRUNC):
285 aevent = AUE_OPEN_RWTC;
286 break;
287
288 case (O_RDWR | O_TRUNC):
289 aevent = AUE_OPEN_RWT;
290 break;
291
292 case O_WRONLY:
293 aevent = AUE_OPEN_W;
294 break;
295
296 case (O_WRONLY | O_CREAT):
297 aevent = AUE_OPEN_WC;
298 break;
299
300 case (O_WRONLY | O_CREAT | O_TRUNC):
301 aevent = AUE_OPEN_WTC;
302 break;
303
304 case (O_WRONLY | O_TRUNC):
305 aevent = AUE_OPEN_WT;
306 break;
307
308 default:
309 aevent = AUE_OPEN;
310 break;
311 }
312
313#if 0
314 /*
315 * Convert chatty errors to better matching events. Failures to
316 * find a file are really just attribute events -- so recast them as
317 * such.
318 *
319 * XXXAUDIT: Solaris defines that AUE_OPEN will never be returned, it
320 * is just a placeholder. However, in Darwin we return that in
321 * preference to other events. For now, comment this out as we don't
322 * have a BSM conversion routine for AUE_OPEN.
323 */
324 switch (aevent) {
325 case AUE_OPEN_R:
326 case AUE_OPEN_RT:
327 case AUE_OPEN_RW:
328 case AUE_OPEN_RWT:
329 case AUE_OPEN_W:
330 case AUE_OPEN_WT:
331 if (error == ENOENT)
332 aevent = AUE_OPEN;
333 }
334#endif
335 return (aevent);
336}
337
338/*
339 * Convert a MSGCTL command to a specific event.
340 */
341int
342audit_msgctl_to_event(int cmd)
343{
344
345 switch (cmd) {
346 case IPC_RMID:
347 return (AUE_MSGCTL_RMID);
348
349 case IPC_SET:
350 return (AUE_MSGCTL_SET);
351
352 case IPC_STAT:
353 return (AUE_MSGCTL_STAT);
354
355 default:
356 /* We will audit a bad command. */
357 return (AUE_MSGCTL);
358 }
359}
360
361/*
362 * Convert a SEMCTL command to a specific event.
363 */
364int
365audit_semctl_to_event(int cmd)
366{
367
368 switch (cmd) {
369 case GETALL:
370 return (AUE_SEMCTL_GETALL);
371
372 case GETNCNT:
373 return (AUE_SEMCTL_GETNCNT);
374
375 case GETPID:
376 return (AUE_SEMCTL_GETPID);
377
378 case GETVAL:
379 return (AUE_SEMCTL_GETVAL);
380
381 case GETZCNT:
382 return (AUE_SEMCTL_GETZCNT);
383
384 case IPC_RMID:
385 return (AUE_SEMCTL_RMID);
386
387 case IPC_SET:
388 return (AUE_SEMCTL_SET);
389
390 case SETALL:
391 return (AUE_SEMCTL_SETALL);
392
393 case SETVAL:
394 return (AUE_SEMCTL_SETVAL);
395
396 case IPC_STAT:
397 return (AUE_SEMCTL_STAT);
398
399 default:
400 /* We will audit a bad command. */
401 return (AUE_SEMCTL);
402 }
403}
404
405/*
406 * Convert a command for the auditon() system call to a audit event.
407 */
408int
409auditon_command_event(int cmd)
410{
411
412 switch(cmd) {
413 case A_GETPOLICY:
414 return (AUE_AUDITON_GPOLICY);
415
416 case A_SETPOLICY:
417 return (AUE_AUDITON_SPOLICY);
418
419 case A_GETKMASK:
420 return (AUE_AUDITON_GETKMASK);
421
422 case A_SETKMASK:
423 return (AUE_AUDITON_SETKMASK);
424
425 case A_GETQCTRL:
426 return (AUE_AUDITON_GQCTRL);
427
428 case A_SETQCTRL:
429 return (AUE_AUDITON_SQCTRL);
430
431 case A_GETCWD:
432 return (AUE_AUDITON_GETCWD);
433
434 case A_GETCAR:
435 return (AUE_AUDITON_GETCAR);
436
437 case A_GETSTAT:
438 return (AUE_AUDITON_GETSTAT);
439
440 case A_SETSTAT:
441 return (AUE_AUDITON_SETSTAT);
442
443 case A_SETUMASK:
444 return (AUE_AUDITON_SETUMASK);
445
446 case A_SETSMASK:
447 return (AUE_AUDITON_SETSMASK);
448
449 case A_GETCOND:
450 return (AUE_AUDITON_GETCOND);
451
452 case A_SETCOND:
453 return (AUE_AUDITON_SETCOND);
454
455 case A_GETCLASS:
456 return (AUE_AUDITON_GETCLASS);
457
458 case A_SETCLASS:
459 return (AUE_AUDITON_SETCLASS);
460
461 case A_GETPINFO:
462 case A_SETPMASK:
463 case A_SETFSIZE:
464 case A_GETFSIZE:
465 case A_GETPINFO_ADDR:
466 case A_GETKAUDIT:
467 case A_SETKAUDIT:
468 default:
469 return (AUE_AUDITON); /* No special record */
470 }
471}
472
473/*
474 * Create a canonical path from given path by prefixing either the root
475 * directory, or the current working directory. If the process working
476 * directory is NULL, we could use 'rootvnode' to obtain the root directory,
477 * but this results in a volfs name written to the audit log. So we will
478 * leave the filename starting with '/' in the audit log in this case.
43#include <sys/syscall.h>
44#include <sys/sysctl.h>
45#include <sys/sysent.h>
46#include <sys/vnode.h>
47
48#include <bsm/audit.h>
49#include <bsm/audit_kevents.h>
50#include <security/audit/audit.h>
51#include <security/audit/audit_private.h>
52
53/*
54 * Hash table functions for the audit event number to event class mask
55 * mapping.
56 */
57#define EVCLASSMAP_HASH_TABLE_SIZE 251
58struct evclass_elem {
59 au_event_t event;
60 au_class_t class;
61 LIST_ENTRY(evclass_elem) entry;
62};
63struct evclass_list {
64 LIST_HEAD(, evclass_elem) head;
65};
66
67static MALLOC_DEFINE(M_AUDITEVCLASS, "audit_evclass", "Audit event class");
68static struct mtx evclass_mtx;
69static struct evclass_list evclass_hash[EVCLASSMAP_HASH_TABLE_SIZE];
70
71/*
72 * Look up the class for an audit event in the class mapping table.
73 */
74au_class_t
75au_event_class(au_event_t event)
76{
77 struct evclass_list *evcl;
78 struct evclass_elem *evc;
79 au_class_t class;
80
81 mtx_lock(&evclass_mtx);
82 evcl = &evclass_hash[event % EVCLASSMAP_HASH_TABLE_SIZE];
83 class = 0;
84 LIST_FOREACH(evc, &evcl->head, entry) {
85 if (evc->event == event) {
86 class = evc->class;
87 goto out;
88 }
89 }
90out:
91 mtx_unlock(&evclass_mtx);
92 return (class);
93}
94
95/*
96 * Insert a event to class mapping. If the event already exists in the
97 * mapping, then replace the mapping with the new one.
98 *
99 * XXX There is currently no constraints placed on the number of mappings.
100 * May want to either limit to a number, or in terms of memory usage.
101 */
102void
103au_evclassmap_insert(au_event_t event, au_class_t class)
104{
105 struct evclass_list *evcl;
106 struct evclass_elem *evc, *evc_new;
107
108 /*
109 * Pessimistically, always allocate storage before acquiring mutex.
110 * Free if there is already a mapping for this event.
111 */
112 evc_new = malloc(sizeof(*evc), M_AUDITEVCLASS, M_WAITOK);
113
114 mtx_lock(&evclass_mtx);
115 evcl = &evclass_hash[event % EVCLASSMAP_HASH_TABLE_SIZE];
116 LIST_FOREACH(evc, &evcl->head, entry) {
117 if (evc->event == event) {
118 evc->class = class;
119 mtx_unlock(&evclass_mtx);
120 free(evc_new, M_AUDITEVCLASS);
121 return;
122 }
123 }
124 evc = evc_new;
125 evc->event = event;
126 evc->class = class;
127 LIST_INSERT_HEAD(&evcl->head, evc, entry);
128 mtx_unlock(&evclass_mtx);
129}
130
131void
132au_evclassmap_init(void)
133{
134 int i;
135
136 mtx_init(&evclass_mtx, "evclass_mtx", NULL, MTX_DEF);
137 for (i = 0; i < EVCLASSMAP_HASH_TABLE_SIZE; i++)
138 LIST_INIT(&evclass_hash[i].head);
139
140 /*
141 * Set up the initial event to class mapping for system calls.
142 *
143 * XXXRW: Really, this should walk all possible audit events, not all
144 * native ABI system calls, as there may be audit events reachable
145 * only through non-native system calls. It also seems a shame to
146 * frob the mutex this early.
147 */
148 for (i = 0; i < SYS_MAXSYSCALL; i++) {
149 if (sysent[i].sy_auevent != AUE_NULL)
150 au_evclassmap_insert(sysent[i].sy_auevent, 0);
151 }
152}
153
154/*
155 * Check whether an event is aditable by comparing the mask of classes this
156 * event is part of against the given mask.
157 */
158int
159au_preselect(au_event_t event, au_class_t class, au_mask_t *mask_p, int sorf)
160{
161 au_class_t effmask = 0;
162
163 if (mask_p == NULL)
164 return (-1);
165
166 /*
167 * Perform the actual check of the masks against the event.
168 */
169 if (sorf & AU_PRS_SUCCESS)
170 effmask |= (mask_p->am_success & class);
171
172 if (sorf & AU_PRS_FAILURE)
173 effmask |= (mask_p->am_failure & class);
174
175 if (effmask)
176 return (1);
177 else
178 return (0);
179}
180
181/*
182 * Convert sysctl names and present arguments to events.
183 */
184au_event_t
185audit_ctlname_to_sysctlevent(int name[], uint64_t valid_arg)
186{
187
188 /* can't parse it - so return the worst case */
189 if ((valid_arg & (ARG_CTLNAME | ARG_LEN)) != (ARG_CTLNAME | ARG_LEN))
190 return (AUE_SYSCTL);
191
192 switch (name[0]) {
193 /* non-admin "lookups" treat them special */
194 case KERN_OSTYPE:
195 case KERN_OSRELEASE:
196 case KERN_OSREV:
197 case KERN_VERSION:
198 case KERN_ARGMAX:
199 case KERN_CLOCKRATE:
200 case KERN_BOOTTIME:
201 case KERN_POSIX1:
202 case KERN_NGROUPS:
203 case KERN_JOB_CONTROL:
204 case KERN_SAVED_IDS:
205 case KERN_OSRELDATE:
206 case KERN_DUMMY:
207 return (AUE_SYSCTL_NONADMIN);
208
209 /* only treat the changeable controls as admin */
210 case KERN_MAXVNODES:
211 case KERN_MAXPROC:
212 case KERN_MAXFILES:
213 case KERN_MAXPROCPERUID:
214 case KERN_MAXFILESPERPROC:
215 case KERN_HOSTID:
216 case KERN_SECURELVL:
217 case KERN_HOSTNAME:
218 case KERN_VNODE:
219 case KERN_PROC:
220 case KERN_FILE:
221 case KERN_PROF:
222 case KERN_NISDOMAINNAME:
223 case KERN_UPDATEINTERVAL:
224 case KERN_NTP_PLL:
225 case KERN_BOOTFILE:
226 case KERN_DUMPDEV:
227 case KERN_IPC:
228 case KERN_PS_STRINGS:
229 case KERN_USRSTACK:
230 case KERN_LOGSIGEXIT:
231 case KERN_IOV_MAX:
232 case KERN_MAXID:
233 return ((valid_arg & ARG_VALUE) ?
234 AUE_SYSCTL : AUE_SYSCTL_NONADMIN);
235
236 default:
237 return (AUE_SYSCTL);
238 }
239 /* NOTREACHED */
240}
241
242/*
243 * Convert an open flags specifier into a specific type of open event for
244 * auditing purposes.
245 */
246au_event_t
247audit_flags_and_error_to_openevent(int oflags, int error)
248{
249 au_event_t aevent;
250
251 /*
252 * Need to check only those flags we care about.
253 */
254 oflags = oflags & (O_RDONLY | O_CREAT | O_TRUNC | O_RDWR | O_WRONLY);
255
256 /*
257 * These checks determine what flags are on with the condition that
258 * ONLY that combination is on, and no other flags are on.
259 */
260 switch (oflags) {
261 case O_RDONLY:
262 aevent = AUE_OPEN_R;
263 break;
264
265 case (O_RDONLY | O_CREAT):
266 aevent = AUE_OPEN_RC;
267 break;
268
269 case (O_RDONLY | O_CREAT | O_TRUNC):
270 aevent = AUE_OPEN_RTC;
271 break;
272
273 case (O_RDONLY | O_TRUNC):
274 aevent = AUE_OPEN_RT;
275 break;
276
277 case O_RDWR:
278 aevent = AUE_OPEN_RW;
279 break;
280
281 case (O_RDWR | O_CREAT):
282 aevent = AUE_OPEN_RWC;
283 break;
284
285 case (O_RDWR | O_CREAT | O_TRUNC):
286 aevent = AUE_OPEN_RWTC;
287 break;
288
289 case (O_RDWR | O_TRUNC):
290 aevent = AUE_OPEN_RWT;
291 break;
292
293 case O_WRONLY:
294 aevent = AUE_OPEN_W;
295 break;
296
297 case (O_WRONLY | O_CREAT):
298 aevent = AUE_OPEN_WC;
299 break;
300
301 case (O_WRONLY | O_CREAT | O_TRUNC):
302 aevent = AUE_OPEN_WTC;
303 break;
304
305 case (O_WRONLY | O_TRUNC):
306 aevent = AUE_OPEN_WT;
307 break;
308
309 default:
310 aevent = AUE_OPEN;
311 break;
312 }
313
314#if 0
315 /*
316 * Convert chatty errors to better matching events. Failures to
317 * find a file are really just attribute events -- so recast them as
318 * such.
319 *
320 * XXXAUDIT: Solaris defines that AUE_OPEN will never be returned, it
321 * is just a placeholder. However, in Darwin we return that in
322 * preference to other events. For now, comment this out as we don't
323 * have a BSM conversion routine for AUE_OPEN.
324 */
325 switch (aevent) {
326 case AUE_OPEN_R:
327 case AUE_OPEN_RT:
328 case AUE_OPEN_RW:
329 case AUE_OPEN_RWT:
330 case AUE_OPEN_W:
331 case AUE_OPEN_WT:
332 if (error == ENOENT)
333 aevent = AUE_OPEN;
334 }
335#endif
336 return (aevent);
337}
338
339/*
340 * Convert a MSGCTL command to a specific event.
341 */
342int
343audit_msgctl_to_event(int cmd)
344{
345
346 switch (cmd) {
347 case IPC_RMID:
348 return (AUE_MSGCTL_RMID);
349
350 case IPC_SET:
351 return (AUE_MSGCTL_SET);
352
353 case IPC_STAT:
354 return (AUE_MSGCTL_STAT);
355
356 default:
357 /* We will audit a bad command. */
358 return (AUE_MSGCTL);
359 }
360}
361
362/*
363 * Convert a SEMCTL command to a specific event.
364 */
365int
366audit_semctl_to_event(int cmd)
367{
368
369 switch (cmd) {
370 case GETALL:
371 return (AUE_SEMCTL_GETALL);
372
373 case GETNCNT:
374 return (AUE_SEMCTL_GETNCNT);
375
376 case GETPID:
377 return (AUE_SEMCTL_GETPID);
378
379 case GETVAL:
380 return (AUE_SEMCTL_GETVAL);
381
382 case GETZCNT:
383 return (AUE_SEMCTL_GETZCNT);
384
385 case IPC_RMID:
386 return (AUE_SEMCTL_RMID);
387
388 case IPC_SET:
389 return (AUE_SEMCTL_SET);
390
391 case SETALL:
392 return (AUE_SEMCTL_SETALL);
393
394 case SETVAL:
395 return (AUE_SEMCTL_SETVAL);
396
397 case IPC_STAT:
398 return (AUE_SEMCTL_STAT);
399
400 default:
401 /* We will audit a bad command. */
402 return (AUE_SEMCTL);
403 }
404}
405
406/*
407 * Convert a command for the auditon() system call to a audit event.
408 */
409int
410auditon_command_event(int cmd)
411{
412
413 switch(cmd) {
414 case A_GETPOLICY:
415 return (AUE_AUDITON_GPOLICY);
416
417 case A_SETPOLICY:
418 return (AUE_AUDITON_SPOLICY);
419
420 case A_GETKMASK:
421 return (AUE_AUDITON_GETKMASK);
422
423 case A_SETKMASK:
424 return (AUE_AUDITON_SETKMASK);
425
426 case A_GETQCTRL:
427 return (AUE_AUDITON_GQCTRL);
428
429 case A_SETQCTRL:
430 return (AUE_AUDITON_SQCTRL);
431
432 case A_GETCWD:
433 return (AUE_AUDITON_GETCWD);
434
435 case A_GETCAR:
436 return (AUE_AUDITON_GETCAR);
437
438 case A_GETSTAT:
439 return (AUE_AUDITON_GETSTAT);
440
441 case A_SETSTAT:
442 return (AUE_AUDITON_SETSTAT);
443
444 case A_SETUMASK:
445 return (AUE_AUDITON_SETUMASK);
446
447 case A_SETSMASK:
448 return (AUE_AUDITON_SETSMASK);
449
450 case A_GETCOND:
451 return (AUE_AUDITON_GETCOND);
452
453 case A_SETCOND:
454 return (AUE_AUDITON_SETCOND);
455
456 case A_GETCLASS:
457 return (AUE_AUDITON_GETCLASS);
458
459 case A_SETCLASS:
460 return (AUE_AUDITON_SETCLASS);
461
462 case A_GETPINFO:
463 case A_SETPMASK:
464 case A_SETFSIZE:
465 case A_GETFSIZE:
466 case A_GETPINFO_ADDR:
467 case A_GETKAUDIT:
468 case A_SETKAUDIT:
469 default:
470 return (AUE_AUDITON); /* No special record */
471 }
472}
473
474/*
475 * Create a canonical path from given path by prefixing either the root
476 * directory, or the current working directory. If the process working
477 * directory is NULL, we could use 'rootvnode' to obtain the root directory,
478 * but this results in a volfs name written to the audit log. So we will
479 * leave the filename starting with '/' in the audit log in this case.
479 *
480 * XXXRW: Since we combine two paths here, ideally a buffer of size
481 * MAXPATHLEN * 2 would be passed in.
482 */
483void
484audit_canon_path(struct thread *td, char *path, char *cpath)
485{
480 */
481void
482audit_canon_path(struct thread *td, char *path, char *cpath)
483{
486 char *bufp;
487 char *retbuf, *freebuf;
488 struct vnode *vnp;
484 struct vnode *cvnp, *rvnp;
485 char *rbuf, *fbuf, *copy;
489 struct filedesc *fdp;
486 struct filedesc *fdp;
490 int cisr, error, vfslocked;
487 struct sbuf sbf;
488 int error, cwir, locked;
491
489
492 WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
493 "audit_canon_path() at %s:%d", __FILE__, __LINE__);
490 WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "%s: at %s:%d",
491 __func__, __FILE__, __LINE__);
494
492
493 copy = path;
494 rvnp = cvnp = NULL;
495 fdp = td->td_proc->p_fd;
495 fdp = td->td_proc->p_fd;
496 bufp = path;
497 cisr = 0;
498 FILEDESC_SLOCK(fdp);
496 FILEDESC_SLOCK(fdp);
499 if (*(path) == '/') {
500 while (*(bufp) == '/')
501 bufp++; /* Skip leading '/'s. */
502 /*
503 * If no process root, or it is the same as the system root,
504 * audit the path as passed in with a single '/'.
505 */
506 if ((fdp->fd_rdir == NULL) ||
507 (fdp->fd_rdir == rootvnode)) {
508 vnp = NULL;
509 bufp--; /* Restore one '/'. */
510 } else {
511 vnp = fdp->fd_rdir; /* Use process root. */
512 vref(vnp);
513 }
514 } else {
515 vnp = fdp->fd_cdir; /* Prepend the current dir. */
516 cisr = (fdp->fd_rdir == fdp->fd_cdir);
517 vref(vnp);
518 bufp = path;
497 /*
498 * Make sure that we handle the chroot(2) case. If there is an
499 * alternate root directory, prepend it to the audited pathname.
500 */
501 if (fdp->fd_rdir != NULL && fdp->fd_rdir != rootvnode) {
502 rvnp = fdp->fd_rdir;
503 vhold(rvnp);
519 }
504 }
505 /*
506 * If the supplied path is relative, make sure we capture the current
507 * working directory so we can prepend it to the supplied relative
508 * path.
509 */
510 if (*path != '/') {
511 cvnp = fdp->fd_cdir;
512 vhold(cvnp);
513 }
514 cwir = (fdp->fd_rdir == fdp->fd_cdir);
520 FILEDESC_SUNLOCK(fdp);
515 FILEDESC_SUNLOCK(fdp);
521 if (vnp != NULL) {
516 /*
517 * NB: We require that the supplied array be at least MAXPATHLEN bytes
518 * long. If this is not the case, then we can run into serious trouble.
519 */
520 (void) sbuf_new(&sbf, cpath, MAXPATHLEN, SBUF_FIXEDLEN);
521 /*
522 * Strip leading forward slashes.
523 */
524 while (*copy == '/')
525 copy++;
526 /*
527 * Make sure we handle chroot(2) and prepend the global path to these
528 * environments.
529 *
530 * NB: vn_fullpath(9) on FreeBSD is less reliable than vn_getpath(9)
531 * on Darwin. As a result, this may need some additional attention
532 * in the future.
533 */
534 if (rvnp != NULL) {
522 /*
535 /*
523 * XXX: vn_fullpath() on FreeBSD is "less reliable" than
524 * vn_getpath() on Darwin, so this will need more attention
525 * in the future. Also, the question and string bounding
526 * here seems a bit questionable and will also require
527 * attention.
536 * Although unlikely, it is possible for filesystems to define
537 * their own VOP_LOCK, so strictly speaking, we need to
538 * conditionally pickup Giant around calls to vn_lock(9)
528 */
539 */
529 vfslocked = VFS_LOCK_GIANT(vnp->v_mount);
530 vn_lock(vnp, LK_EXCLUSIVE | LK_RETRY);
531 error = vn_fullpath(td, vnp, &retbuf, &freebuf);
532 if (error == 0) {
533 /* Copy and free buffer allocated by vn_fullpath().
534 * If the current working directory was the same as
535 * the root directory, and the path was a relative
536 * pathname, do not separate the two components with
537 * the '/' character.
538 */
539 snprintf(cpath, MAXPATHLEN, "%s%s%s", retbuf,
540 cisr ? "" : "/", bufp);
541 free(freebuf, M_TEMP);
542 } else
540 locked = VFS_LOCK_GIANT(rvnp->v_mount);
541 vn_lock(rvnp, LK_EXCLUSIVE | LK_RETRY);
542 vdrop(rvnp);
543 error = vn_fullpath_global(td, rvnp, &rbuf, &fbuf);
544 VOP_UNLOCK(rvnp, 0);
545 VFS_UNLOCK_GIANT(locked);
546 if (error) {
543 cpath[0] = '\0';
547 cpath[0] = '\0';
544 vput(vnp);
545 VFS_UNLOCK_GIANT(vfslocked);
546 } else
547 strlcpy(cpath, bufp, MAXPATHLEN);
548 if (cvnp != NULL)
549 vdrop(cvnp);
550 return;
551 }
552 (void) sbuf_cat(&sbf, rbuf);
553 free(fbuf, M_TEMP);
554 }
555 if (cvnp != NULL) {
556 locked = VFS_LOCK_GIANT(cvnp->v_mount);
557 vn_lock(cvnp, LK_EXCLUSIVE | LK_RETRY);
558 vdrop(cvnp);
559 error = vn_fullpath(td, cvnp, &rbuf, &fbuf);
560 VOP_UNLOCK(cvnp, 0);
561 VFS_UNLOCK_GIANT(locked);
562 if (error) {
563 cpath[0] = '\0';
564 return;
565 }
566 (void) sbuf_cat(&sbf, rbuf);
567 free(fbuf, M_TEMP);
568 }
569 if (cwir == 0 || (cwir != 0 && cvnp == NULL))
570 (void) sbuf_cat(&sbf, "/");
571 /*
572 * Now that we have processed any alternate root and relative path
573 * names, add the supplied pathname.
574 */
575 (void) sbuf_cat(&sbf, copy);
576 /*
577 * One or more of the previous sbuf operations could have resulted in
578 * the supplied buffer being overflowed. Check to see if this is the
579 * case.
580 */
581 if (sbuf_overflowed(&sbf) != 0) {
582 cpath[0] = '\0';
583 return;
584 }
585 sbuf_finish(&sbf);
548}
586}