/[path-sandbox]/trunk/libsandbox.c
Gentoo

Contents of /trunk/libsandbox.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 100 - (show annotations) (download) (as text)
Fri May 13 14:18:05 2005 UTC (9 years, 2 months ago) by azarah
File MIME type: text/x-csrc
File size: 39907 byte(s)
Various LD_PRELOAD cleanups.  Do not unset LD_PRELOAD for parent.

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

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

  ViewVC Help
Powered by ViewVC 1.1.20