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

Contents of /trunk/libsandbox.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 26 - (show annotations) (download) (as text)
Mon Dec 6 21:42:51 2004 UTC (9 years, 7 months ago) by ferringb
File MIME type: text/x-csrc
File size: 32794 byte(s)
hopefully cvs is done being stupid.  Compilation fixes, along w/ make dist fix.

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