]> 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 r175261,
[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 = 0;
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, 0);
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_class_t class, au_mask_t *mask_p, int sorf)
158 {
159         au_class_t effmask = 0;
160
161         if (mask_p == NULL)
162                 return (-1);
163
164         /*
165          * Perform the actual check of the masks against the event.
166          */
167         if (sorf & AU_PRS_SUCCESS)
168                 effmask |= (mask_p->am_success & class);
169
170         if (sorf & AU_PRS_FAILURE)
171                 effmask |= (mask_p->am_failure & class);
172
173         if (effmask)
174                 return (1);
175         else
176                 return (0);
177 }
178
179 /*
180  * Convert sysctl names and present arguments to events.
181  */
182 au_event_t
183 ctlname_to_sysctlevent(int name[], uint64_t valid_arg)
184 {
185
186         /* can't parse it - so return the worst case */
187         if ((valid_arg & (ARG_CTLNAME | ARG_LEN)) != (ARG_CTLNAME | ARG_LEN))
188                 return (AUE_SYSCTL);
189
190         switch (name[0]) {
191         /* non-admin "lookups" treat them special */
192         case KERN_OSTYPE:
193         case KERN_OSRELEASE:
194         case KERN_OSREV:
195         case KERN_VERSION:
196         case KERN_ARGMAX:
197         case KERN_CLOCKRATE:
198         case KERN_BOOTTIME:
199         case KERN_POSIX1:
200         case KERN_NGROUPS:
201         case KERN_JOB_CONTROL:
202         case KERN_SAVED_IDS:
203         case KERN_OSRELDATE:
204         case KERN_DUMMY:
205                 return (AUE_SYSCTL_NONADMIN);
206
207         /* only treat the changeable controls as admin */
208         case KERN_MAXVNODES:
209         case KERN_MAXPROC:
210         case KERN_MAXFILES:
211         case KERN_MAXPROCPERUID:
212         case KERN_MAXFILESPERPROC:
213         case KERN_HOSTID:
214         case KERN_SECURELVL:
215         case KERN_HOSTNAME:
216         case KERN_VNODE:
217         case KERN_PROC:
218         case KERN_FILE:
219         case KERN_PROF:
220         case KERN_NISDOMAINNAME:
221         case KERN_UPDATEINTERVAL:
222         case KERN_NTP_PLL:
223         case KERN_BOOTFILE:
224         case KERN_DUMPDEV:
225         case KERN_IPC:
226         case KERN_PS_STRINGS:
227         case KERN_USRSTACK:
228         case KERN_LOGSIGEXIT:
229         case KERN_IOV_MAX:
230         case KERN_MAXID:
231                 return ((valid_arg & ARG_VALUE) ?
232                         AUE_SYSCTL : AUE_SYSCTL_NONADMIN);
233
234         default:
235                 return (AUE_SYSCTL);
236         }
237         /* NOTREACHED */
238 }
239
240 /*
241  * Convert an open flags specifier into a specific type of open event for
242  * auditing purposes.
243  */
244 au_event_t
245 flags_and_error_to_openevent(int oflags, int error)
246 {
247         au_event_t aevent;
248
249         /*
250          * Need to check only those flags we care about.
251          */
252         oflags = oflags & (O_RDONLY | O_CREAT | O_TRUNC | O_RDWR | O_WRONLY);
253
254         /*
255          * These checks determine what flags are on with the condition that
256          * ONLY that combination is on, and no other flags are on.
257          */
258         switch (oflags) {
259         case O_RDONLY:
260                 aevent = AUE_OPEN_R;
261                 break;
262
263         case (O_RDONLY | O_CREAT):
264                 aevent = AUE_OPEN_RC;
265                 break;
266
267         case (O_RDONLY | O_CREAT | O_TRUNC):
268                 aevent = AUE_OPEN_RTC;
269                 break;
270
271         case (O_RDONLY | O_TRUNC):
272                 aevent = AUE_OPEN_RT;
273                 break;
274
275         case O_RDWR:
276                 aevent = AUE_OPEN_RW;
277                 break;
278
279         case (O_RDWR | O_CREAT):
280                 aevent = AUE_OPEN_RWC;
281                 break;
282
283         case (O_RDWR | O_CREAT | O_TRUNC):
284                 aevent = AUE_OPEN_RWTC;
285                 break;
286
287         case (O_RDWR | O_TRUNC):
288                 aevent = AUE_OPEN_RWT;
289                 break;
290
291         case O_WRONLY:
292                 aevent = AUE_OPEN_W;
293                 break;
294
295         case (O_WRONLY | O_CREAT):
296                 aevent = AUE_OPEN_WC;
297                 break;
298
299         case (O_WRONLY | O_CREAT | O_TRUNC):
300                 aevent = AUE_OPEN_WTC;
301                 break;
302
303         case (O_WRONLY | O_TRUNC):
304                 aevent = AUE_OPEN_WT;
305                 break;
306
307         default:
308                 aevent = AUE_OPEN;
309                 break;
310         }
311
312 #if 0
313         /*
314          * Convert chatty errors to better matching events.  Failures to
315          * find a file are really just attribute events -- so recast them as
316          * such.
317          *
318          * XXXAUDIT: Solaris defines that AUE_OPEN will never be returned, it
319          * is just a placeholder.  However, in Darwin we return that in
320          * preference to other events.  For now, comment this out as we don't
321          * have a BSM conversion routine for AUE_OPEN.
322          */
323         switch (aevent) {
324         case AUE_OPEN_R:
325         case AUE_OPEN_RT:
326         case AUE_OPEN_RW:
327         case AUE_OPEN_RWT:
328         case AUE_OPEN_W:
329         case AUE_OPEN_WT:
330                 if (error == ENOENT)
331                         aevent = AUE_OPEN;
332         }
333 #endif
334         return (aevent);
335 }
336
337 /*
338  * Convert a MSGCTL command to a specific event.
339  */
340 int
341 msgctl_to_event(int cmd)
342 {
343
344         switch (cmd) {
345         case IPC_RMID:
346                 return (AUE_MSGCTL_RMID);
347
348         case IPC_SET:
349                 return (AUE_MSGCTL_SET);
350
351         case IPC_STAT:
352                 return (AUE_MSGCTL_STAT);
353
354         default:
355                 /* We will audit a bad command. */
356                 return (AUE_MSGCTL);
357         }
358 }
359
360 /*
361  * Convert a SEMCTL command to a specific event.
362  */
363 int
364 semctl_to_event(int cmd)
365 {
366
367         switch (cmd) {
368         case GETALL:
369                 return (AUE_SEMCTL_GETALL);
370
371         case GETNCNT:
372                 return (AUE_SEMCTL_GETNCNT);
373
374         case GETPID:
375                 return (AUE_SEMCTL_GETPID);
376
377         case GETVAL:
378                 return (AUE_SEMCTL_GETVAL);
379
380         case GETZCNT:
381                 return (AUE_SEMCTL_GETZCNT);
382
383         case IPC_RMID:
384                 return (AUE_SEMCTL_RMID);
385
386         case IPC_SET:
387                 return (AUE_SEMCTL_SET);
388
389         case SETALL:
390                 return (AUE_SEMCTL_SETALL);
391
392         case SETVAL:
393                 return (AUE_SEMCTL_SETVAL);
394
395         case IPC_STAT:
396                 return (AUE_SEMCTL_STAT);
397
398         default:
399                 /* We will audit a bad command */
400                 return (AUE_SEMCTL);
401         }
402 }
403
404 /*
405  * Convert a command for the auditon() system call to a audit event.
406  */
407 int
408 auditon_command_event(int cmd)
409 {
410
411         switch(cmd) {
412         case A_GETPOLICY:
413                 return (AUE_AUDITON_GPOLICY);
414
415         case A_SETPOLICY:
416                 return (AUE_AUDITON_SPOLICY);
417
418         case A_GETKMASK:
419                 return (AUE_AUDITON_GETKMASK);
420
421         case A_SETKMASK:
422                 return (AUE_AUDITON_SETKMASK);
423
424         case A_GETQCTRL:
425                 return (AUE_AUDITON_GQCTRL);
426
427         case A_SETQCTRL:
428                 return (AUE_AUDITON_SQCTRL);
429
430         case A_GETCWD:
431                 return (AUE_AUDITON_GETCWD);
432
433         case A_GETCAR:
434                 return (AUE_AUDITON_GETCAR);
435
436         case A_GETSTAT:
437                 return (AUE_AUDITON_GETSTAT);
438
439         case A_SETSTAT:
440                 return (AUE_AUDITON_SETSTAT);
441
442         case A_SETUMASK:
443                 return (AUE_AUDITON_SETUMASK);
444
445         case A_SETSMASK:
446                 return (AUE_AUDITON_SETSMASK);
447
448         case A_GETCOND:
449                 return (AUE_AUDITON_GETCOND);
450
451         case A_SETCOND:
452                 return (AUE_AUDITON_SETCOND);
453
454         case A_GETCLASS:
455                 return (AUE_AUDITON_GETCLASS);
456
457         case A_SETCLASS:
458                 return (AUE_AUDITON_SETCLASS);
459
460         case A_GETPINFO:
461         case A_SETPMASK:
462         case A_SETFSIZE:
463         case A_GETFSIZE:
464         case A_GETPINFO_ADDR:
465         case A_GETKAUDIT:
466         case A_SETKAUDIT:
467         default:
468                 return (AUE_AUDITON);   /* No special record */
469         }
470 }
471
472 /*
473  * Create a canonical path from given path by prefixing either the root
474  * directory, or the current working directory.  If the process working
475  * directory is NULL, we could use 'rootvnode' to obtain the root directory,
476  * but this results in a volfs name written to the audit log. So we will
477  * leave the filename starting with '/' in the audit log in this case.
478  *
479  * XXXRW: Since we combine two paths here, ideally a buffer of size
480  * MAXPATHLEN * 2 would be passed in.
481  */
482 void
483 canon_path(struct thread *td, char *path, char *cpath)
484 {
485         char *bufp;
486         char *retbuf, *freebuf;
487         struct vnode *vnp;
488         struct filedesc *fdp;
489         int cisr, error, vfslocked;
490
491         WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
492             "canon_path() at %s:%d", __FILE__, __LINE__);
493
494         fdp = td->td_proc->p_fd;
495         bufp = path;
496         cisr = 0;
497         FILEDESC_SLOCK(fdp);
498         if (*(path) == '/') {
499                 while (*(bufp) == '/')
500                         bufp++;                 /* Skip leading '/'s. */
501                 /*
502                  * If no process root, or it is the same as the system root,
503                  * audit the path as passed in with a single '/'.
504                  */
505                 if ((fdp->fd_rdir == NULL) ||
506                     (fdp->fd_rdir == rootvnode)) {
507                         vnp = NULL;
508                         bufp--;                 /* Restore one '/'. */
509                 } else {
510                         vnp = fdp->fd_rdir;     /* Use process root. */
511                         vref(vnp);
512                 }
513         } else {
514                 vnp = fdp->fd_cdir;     /* Prepend the current dir. */
515                 cisr = (fdp->fd_rdir == fdp->fd_cdir);
516                 vref(vnp);
517                 bufp = path;
518         }
519         FILEDESC_SUNLOCK(fdp);
520         if (vnp != NULL) {
521                 /*
522                  * XXX: vn_fullpath() on FreeBSD is "less reliable" than
523                  * vn_getpath() on Darwin, so this will need more attention
524                  * in the future.  Also, the question and string bounding
525                  * here seems a bit questionable and will also require
526                  * attention.
527                  */
528                 vfslocked = VFS_LOCK_GIANT(vnp->v_mount);
529                 vn_lock(vnp, LK_EXCLUSIVE | LK_RETRY);
530                 error = vn_fullpath(td, vnp, &retbuf, &freebuf);
531                 if (error == 0) {
532                         /* Copy and free buffer allocated by vn_fullpath().
533                          * If the current working directory was the same as
534                          * the root directory, and the path was a relative
535                          * pathname, do not separate the two components with
536                          * the '/' character.
537                          */
538                         snprintf(cpath, MAXPATHLEN, "%s%s%s", retbuf,
539                             cisr ? "" : "/", bufp);
540                         free(freebuf, M_TEMP);
541                 } else
542                         cpath[0] = '\0';
543                 vput(vnp);
544                 VFS_UNLOCK_GIANT(vfslocked);
545         } else
546                 strlcpy(cpath, bufp, MAXPATHLEN);
547 }