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

Contents of /trunk/libsandbox.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 24 - (show annotations) (download) (as text)
Sun Dec 5 05:42:10 2004 UTC (9 years, 8 months ago) by ferringb
File MIME type: text/x-csrc
File size: 32770 byte(s)
should make things compile again

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