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

Contents of /trunk/libsandbox.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2 - (show annotations) (download) (as text)
Fri Nov 19 22:03:42 2004 UTC (10 years, 1 month ago) by ferringb
File MIME type: text/x-csrc
File size: 32748 byte(s)
Initial revision

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