/[gentoo-src]/sandbox/libsandbox.c
Gentoo

Contents of /sandbox/libsandbox.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.25 - (hide annotations) (download) (as text)
Sun Jun 5 07:45:28 2005 UTC (9 years, 4 months ago) by vapier
Branch: MAIN
CVS Tags: HEAD
Changes since 1.24: +12 -13 lines
File MIME type: text/x-csrc
whitespace tweaks

1 ferringb 1.1 /*
2     * Path sandbox for the gentoo linux portage package system, initially
3     * based on the ROCK Linux Wrapper for getting a list of created files
4     *
5     * to integrate with bash, bash should have been built like this
6     *
7     * ./configure --prefix=<prefix> --host=<host> --without-gnu-malloc
8     *
9     * it's very important that the --enable-static-link option is NOT specified
10     *
11     * Copyright (C) 2001 Geert Bevin, Uwyn, http://www.uwyn.com
12     * Distributed under the terms of the GNU General Public License, v2 or later
13     * Author : Geert Bevin <gbevin@uwyn.com>
14     *
15     * Post Bevin leaving Gentoo ranks:
16     * --------------------------------
17     * Ripped out all the wrappers, and implemented those of InstallWatch.
18     * Losts of cleanups and bugfixes. Implement a execve that forces $LIBSANDBOX
19     * in $LD_PRELOAD. Reformat the whole thing to look somewhat like the reworked
20     * sandbox.c from Brad House <brad@mainstreetsoftworks.com>.
21     *
22     * Martin Schlemmer <azarah@gentoo.org> (18 Aug 2002)
23     *
24     * Partly Copyright (C) 1998-9 Pancrazio `Ezio' de Mauro <p@demauro.net>,
25     * as some of the InstallWatch code was used.
26     *
27     *
28 vapier 1.25 * $Header: /var/cvsroot/gentoo-src/sandbox/libsandbox.c,v 1.24 2005/05/13 15:23:28 azarah Exp $
29 ferringb 1.1 *
30     */
31    
32     /* Uncomment below to enable wrapping of mknod().
33     * This is broken currently. */
34     /* #define WRAP_MKNOD 1 */
35    
36     /* Uncomment below to enable the use of strtok_r(). */
37     #define REENTRANT_STRTOK 1
38    
39     /* Uncomment below to enable memory debugging. */
40     /* #define SB_MEM_DEBUG 1 */
41    
42     #define open xxx_open
43     #define open64 xxx_open64
44    
45     /* Wrapping mknod, do not have any effect, and
46     * wrapping __xmknod causes calls to it to segfault
47     */
48     #ifdef WRAP_MKNOD
49     # define __xmknod xxx___xmknod
50     #endif
51    
52     #include <dirent.h>
53     #include <dlfcn.h>
54     #include <errno.h>
55     #include <fcntl.h>
56 azarah 1.10 #include <libgen.h>
57 ferringb 1.1 #include <stdarg.h>
58     #include <stdio.h>
59     #include <stdlib.h>
60     #include <string.h>
61     #include <sys/file.h>
62     #include <sys/stat.h>
63     #include <sys/types.h>
64     #include <sys/param.h>
65     #include <unistd.h>
66     #include <utime.h>
67 ferringb 1.4 #include "config.h"
68 ferringb 1.5 #include "localdecls.h"
69 azarah 1.7 #include "symbols.h"
70 ferringb 1.1
71     #ifdef SB_MEM_DEBUG
72     # include <mcheck.h>
73     #endif
74    
75     #ifdef WRAP_MKNOD
76     # undef __xmknod
77     #endif
78    
79     #undef open
80     #undef open64
81    
82 ferringb 1.3 //#include "localdecls.h"
83 ferringb 1.1 #include "sandbox.h"
84    
85     /* Macros to check if a function should be executed */
86     #define FUNCTION_SANDBOX_SAFE(func, path) \
87 azarah 1.8 ((0 == is_sandbox_on()) || (1 == before_syscall(func, path)))
88 ferringb 1.1
89     #define FUNCTION_SANDBOX_SAFE_INT(func, path, flags) \
90 azarah 1.8 ((0 == is_sandbox_on()) || (1 == before_syscall_open_int(func, path, flags)))
91 ferringb 1.1
92     #define FUNCTION_SANDBOX_SAFE_CHAR(func, path, mode) \
93 azarah 1.8 ((0 == is_sandbox_on()) || (1 == before_syscall_open_char(func, path, mode)))
94 ferringb 1.1
95     /* Macro to check if a wrapper is defined, if not
96     * then try to resolve it again. */
97     #define check_dlsym(name) \
98     { \
99 vapier 1.25 int old_errno=errno; \
100     if (!true_ ## name) \
101     true_ ## name = get_dlsym(symname_ ## name, symver_ ## name); \
102     errno=old_errno; \
103 ferringb 1.1 }
104    
105     /* Macro to check if we could canonicalize a path. It returns an integer on
106     * failure. */
107     #define canonicalize_int(path, resolved_path) \
108     { \
109 vapier 1.25 if (0 != canonicalize(path, resolved_path)) \
110     return -1; \
111 ferringb 1.1 }
112    
113     /* Macro to check if we could canonicalize a path. It returns a NULL pointer on
114     * failure. */
115     #define canonicalize_ptr(path, resolved_path) \
116     { \
117 vapier 1.25 if (0 != canonicalize(path, resolved_path)) \
118     return NULL; \
119 ferringb 1.1 }
120    
121 azarah 1.22 static char sandbox_lib[SB_PATH_MAX];
122 ferringb 1.1 //static char sandbox_pids_file[255];
123     static char *sandbox_pids_file;
124    
125     typedef struct {
126     int show_access_violation;
127     char **deny_prefixes;
128     int num_deny_prefixes;
129     char **read_prefixes;
130     int num_read_prefixes;
131     char **write_prefixes;
132     int num_write_prefixes;
133     char **predict_prefixes;
134     int num_predict_prefixes;
135     char **write_denied_prefixes;
136     int num_write_denied_prefixes;
137     } sbcontext_t;
138    
139 azarah 1.18 static sbcontext_t sbcontext;
140 ferringb 1.21 static char **cached_env_vars;
141 azarah 1.19 static int sb_init = 0;
142    
143 azarah 1.12 void __attribute__ ((constructor)) libsb_init(void);
144     void __attribute__ ((destructor)) libsb_fini(void);
145 azarah 1.7
146 ferringb 1.1 /* glibc modified realpath() functions */
147 azarah 1.15 static char *erealpath(const char *, char *);
148 ferringb 1.1 /* glibc modified getcwd() functions */
149 azarah 1.7 static char *egetcwd(char *, size_t);
150 ferringb 1.1
151     static void init_wrappers(void);
152 azarah 1.7 static void *get_dlsym(const char *, const char *);
153 ferringb 1.1 static int canonicalize(const char *, char *);
154 azarah 1.18 static char *filter_path(const char *, int);
155     static int check_access(sbcontext_t *, const char *, const char *, const char *);
156 ferringb 1.1 static int check_syscall(sbcontext_t *, const char *, const char *);
157     static int before_syscall(const char *, const char *);
158     static int before_syscall_open_int(const char *, const char *, int);
159     static int before_syscall_open_char(const char *, const char *, const char *);
160     static void clean_env_entries(char ***, int *);
161     static void init_context(sbcontext_t *);
162 ferringb 1.21 static void init_env_entries(char ***, int *, const char *, const char *, int);
163 ferringb 1.1 static int is_sandbox_on();
164     static int is_sandbox_pid();
165    
166     /* Wrapped functions */
167    
168     extern int chmod(const char *, mode_t);
169     static int (*true_chmod) (const char *, mode_t);
170     extern int chown(const char *, uid_t, gid_t);
171     static int (*true_chown) (const char *, uid_t, gid_t);
172     extern int creat(const char *, mode_t);
173     static int (*true_creat) (const char *, mode_t);
174     extern FILE *fopen(const char *, const char *);
175     static FILE *(*true_fopen) (const char *, const char *);
176     extern int lchown(const char *, uid_t, gid_t);
177     static int (*true_lchown) (const char *, uid_t, gid_t);
178     extern int link(const char *, const char *);
179     static int (*true_link) (const char *, const char *);
180     extern int mkdir(const char *, mode_t);
181     static int (*true_mkdir) (const char *, mode_t);
182     extern DIR *opendir(const char *);
183     static DIR *(*true_opendir) (const char *);
184     #ifdef WRAP_MKNOD
185     extern int __xmknod(const char *, mode_t, dev_t);
186     static int (*true___xmknod) (const char *, mode_t, dev_t);
187     #endif
188     extern int open(const char *, int, ...);
189     static int (*true_open) (const char *, int, ...);
190     extern int rename(const char *, const char *);
191     static int (*true_rename) (const char *, const char *);
192     extern int rmdir(const char *);
193     static int (*true_rmdir) (const char *);
194     extern int symlink(const char *, const char *);
195     static int (*true_symlink) (const char *, const char *);
196     extern int truncate(const char *, TRUNCATE_T);
197     static int (*true_truncate) (const char *, TRUNCATE_T);
198     extern int unlink(const char *);
199     static int (*true_unlink) (const char *);
200    
201     #if (GLIBC_MINOR >= 1)
202    
203     extern int creat64(const char *, __mode_t);
204     static int (*true_creat64) (const char *, __mode_t);
205     extern FILE *fopen64(const char *, const char *);
206     static FILE *(*true_fopen64) (const char *, const char *);
207     extern int open64(const char *, int, ...);
208     static int (*true_open64) (const char *, int, ...);
209     extern int truncate64(const char *, __off64_t);
210     static int (*true_truncate64) (const char *, __off64_t);
211    
212     #endif
213    
214     extern int execve(const char *filename, char *const argv[], char *const envp[]);
215     static int (*true_execve) (const char *, char *const[], char *const[]);
216    
217     /*
218     * Initialize the shabang
219     */
220    
221 azarah 1.7 static void init_wrappers(void)
222     {
223     check_dlsym(chmod);
224     check_dlsym(chown);
225     check_dlsym(creat);
226     check_dlsym(fopen);
227     check_dlsym(lchown);
228     check_dlsym(link);
229     check_dlsym(mkdir);
230     check_dlsym(opendir);
231     #ifdef WRAP_MKNOD
232     check_dlsym(__xmknod);
233     #endif
234     check_dlsym(open);
235     check_dlsym(rename);
236     check_dlsym(rmdir);
237     check_dlsym(symlink);
238     check_dlsym(truncate);
239     check_dlsym(unlink);
240    
241     #if (GLIBC_MINOR >= 1)
242     check_dlsym(creat64);
243     check_dlsym(fopen64);
244     check_dlsym(open64);
245     check_dlsym(truncate64);
246     #endif
247    
248     check_dlsym(execve);
249     }
250    
251     static void *libc_handle = NULL;
252    
253     static void *get_dlsym(const char *symname, const char *symver)
254 ferringb 1.1 {
255 azarah 1.7 void *symaddr = NULL;
256 ferringb 1.1
257 azarah 1.7 if (NULL == libc_handle) {
258 ferringb 1.1 #ifdef BROKEN_RTLD_NEXT
259 azarah 1.8 libc_handle = dlopen(LIBC_VERSION, RTLD_LAZY);
260 azarah 1.7 if (!libc_handle) {
261     printf("libsandbox.so: Can't dlopen libc: %s\n", dlerror());
262     abort();
263     }
264 ferringb 1.1 #else
265 azarah 1.8 libc_handle = RTLD_NEXT;
266 ferringb 1.1 #endif
267 azarah 1.7 }
268 ferringb 1.1
269 azarah 1.7 if (NULL == symver)
270     symaddr = dlsym(libc_handle, symname);
271     else
272     symaddr = dlvsym(libc_handle, symname, symver);
273     if (!symaddr) {
274     printf("libsandbox.so: Can't resolve %s: %s\n", symname, dlerror());
275     abort();
276     }
277 ferringb 1.1
278 azarah 1.7 return symaddr;
279 ferringb 1.1 }
280    
281 azarah 1.10
282 azarah 1.12 void __attribute__ ((destructor)) libsb_fini(void)
283 ferringb 1.1 {
284 ferringb 1.21 int x;
285     if(NULL != cached_env_vars) {
286     for(x=0; x < 4; x++) {
287     if(NULL != cached_env_vars[x])
288     free(cached_env_vars[x]);
289     }
290     free(cached_env_vars);
291     }
292 azarah 1.18 clean_env_entries(&(sbcontext.deny_prefixes),
293     &(sbcontext.num_deny_prefixes));
294     clean_env_entries(&(sbcontext.read_prefixes),
295     &(sbcontext.num_read_prefixes));
296     clean_env_entries(&(sbcontext.write_prefixes),
297     &(sbcontext.num_write_prefixes));
298     clean_env_entries(&(sbcontext.predict_prefixes),
299     &(sbcontext.num_predict_prefixes));
300    
301 azarah 1.8 free(sandbox_pids_file);
302 ferringb 1.1 }
303    
304 azarah 1.12 void __attribute__ ((constructor)) libsb_init(void)
305 ferringb 1.1 {
306     int old_errno = errno;
307 azarah 1.22 char tmp_dir[SB_PATH_MAX];
308 ferringb 1.1
309     #ifdef SB_MEM_DEBUG
310     mtrace();
311     #endif
312    
313     init_wrappers();
314    
315     /* Get the path and name to this library */
316 azarah 1.22 snprintf(sandbox_lib, SB_PATH_MAX, "%s", get_sandbox_lib("/"));
317    
318 azarah 1.24 if (-1 == get_tmp_dir(tmp_dir))
319 azarah 1.22 snprintf(tmp_dir, SB_PATH_MAX, "%s", TMPDIR);
320 ferringb 1.1
321     /* Generate sandbox pids-file path */
322 azarah 1.22 sandbox_pids_file = get_sandbox_pids_file(tmp_dir);
323 ferringb 1.1
324 ferringb 1.21 // sb_init = 1;
325 azarah 1.19
326 ferringb 1.1 errno = old_errno;
327     }
328    
329 azarah 1.8 static int canonicalize(const char *path, char *resolved_path)
330 ferringb 1.1 {
331     int old_errno = errno;
332     char *retval;
333    
334     *resolved_path = '\0';
335    
336     /* If path == NULL, return or we get a segfault */
337     if (NULL == path) {
338     errno = EINVAL;
339     return -1;
340     }
341    
342     /* Do not try to resolve an empty path */
343     if ('\0' == path[0]) {
344     errno = old_errno;
345     return 0;
346     }
347    
348     retval = erealpath(path, resolved_path);
349    
350 azarah 1.10 if ((NULL == retval) && (path[0] != '/')) {
351 ferringb 1.1 /* The path could not be canonicalized, append it
352     * to the current working directory if it was not
353     * an absolute path
354     */
355     if (errno == ENAMETOOLONG)
356     return -1;
357    
358     egetcwd(resolved_path, SB_PATH_MAX - 2);
359     strcat(resolved_path, "/");
360     strncat(resolved_path, path, SB_PATH_MAX - 1);
361    
362 azarah 1.10 if (NULL == erealpath(resolved_path, resolved_path)) {
363 ferringb 1.1 if (errno == ENAMETOOLONG) {
364     /* The resolved path is too long for the buffer to hold */
365     return -1;
366     } else {
367     /* Whatever it resolved, is not a valid path */
368     errno = ENOENT;
369     return -1;
370     }
371     }
372    
373 azarah 1.10 } else if ((NULL == retval) && (path[0] == '/')) {
374 ferringb 1.1 /* Whatever it resolved, is not a valid path */
375     errno = ENOENT;
376     return -1;
377     }
378    
379     errno = old_errno;
380     return 0;
381     }
382    
383 azarah 1.18 static char *filter_path(const char *path, int follow_link)
384     {
385     struct stat st;
386     int old_errno = errno;
387     char *tmp_str1, *tmp_str2;
388     char *dname, *bname;
389     char *filtered_path;
390    
391     if (NULL == path)
392     return NULL;
393    
394     filtered_path = malloc(SB_PATH_MAX * sizeof(char));
395     if (NULL == filtered_path)
396     return NULL;
397    
398     if (0 == follow_link) {
399     if (-1 == canonicalize(path, filtered_path))
400     goto error;
401     } else {
402     /* Basically we get the realpath which should resolve symlinks,
403     * etc. If that fails (might not exist), we try to get the
404     * realpath of the parent directory, as that should hopefully
405     * exist. If all else fails, just go with canonicalize */
406     if (NULL == realpath(path, filtered_path)) {
407     tmp_str1 = strndup(path, SB_PATH_MAX - 1);
408     if (NULL == tmp_str1)
409     goto error;
410    
411     dname = dirname(tmp_str1);
412    
413     /* If not, then check if we can resolve the
414     * parent directory */
415     if (NULL == realpath(dname, filtered_path)) {
416     /* Fall back to canonicalize */
417     if (-1 == canonicalize(path, filtered_path)) {
418     free(tmp_str1);
419     goto error;
420     }
421     } else {
422     /* OK, now add the basename to keep our access
423     * checking happy (don't want '/usr/lib' if we
424     * tried to do something with non-existing
425     * file '/usr/lib/cf*' ...) */
426     tmp_str2 = strndup(path, SB_PATH_MAX - 1);
427     if (NULL == tmp_str2) {
428     free(tmp_str1);
429     goto error;
430     }
431    
432     bname = basename(tmp_str2);
433     if (filtered_path[strlen(filtered_path) - 1] != '/')
434     strncat(filtered_path, "/",
435     SB_PATH_MAX - strlen(filtered_path));
436     strncat(filtered_path, bname,
437     SB_PATH_MAX - strlen(filtered_path));
438     free(tmp_str2);
439     }
440    
441     free(tmp_str1);
442     }
443     }
444    
445     errno = old_errno;
446    
447     return filtered_path;
448     error:
449     free(filtered_path);
450     return NULL;
451     }
452    
453 ferringb 1.1 /*
454     * Wrapper Functions
455     */
456    
457 azarah 1.7 int chmod(const char *path, mode_t mode)
458 ferringb 1.1 {
459     int result = -1;
460     char canonic[SB_PATH_MAX];
461    
462     canonicalize_int(path, canonic);
463    
464     if FUNCTION_SANDBOX_SAFE
465     ("chmod", canonic) {
466     check_dlsym(chmod);
467     result = true_chmod(path, mode);
468     }
469    
470     return result;
471     }
472    
473 azarah 1.8 int chown(const char *path, uid_t owner, gid_t group)
474 ferringb 1.1 {
475     int result = -1;
476     char canonic[SB_PATH_MAX];
477    
478     canonicalize_int(path, canonic);
479    
480     if FUNCTION_SANDBOX_SAFE
481     ("chown", canonic) {
482     check_dlsym(chown);
483     result = true_chown(path, owner, group);
484     }
485    
486     return result;
487     }
488    
489 azarah 1.8 int creat(const char *pathname, mode_t mode)
490 ferringb 1.1 {
491     /* Is it a system call? */
492     int result = -1;
493     char canonic[SB_PATH_MAX];
494    
495     canonicalize_int(pathname, canonic);
496    
497     if FUNCTION_SANDBOX_SAFE
498     ("creat", canonic) {
499     check_dlsym(open);
500     result = true_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
501     }
502    
503     return result;
504     }
505    
506 azarah 1.8 FILE *fopen(const char *pathname, const char *mode)
507 ferringb 1.1 {
508     FILE *result = NULL;
509     char canonic[SB_PATH_MAX];
510    
511     canonicalize_ptr(pathname, canonic);
512    
513     if FUNCTION_SANDBOX_SAFE_CHAR
514     ("fopen", canonic, mode) {
515     check_dlsym(fopen);
516     result = true_fopen(pathname, mode);
517     }
518    
519     return result;
520     }
521    
522 azarah 1.8 int lchown(const char *path, uid_t owner, gid_t group)
523 ferringb 1.1 {
524     int result = -1;
525     char canonic[SB_PATH_MAX];
526    
527     canonicalize_int(path, canonic);
528    
529     if FUNCTION_SANDBOX_SAFE
530     ("lchown", canonic) {
531     check_dlsym(lchown);
532     result = true_lchown(path, owner, group);
533     }
534    
535     return result;
536     }
537    
538 azarah 1.8 int link(const char *oldpath, const char *newpath)
539 ferringb 1.1 {
540     int result = -1;
541     char old_canonic[SB_PATH_MAX], new_canonic[SB_PATH_MAX];
542    
543     canonicalize_int(oldpath, old_canonic);
544     canonicalize_int(newpath, new_canonic);
545    
546     if FUNCTION_SANDBOX_SAFE
547     ("link", new_canonic) {
548     check_dlsym(link);
549     result = true_link(oldpath, newpath);
550     }
551    
552     return result;
553     }
554    
555 azarah 1.8 int mkdir(const char *pathname, mode_t mode)
556 ferringb 1.1 {
557 azarah 1.10 struct stat st;
558 ferringb 1.1 int result = -1, my_errno = errno;
559     char canonic[SB_PATH_MAX];
560    
561     canonicalize_int(pathname, canonic);
562    
563 azarah 1.10 /* XXX: Hack to prevent errors if the directory exist,
564     * and are not writable - we rather return EEXIST rather
565     * than failing */
566 ferringb 1.1 if (0 == lstat(canonic, &st)) {
567     errno = EEXIST;
568 azarah 1.8 return -1;
569 ferringb 1.1 }
570     errno = my_errno;
571    
572     if FUNCTION_SANDBOX_SAFE
573     ("mkdir", canonic) {
574     check_dlsym(mkdir);
575     result = true_mkdir(pathname, mode);
576     }
577    
578     return result;
579     }
580    
581 azarah 1.8 DIR *opendir(const char *name)
582 ferringb 1.1 {
583     DIR *result = NULL;
584     char canonic[SB_PATH_MAX];
585    
586     canonicalize_ptr(name, canonic);
587    
588     if FUNCTION_SANDBOX_SAFE
589     ("opendir", canonic) {
590     check_dlsym(opendir);
591     result = true_opendir(name);
592     }
593    
594     return result;
595     }
596    
597     #ifdef WRAP_MKNOD
598    
599 azarah 1.8 int __xmknod(const char *pathname, mode_t mode, dev_t dev)
600 ferringb 1.1 {
601     int result = -1;
602     char canonic[SB_PATH_MAX];
603    
604     canonicalize_int(pathname, canonic);
605    
606     if FUNCTION_SANDBOX_SAFE
607     ("__xmknod", canonic) {
608     check_dlsym(__xmknod);
609     result = true___xmknod(pathname, mode, dev);
610     }
611    
612     return result;
613     }
614    
615     #endif
616    
617 azarah 1.10 /* Eventually, there is a third parameter: it's mode_t mode */
618 azarah 1.8 int open(const char *pathname, int flags, ...)
619 ferringb 1.1 {
620     va_list ap;
621     mode_t mode = 0;
622     int result = -1;
623     char canonic[SB_PATH_MAX];
624    
625     if (flags & O_CREAT) {
626     va_start(ap, flags);
627     mode = va_arg(ap, mode_t);
628     va_end(ap);
629     }
630    
631     canonicalize_int(pathname, canonic);
632    
633     if FUNCTION_SANDBOX_SAFE_INT
634     ("open", canonic, flags) {
635     check_dlsym(open);
636     result = true_open(pathname, flags, mode);
637     }
638    
639     return result;
640     }
641    
642 azarah 1.8 int rename(const char *oldpath, const char *newpath)
643 ferringb 1.1 {
644     int result = -1;
645     char old_canonic[SB_PATH_MAX], new_canonic[SB_PATH_MAX];
646    
647     canonicalize_int(oldpath, old_canonic);
648     canonicalize_int(newpath, new_canonic);
649    
650     if (FUNCTION_SANDBOX_SAFE("rename", old_canonic) &&
651 azarah 1.8 FUNCTION_SANDBOX_SAFE("rename", new_canonic)) {
652 ferringb 1.1 check_dlsym(rename);
653     result = true_rename(oldpath, newpath);
654     }
655    
656     return result;
657     }
658    
659 azarah 1.8 int rmdir(const char *pathname)
660 ferringb 1.1 {
661     int result = -1;
662     char canonic[SB_PATH_MAX];
663    
664     canonicalize_int(pathname, canonic);
665    
666     if FUNCTION_SANDBOX_SAFE
667     ("rmdir", canonic) {
668     check_dlsym(rmdir);
669     result = true_rmdir(pathname);
670     }
671    
672     return result;
673     }
674    
675 azarah 1.8 int symlink(const char *oldpath, const char *newpath)
676 ferringb 1.1 {
677     int result = -1;
678     char old_canonic[SB_PATH_MAX], new_canonic[SB_PATH_MAX];
679    
680     canonicalize_int(oldpath, old_canonic);
681     canonicalize_int(newpath, new_canonic);
682    
683     if FUNCTION_SANDBOX_SAFE
684     ("symlink", new_canonic) {
685     check_dlsym(symlink);
686     result = true_symlink(oldpath, newpath);
687     }
688    
689     return result;
690     }
691    
692 azarah 1.8 int truncate(const char *path, TRUNCATE_T length)
693 ferringb 1.1 {
694     int result = -1;
695     char canonic[SB_PATH_MAX];
696    
697     canonicalize_int(path, canonic);
698    
699     if FUNCTION_SANDBOX_SAFE
700     ("truncate", canonic) {
701     check_dlsym(truncate);
702     result = true_truncate(path, length);
703     }
704    
705     return result;
706     }
707    
708 azarah 1.8 int unlink(const char *pathname)
709 ferringb 1.1 {
710     int result = -1;
711     char canonic[SB_PATH_MAX];
712    
713     canonicalize_int(pathname, canonic);
714    
715 azarah 1.10 /* XXX: Hack to make sure sandboxed process cannot remove
716     * a device node, bug #79836. */
717 azarah 1.16 if ((0 == strncmp(canonic, "/dev/null", 9)) ||
718     (0 == strncmp(canonic, "/dev/zero", 9))) {
719 azarah 1.9 errno = EACCES;
720     return result;
721     }
722    
723 ferringb 1.1 if FUNCTION_SANDBOX_SAFE
724     ("unlink", canonic) {
725     check_dlsym(unlink);
726     result = true_unlink(pathname);
727     }
728    
729     return result;
730     }
731    
732     #if (GLIBC_MINOR >= 1)
733    
734 azarah 1.8 int creat64(const char *pathname, __mode_t mode)
735 ferringb 1.1 {
736     /* Is it a system call? */
737     int result = -1;
738     char canonic[SB_PATH_MAX];
739    
740     canonicalize_int(pathname, canonic);
741    
742     if FUNCTION_SANDBOX_SAFE
743     ("creat64", canonic) {
744     check_dlsym(open64);
745     result = true_open64(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
746     }
747    
748     return result;
749     }
750    
751 azarah 1.8 FILE *fopen64(const char *pathname, const char *mode)
752 ferringb 1.1 {
753     FILE *result = NULL;
754     char canonic[SB_PATH_MAX];
755    
756     canonicalize_ptr(pathname, canonic);
757    
758     if FUNCTION_SANDBOX_SAFE_CHAR
759     ("fopen64", canonic, mode) {
760     check_dlsym(fopen64);
761 azarah 1.8 result = true_fopen64(pathname, mode);
762 ferringb 1.1 }
763    
764     return result;
765     }
766    
767 azarah 1.10 /* Eventually, there is a third parameter: it's mode_t mode */
768 azarah 1.8 int open64(const char *pathname, int flags, ...)
769 ferringb 1.1 {
770     va_list ap;
771     mode_t mode = 0;
772     int result = -1;
773     char canonic[SB_PATH_MAX];
774    
775     if (flags & O_CREAT) {
776     va_start(ap, flags);
777     mode = va_arg(ap, mode_t);
778     va_end(ap);
779     }
780    
781     canonicalize_int(pathname, canonic);
782    
783     if FUNCTION_SANDBOX_SAFE_INT
784     ("open64", canonic, flags) {
785     check_dlsym(open64);
786     result = true_open64(pathname, flags, mode);
787     }
788    
789     return result;
790     }
791    
792 azarah 1.8 int truncate64(const char *path, __off64_t length)
793 ferringb 1.1 {
794     int result = -1;
795     char canonic[SB_PATH_MAX];
796    
797     canonicalize_int(path, canonic);
798    
799     if FUNCTION_SANDBOX_SAFE
800     ("truncate64", canonic) {
801     check_dlsym(truncate64);
802     result = true_truncate64(path, length);
803     }
804    
805     return result;
806     }
807    
808 azarah 1.8 #endif /* GLIBC_MINOR >= 1 */
809 ferringb 1.1
810     /*
811     * Exec Wrappers
812     */
813    
814 azarah 1.8 int execve(const char *filename, char *const argv[], char *const envp[])
815 ferringb 1.1 {
816     int old_errno = errno;
817     int result = -1;
818     int count = 0;
819     int env_len = 0;
820     char canonic[SB_PATH_MAX];
821     char **my_env = NULL;
822     int kill_env = 1;
823     /* We limit the size LD_PRELOAD can be here, but it should be enough */
824     char tmp_str[4096];
825    
826     canonicalize_int(filename, canonic);
827    
828     if FUNCTION_SANDBOX_SAFE
829     ("execve", canonic) {
830     while (envp[count] != NULL) {
831 azarah 1.7 /* Check if we do not have to do anything */
832 azarah 1.23 if (strstr(envp[count], LD_PRELOAD_EQ) == envp[count]) {
833 ferringb 1.1 if (NULL != strstr(envp[count], sandbox_lib)) {
834 azarah 1.7 my_env = (char **)envp;
835 ferringb 1.1 kill_env = 0;
836 azarah 1.7 goto end_loop;
837     }
838     }
839    
840     /* If LD_PRELOAD is set and sandbox_lib not in it */
841 azarah 1.23 if (((strstr(envp[count], LD_PRELOAD_EQ) == envp[count]) &&
842 azarah 1.7 (NULL == strstr(envp[count], sandbox_lib))) ||
843     /* Or LD_PRELOAD is not set, and this is the last loop */
844 azarah 1.23 ((strstr(envp[count], LD_PRELOAD_EQ) != envp[count]) &&
845 azarah 1.7 (NULL == envp[count + 1]))) {
846 azarah 1.8 int i = 0;
847 azarah 1.7 int add_ldpreload = 0;
848     const int max_envp_len = strlen(envp[count]) + strlen(sandbox_lib) + 1;
849 ferringb 1.1
850 azarah 1.8 /* Fail safe ... */
851     if (max_envp_len > 4096) {
852     fprintf(stderr, "sandbox: max_envp_len too big!\n");
853     errno = ENOMEM;
854     return result;
855     }
856 ferringb 1.1
857 azarah 1.8 /* Calculate envp size */
858 azarah 1.7 my_env = (char **)envp;
859 azarah 1.8 do
860 azarah 1.7 env_len++;
861     while (NULL != *my_env++);
862 ferringb 1.1
863 azarah 1.7 /* Should we add LD_PRELOAD ? */
864 azarah 1.23 if (strstr(envp[count], LD_PRELOAD_EQ) != envp[count])
865 azarah 1.7 add_ldpreload = 1;
866    
867     my_env = (char **)calloc(env_len + add_ldpreload, sizeof(char *));
868 azarah 1.8 if (NULL == my_env) {
869     errno = ENOMEM;
870     return result;
871     }
872     /* Copy envp to my_env */
873     do
874 azarah 1.7 /* Leave a space for LD_PRELOAD if needed */
875     my_env[i + add_ldpreload] = envp[i];
876     while (NULL != envp[i++]);
877 ferringb 1.1
878 azarah 1.7 /* Add 'LD_PRELOAD=' to the beginning of our new string */
879 azarah 1.23 snprintf(tmp_str, max_envp_len, "%s%s", LD_PRELOAD_EQ, sandbox_lib);
880 ferringb 1.1
881 azarah 1.8 /* LD_PRELOAD already have variables other than sandbox_lib,
882     * thus we have to add sandbox_lib seperated via a whitespace. */
883 azarah 1.7 if (0 == add_ldpreload) {
884     snprintf(&(tmp_str[strlen(tmp_str)]),
885     max_envp_len - strlen(tmp_str) + 1, " %s",
886 azarah 1.23 &(envp[count][strlen(LD_PRELOAD_EQ)]));
887 azarah 1.8 }
888 ferringb 1.1
889 azarah 1.8 /* Valid string? */
890     tmp_str[max_envp_len] = '\0';
891 ferringb 1.1
892 azarah 1.8 /* Ok, replace my_env[count] with our version that contains
893     * sandbox_lib ... */
894 azarah 1.7 if (1 == add_ldpreload)
895     /* We reserved a space for LD_PRELOAD above */
896     my_env[0] = tmp_str;
897     else
898 ferringb 1.1 my_env[count] = tmp_str;
899    
900 azarah 1.7 goto end_loop;
901 ferringb 1.1 }
902     count++;
903     }
904    
905 vapier 1.25 end_loop:
906 ferringb 1.1 errno = old_errno;
907     check_dlsym(execve);
908     result = true_execve(filename, argv, my_env);
909     old_errno = errno;
910    
911     if (my_env && kill_env) {
912 azarah 1.7 free(tmp_str);
913 ferringb 1.1 free(my_env);
914     my_env = NULL;
915     }
916 azarah 1.8 }
917 ferringb 1.1
918     errno = old_errno;
919    
920     return result;
921     }
922    
923     /*
924     * Internal Functions
925     */
926    
927     #if (GLIBC_MINOR == 1)
928    
929     /* This hack is needed for glibc 2.1.1 (and others?)
930     * (not really needed, but good example) */
931     extern int fclose(FILE *);
932     static int (*true_fclose) (FILE *) = NULL;
933 azarah 1.8 int fclose(FILE * file)
934 ferringb 1.1 {
935     int result = -1;
936    
937     check_dlsym(fclose);
938     result = true_fclose(file);
939    
940     return result;
941     }
942    
943 azarah 1.8 #endif /* GLIBC_MINOR == 1 */
944 ferringb 1.1
945 azarah 1.8 static void init_context(sbcontext_t * context)
946 ferringb 1.1 {
947     context->show_access_violation = 1;
948     context->deny_prefixes = NULL;
949     context->num_deny_prefixes = 0;
950     context->read_prefixes = NULL;
951     context->num_read_prefixes = 0;
952     context->write_prefixes = NULL;
953     context->num_write_prefixes = 0;
954     context->predict_prefixes = NULL;
955     context->num_predict_prefixes = 0;
956     context->write_denied_prefixes = NULL;
957     context->num_write_denied_prefixes = 0;
958     }
959    
960 azarah 1.8 static int is_sandbox_pid()
961 ferringb 1.1 {
962     int old_errno = errno;
963     int result = 0;
964     FILE *pids_stream = NULL;
965     int pids_file = -1;
966     int current_pid = 0;
967     int tmp_pid = 0;
968    
969     init_wrappers();
970    
971     pids_stream = true_fopen(sandbox_pids_file, "r");
972    
973     if (NULL == pids_stream) {
974     perror(">>> pids file fopen");
975     } else {
976     pids_file = fileno(pids_stream);
977    
978     if (pids_file < 0) {
979     perror(">>> pids file fileno");
980     } else {
981     current_pid = getpid();
982    
983     while (EOF != fscanf(pids_stream, "%d\n", &tmp_pid)) {
984     if (tmp_pid == current_pid) {
985     result = 1;
986     break;
987     }
988     }
989     }
990     if (EOF == fclose(pids_stream)) {
991     perror(">>> pids file fclose");
992     }
993     pids_stream = NULL;
994     pids_file = -1;
995     }
996    
997     errno = old_errno;
998    
999     return result;
1000     }
1001    
1002 azarah 1.8 static void clean_env_entries(char ***prefixes_array, int *prefixes_num)
1003 ferringb 1.1 {
1004     int old_errno = errno;
1005     int i = 0;
1006    
1007     if (NULL != *prefixes_array) {
1008     for (i = 0; i < *prefixes_num; i++) {
1009     if (NULL != (*prefixes_array)[i]) {
1010     free((*prefixes_array)[i]);
1011     (*prefixes_array)[i] = NULL;
1012     }
1013     }
1014 azarah 1.10 if (NULL != *prefixes_array)
1015 ferringb 1.1 free(*prefixes_array);
1016     *prefixes_array = NULL;
1017     *prefixes_num = 0;
1018     }
1019    
1020     errno = old_errno;
1021     }
1022    
1023 azarah 1.10 #define pfx_num (*prefixes_num)
1024     #define pfx_array (*prefixes_array)
1025     #define pfx_item ((*prefixes_array)[(*prefixes_num)])
1026    
1027 ferringb 1.21 static void init_env_entries(char ***prefixes_array, int *prefixes_num, const char *env, const char *prefixes_env, int warn)
1028 ferringb 1.1 {
1029     int old_errno = errno;
1030 ferringb 1.21 // char *prefixes_env = getenv(env);
1031 ferringb 1.1
1032     if (NULL == prefixes_env) {
1033 azarah 1.19 /* Do not warn if this is in init stage, as we might get
1034     * issues due to LD_PRELOAD already set (bug #91431). */
1035     if (1 == sb_init)
1036     fprintf(stderr, "Sandbox error : the %s environmental variable should be defined.\n", env);
1037 ferringb 1.21 if(pfx_array) {
1038     int x;
1039     for(x=0; x < pfx_num; x++)
1040     free(pfx_item);
1041     free(pfx_array);
1042     }
1043     pfx_num = 0;
1044 ferringb 1.1 } else {
1045     char *buffer = NULL;
1046     int prefixes_env_length = strlen(prefixes_env);
1047     int i = 0;
1048     int num_delimiters = 0;
1049     char *token = NULL;
1050 azarah 1.10 char *rpath = NULL;
1051 ferringb 1.1
1052     for (i = 0; i < prefixes_env_length; i++) {
1053     if (':' == prefixes_env[i]) {
1054     num_delimiters++;
1055     }
1056     }
1057    
1058     if (num_delimiters > 0) {
1059 azarah 1.10 pfx_array = malloc(((num_delimiters * 2) + 1) * sizeof(char *));
1060     if (NULL == pfx_array)
1061     return;
1062 ferringb 1.1 buffer = strndupa(prefixes_env, prefixes_env_length);
1063 azarah 1.10 if (NULL == buffer)
1064     return;
1065 ferringb 1.1
1066     #ifdef REENTRANT_STRTOK
1067     token = strtok_r(buffer, ":", &buffer);
1068     #else
1069     token = strtok(buffer, ":");
1070     #endif
1071    
1072     while ((NULL != token) && (strlen(token) > 0)) {
1073 azarah 1.10 pfx_item = filter_path(token, 0);
1074     if (NULL != pfx_item) {
1075     pfx_num++;
1076    
1077     /* Now add the realpath if it exists and
1078     * are not a duplicate */
1079     rpath = malloc(SB_PATH_MAX * sizeof(char));
1080     if (NULL != rpath) {
1081     pfx_item = realpath(*(&(pfx_item) - 1), rpath);
1082     if ((NULL != pfx_item) &&
1083     (0 != strcmp(*(&(pfx_item) - 1), pfx_item))) {
1084     pfx_num++;
1085     } else {
1086     free(rpath);
1087     pfx_item = NULL;
1088     }
1089     }
1090     }
1091 ferringb 1.1
1092     #ifdef REENTRANT_STRTOK
1093     token = strtok_r(NULL, ":", &buffer);
1094     #else
1095     token = strtok(NULL, ":");
1096     #endif
1097     }
1098     } else if (prefixes_env_length > 0) {
1099 azarah 1.10 pfx_array = malloc(2 * sizeof(char *));
1100     if (NULL == pfx_array)
1101     return;
1102    
1103     pfx_item = filter_path(prefixes_env, 0);
1104     if (NULL != pfx_item) {
1105     pfx_num++;
1106    
1107     /* Now add the realpath if it exists and
1108     * are not a duplicate */
1109     rpath = malloc(SB_PATH_MAX * sizeof(char));
1110     if (NULL != rpath) {
1111     pfx_item = realpath(*(&(pfx_item) - 1), rpath);
1112     if ((NULL != pfx_item) &&
1113     (0 != strcmp(*(&(pfx_item) - 1), pfx_item))) {
1114     pfx_num++;
1115     } else {
1116     free(rpath);
1117     pfx_item = NULL;
1118     }
1119     }
1120     }
1121 ferringb 1.1 }
1122     }
1123    
1124     errno = old_errno;
1125     }
1126    
1127 azarah 1.18 static int check_access(sbcontext_t * sbcontext, const char *func, const char *path, const char *fpath)
1128 ferringb 1.1 {
1129     int old_errno = errno;
1130     int result = -1;
1131     int i = 0;
1132    
1133 azarah 1.18 if ((0 == strncmp(fpath, "/etc/ld.so.preload", 18)) &&
1134 azarah 1.8 (is_sandbox_pid())) {
1135 ferringb 1.1 result = 1;
1136     }
1137    
1138 azarah 1.10 if ((-1 == result) && (NULL != sbcontext->deny_prefixes)) {
1139     for (i = 0; i < sbcontext->num_deny_prefixes; i++) {
1140     if (NULL != sbcontext->deny_prefixes[i]) {
1141 azarah 1.18 if (0 == strncmp(fpath,
1142 azarah 1.10 sbcontext->deny_prefixes[i],
1143     strlen(sbcontext->deny_prefixes[i]))) {
1144     result = 0;
1145     break;
1146     }
1147     }
1148     }
1149     }
1150    
1151 ferringb 1.1 if (-1 == result) {
1152 azarah 1.10 if ((NULL != sbcontext->read_prefixes) &&
1153     ((0 == strncmp(func, "open_rd", 7)) ||
1154     (0 == strncmp(func, "popen", 5)) ||
1155     (0 == strncmp(func, "opendir", 7)) ||
1156     (0 == strncmp(func, "system", 6)) ||
1157     (0 == strncmp(func, "execl", 5)) ||
1158     (0 == strncmp(func, "execlp", 6)) ||
1159     (0 == strncmp(func, "execle", 6)) ||
1160     (0 == strncmp(func, "execv", 5)) ||
1161     (0 == strncmp(func, "execvp", 6)) ||
1162     (0 == strncmp(func, "execve", 6)))) {
1163     for (i = 0; i < sbcontext->num_read_prefixes; i++) {
1164     if (NULL != sbcontext->read_prefixes[i]) {
1165 azarah 1.18 if (0 == strncmp(fpath,
1166 azarah 1.10 sbcontext->read_prefixes[i],
1167     strlen(sbcontext->read_prefixes[i]))) {
1168     result = 1;
1169 ferringb 1.1 break;
1170     }
1171     }
1172     }
1173     }
1174 azarah 1.10 if ((NULL != sbcontext->write_prefixes) &&
1175     ((0 == strncmp(func, "open_wr", 7)) ||
1176     (0 == strncmp(func, "creat", 5)) ||
1177     (0 == strncmp(func, "creat64", 7)) ||
1178     (0 == strncmp(func, "mkdir", 5)) ||
1179     (0 == strncmp(func, "mknod", 5)) ||
1180     (0 == strncmp(func, "mkfifo", 6)) ||
1181     (0 == strncmp(func, "link", 4)) ||
1182     (0 == strncmp(func, "symlink", 7)) ||
1183     (0 == strncmp(func, "rename", 6)) ||
1184     (0 == strncmp(func, "utime", 5)) ||
1185     (0 == strncmp(func, "utimes", 6)) ||
1186     (0 == strncmp(func, "unlink", 6)) ||
1187     (0 == strncmp(func, "rmdir", 5)) ||
1188     (0 == strncmp(func, "chown", 5)) ||
1189     (0 == strncmp(func, "lchown", 6)) ||
1190     (0 == strncmp(func, "chmod", 5)) ||
1191     (0 == strncmp(func, "truncate", 8)) ||
1192     (0 == strncmp(func, "ftruncate", 9)) ||
1193     (0 == strncmp(func, "truncate64", 10)) ||
1194     (0 == strncmp(func, "ftruncate64", 11)))) {
1195     struct stat st;
1196    
1197     /* No need to check here, as we do it above
1198     if (NULL != sbcontext->write_prefixes) { */
1199     /* XXX: Hack to enable us to remove symlinks pointing
1200     * to protected stuff. First we make sure that the
1201     * passed path is writable, and if so, check if its a
1202     * symlink, and give access only if the resolved path
1203     * of the symlink's parent also have write access. */
1204 azarah 1.14 if (((0 == strncmp(func, "unlink", 6)) ||
1205 azarah 1.20 (0 == strncmp(func, "lchown", 6)) ||
1206     (0 == strncmp(func, "rename", 6))) &&
1207 azarah 1.10 ((-1 != lstat(path, &st)) && (S_ISLNK(st.st_mode)))) {
1208     int hresult = -1;
1209    
1210     /* Check if the symlink unresolved path have access */
1211     for (i = 0; i < sbcontext->num_write_prefixes; i++) {
1212     if (NULL != sbcontext->write_prefixes[i]) {
1213     if (0 == strncmp(path,
1214     sbcontext->write_prefixes[i],
1215     strlen(sbcontext->write_prefixes[i]))) {
1216     /* Does have write access on path */
1217     hresult = 1;
1218 ferringb 1.1 break;
1219     }
1220     }
1221     }
1222 azarah 1.10 if (1 == hresult) {
1223     char tmp_buf[SB_PATH_MAX];
1224     char *dname, *rpath;
1225    
1226     strncpy(tmp_buf, path, SB_PATH_MAX - 1);
1227     tmp_buf[SB_PATH_MAX - 1] = '\0';
1228    
1229     dname = dirname(tmp_buf);
1230     /* Get symlink resolved path */
1231     rpath = filter_path(dname, 1);
1232     if (NULL == rpath)
1233     /* Don't really worry here about
1234     * memory issues */
1235     goto unlink_hack_end;
1236    
1237     /* Now check if the symlink resolved path have access */
1238     for (i = 0; i < sbcontext->num_write_prefixes; i++) {
1239     if (NULL != sbcontext->write_prefixes[i]) {
1240     if (0 == strncmp(rpath,
1241     sbcontext->write_prefixes[i],
1242     strlen(sbcontext->write_prefixes[i]))) {
1243     /* Does have write access on path */
1244     hresult = 2;
1245     break;
1246     }
1247     }
1248     }
1249     free(rpath);
1250    
1251     if (2 == hresult) {
1252     /* Ok, enable the hack as it is a symlink */
1253     result = 1;
1254     }
1255     }
1256     }
1257     unlink_hack_end:
1258    
1259     if (NULL != sbcontext->write_denied_prefixes) {
1260 ferringb 1.1 for (i = 0; i < sbcontext->num_write_denied_prefixes; i++) {
1261     if (NULL != sbcontext->write_denied_prefixes[i]) {
1262 azarah 1.18 if (0 == strncmp(fpath,
1263 azarah 1.8 sbcontext->write_denied_prefixes[i],
1264     strlen(sbcontext->write_denied_prefixes[i]))) {
1265 azarah 1.10 /* Special paths in writable context that should
1266     * be denied - not implemented yet */
1267 ferringb 1.1 result = 0;
1268     break;
1269     }
1270     }
1271     }
1272 azarah 1.10 }
1273 ferringb 1.1
1274 azarah 1.10 if ((-1 == result) && (NULL != sbcontext->write_prefixes)) {
1275     for (i = 0; i < sbcontext->num_write_prefixes; i++) {
1276     if (NULL != sbcontext->write_prefixes[i]) {
1277 azarah 1.18 if (0 == strncmp(fpath,
1278 azarah 1.10 sbcontext->write_prefixes[i],
1279     strlen(sbcontext->write_prefixes[i]))) {
1280     /* Falls in a writable path */
1281     result = 1;
1282     break;
1283 ferringb 1.1 }
1284     }
1285 azarah 1.10 }
1286     }
1287 ferringb 1.1
1288 azarah 1.10 if ((-1 == result) && (NULL != sbcontext->predict_prefixes)) {
1289     for (i = 0; i < sbcontext->num_predict_prefixes; i++) {
1290     if (NULL != sbcontext->predict_prefixes[i]) {
1291 azarah 1.18 if (0 == strncmp(fpath,
1292 azarah 1.10 sbcontext->predict_prefixes[i],
1293     strlen(sbcontext->predict_prefixes[i]))) {
1294     /* Is a known access violation, so deny access,
1295     * and do not log it */
1296     sbcontext->show_access_violation = 0;
1297     result = 0;
1298     break;
1299 ferringb 1.1 }
1300     }
1301     }
1302     }
1303     }
1304     }
1305    
1306     if (-1 == result) {
1307     result = 0;
1308     }
1309    
1310     errno = old_errno;
1311    
1312     return result;
1313     }
1314    
1315 azarah 1.8 static int check_syscall(sbcontext_t * sbcontext, const char *func, const char *file)
1316 ferringb 1.1 {
1317     int old_errno = errno;
1318     int result = 1;
1319     struct stat log_stat;
1320     char *log_path = NULL;
1321     char *absolute_path = NULL;
1322 azarah 1.18 char *resolved_path = NULL;
1323 ferringb 1.1 char *tmp_buffer = NULL;
1324     int log_file = 0;
1325     struct stat debug_log_stat;
1326     char *debug_log_env = NULL;
1327     char *debug_log_path = NULL;
1328     int debug_log_file = 0;
1329     char buffer[512];
1330     char *dpath = NULL;
1331    
1332     init_wrappers();
1333    
1334 azarah 1.18 absolute_path = filter_path(file, 0);
1335     resolved_path = filter_path(file, 1);
1336     if ((NULL == absolute_path) || (NULL == resolved_path)) {
1337     if (NULL != absolute_path)
1338     free(absolute_path);
1339     if (NULL != resolved_path)
1340     free(resolved_path);
1341     return 0;
1342 ferringb 1.1 }
1343    
1344     log_path = getenv("SANDBOX_LOG");
1345     debug_log_env = getenv("SANDBOX_DEBUG");
1346     debug_log_path = getenv("SANDBOX_DEBUG_LOG");
1347    
1348     if (((NULL == log_path) ||
1349 azarah 1.8 (0 != strncmp(absolute_path, log_path, strlen(log_path)))) &&
1350     ((NULL == debug_log_env) ||
1351     (NULL == debug_log_path) ||
1352     (0 != strncmp(absolute_path, debug_log_path, strlen(debug_log_path)))) &&
1353 azarah 1.18 (0 == check_access(sbcontext, func, absolute_path, resolved_path))) {
1354 ferringb 1.1 if (1 == sbcontext->show_access_violation) {
1355 azarah 1.8 fprintf(stderr, "\e[31;01mACCESS DENIED\033[0m %s:%*s%s\n",
1356     func, (int)(10 - strlen(func)), "", absolute_path);
1357 ferringb 1.1
1358     if (NULL != log_path) {
1359 azarah 1.18 if (0 != strncmp(absolute_path, resolved_path, strlen(absolute_path))) {
1360 genone 1.13 sprintf(buffer, "%s:%*s%s (symlink to %s)\n", func, (int)(10-strlen(func)), "",
1361 azarah 1.18 absolute_path, resolved_path);
1362 genone 1.13 } else {
1363     sprintf(buffer, "%s:%*s%s\n", func, (int)(10 - strlen(func)), "", absolute_path);
1364     }
1365 ferringb 1.1 // log_path somehow gets corrupted. figuring out why would be good.
1366     dpath = strdup(log_path);
1367 azarah 1.8 if ((0 == lstat(log_path, &log_stat)) &&
1368     (0 == S_ISREG(log_stat.st_mode))) {
1369     fprintf(stderr, "\e[31;01mSECURITY BREACH\033[0m %s already exists and is not a regular file.\n", dpath);
1370 azarah 1.18 } else if (0 == check_access(sbcontext, "open_wr", dpath, filter_path(dpath, 1))) {
1371 ferringb 1.1 unsetenv("SANDBOX_LOG");
1372 azarah 1.8 fprintf(stderr, "\e[31;01mSECURITY BREACH\033[0m SANDBOX_LOG %s isn't allowed via SANDBOX_WRITE\n", dpath);
1373 ferringb 1.1 } else {
1374 azarah 1.8 log_file = true_open(dpath, O_APPEND | O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
1375 ferringb 1.1 if (log_file >= 0) {
1376     write(log_file, buffer, strlen(buffer));
1377     close(log_file);
1378     }
1379     }
1380     free(dpath);
1381     }
1382     }
1383    
1384     result = 0;
1385     } else if (NULL != debug_log_env) {
1386     if (NULL != debug_log_path) {
1387     if (0 != strncmp(absolute_path, debug_log_path, strlen(debug_log_path))) {
1388 azarah 1.8 sprintf(buffer, "%s:%*s%s\n", func, (int)(10 - strlen(func)), "", absolute_path);
1389 ferringb 1.1 //debug_log_path somehow gets corupted, same thing as log_path above.
1390     dpath = strdup(debug_log_path);
1391     if ((0 == lstat(debug_log_path, &debug_log_stat))
1392 azarah 1.8 && (0 == S_ISREG(debug_log_stat.st_mode))) {
1393     fprintf(stderr, "\e[31;01mSECURITY BREACH\033[0m %s already exists and is not a regular file.\n",
1394 ferringb 1.1 debug_log_path);
1395 azarah 1.18 } else if (0 == check_access(sbcontext, "open_wr", dpath, filter_path(dpath, 1))) {
1396 ferringb 1.1 unsetenv("SANDBOX_DEBUG");
1397     unsetenv("SANDBOX_DEBUG_LOG");
1398 azarah 1.8 fprintf(stderr, "\e[31;01mSECURITY BREACH\033[0m SANDBOX_DEBUG_LOG %s isn't allowed by SANDBOX_WRITE.\n",
1399 ferringb 1.1 dpath);
1400 azarah 1.8 } else {
1401 vapier 1.25 debug_log_file = true_open(dpath, O_APPEND | O_WRONLY | O_CREAT,
1402     S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
1403 ferringb 1.1 if (debug_log_file >= 0) {
1404     write(debug_log_file, buffer, strlen(buffer));
1405     close(debug_log_file);
1406     }
1407     }
1408     free(dpath);
1409     }
1410     } else {
1411 azarah 1.8 fprintf(stderr, "\e[32;01mACCESS ALLOWED\033[0m %s:%*s%s\n",
1412     func, (int)(10 - strlen(func)), "", absolute_path);
1413 ferringb 1.1 }
1414     }
1415    
1416 azarah 1.18 if (NULL != absolute_path)
1417 ferringb 1.1 free(absolute_path);
1418 azarah 1.18 if (NULL != resolved_path)
1419     free(resolved_path);
1420 ferringb 1.1
1421     errno = old_errno;
1422    
1423     return result;
1424     }
1425    
1426 azarah 1.8 static int is_sandbox_on()
1427 ferringb 1.1 {
1428     int old_errno = errno;
1429    
1430     /* $SANDBOX_ACTIVE is an env variable that should ONLY
1431     * be used internal by sandbox.c and libsanbox.c. External
1432     * sources should NEVER set it, else the sandbox is enabled
1433     * in some cases when run in parallel with another sandbox,
1434     * but not even in the sandbox shell.
1435     *
1436     * Azarah (3 Aug 2002)
1437     */
1438     if ((NULL != getenv("SANDBOX_ON")) &&
1439 azarah 1.8 (0 == strncmp(getenv("SANDBOX_ON"), "1", 1)) &&
1440     (NULL != getenv("SANDBOX_ACTIVE")) &&
1441     (0 == strncmp(getenv("SANDBOX_ACTIVE"), "armedandready", 13))) {
1442 ferringb 1.1 errno = old_errno;
1443     return 1;
1444     } else {
1445     errno = old_errno;
1446     return 0;
1447     }
1448     }
1449    
1450 azarah 1.8 static int before_syscall(const char *func, const char *file)
1451 ferringb 1.1 {
1452     int old_errno = errno;
1453     int result = 1;
1454 azarah 1.18 // static sbcontext_t sbcontext;
1455 ferringb 1.21 char *deny = getenv("SANDBOX_DENY");
1456     char *read = getenv("SANDBOX_READ");
1457     char *write = getenv("SANDBOX_WRITE");
1458     char *predict = getenv("SANDBOX_PREDICT");
1459 ferringb 1.1
1460     if (!strlen(file)) {
1461     /* The file/directory does not exist */
1462     errno = ENOENT;
1463     return 0;
1464     }
1465    
1466 ferringb 1.21 if(sb_init == 0) {
1467     init_context(&sbcontext);
1468     cached_env_vars = malloc(sizeof(char *)*4);
1469     cached_env_vars[0] = cached_env_vars[1] = cached_env_vars[2] = cached_env_vars[3] = NULL;
1470     sb_init=1;
1471     }
1472    
1473     if((deny == NULL && cached_env_vars[0] != deny) || cached_env_vars[0] == NULL ||
1474     strcmp(cached_env_vars[0], deny) != 0) {
1475    
1476     clean_env_entries(&(sbcontext.deny_prefixes),
1477     &(sbcontext.num_deny_prefixes));
1478    
1479     if(NULL != cached_env_vars[0])
1480     free(cached_env_vars[0]);
1481    
1482     if(NULL != deny) {
1483     init_env_entries(&(sbcontext.deny_prefixes),
1484     &(sbcontext.num_deny_prefixes), "SANDBOX_DENY", deny, 1);
1485     cached_env_vars[0] = strdup(deny);
1486     } else {
1487     cached_env_vars[0] = NULL;
1488     }
1489     }
1490    
1491     if((read == NULL && cached_env_vars[1] != read) || cached_env_vars[1] == NULL ||
1492     strcmp(cached_env_vars[1], read) != 0) {
1493    
1494     clean_env_entries(&(sbcontext.read_prefixes),
1495     &(sbcontext.num_read_prefixes));
1496    
1497     if(NULL != cached_env_vars[1])
1498     free(cached_env_vars[1]);
1499    
1500     if(NULL != read) {
1501     init_env_entries(&(sbcontext.read_prefixes),
1502     &(sbcontext.num_read_prefixes), "SANDBOX_READ", read, 1);
1503     cached_env_vars[1] = strdup(read);
1504     } else {
1505     cached_env_vars[1] = NULL;
1506     }
1507     }
1508    
1509     if((write == NULL && cached_env_vars[2] != write) || cached_env_vars[2] == NULL ||
1510     strcmp(cached_env_vars[2], write) != 0) {
1511    
1512     clean_env_entries(&(sbcontext.write_prefixes),
1513     &(sbcontext.num_write_prefixes));
1514    
1515     if(NULL != cached_env_vars[2])
1516     free(cached_env_vars[2]);
1517    
1518     if(NULL != write) {
1519     init_env_entries(&(sbcontext.write_prefixes),
1520     &(sbcontext.num_write_prefixes), "SANDBOX_WRITE", write, 1);
1521     cached_env_vars[2] = strdup(write);
1522     } else {
1523     cached_env_vars[2] = NULL;
1524     }
1525     }
1526    
1527     if((predict == NULL && cached_env_vars[3] != predict) || cached_env_vars[3] == NULL ||
1528     strcmp(cached_env_vars[3], predict) != 0) {
1529    
1530     clean_env_entries(&(sbcontext.predict_prefixes),
1531     &(sbcontext.num_predict_prefixes));
1532    
1533     if(NULL != cached_env_vars[3])
1534     free(cached_env_vars[3]);
1535    
1536     if(NULL != predict) {
1537     init_env_entries(&(sbcontext.predict_prefixes),
1538     &(sbcontext.num_predict_prefixes), "SANDBOX_PREDICT", predict, 1);
1539     cached_env_vars[3] = strdup(predict);
1540     } else {
1541     cached_env_vars[3] = NULL;
1542     }
1543    
1544     }
1545 ferringb 1.1
1546     result = check_syscall(&sbcontext, func, file);
1547    
1548     errno = old_errno;
1549    
1550     if (0 == result) {
1551     errno = EACCES;
1552     }
1553    
1554     return result;
1555     }
1556    
1557 azarah 1.8 static int before_syscall_open_int(const char *func, const char *file, int flags)
1558 ferringb 1.1 {
1559     if ((flags & O_WRONLY) || (flags & O_RDWR)) {
1560     return before_syscall("open_wr", file);
1561     } else {
1562     return before_syscall("open_rd", file);
1563     }
1564     }
1565    
1566 azarah 1.8 static int before_syscall_open_char(const char *func, const char *file, const char *mode)
1567 ferringb 1.1 {
1568     if (*mode == 'r' && ((strcmp(mode, "r") == 0) ||
1569 azarah 1.8 /* The strspn accept args are known non-writable modifiers */
1570     (strlen(++mode) == strspn(mode, "xbtmc")))) {
1571 ferringb 1.1 return before_syscall("open_rd", file);
1572     } else {
1573     return before_syscall("open_wr", file);
1574     }
1575     }
1576    
1577     #include "getcwd.c"
1578     #include "canonicalize.c"
1579 azarah 1.15 #include "sandbox_futils.c"
1580 ferringb 1.1
1581 azarah 1.8 // vim:noexpandtab noai:cindent ai

  ViewVC Help
Powered by ViewVC 1.1.20