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

Contents of /trunk/libsandbox.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 110 - (show annotations) (download) (as text)
Thu Jun 9 14:42:11 2005 UTC (10 years ago) by azarah
File MIME type: text/x-csrc
File size: 40888 byte(s)
Make sure our true_* pointers are initialized to NULL, and that we check for
all references that they are valid.

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