]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/security/audit/audit_bsm_klib.c
This commit was generated by cvs2svn to compensate for changes in r159063,
[FreeBSD/FreeBSD.git] / sys / security / audit / audit_bsm_klib.c
1 /*
2  * Copyright (c) 1999-2005 Apple Computer, 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 Computer, 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  * $FreeBSD$
31  */
32
33 #include <sys/param.h>
34 #include <sys/fcntl.h>
35 #include <sys/filedesc.h>
36 #include <sys/libkern.h>
37 #include <sys/malloc.h>
38 #include <sys/mount.h>
39 #include <sys/proc.h>
40 #include <sys/sem.h>
41 #include <sys/syscall.h>
42 #include <sys/sysctl.h>
43 #include <sys/sysent.h>
44 #include <sys/vnode.h>
45
46 #include <bsm/audit.h>
47 #include <bsm/audit_kevents.h>
48 #include <security/audit/audit.h>
49 #include <security/audit/audit_private.h>
50
51 /*
52  * Hash table functions for the audit event number to event class mask
53  * mapping.
54  */
55 #define EVCLASSMAP_HASH_TABLE_SIZE 251
56 struct evclass_elem {
57         au_event_t event;
58         au_class_t class;
59         LIST_ENTRY(evclass_elem) entry;
60 };
61 struct evclass_list {
62         LIST_HEAD(, evclass_elem) head;
63 };
64
65 static MALLOC_DEFINE(M_AUDITEVCLASS, "audit_evclass", "Audit event class");
66 static struct mtx               evclass_mtx;
67 static struct evclass_list      evclass_hash[EVCLASSMAP_HASH_TABLE_SIZE];
68
69 /*
70  * Look up the class for an audit event in the class mapping table.
71  */
72 au_class_t
73 au_event_class(au_event_t event)
74 {
75         struct evclass_list *evcl;
76         struct evclass_elem *evc;
77         au_class_t class;
78
79         mtx_lock(&evclass_mtx);
80         evcl = &evclass_hash[event % EVCLASSMAP_HASH_TABLE_SIZE];
81         class = AU_NULL;
82         LIST_FOREACH(evc, &evcl->head, entry) {
83                 if (evc->event == event) {
84                         class = evc->class;
85                         goto out;
86                 }
87         }
88 out:
89         mtx_unlock(&evclass_mtx);
90         return (class);
91 }
92
93 /*
94  * Insert a event to class mapping. If the event already exists in the
95  * mapping, then replace the mapping with the new one.
96  *
97  * XXX There is currently no constraints placed on the number of mappings.
98  * May want to either limit to a number, or in terms of memory usage.
99  */
100 void
101 au_evclassmap_insert(au_event_t event, au_class_t class)
102 {
103         struct evclass_list *evcl;
104         struct evclass_elem *evc, *evc_new;
105
106         /*
107          * Pessimistically, always allocate storage before acquiring mutex.
108          * Free if there is already a mapping for this event.
109          */
110         evc_new = malloc(sizeof(*evc), M_AUDITEVCLASS, M_WAITOK);
111
112         mtx_lock(&evclass_mtx);
113         evcl = &evclass_hash[event % EVCLASSMAP_HASH_TABLE_SIZE];
114         LIST_FOREACH(evc, &evcl->head, entry) {
115                 if (evc->event == event) {
116                         evc->class = class;
117                         mtx_unlock(&evclass_mtx);
118                         free(evc_new, M_AUDITEVCLASS);
119                         return;
120                 }
121         }
122         evc = evc_new;
123         evc->event = event;
124         evc->class = class;
125         LIST_INSERT_HEAD(&evcl->head, evc, entry);
126         mtx_unlock(&evclass_mtx);
127 }
128
129 void
130 au_evclassmap_init(void)
131 {
132         int i;
133
134         mtx_init(&evclass_mtx, "evclass_mtx", NULL, MTX_DEF);
135         for (i = 0; i < EVCLASSMAP_HASH_TABLE_SIZE; i++)
136                 LIST_INIT(&evclass_hash[i].head);
137
138         /*
139          * Set up the initial event to class mapping for system calls.
140          *
141          * XXXRW: Really, this should walk all possible audit events, not all
142          * native ABI system calls, as there may be audit events reachable
143          * only through non-native system calls.  It also seems a shame to
144          * frob the mutex this early.
145          */
146         for (i = 0; i < SYS_MAXSYSCALL; i++) {
147                 if (sysent[i].sy_auevent != AUE_NULL)
148                         au_evclassmap_insert(sysent[i].sy_auevent, AU_NULL);
149         }
150 }
151
152 /*
153  * Check whether an event is aditable by comparing the mask of classes this
154  * event is part of against the given mask.
155  */
156 int
157 au_preselect(au_event_t event, au_mask_t *mask_p, int sorf)
158 {
159         au_class_t effmask = 0;
160         au_class_t ae_class;
161
162         if (mask_p == NULL)
163                 return (-1);
164
165         ae_class = au_event_class(event);
166
167         /*
168          * Perform the actual check of the masks against the event.
169          */
170         if (sorf & AU_PRS_SUCCESS)
171                 effmask |= (mask_p->am_success & ae_class);
172
173         if (sorf & AU_PRS_FAILURE)
174                 effmask |= (mask_p->am_failure & ae_class);
175
176         if (effmask)
177                 return (1);
178         else
179                 return (0);
180 }
181
182 /*
183  * Convert sysctl names and present arguments to events.
184  */
185 au_event_t
186 ctlname_to_sysctlevent(int name[], uint64_t valid_arg)
187 {
188
189         /* can't parse it - so return the worst case */
190         if ((valid_arg & (ARG_CTLNAME | ARG_LEN)) != (ARG_CTLNAME | ARG_LEN))
191                 return (AUE_SYSCTL);
192
193         switch (name[0]) {
194         /* non-admin "lookups" treat them special */
195         case KERN_OSTYPE:
196         case KERN_OSRELEASE:
197         case KERN_OSREV:
198         case KERN_VERSION:
199         case KERN_ARGMAX:
200         case KERN_CLOCKRATE:
201         case KERN_BOOTTIME:
202         case KERN_POSIX1:
203         case KERN_NGROUPS:
204         case KERN_JOB_CONTROL:
205         case KERN_SAVED_IDS:
206         case KERN_OSRELDATE:
207         case KERN_DUMMY:
208                 return (AUE_SYSCTL_NONADMIN);
209
210         /* only treat the changeable controls as admin */
211         case KERN_MAXVNODES:
212         case KERN_MAXPROC:
213         case KERN_MAXFILES:
214         case KERN_MAXPROCPERUID:
215         case KERN_MAXFILESPERPROC:
216         case KERN_HOSTID:
217         case KERN_SECURELVL:
218         case KERN_HOSTNAME:
219         case KERN_VNODE:
220         case KERN_PROC:
221         case KERN_FILE:
222         case KERN_PROF:
223         case KERN_NISDOMAINNAME:
224         case KERN_UPDATEINTERVAL:
225         case KERN_NTP_PLL:
226         case KERN_BOOTFILE:
227         case KERN_DUMPDEV:
228         case KERN_IPC:
229         case KERN_PS_STRINGS:
230         case KERN_USRSTACK:
231         case KERN_LOGSIGEXIT:
232         case KERN_IOV_MAX:
233         case KERN_MAXID:
234                 return ((valid_arg & ARG_VALUE) ?
235                         AUE_SYSCTL : AUE_SYSCTL_NONADMIN);
236
237         default:
238                 return (AUE_SYSCTL);
239         }
240         /* NOTREACHED */
241 }
242
243 /*
244  * Convert an open flags specifier into a specific type of open event for
245  * auditing purposes.
246  */
247 au_event_t
248 flags_and_error_to_openevent(int oflags, int error)
249 {
250         au_event_t aevent;
251
252         /*
253          * Need to check only those flags we care about.
254          */
255         oflags = oflags & (O_RDONLY | O_CREAT | O_TRUNC | O_RDWR | O_WRONLY);
256
257         /*
258          * These checks determine what flags are on with the condition that
259          * ONLY that combination is on, and no other flags are on.
260          */
261         switch (oflags) {
262         case O_RDONLY:
263                 aevent = AUE_OPEN_R;
264                 break;
265
266         case (O_RDONLY | O_CREAT):
267                 aevent = AUE_OPEN_RC;
268                 break;
269
270         case (O_RDONLY | O_CREAT | O_TRUNC):
271                 aevent = AUE_OPEN_RTC;
272                 break;
273
274         case (O_RDONLY | O_TRUNC):
275                 aevent = AUE_OPEN_RT;
276                 break;
277
278         case O_RDWR:
279                 aevent = AUE_OPEN_RW;
280                 break;
281
282         case (O_RDWR | O_CREAT):
283                 aevent = AUE_OPEN_RWC;
284                 break;
285
286         case (O_RDWR | O_CREAT | O_TRUNC):
287                 aevent = AUE_OPEN_RWTC;
288                 break;
289
290         case (O_RDWR | O_TRUNC):
291                 aevent = AUE_OPEN_RWT;
292                 break;
293
294         case O_WRONLY:
295                 aevent = AUE_OPEN_W;
296                 break;
297
298         case (O_WRONLY | O_CREAT):
299                 aevent = AUE_OPEN_WC;
300                 break;
301
302         case (O_WRONLY | O_CREAT | O_TRUNC):
303                 aevent = AUE_OPEN_WTC;
304                 break;
305
306         case (O_WRONLY | O_TRUNC):
307                 aevent = AUE_OPEN_WT;
308                 break;
309
310         default:
311                 aevent = AUE_OPEN;
312                 break;
313         }
314
315 #if 0
316         /*
317          * Convert chatty errors to better matching events.
318          * Failures to find a file are really just attribute
319          * events - so recast them as such.
320          *
321          * XXXAUDIT: Solaris defines that AUE_OPEN will never be returned, it
322          * is just a placeholder.  However, in Darwin we return that in
323          * preference to other events.  For now, comment this out as we don't
324          * have a BSM conversion routine for AUE_OPEN.
325          */
326         switch (aevent) {
327         case AUE_OPEN_R:
328         case AUE_OPEN_RT:
329         case AUE_OPEN_RW:
330         case AUE_OPEN_RWT:
331         case AUE_OPEN_W:
332         case AUE_OPEN_WT:
333                 if (error == ENOENT)
334                         aevent = AUE_OPEN;
335         }
336 #endif
337         return (aevent);
338 }
339
340 /*
341  * Convert a MSGCTL command to a specific event.
342  */
343 int
344 msgctl_to_event(int cmd)
345 {
346
347         switch (cmd) {
348         case IPC_RMID:
349                 return (AUE_MSGCTL_RMID);
350
351         case IPC_SET:
352                 return (AUE_MSGCTL_SET);
353
354         case IPC_STAT:
355                 return (AUE_MSGCTL_STAT);
356
357         default:
358                 /* We will audit a bad command */
359                 return (AUE_MSGCTL);
360         }
361 }
362
363 /*
364  * Convert a SEMCTL command to a specific event.
365  */
366 int
367 semctl_to_event(int cmd)
368 {
369
370         switch (cmd) {
371         case GETALL:
372                 return (AUE_SEMCTL_GETALL);
373
374         case GETNCNT:
375                 return (AUE_SEMCTL_GETNCNT);
376
377         case GETPID:
378                 return (AUE_SEMCTL_GETPID);
379
380         case GETVAL:
381                 return (AUE_SEMCTL_GETVAL);
382
383         case GETZCNT:
384                 return (AUE_SEMCTL_GETZCNT);
385
386         case IPC_RMID:
387                 return (AUE_SEMCTL_RMID);
388
389         case IPC_SET:
390                 return (AUE_SEMCTL_SET);
391
392         case SETALL:
393                 return (AUE_SEMCTL_SETALL);
394
395         case SETVAL:
396                 return (AUE_SEMCTL_SETVAL);
397
398         case IPC_STAT:
399                 return (AUE_SEMCTL_STAT);
400
401         default:
402                 /* We will audit a bad command */
403                 return (AUE_SEMCTL);
404         }
405 }
406
407 /*
408  * Convert a command for the auditon() system call to a audit event.
409  */
410 int
411 auditon_command_event(int cmd)
412 {
413
414         switch(cmd) {
415         case A_GETPOLICY:
416                 return (AUE_AUDITON_GPOLICY);
417
418         case A_SETPOLICY:
419                 return (AUE_AUDITON_SPOLICY);
420
421         case A_GETKMASK:
422                 return (AUE_AUDITON_GETKMASK);
423
424         case A_SETKMASK:
425                 return (AUE_AUDITON_SETKMASK);
426
427         case A_GETQCTRL:
428                 return (AUE_AUDITON_GQCTRL);
429
430         case A_SETQCTRL:
431                 return (AUE_AUDITON_SQCTRL);
432
433         case A_GETCWD:
434                 return (AUE_AUDITON_GETCWD);
435
436         case A_GETCAR:
437                 return (AUE_AUDITON_GETCAR);
438
439         case A_GETSTAT:
440                 return (AUE_AUDITON_GETSTAT);
441
442         case A_SETSTAT:
443                 return (AUE_AUDITON_SETSTAT);
444
445         case A_SETUMASK:
446                 return (AUE_AUDITON_SETUMASK);
447
448         case A_SETSMASK:
449                 return (AUE_AUDITON_SETSMASK);
450
451         case A_GETCOND:
452                 return (AUE_AUDITON_GETCOND);
453
454         case A_SETCOND:
455                 return (AUE_AUDITON_SETCOND);
456
457         case A_GETCLASS:
458                 return (AUE_AUDITON_GETCLASS);
459
460         case A_SETCLASS:
461                 return (AUE_AUDITON_SETCLASS);
462
463         case A_GETPINFO:
464         case A_SETPMASK:
465         case A_SETFSIZE:
466         case A_GETFSIZE:
467         case A_GETPINFO_ADDR:
468         case A_GETKAUDIT:
469         case A_SETKAUDIT:
470         default:
471                 return (AUE_AUDITON);   /* No special record */
472         }
473 }
474
475 /*
476  * Create a canonical path from given path by prefixing either the root
477  * directory, or the current working directory.  If the process working
478  * directory is NULL, we could use 'rootvnode' to obtain the root directoty,
479  * but this results in a volfs name written to the audit log. So we will
480  * leave the filename starting with '/' in the audit log in this case.
481  *
482  * XXXRW: Since we combine two paths here, ideally a buffer of size
483  * MAXPATHLEN * 2 would be passed in.
484  */
485 void
486 canon_path(struct thread *td, char *path, char *cpath)
487 {
488         char *bufp;
489         char *retbuf, *freebuf;
490         struct vnode *vnp;
491         struct filedesc *fdp;
492         int error, vfslocked;
493
494         fdp = td->td_proc->p_fd;
495         bufp = path;
496         FILEDESC_LOCK(fdp);
497         if (*(path) == '/') {
498                 while (*(bufp) == '/')
499                         bufp++;                 /* Skip leading '/'s. */
500                 /*
501                  * If no process root, or it is the same as the system root,
502                  * audit the path as passed in with a single '/'.
503                  */
504                 if ((fdp->fd_rdir == NULL) ||
505                     (fdp->fd_rdir == rootvnode)) {
506                         vnp = NULL;
507                         bufp--;                 /* Restore one '/'. */
508                 } else {
509                         vnp = fdp->fd_rdir;     /* Use process root. */
510                         vref(vnp);
511                 }
512         } else {
513                 vnp = fdp->fd_cdir;     /* Prepend the current dir. */
514                 vref(vnp);
515                 bufp = path;
516         }
517         FILEDESC_UNLOCK(fdp);
518         if (vnp != NULL) {
519                 /*
520                  * XXX: vn_fullpath() on FreeBSD is "less reliable" than
521                  * vn_getpath() on Darwin, so this will need more attention
522                  * in the future.  Also, the question and string bounding
523                  * here seems a bit questionable and will also require
524                  * attention.
525                  */
526                 vfslocked = VFS_LOCK_GIANT(vnp->v_mount);
527                 vn_lock(vnp, LK_EXCLUSIVE | LK_RETRY, td);
528                 error = vn_fullpath(td, vnp, &retbuf, &freebuf);
529                 if (error == 0) {
530                         /* Copy and free buffer allocated by vn_fullpath(). */
531                         snprintf(cpath, MAXPATHLEN, "%s/%s", retbuf, bufp);
532                         free(freebuf, M_TEMP);
533                 } else
534                         cpath[0] = '\0';
535                 vput(vnp);
536                 VFS_UNLOCK_GIANT(vfslocked);
537         } else {
538                 strlcpy(cpath, bufp, MAXPATHLEN);
539         }
540 }