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

Contents of /trunk/libsandbox.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 28 - (show annotations) (download) (as text)
Wed Mar 2 05:48:12 2005 UTC (9 years, 7 months ago) by ferringb
File MIME type: text/x-csrc
File size: 32959 byte(s)
killed off _init and _fini in favor of
void __attribute__ ((constructor)) init_func and
void __attribute__ ((destructor)) closing_func.  _(init|func) were deprecated.

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 <stdarg.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60 #include <sys/file.h>
61 #include <sys/stat.h>
62 #include <sys/types.h>
63 #include <sys/param.h>
64 #include <unistd.h>
65 #include <utime.h>
66 #include "config.h"
67 #include "localdecls.h"
68
69 #ifdef SB_MEM_DEBUG
70 # include <mcheck.h>
71 #endif
72
73 #ifdef WRAP_MKNOD
74 # undef __xmknod
75 #endif
76
77 #undef open
78 #undef open64
79
80 //#include "localdecls.h"
81 #include "sandbox.h"
82
83 /* Macros to check if a function should be executed */
84 #define FUNCTION_SANDBOX_SAFE(func, path) \
85 ((0 == is_sandbox_on()) || (1 == before_syscall(func, path)))
86
87 #define FUNCTION_SANDBOX_SAFE_INT(func, path, flags) \
88 ((0 == is_sandbox_on()) || (1 == before_syscall_open_int(func, path, flags)))
89
90 #define FUNCTION_SANDBOX_SAFE_CHAR(func, path, mode) \
91 ((0 == is_sandbox_on()) || (1 == before_syscall_open_char(func, path, mode)))
92
93 /* Macro to check if a wrapper is defined, if not
94 * then try to resolve it again. */
95 #define check_dlsym(name) \
96 { \
97 int old_errno=errno; \
98 if (!true_ ## name) true_ ## name=get_dlsym(#name); \
99 errno=old_errno; \
100 }
101
102 /* Macro to check if we could canonicalize a path. It returns an integer on
103 * failure. */
104 #define canonicalize_int(path, resolved_path) \
105 { \
106 if (0 != canonicalize(path, resolved_path)) \
107 return -1; \
108 }
109
110 /* Macro to check if we could canonicalize a path. It returns a NULL pointer on
111 * failure. */
112 #define canonicalize_ptr(path, resolved_path) \
113 { \
114 if (0 != canonicalize(path, resolved_path)) \
115 return NULL; \
116 }
117
118 static char sandbox_lib[255];
119 //static char sandbox_pids_file[255];
120 static char *sandbox_pids_file;
121
122 typedef struct {
123 int show_access_violation;
124 char **deny_prefixes;
125 int num_deny_prefixes;
126 char **read_prefixes;
127 int num_read_prefixes;
128 char **write_prefixes;
129 int num_write_prefixes;
130 char **predict_prefixes;
131 int num_predict_prefixes;
132 char **write_denied_prefixes;
133 int num_write_denied_prefixes;
134 } sbcontext_t;
135
136 /* glibc modified realpath() functions */
137 char *erealpath(const char *name, char *resolved);
138 /* glibc modified getcwd() functions */
139 char *egetcwd(char *, size_t);
140
141 static void init_wrappers(void);
142 static void *get_dlsym(const char *);
143 static int canonicalize(const char *, char *);
144 static int check_access(sbcontext_t *, const char *, const char *);
145 static int check_syscall(sbcontext_t *, const char *, const char *);
146 static int before_syscall(const char *, const char *);
147 static int before_syscall_open_int(const char *, const char *, int);
148 static int before_syscall_open_char(const char *, const char *, const char *);
149 static void clean_env_entries(char ***, int *);
150 static void init_context(sbcontext_t *);
151 static void init_env_entries(char ***, int *, char *, int);
152 static char *filter_path(const char *);
153 static int is_sandbox_on();
154 static int is_sandbox_pid();
155
156 /* Wrapped functions */
157
158 extern int chmod(const char *, mode_t);
159 static int (*true_chmod) (const char *, mode_t);
160 extern int chown(const char *, uid_t, gid_t);
161 static int (*true_chown) (const char *, uid_t, gid_t);
162 extern int creat(const char *, mode_t);
163 static int (*true_creat) (const char *, mode_t);
164 extern FILE *fopen(const char *, const char *);
165 static FILE *(*true_fopen) (const char *, const char *);
166 extern int lchown(const char *, uid_t, gid_t);
167 static int (*true_lchown) (const char *, uid_t, gid_t);
168 extern int link(const char *, const char *);
169 static int (*true_link) (const char *, const char *);
170 extern int mkdir(const char *, mode_t);
171 static int (*true_mkdir) (const char *, mode_t);
172 extern DIR *opendir(const char *);
173 static DIR *(*true_opendir) (const char *);
174 #ifdef WRAP_MKNOD
175 extern int __xmknod(const char *, mode_t, dev_t);
176 static int (*true___xmknod) (const char *, mode_t, dev_t);
177 #endif
178 extern int open(const char *, int, ...);
179 static int (*true_open) (const char *, int, ...);
180 extern int rename(const char *, const char *);
181 static int (*true_rename) (const char *, const char *);
182 extern int rmdir(const char *);
183 static int (*true_rmdir) (const char *);
184 extern int symlink(const char *, const char *);
185 static int (*true_symlink) (const char *, const char *);
186 extern int truncate(const char *, TRUNCATE_T);
187 static int (*true_truncate) (const char *, TRUNCATE_T);
188 extern int unlink(const char *);
189 static int (*true_unlink) (const char *);
190
191 #if (GLIBC_MINOR >= 1)
192
193 extern int creat64(const char *, __mode_t);
194 static int (*true_creat64) (const char *, __mode_t);
195 extern FILE *fopen64(const char *, const char *);
196 static FILE *(*true_fopen64) (const char *, const char *);
197 extern int open64(const char *, int, ...);
198 static int (*true_open64) (const char *, int, ...);
199 extern int truncate64(const char *, __off64_t);
200 static int (*true_truncate64) (const char *, __off64_t);
201
202 #endif
203
204 extern int execve(const char *filename, char *const argv[], char *const envp[]);
205 static int (*true_execve) (const char *, char *const[], char *const[]);
206
207 /*
208 * Initialize the shabang
209 */
210
211 static void
212 init_wrappers(void)
213 {
214 void *libc_handle = NULL;
215
216 #ifdef BROKEN_RTLD_NEXT
217 // printf ("RTLD_LAZY");
218 libc_handle = dlopen(LIBC_VERSION, RTLD_LAZY);
219 #else
220 // printf ("RTLD_NEXT");
221 libc_handle = RTLD_NEXT;
222 #endif
223
224 true_chmod = dlsym(libc_handle, "chmod");
225 true_chown = dlsym(libc_handle, "chown");
226 true_creat = dlsym(libc_handle, "creat");
227 true_fopen = dlsym(libc_handle, "fopen");
228 true_lchown = dlsym(libc_handle, "lchown");
229 true_link = dlsym(libc_handle, "link");
230 true_mkdir = dlsym(libc_handle, "mkdir");
231 true_opendir = dlsym(libc_handle, "opendir");
232 #ifdef WRAP_MKNOD
233 true___xmknod = dlsym(libc_handle, "__xmknod");
234 #endif
235 true_open = dlsym(libc_handle, "open");
236 true_rename = dlsym(libc_handle, "rename");
237 true_rmdir = dlsym(libc_handle, "rmdir");
238 true_symlink = dlsym(libc_handle, "symlink");
239 true_truncate = dlsym(libc_handle, "truncate");
240 true_unlink = dlsym(libc_handle, "unlink");
241
242 #if (GLIBC_MINOR >= 1)
243 true_creat64 = dlsym(libc_handle, "creat64");
244 true_fopen64 = dlsym(libc_handle, "fopen64");
245 true_open64 = dlsym(libc_handle, "open64");
246 true_truncate64 = dlsym(libc_handle, "truncate64");
247 #endif
248
249 true_execve = dlsym(libc_handle, "execve");
250 }
251
252 void __attribute__ ((constructor)) my_init(void);
253 void __attribute__ ((destructor)) my_fini(void);
254
255 void __attribute__ ((destructor))
256 my_fini(void)
257 {
258 free(sandbox_pids_file);
259 }
260
261 void __attribute__ ((constructor))
262 my_init(void)
263 {
264 int old_errno = errno;
265 char *tmp_string = NULL;
266
267 #ifdef SB_MEM_DEBUG
268 mtrace();
269 #endif
270
271 init_wrappers();
272
273 /* Get the path and name to this library */
274 tmp_string = get_sandbox_lib("/");
275 strncpy(sandbox_lib, tmp_string, sizeof(sandbox_lib)-1);
276 if (tmp_string)
277 free(tmp_string);
278 tmp_string = NULL;
279
280 /* Generate sandbox pids-file path */
281 sandbox_pids_file = get_sandbox_pids_file();
282
283 errno = old_errno;
284 }
285
286
287
288 static int
289 canonicalize(const char *path, char *resolved_path)
290 {
291 int old_errno = errno;
292 char *retval;
293
294 *resolved_path = '\0';
295
296 /* If path == NULL, return or we get a segfault */
297 if (NULL == path) {
298 errno = EINVAL;
299 return -1;
300 }
301
302 /* Do not try to resolve an empty path */
303 if ('\0' == path[0]) {
304 errno = old_errno;
305 return 0;
306 }
307
308 retval = erealpath(path, resolved_path);
309
310 if ((!retval) && (path[0] != '/')) {
311 /* The path could not be canonicalized, append it
312 * to the current working directory if it was not
313 * an absolute path
314 */
315 if (errno == ENAMETOOLONG)
316 return -1;
317
318 egetcwd(resolved_path, SB_PATH_MAX - 2);
319 strcat(resolved_path, "/");
320 strncat(resolved_path, path, SB_PATH_MAX - 1);
321
322 if (!erealpath(resolved_path, resolved_path)) {
323 if (errno == ENAMETOOLONG) {
324 /* The resolved path is too long for the buffer to hold */
325 return -1;
326 } else {
327 /* Whatever it resolved, is not a valid path */
328 errno = ENOENT;
329 return -1;
330 }
331 }
332
333 } else if ((!retval) && (path[0] == '/')) {
334 /* Whatever it resolved, is not a valid path */
335 errno = ENOENT;
336 return -1;
337 }
338
339 errno = old_errno;
340 return 0;
341 }
342
343 static void *
344 get_dlsym(const char *symname)
345 {
346 void *libc_handle = NULL;
347 void *symaddr = NULL;
348
349 #ifdef BROKEN_RTLD_NEXT
350 libc_handle = dlopen(LIBC_VERSION, RTLD_LAZY);
351 if (!libc_handle) {
352 printf("libsandbox.so: Can't dlopen libc: %s\n", dlerror());
353 abort();
354 }
355 #else
356 libc_handle = RTLD_NEXT;
357 #endif
358
359 symaddr = dlsym(libc_handle, symname);
360 if (!symaddr) {
361 printf("libsandbox.so: Can't resolve %s: %s\n", symname, dlerror());
362 abort();
363 }
364
365 return symaddr;
366 }
367
368 /*
369 * Wrapper Functions
370 */
371
372 int
373 chmod(const char *path, mode_t mode)
374 {
375 int result = -1;
376 char canonic[SB_PATH_MAX];
377
378 canonicalize_int(path, canonic);
379
380 if FUNCTION_SANDBOX_SAFE
381 ("chmod", canonic) {
382 check_dlsym(chmod);
383 result = true_chmod(path, mode);
384 }
385
386 return result;
387 }
388
389 int
390 chown(const char *path, uid_t owner, gid_t group)
391 {
392 int result = -1;
393 char canonic[SB_PATH_MAX];
394
395 canonicalize_int(path, canonic);
396
397 if FUNCTION_SANDBOX_SAFE
398 ("chown", canonic) {
399 check_dlsym(chown);
400 result = true_chown(path, owner, group);
401 }
402
403 return result;
404 }
405
406 int
407 creat(const char *pathname, mode_t mode)
408 {
409 /* Is it a system call? */
410 int result = -1;
411 char canonic[SB_PATH_MAX];
412
413 canonicalize_int(pathname, canonic);
414
415 if FUNCTION_SANDBOX_SAFE
416 ("creat", canonic) {
417 check_dlsym(open);
418 result = true_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
419 }
420
421 return result;
422 }
423
424 FILE *
425 fopen(const char *pathname, const char *mode)
426 {
427 FILE *result = NULL;
428 char canonic[SB_PATH_MAX];
429
430 canonicalize_ptr(pathname, canonic);
431
432 if FUNCTION_SANDBOX_SAFE_CHAR
433 ("fopen", canonic, mode) {
434 check_dlsym(fopen);
435 result = true_fopen(pathname, mode);
436 }
437
438 return result;
439 }
440
441 int
442 lchown(const char *path, uid_t owner, gid_t group)
443 {
444 int result = -1;
445 char canonic[SB_PATH_MAX];
446
447 canonicalize_int(path, canonic);
448
449 if FUNCTION_SANDBOX_SAFE
450 ("lchown", canonic) {
451 check_dlsym(lchown);
452 result = true_lchown(path, owner, group);
453 }
454
455 return result;
456 }
457
458 int
459 link(const char *oldpath, const char *newpath)
460 {
461 int result = -1;
462 char old_canonic[SB_PATH_MAX], new_canonic[SB_PATH_MAX];
463
464 canonicalize_int(oldpath, old_canonic);
465 canonicalize_int(newpath, new_canonic);
466
467 if FUNCTION_SANDBOX_SAFE
468 ("link", new_canonic) {
469 check_dlsym(link);
470 result = true_link(oldpath, newpath);
471 }
472
473 return result;
474 }
475
476 int
477 mkdir(const char *pathname, mode_t mode)
478 // returns 0 success, or -1 if an error occurred
479 {
480 int result = -1, my_errno = errno;
481 char canonic[SB_PATH_MAX];
482 struct stat st;
483
484 canonicalize_int(pathname, canonic);
485
486 /* Check if the directory exist, return EEXIST rather than failing */
487 if (0 == lstat(canonic, &st)) {
488 errno = EEXIST;
489 return -1;
490 }
491 errno = my_errno;
492
493 if FUNCTION_SANDBOX_SAFE
494 ("mkdir", canonic) {
495 check_dlsym(mkdir);
496 result = true_mkdir(pathname, mode);
497 }
498
499 return result;
500 }
501
502 DIR *
503 opendir(const char *name)
504 {
505 DIR *result = NULL;
506 char canonic[SB_PATH_MAX];
507
508 canonicalize_ptr(name, canonic);
509
510 if FUNCTION_SANDBOX_SAFE
511 ("opendir", canonic) {
512 check_dlsym(opendir);
513 result = true_opendir(name);
514 }
515
516 return result;
517 }
518
519 #ifdef WRAP_MKNOD
520
521 int
522 __xmknod(const char *pathname, mode_t mode, dev_t dev)
523 {
524 int result = -1;
525 char canonic[SB_PATH_MAX];
526
527 canonicalize_int(pathname, canonic);
528
529 if FUNCTION_SANDBOX_SAFE
530 ("__xmknod", canonic) {
531 check_dlsym(__xmknod);
532 result = true___xmknod(pathname, mode, dev);
533 }
534
535 return result;
536 }
537
538 #endif
539
540 int
541 open(const char *pathname, int flags, ...)
542 {
543 /* Eventually, there is a third parameter: it's mode_t mode */
544 va_list ap;
545 mode_t mode = 0;
546 int result = -1;
547 char canonic[SB_PATH_MAX];
548
549 if (flags & O_CREAT) {
550 va_start(ap, flags);
551 mode = va_arg(ap, mode_t);
552 va_end(ap);
553 }
554
555 canonicalize_int(pathname, canonic);
556
557 if FUNCTION_SANDBOX_SAFE_INT
558 ("open", canonic, flags) {
559 /* We need to resolve open() realtime in some cases,
560 * else we get a segfault when running /bin/ps, etc
561 * in a sandbox */
562 check_dlsym(open);
563 result = true_open(pathname, flags, mode);
564 }
565
566 return result;
567 }
568
569 int
570 rename(const char *oldpath, const char *newpath)
571 {
572 int result = -1;
573 char old_canonic[SB_PATH_MAX], new_canonic[SB_PATH_MAX];
574
575 canonicalize_int(oldpath, old_canonic);
576 canonicalize_int(newpath, new_canonic);
577
578 if (FUNCTION_SANDBOX_SAFE("rename", old_canonic) &&
579 FUNCTION_SANDBOX_SAFE("rename", new_canonic)) {
580 check_dlsym(rename);
581 result = true_rename(oldpath, newpath);
582 }
583
584 return result;
585 }
586
587 int
588 rmdir(const char *pathname)
589 {
590 int result = -1;
591 char canonic[SB_PATH_MAX];
592
593 canonicalize_int(pathname, canonic);
594
595 if FUNCTION_SANDBOX_SAFE
596 ("rmdir", canonic) {
597 check_dlsym(rmdir);
598 result = true_rmdir(pathname);
599 }
600
601 return result;
602 }
603
604 int
605 symlink(const char *oldpath, const char *newpath)
606 {
607 int result = -1;
608 char old_canonic[SB_PATH_MAX], new_canonic[SB_PATH_MAX];
609
610 canonicalize_int(oldpath, old_canonic);
611 canonicalize_int(newpath, new_canonic);
612
613 if FUNCTION_SANDBOX_SAFE
614 ("symlink", new_canonic) {
615 check_dlsym(symlink);
616 result = true_symlink(oldpath, newpath);
617 }
618
619 return result;
620 }
621
622 int
623 truncate(const char *path, TRUNCATE_T length)
624 {
625 int result = -1;
626 char canonic[SB_PATH_MAX];
627
628 canonicalize_int(path, canonic);
629
630 if FUNCTION_SANDBOX_SAFE
631 ("truncate", canonic) {
632 check_dlsym(truncate);
633 result = true_truncate(path, length);
634 }
635
636 return result;
637 }
638
639 int
640 unlink(const char *pathname)
641 {
642 int result = -1;
643 char canonic[SB_PATH_MAX];
644
645 canonicalize_int(pathname, canonic);
646
647 if FUNCTION_SANDBOX_SAFE
648 ("unlink", canonic) {
649 check_dlsym(unlink);
650 result = true_unlink(pathname);
651 }
652
653 return result;
654 }
655
656 #if (GLIBC_MINOR >= 1)
657
658 int
659 creat64(const char *pathname, __mode_t mode)
660 {
661 /* Is it a system call? */
662 int result = -1;
663 char canonic[SB_PATH_MAX];
664
665 canonicalize_int(pathname, canonic);
666
667 if FUNCTION_SANDBOX_SAFE
668 ("creat64", canonic) {
669 check_dlsym(open64);
670 result = true_open64(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
671 }
672
673 return result;
674 }
675
676 FILE *
677 fopen64(const char *pathname, const char *mode)
678 {
679 FILE *result = NULL;
680 char canonic[SB_PATH_MAX];
681
682 canonicalize_ptr(pathname, canonic);
683
684 if FUNCTION_SANDBOX_SAFE_CHAR
685 ("fopen64", canonic, mode) {
686 check_dlsym(fopen64);
687 result = true_fopen(pathname, mode);
688 }
689
690 return result;
691 }
692
693 int
694 open64(const char *pathname, int flags, ...)
695 {
696 /* Eventually, there is a third parameter: it's mode_t mode */
697 va_list ap;
698 mode_t mode = 0;
699 int result = -1;
700 char canonic[SB_PATH_MAX];
701
702 if (flags & O_CREAT) {
703 va_start(ap, flags);
704 mode = va_arg(ap, mode_t);
705 va_end(ap);
706 }
707
708 canonicalize_int(pathname, canonic);
709
710 if FUNCTION_SANDBOX_SAFE_INT
711 ("open64", canonic, flags) {
712 check_dlsym(open64);
713 result = true_open64(pathname, flags, mode);
714 }
715
716 return result;
717 }
718
719 int
720 truncate64(const char *path, __off64_t length)
721 {
722 int result = -1;
723 char canonic[SB_PATH_MAX];
724
725 canonicalize_int(path, canonic);
726
727 if FUNCTION_SANDBOX_SAFE
728 ("truncate64", canonic) {
729 check_dlsym(truncate64);
730 result = true_truncate64(path, length);
731 }
732
733 return result;
734 }
735
736 #endif /* GLIBC_MINOR >= 1 */
737
738 /*
739 * Exec Wrappers
740 */
741
742 int
743 execve(const char *filename, char *const argv[], char *const envp[])
744 {
745 int old_errno = errno;
746 int result = -1;
747 int count = 0;
748 int env_len = 0;
749 char canonic[SB_PATH_MAX];
750 char **my_env = NULL;
751 int kill_env = 1;
752 /* We limit the size LD_PRELOAD can be here, but it should be enough */
753 char tmp_str[4096];
754
755 canonicalize_int(filename, canonic);
756
757 if FUNCTION_SANDBOX_SAFE
758 ("execve", canonic) {
759 while (envp[count] != NULL) {
760 if (strstr(envp[count], "LD_PRELOAD=") == envp[count]) {
761 if (NULL != strstr(envp[count], sandbox_lib)) {
762 my_env = (char **) envp;
763 kill_env = 0;
764 break;
765 } else {
766 int i = 0;
767 const int max_envp_len =
768 strlen(envp[count]) + strlen(sandbox_lib) + 1;
769
770 /* Fail safe ... */
771 if (max_envp_len > 4096) {
772 fprintf(stderr, "sandbox: max_envp_len too big!\n");
773 errno = ENOMEM;
774 return result;
775 }
776
777 /* Calculate envp size */
778 my_env = (char **) envp;
779 do
780 env_len += 1;
781 while (*my_env++);
782
783 my_env = (char **) malloc((env_len + 2) * sizeof (char *));
784 if (NULL == my_env) {
785 errno = ENOMEM;
786 return result;
787 }
788 /* Copy envp to my_env */
789 do
790 my_env[i] = envp[i];
791 while (envp[i++]);
792
793 /* Set tmp_str to envp[count] */
794 strncpy(tmp_str, envp[count], max_envp_len - 1);
795
796 /* LD_PRELOAD already have variables other than sandbox_lib,
797 * thus we have to add sandbox_lib seperated via a whitespace. */
798 if (0 != strncmp(envp[count], "LD_PRELOAD=", max_envp_len - 1)) {
799 strncat(tmp_str, " ", max_envp_len - strlen(tmp_str));
800 strncat(tmp_str, sandbox_lib, max_envp_len - strlen(tmp_str));
801 } else {
802 strncat(tmp_str, sandbox_lib, max_envp_len - strlen(tmp_str));
803 }
804
805 /* Valid string? */
806 tmp_str[max_envp_len] = '\0';
807
808 /* Ok, replace my_env[count] with our version that contains
809 * sandbox_lib ... */
810 my_env[count] = tmp_str;
811
812 break;
813 }
814 }
815 count++;
816 }
817
818 errno = old_errno;
819 check_dlsym(execve);
820 result = true_execve(filename, argv, my_env);
821 old_errno = errno;
822
823 if (my_env && kill_env) {
824 free(my_env);
825 my_env = NULL;
826 }
827 }
828
829 errno = old_errno;
830
831 return result;
832 }
833
834 /*
835 * Internal Functions
836 */
837
838 #if (GLIBC_MINOR == 1)
839
840 /* This hack is needed for glibc 2.1.1 (and others?)
841 * (not really needed, but good example) */
842 extern int fclose(FILE *);
843 static int (*true_fclose) (FILE *) = NULL;
844 int
845 fclose(FILE * file)
846 {
847 int result = -1;
848
849 check_dlsym(fclose);
850 result = true_fclose(file);
851
852 return result;
853 }
854
855 #endif /* GLIBC_MINOR == 1 */
856
857 static void
858 init_context(sbcontext_t * context)
859 {
860 context->show_access_violation = 1;
861 context->deny_prefixes = NULL;
862 context->num_deny_prefixes = 0;
863 context->read_prefixes = NULL;
864 context->num_read_prefixes = 0;
865 context->write_prefixes = NULL;
866 context->num_write_prefixes = 0;
867 context->predict_prefixes = NULL;
868 context->num_predict_prefixes = 0;
869 context->write_denied_prefixes = NULL;
870 context->num_write_denied_prefixes = 0;
871 }
872
873 static int
874 is_sandbox_pid()
875 {
876 int old_errno = errno;
877 int result = 0;
878 FILE *pids_stream = NULL;
879 int pids_file = -1;
880 int current_pid = 0;
881 int tmp_pid = 0;
882
883 init_wrappers();
884
885 pids_stream = true_fopen(sandbox_pids_file, "r");
886
887 if (NULL == pids_stream) {
888 perror(">>> pids file fopen");
889 } else {
890 pids_file = fileno(pids_stream);
891
892 if (pids_file < 0) {
893 perror(">>> pids file fileno");
894 } else {
895 current_pid = getpid();
896
897 while (EOF != fscanf(pids_stream, "%d\n", &tmp_pid)) {
898 if (tmp_pid == current_pid) {
899 result = 1;
900 break;
901 }
902 }
903 }
904 if (EOF == fclose(pids_stream)) {
905 perror(">>> pids file fclose");
906 }
907 pids_stream = NULL;
908 pids_file = -1;
909 }
910
911 errno = old_errno;
912
913 return result;
914 }
915
916 static void
917 clean_env_entries(char ***prefixes_array, int *prefixes_num)
918 {
919 int old_errno = errno;
920 int i = 0;
921
922 if (NULL != *prefixes_array) {
923 for (i = 0; i < *prefixes_num; i++) {
924 if (NULL != (*prefixes_array)[i]) {
925 free((*prefixes_array)[i]);
926 (*prefixes_array)[i] = NULL;
927 }
928 }
929 if (*prefixes_array)
930 free(*prefixes_array);
931 *prefixes_array = NULL;
932 *prefixes_num = 0;
933 }
934
935 errno = old_errno;
936 }
937
938 static void
939 init_env_entries(char ***prefixes_array, int *prefixes_num, char *env, int warn)
940 {
941 int old_errno = errno;
942 char *prefixes_env = getenv(env);
943
944 if (NULL == prefixes_env) {
945 fprintf(stderr,
946 "Sandbox error : the %s environmental variable should be defined.\n",
947 env);
948 } else {
949 char *buffer = NULL;
950 int prefixes_env_length = strlen(prefixes_env);
951 int i = 0;
952 int num_delimiters = 0;
953 char *token = NULL;
954 char *prefix = NULL;
955
956 for (i = 0; i < prefixes_env_length; i++) {
957 if (':' == prefixes_env[i]) {
958 num_delimiters++;
959 }
960 }
961
962 if (num_delimiters > 0) {
963 *prefixes_array =
964 (char **) malloc((num_delimiters + 1) * sizeof (char *));
965 buffer = strndupa(prefixes_env, prefixes_env_length);
966
967 #ifdef REENTRANT_STRTOK
968 token = strtok_r(buffer, ":", &buffer);
969 #else
970 token = strtok(buffer, ":");
971 #endif
972
973 while ((NULL != token) && (strlen(token) > 0)) {
974 prefix = strndup(token, strlen(token));
975 (*prefixes_array)[(*prefixes_num)++] = filter_path(prefix);
976
977 #ifdef REENTRANT_STRTOK
978 token = strtok_r(NULL, ":", &buffer);
979 #else
980 token = strtok(NULL, ":");
981 #endif
982
983 if (prefix)
984 free(prefix);
985 prefix = NULL;
986 }
987 } else if (prefixes_env_length > 0) {
988 (*prefixes_array) = (char **) malloc(sizeof (char *));
989
990 (*prefixes_array)[(*prefixes_num)++] = filter_path(prefixes_env);
991 }
992 }
993
994 errno = old_errno;
995 }
996
997 static char *
998 filter_path(const char *path)
999 {
1000 int old_errno = errno;
1001 char *filtered_path = (char *) malloc(SB_PATH_MAX * sizeof (char));
1002
1003 canonicalize_ptr(path, filtered_path);
1004
1005 errno = old_errno;
1006
1007 return filtered_path;
1008 }
1009
1010 static int
1011 check_access(sbcontext_t * sbcontext, const char *func, const char *path)
1012 {
1013 int old_errno = errno;
1014 int result = -1;
1015 int i = 0;
1016 char *filtered_path = filter_path(path);
1017
1018 if ('/' != filtered_path[0]) {
1019 errno = old_errno;
1020
1021 if (filtered_path)
1022 free(filtered_path);
1023 filtered_path = NULL;
1024
1025 return 0;
1026 }
1027
1028 if ((0 == strncmp(filtered_path, "/etc/ld.so.preload", 18))
1029 && (is_sandbox_pid())) {
1030 result = 1;
1031 }
1032
1033 if (-1 == result) {
1034 if (NULL != sbcontext->deny_prefixes) {
1035 for (i = 0; i < sbcontext->num_deny_prefixes; i++) {
1036 if (NULL != sbcontext->deny_prefixes[i]) {
1037 if (0 == strncmp(filtered_path,
1038 sbcontext->
1039 deny_prefixes[i],
1040 strlen(sbcontext->deny_prefixes[i]))) {
1041 result = 0;
1042 break;
1043 }
1044 }
1045 }
1046 }
1047
1048 if (-1 == result) {
1049 if ((NULL != sbcontext->read_prefixes) &&
1050 ((0 == strncmp(func, "open_rd", 7)) ||
1051 (0 == strncmp(func, "popen", 5)) ||
1052 (0 == strncmp(func, "opendir", 7)) ||
1053 (0 == strncmp(func, "system", 6)) ||
1054 (0 == strncmp(func, "execl", 5)) ||
1055 (0 == strncmp(func, "execlp", 6)) ||
1056 (0 == strncmp(func, "execle", 6)) ||
1057 (0 == strncmp(func, "execv", 5)) ||
1058 (0 == strncmp(func, "execvp", 6)) ||
1059 (0 == strncmp(func, "execve", 6))
1060 )
1061 ) {
1062 for (i = 0; i < sbcontext->num_read_prefixes; i++) {
1063 if (NULL != sbcontext->read_prefixes[i]) {
1064 if (0 == strncmp(filtered_path,
1065 sbcontext->
1066 read_prefixes[i],
1067 strlen(sbcontext->read_prefixes[i]))) {
1068 result = 1;
1069 break;
1070 }
1071 }
1072 }
1073 } else if ((NULL != sbcontext->write_prefixes) &&
1074 ((0 == strncmp(func, "open_wr", 7)) ||
1075 (0 == strncmp(func, "creat", 5)) ||
1076 (0 == strncmp(func, "creat64", 7)) ||
1077 (0 == strncmp(func, "mkdir", 5)) ||
1078 (0 == strncmp(func, "mknod", 5)) ||
1079 (0 == strncmp(func, "mkfifo", 6)) ||
1080 (0 == strncmp(func, "link", 4)) ||
1081 (0 == strncmp(func, "symlink", 7)) ||
1082 (0 == strncmp(func, "rename", 6)) ||
1083 (0 == strncmp(func, "utime", 5)) ||
1084 (0 == strncmp(func, "utimes", 6)) ||
1085 (0 == strncmp(func, "unlink", 6)) ||
1086 (0 == strncmp(func, "rmdir", 5)) ||
1087 (0 == strncmp(func, "chown", 5)) ||
1088 (0 == strncmp(func, "lchown", 6)) ||
1089 (0 == strncmp(func, "chmod", 5)) ||
1090 (0 == strncmp(func, "truncate", 8)) ||
1091 (0 == strncmp(func, "ftruncate", 9)) ||
1092 (0 == strncmp(func, "truncate64", 10)) ||
1093 (0 == strncmp(func, "ftruncate64", 11))
1094 )
1095 ) {
1096 struct stat tmp_stat;
1097
1098 for (i = 0; i < sbcontext->num_write_denied_prefixes; i++) {
1099 if (NULL != sbcontext->write_denied_prefixes[i]) {
1100 if (0 ==
1101 strncmp(filtered_path,
1102 sbcontext->
1103 write_denied_prefixes
1104 [i], strlen(sbcontext->write_denied_prefixes[i]))) {
1105 result = 0;
1106 break;
1107 }
1108 }
1109 }
1110
1111 if (-1 == result) {
1112 for (i = 0; i < sbcontext->num_write_prefixes; i++) {
1113 if (NULL != sbcontext->write_prefixes[i]) {
1114 if (0 ==
1115 strncmp
1116 (filtered_path,
1117 sbcontext->write_prefixes[i],
1118 strlen(sbcontext->write_prefixes[i]))) {
1119 result = 1;
1120 break;
1121 }
1122 }
1123 }
1124
1125 if (-1 == result) {
1126 /* hack to prevent mkdir of existing dirs to show errors */
1127 if (0 == strncmp(func, "mkdir", 5)) {
1128 if (0 == stat(filtered_path, &tmp_stat)) {
1129 sbcontext->show_access_violation = 0;
1130 result = 0;
1131 }
1132 }
1133
1134 if (-1 == result) {
1135 for (i = 0; i < sbcontext->num_predict_prefixes; i++) {
1136 if (NULL != sbcontext->predict_prefixes[i]) {
1137 if (0 ==
1138 strncmp
1139 (filtered_path,
1140 sbcontext->
1141 predict_prefixes[i],
1142 strlen(sbcontext->predict_prefixes[i]))) {
1143 sbcontext->show_access_violation = 0;
1144 result = 0;
1145 break;
1146 }
1147 }
1148 }
1149 }
1150 }
1151 }
1152 }
1153 }
1154 }
1155
1156 if (-1 == result) {
1157 result = 0;
1158 }
1159
1160 if (filtered_path)
1161 free(filtered_path);
1162 filtered_path = NULL;
1163
1164 errno = old_errno;
1165
1166 return result;
1167 }
1168
1169 static int
1170 check_syscall(sbcontext_t * sbcontext, const char *func, const char *file)
1171 {
1172 int old_errno = errno;
1173 int result = 1;
1174 struct stat log_stat;
1175 char *log_path = NULL;
1176 char *absolute_path = NULL;
1177 char *tmp_buffer = NULL;
1178 int log_file = 0;
1179 struct stat debug_log_stat;
1180 char *debug_log_env = NULL;
1181 char *debug_log_path = NULL;
1182 int debug_log_file = 0;
1183 char buffer[512];
1184 char *dpath = NULL;
1185
1186 init_wrappers();
1187
1188 if ('/' == file[0]) {
1189 absolute_path = (char *) malloc((strlen(file) + 1) * sizeof (char));
1190 sprintf(absolute_path, "%s", file);
1191 } else {
1192 tmp_buffer = (char *) malloc(SB_PATH_MAX * sizeof (char));
1193 egetcwd(tmp_buffer, SB_PATH_MAX - 1);
1194 absolute_path = (char *) malloc((strlen(tmp_buffer) + 1 + strlen(file) + 1) * sizeof (char));
1195 sprintf(absolute_path, "%s/%s", tmp_buffer, file);
1196 if (tmp_buffer)
1197 free(tmp_buffer);
1198 tmp_buffer = NULL;
1199 }
1200
1201 log_path = getenv("SANDBOX_LOG");
1202 debug_log_env = getenv("SANDBOX_DEBUG");
1203 debug_log_path = getenv("SANDBOX_DEBUG_LOG");
1204
1205 if (((NULL == log_path) ||
1206 (0 != strncmp(absolute_path, log_path, strlen(log_path)))) &&
1207 ((NULL == debug_log_env) ||
1208 (NULL == debug_log_path) ||
1209 (0 != strncmp(absolute_path, debug_log_path, strlen(debug_log_path))))
1210 && (0 == check_access(sbcontext, func, absolute_path))
1211 ) {
1212 if (1 == sbcontext->show_access_violation) {
1213 fprintf(stderr,
1214 "\e[31;01mACCESS DENIED\033[0m %s:%*s%s\n",
1215 func, (int) (10 - strlen(func)), "", absolute_path);
1216
1217 if (NULL != log_path) {
1218 sprintf(buffer, "%s:%*s%s\n", func, (int) (10 - strlen(func)), "",
1219 absolute_path);
1220 // log_path somehow gets corrupted. figuring out why would be good.
1221 dpath = strdup(log_path);
1222 if ((0 == lstat(log_path, &log_stat))
1223 && (0 == S_ISREG(log_stat.st_mode))
1224 ) {
1225 fprintf(stderr,
1226 "\e[31;01mSECURITY BREACH\033[0m %s already exists and is not a regular file.\n",
1227 dpath);
1228 } else if (0 == check_access(sbcontext, "open_wr", dpath)) {
1229 unsetenv("SANDBOX_LOG");
1230 fprintf(stderr,
1231 "\e[31;01mSECURITY BREACH\033[0m SANDBOX_LOG %s isn't allowed via SANDBOX_WRITE\n",
1232 dpath);
1233 } else {
1234 log_file = true_open(dpath,
1235 O_APPEND | O_WRONLY
1236 | O_CREAT,
1237 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
1238 if (log_file >= 0) {
1239 write(log_file, buffer, strlen(buffer));
1240 close(log_file);
1241 }
1242 }
1243 free(dpath);
1244 }
1245 }
1246
1247 result = 0;
1248 } else if (NULL != debug_log_env) {
1249 if (NULL != debug_log_path) {
1250 if (0 != strncmp(absolute_path, debug_log_path, strlen(debug_log_path))) {
1251 sprintf(buffer, "%s:%*s%s\n", func, (int) (10 - strlen(func)), "",
1252 absolute_path);
1253 //debug_log_path somehow gets corupted, same thing as log_path above.
1254 dpath = strdup(debug_log_path);
1255 if ((0 == lstat(debug_log_path, &debug_log_stat))
1256 && (0 == S_ISREG(debug_log_stat.st_mode))
1257 ) {
1258 fprintf(stderr,
1259 "\e[31;01mSECURITY BREACH\033[0m %s already exists and is not a regular file.\n",
1260 debug_log_path);
1261 } else if (0 == check_access(sbcontext, "open_wr", dpath)) {
1262 unsetenv("SANDBOX_DEBUG");
1263 unsetenv("SANDBOX_DEBUG_LOG");
1264 fprintf(stderr,
1265 "\e[31;01mSECURITY BREACH\033[0m SANDBOX_DEBUG_LOG %s isn't allowed by SANDBOX_WRITE.\n",
1266 dpath);
1267 } else {
1268 debug_log_file =
1269 true_open(dpath,
1270 O_APPEND | O_WRONLY |
1271 O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
1272 if (debug_log_file >= 0) {
1273 write(debug_log_file, buffer, strlen(buffer));
1274 close(debug_log_file);
1275 }
1276 }
1277 free(dpath);
1278 }
1279 } else {
1280 fprintf(stderr,
1281 "\e[32;01mACCESS ALLOWED\033[0m %s:%*s%s\n",
1282 func, (int) (10 - strlen(func)), "", absolute_path);
1283 }
1284 }
1285
1286 if (absolute_path)
1287 free(absolute_path);
1288 absolute_path = NULL;
1289
1290 errno = old_errno;
1291
1292 return result;
1293 }
1294
1295 static int
1296 is_sandbox_on()
1297 {
1298 int old_errno = errno;
1299
1300 /* $SANDBOX_ACTIVE is an env variable that should ONLY
1301 * be used internal by sandbox.c and libsanbox.c. External
1302 * sources should NEVER set it, else the sandbox is enabled
1303 * in some cases when run in parallel with another sandbox,
1304 * but not even in the sandbox shell.
1305 *
1306 * Azarah (3 Aug 2002)
1307 */
1308 if ((NULL != getenv("SANDBOX_ON")) &&
1309 (0 == strncmp(getenv("SANDBOX_ON"), "1", 1)) &&
1310 (NULL != getenv("SANDBOX_ACTIVE")) &&
1311 (0 == strncmp(getenv("SANDBOX_ACTIVE"), "armedandready", 13))
1312 ) {
1313 errno = old_errno;
1314
1315 return 1;
1316 } else {
1317 errno = old_errno;
1318
1319 return 0;
1320 }
1321 }
1322
1323 static int
1324 before_syscall(const char *func, const char *file)
1325 {
1326 int old_errno = errno;
1327 int result = 1;
1328 sbcontext_t sbcontext;
1329
1330 if (!strlen(file)) {
1331 /* The file/directory does not exist */
1332 errno = ENOENT;
1333 return 0;
1334 }
1335
1336 init_context(&sbcontext);
1337
1338 init_env_entries(&(sbcontext.deny_prefixes),
1339 &(sbcontext.num_deny_prefixes), "SANDBOX_DENY", 1);
1340 init_env_entries(&(sbcontext.read_prefixes),
1341 &(sbcontext.num_read_prefixes), "SANDBOX_READ", 1);
1342 init_env_entries(&(sbcontext.write_prefixes),
1343 &(sbcontext.num_write_prefixes), "SANDBOX_WRITE", 1);
1344 init_env_entries(&(sbcontext.predict_prefixes),
1345 &(sbcontext.num_predict_prefixes), "SANDBOX_PREDICT", 1);
1346
1347 result = check_syscall(&sbcontext, func, file);
1348
1349 clean_env_entries(&(sbcontext.deny_prefixes), &(sbcontext.num_deny_prefixes));
1350 clean_env_entries(&(sbcontext.read_prefixes), &(sbcontext.num_read_prefixes));
1351 clean_env_entries(&(sbcontext.write_prefixes),
1352 &(sbcontext.num_write_prefixes));
1353 clean_env_entries(&(sbcontext.predict_prefixes),
1354 &(sbcontext.num_predict_prefixes));
1355
1356 errno = old_errno;
1357
1358 if (0 == result) {
1359 errno = EACCES;
1360 }
1361
1362 return result;
1363 }
1364
1365 static int
1366 before_syscall_open_int(const char *func, const char *file, int flags)
1367 {
1368 if ((flags & O_WRONLY) || (flags & O_RDWR)) {
1369 return before_syscall("open_wr", file);
1370 } else {
1371 return before_syscall("open_rd", file);
1372 }
1373 }
1374
1375 static int
1376 before_syscall_open_char(const char *func, const char *file, const char *mode)
1377 {
1378 if (*mode == 'r' && ((strcmp(mode, "r") == 0) ||
1379 /* The strspn accept args are known non-writable modifiers */
1380 (strlen(++mode) == strspn(mode, "xbtmc")))) {
1381 return before_syscall("open_rd", file);
1382 } else {
1383 return before_syscall("open_wr", file);
1384 }
1385 }
1386
1387 #include "getcwd.c"
1388 #include "canonicalize.c"
1389
1390 // vim:expandtab noai:cindent ai

Properties

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

  ViewVC Help
Powered by ViewVC 1.1.20