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

Contents of /trunk/libsandbox.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 30 - (show annotations) (download) (as text)
Wed Mar 2 09:04:45 2005 UTC (9 years, 4 months ago) by azarah
File MIME type: text/x-csrc
File size: 32834 byte(s)
White space fixes.

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