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

Contents of /trunk/libsandbox.c

Parent Directory Parent Directory | Revision Log Revision Log


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