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

Contents of /trunk/src/libsandbox.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 248 - (show annotations) (download) (as text)
Wed May 3 11:18:28 2006 UTC (8 years, 7 months ago) by azarah
File MIME type: text/x-csrc
File size: 40175 byte(s)
If glibc/kernel side of getcwd() screwed up, return ENAMETOOLONG.

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 memory debugging. */
33 /* #define SB_MEM_DEBUG 1 */
34
35 #define open xxx_open
36 #define open64 xxx_open64
37
38 #include "config.h"
39
40 /* Better way would be to only define _GNU_SOURCE when __GLIBC__ is defined,
41 * but including features.h and then defining _GNU_SOURCE do not work */
42 #if defined(HAVE_RTLD_NEXT)
43 # define _GNU_SOURCE
44 #endif
45 #include <dirent.h>
46 #include <dlfcn.h>
47 #include <errno.h>
48 #include <fcntl.h>
49 #include <libgen.h>
50 #include <stdarg.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <sys/file.h>
55 #include <sys/stat.h>
56 #include <sys/types.h>
57 #include <sys/param.h>
58 #include <unistd.h>
59 #include <utime.h>
60
61 #include "localdecls.h"
62
63 #if !defined(BROKEN_RTLD_NEXT) && defined(HAVE_RTLD_NEXT)
64 # define USE_RTLD_NEXT
65 #endif
66
67 #ifdef SB_MEM_DEBUG
68 # include <mcheck.h>
69 #endif
70
71 #undef open
72 #undef open64
73
74 #include "sandbox.h"
75
76 /* Macros to check if a function should be executed */
77 #define FUNCTION_SANDBOX_SAFE(_func, _path) \
78 ((0 == is_sandbox_on()) || (1 == before_syscall(_func, _path)))
79
80 #define FUNCTION_SANDBOX_SAFE_ACCESS(_func, _path, _flags) \
81 ((0 == is_sandbox_on()) || (1 == before_syscall_access(_func, _path, _flags)))
82
83 #define FUNCTION_SANDBOX_SAFE_OPEN_INT(_func, _path, _flags) \
84 ((0 == is_sandbox_on()) || (1 == before_syscall_open_int(_func, _path, _flags)))
85
86 #define FUNCTION_SANDBOX_SAFE_OPEN_CHAR(_func, _path, _mode) \
87 ((0 == is_sandbox_on()) || (1 == before_syscall_open_char(_func, _path, _mode)))
88
89 /* Macro to check if a wrapper is defined, if not
90 * then try to resolve it again. */
91 #define check_dlsym(_name) \
92 { \
93 int old_errno = errno; \
94 if (!true_ ## _name) \
95 true_ ## _name = get_dlsym(symname_ ## _name, symver_ ## _name); \
96 errno = old_errno; \
97 }
98
99 static char sandbox_lib[SB_PATH_MAX];
100
101 typedef struct {
102 int show_access_violation;
103 char **deny_prefixes;
104 int num_deny_prefixes;
105 char **read_prefixes;
106 int num_read_prefixes;
107 char **write_prefixes;
108 int num_write_prefixes;
109 char **predict_prefixes;
110 int num_predict_prefixes;
111 char **write_denied_prefixes;
112 int num_write_denied_prefixes;
113 } sbcontext_t;
114
115 static sbcontext_t sbcontext;
116 static char **cached_env_vars;
117 int sandbox_on = 1;
118 static int sb_init = 0;
119 static int sb_path_size_warning = 0;
120
121 void __attribute__ ((constructor)) libsb_init(void);
122 void __attribute__ ((destructor)) libsb_fini(void);
123
124 static void *get_dlsym(const char *, const char *);
125 static int canonicalize(const char *, char *);
126 static char *resolve_path(const char *, int);
127 static int check_prefixes(char **, int, const char *);
128 static int check_access(sbcontext_t *, const char *, const char *, const char *);
129 static int check_syscall(sbcontext_t *, const char *, const char *);
130 static int before_syscall(const char *, const char *);
131 static int before_syscall_access(const char *, const char *, int);
132 static int before_syscall_open_int(const char *, const char *, int);
133 static int before_syscall_open_char(const char *, const char *, const char *);
134 static void clean_env_entries(char ***, int *);
135 static void init_context(sbcontext_t *);
136 static void init_env_entries(char ***, int *, const char *, const char *, int);
137 static int is_sandbox_on();
138
139 /*
140 * Initialize the shabang
141 */
142
143 static void *libc_handle = NULL;
144
145 void __attribute__ ((destructor)) libsb_fini(void)
146 {
147 int x;
148
149 sb_init = 0;
150
151 if(NULL != cached_env_vars) {
152 for(x=0; x < 4; x++) {
153 if(NULL != cached_env_vars[x]) {
154 free(cached_env_vars[x]);
155 cached_env_vars[x] = NULL;
156 }
157 }
158 free(cached_env_vars);
159 cached_env_vars = NULL;
160 }
161
162 clean_env_entries(&(sbcontext.deny_prefixes),
163 &(sbcontext.num_deny_prefixes));
164 clean_env_entries(&(sbcontext.read_prefixes),
165 &(sbcontext.num_read_prefixes));
166 clean_env_entries(&(sbcontext.write_prefixes),
167 &(sbcontext.num_write_prefixes));
168 clean_env_entries(&(sbcontext.predict_prefixes),
169 &(sbcontext.num_predict_prefixes));
170 }
171
172 void __attribute__ ((constructor)) libsb_init(void)
173 {
174 int old_errno = errno;
175
176 #ifdef SB_MEM_DEBUG
177 mtrace();
178 #endif
179
180 /* Get the path and name to this library */
181 get_sandbox_lib(sandbox_lib);
182
183 // sb_init = 1;
184
185 errno = old_errno;
186 }
187
188 static void *get_dlsym(const char *symname, const char *symver)
189 {
190 void *symaddr = NULL;
191
192 if (NULL == libc_handle) {
193 #if !defined(USE_RTLD_NEXT)
194 libc_handle = dlopen(LIBC_VERSION, RTLD_LAZY);
195 if (!libc_handle) {
196 fprintf(stderr, "libsandbox: Can't dlopen libc: %s\n",
197 dlerror());
198 exit(EXIT_FAILURE);
199 }
200 #else
201 libc_handle = RTLD_NEXT;
202 #endif
203 }
204
205 if (NULL == symver)
206 symaddr = dlsym(libc_handle, symname);
207 else
208 symaddr = dlvsym(libc_handle, symname, symver);
209 if (!symaddr) {
210 fprintf(stderr, "libsandbox: Can't resolve %s: %s\n",
211 symname, dlerror());
212 exit(EXIT_FAILURE);
213 }
214
215 return symaddr;
216 }
217
218 static int canonicalize(const char *path, char *resolved_path)
219 {
220 int old_errno = errno;
221 char *retval;
222
223 *resolved_path = '\0';
224
225 /* If path == NULL, return or we get a segfault */
226 if (NULL == path) {
227 errno = EINVAL;
228 return -1;
229 }
230
231 /* Do not try to resolve an empty path */
232 if ('\0' == path[0]) {
233 errno = old_errno;
234 return 0;
235 }
236
237 retval = erealpath(path, resolved_path);
238
239 if ((NULL == retval) && (path[0] != '/')) {
240 /* The path could not be canonicalized, append it
241 * to the current working directory if it was not
242 * an absolute path
243 */
244
245 if (ENAMETOOLONG == errno)
246 return -1;
247
248 if (NULL == egetcwd(resolved_path, SB_PATH_MAX - 2))
249 return -1;
250 snprintf((char *)(resolved_path + strlen(resolved_path)),
251 SB_PATH_MAX - strlen(resolved_path), "/%s", path);
252
253 if (NULL == erealpath(resolved_path, resolved_path)) {
254 if (errno == ENAMETOOLONG) {
255 /* The resolved path is too long for the buffer to hold */
256 return -1;
257 } else {
258 /* Whatever it resolved, is not a valid path */
259 errno = ENOENT;
260 return -1;
261 }
262 }
263
264 } else if ((NULL == retval) && (path[0] == '/')) {
265 /* Whatever it resolved, is not a valid path */
266 errno = ENOENT;
267 return -1;
268 }
269
270 errno = old_errno;
271 return 0;
272 }
273
274 static char *resolve_path(const char *path, int follow_link)
275 {
276 int old_errno = errno;
277 char tmp_str1[SB_PATH_MAX], tmp_str2[SB_PATH_MAX];
278 char *dname, *bname;
279 char *filtered_path;
280
281 if (NULL == path)
282 return NULL;
283
284 filtered_path = malloc(SB_PATH_MAX * sizeof(char));
285 if (NULL == filtered_path)
286 return NULL;
287
288 if (0 == follow_link) {
289 if (-1 == canonicalize(path, filtered_path))
290 return NULL;
291 } else {
292 /* Basically we get the realpath which should resolve symlinks,
293 * etc. If that fails (might not exist), we try to get the
294 * realpath of the parent directory, as that should hopefully
295 * exist. If all else fails, just go with canonicalize */
296 if (NULL == realpath(path, filtered_path)) {
297 snprintf(tmp_str1, SB_PATH_MAX, "%s", path);
298
299 dname = dirname(tmp_str1);
300
301 /* If not, then check if we can resolve the
302 * parent directory */
303 if (NULL == realpath(dname, filtered_path)) {
304 /* Fall back to canonicalize */
305 if (-1 == canonicalize(path, filtered_path))
306 return NULL;
307 } else {
308 /* OK, now add the basename to keep our access
309 * checking happy (don't want '/usr/lib' if we
310 * tried to do something with non-existing
311 * file '/usr/lib/cf*' ...) */
312 snprintf(tmp_str2, SB_PATH_MAX, "%s", path);
313
314 bname = gbasename(tmp_str2);
315 snprintf((char *)(filtered_path + strlen(filtered_path)),
316 SB_PATH_MAX - strlen(filtered_path), "%s%s",
317 (filtered_path[strlen(filtered_path) - 1] != '/') ? "/" : "",
318 bname);
319 }
320 }
321 }
322
323 errno = old_errno;
324
325 return filtered_path;
326 }
327
328 /*
329 * Wrapper Functions
330 */
331
332 #define chmod_decl(_name) \
333 \
334 extern int _name(const char *, mode_t); \
335 static int (*true_ ## _name) (const char *, mode_t) = NULL; \
336 \
337 int _name(const char *path, mode_t mode) \
338 { \
339 int result = -1; \
340 \
341 if FUNCTION_SANDBOX_SAFE("chmod", path) { \
342 check_dlsym(_name); \
343 result = true_ ## _name(path, mode); \
344 } \
345 \
346 return result; \
347 }
348
349 #define chown_decl(_name) \
350 \
351 extern int _name(const char *, uid_t, gid_t); \
352 static int (*true_ ## _name) (const char *, uid_t, gid_t) = NULL; \
353 \
354 int _name(const char *path, uid_t owner, gid_t group) \
355 { \
356 int result = -1; \
357 \
358 if FUNCTION_SANDBOX_SAFE("chown", path) { \
359 check_dlsym(_name); \
360 result = true_ ## _name(path, owner, group); \
361 } \
362 \
363 return result; \
364 }
365
366 #define creat_decl(_name) \
367 \
368 extern int _name(const char *, mode_t); \
369 /* static int (*true_ ## _name) (const char *, mode_t) = NULL; */ \
370 \
371 int _name(const char *pathname, mode_t mode) \
372 { \
373 int result = -1; \
374 \
375 if FUNCTION_SANDBOX_SAFE("creat", pathname) { \
376 check_dlsym(open_DEFAULT); \
377 result = true_open_DEFAULT(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode); \
378 } \
379 \
380 return result; \
381 }
382
383 #define fopen_decl(_name) \
384 \
385 extern FILE *_name(const char *, const char *); \
386 static FILE * (*true_ ## _name) (const char *, const char *) = NULL; \
387 \
388 FILE *_name(const char *pathname, const char *mode) \
389 { \
390 FILE *result = NULL; \
391 \
392 if FUNCTION_SANDBOX_SAFE_OPEN_CHAR("fopen", pathname, mode) { \
393 check_dlsym(_name); \
394 result = true_ ## _name(pathname, mode); \
395 } \
396 \
397 return result; \
398 }
399
400 #define lchown_decl(_name) \
401 \
402 extern int _name(const char *, uid_t, gid_t); \
403 static int (*true_ ## _name) (const char *, uid_t, gid_t) = NULL; \
404 \
405 int _name(const char *path, uid_t owner, gid_t group) \
406 { \
407 int result = -1; \
408 \
409 if FUNCTION_SANDBOX_SAFE("lchown", path) { \
410 check_dlsym(_name); \
411 result = true_ ## _name(path, owner, group); \
412 } \
413 \
414 return result; \
415 }
416
417 #define link_decl(_name) \
418 \
419 extern int _name(const char *, const char *); \
420 static int (*true_ ## _name) (const char *, const char *) = NULL; \
421 \
422 int _name(const char *oldpath, const char *newpath) \
423 { \
424 int result = -1; \
425 \
426 if FUNCTION_SANDBOX_SAFE("link", newpath) { \
427 check_dlsym(_name); \
428 result = true_ ## _name(oldpath, newpath); \
429 } \
430 \
431 return result; \
432 }
433
434 #define mkdir_decl(_name) \
435 \
436 extern int _name(const char *, mode_t); \
437 static int (*true_ ## _name) (const char *, mode_t) = NULL; \
438 \
439 int _name(const char *pathname, mode_t mode) \
440 { \
441 struct stat st; \
442 int result = -1, my_errno = errno; \
443 char canonic[SB_PATH_MAX]; \
444 \
445 if (-1 == canonicalize(pathname, canonic)) \
446 /* Path is too long to canonicalize, do not fail, but just let
447 * the real function handle it (see bug #94630 and #21766). */ \
448 if (ENAMETOOLONG != errno) \
449 return -1; \
450 \
451 /* XXX: Hack to prevent errors if the directory exist,
452 * and are not writable - we rather return EEXIST rather
453 * than failing */ \
454 if (0 == lstat(canonic, &st)) { \
455 errno = EEXIST; \
456 return -1; \
457 } \
458 errno = my_errno; \
459 \
460 if FUNCTION_SANDBOX_SAFE("mkdir", pathname) { \
461 check_dlsym(_name); \
462 result = true_ ## _name(pathname, mode); \
463 } \
464 \
465 return result; \
466 }
467
468 #define opendir_decl(_name) \
469 \
470 extern DIR *_name(const char *); \
471 static DIR * (*true_ ## _name) (const char *) = NULL; \
472 \
473 DIR *_name(const char *name) \
474 { \
475 DIR *result = NULL; \
476 \
477 if FUNCTION_SANDBOX_SAFE("opendir", name) { \
478 check_dlsym(_name); \
479 result = true_ ## _name(name); \
480 } \
481 \
482 return result; \
483 }
484
485 #define mknod_decl(_name) \
486 \
487 extern int _name(const char *, mode_t, dev_t); \
488 static int (*true_ ## _name) (const char *, mode_t, dev_t) = NULL; \
489 \
490 int _name(const char *pathname, mode_t mode, dev_t dev) \
491 { \
492 int result = -1; \
493 \
494 if FUNCTION_SANDBOX_SAFE("mknod", pathname) { \
495 check_dlsym(_name); \
496 result = true_ ## _name(pathname, mode, dev); \
497 } \
498 \
499 return result; \
500 }
501
502 #define __xmknod_decl(_name) \
503 \
504 extern int _name(int, const char *, __mode_t, __dev_t *); \
505 static int (*true_ ## _name) (int, const char *, __mode_t, __dev_t *) = NULL; \
506 \
507 int _name(int ver, const char *pathname, __mode_t mode, __dev_t *dev) \
508 { \
509 int result = -1; \
510 \
511 if FUNCTION_SANDBOX_SAFE("mknod", pathname) { \
512 check_dlsym(_name); \
513 result = true_ ## _name(ver, pathname, mode, dev); \
514 } \
515 \
516 return result; \
517 }
518
519 #define mkfifo_decl(_name) \
520 \
521 extern int _name(const char *, mode_t); \
522 static int (*true_ ## _name) (const char *, mode_t) = NULL; \
523 \
524 int _name(const char *pathname, mode_t mode) \
525 { \
526 int result = -1; \
527 \
528 if FUNCTION_SANDBOX_SAFE("mkfifo", pathname) { \
529 check_dlsym(_name); \
530 result = true_ ## _name(pathname, mode); \
531 } \
532 \
533 return result; \
534 }
535
536 #define access_decl(_name) \
537 \
538 extern int _name(const char *, int); \
539 static int (*true_ ## _name) (const char *, int) = NULL; \
540 \
541 int _name(const char *pathname, int mode) \
542 { \
543 int result = -1; \
544 \
545 if FUNCTION_SANDBOX_SAFE_ACCESS("access", pathname, mode) { \
546 check_dlsym(_name); \
547 result = true_ ## _name(pathname, mode); \
548 } \
549 \
550 return result; \
551 }
552
553 #define open_decl(_name) \
554 \
555 extern int _name(const char *, int, ...); \
556 static int (*true_ ## _name) (const char *, int, ...) = NULL; \
557 \
558 /* Eventually, there is a third parameter: it's mode_t mode */ \
559 int _name(const char *pathname, int flags, ...) \
560 { \
561 va_list ap; \
562 int mode = 0; \
563 int result = -1; \
564 \
565 if (flags & O_CREAT) { \
566 va_start(ap, flags); \
567 mode = va_arg(ap, int); \
568 va_end(ap); \
569 } \
570 \
571 if FUNCTION_SANDBOX_SAFE_OPEN_INT("open", pathname, flags) { \
572 check_dlsym(_name); \
573 if (flags & O_CREAT) \
574 result = true_ ## _name(pathname, flags, mode); \
575 else \
576 result = true_ ## _name(pathname, flags); \
577 } \
578 \
579 return result; \
580 }
581
582 #define rename_decl(_name) \
583 \
584 extern int _name(const char *, const char *); \
585 static int (*true_ ## _name) (const char *, const char *) = NULL; \
586 \
587 int _name(const char *oldpath, const char *newpath) \
588 { \
589 int result = -1; \
590 \
591 if (FUNCTION_SANDBOX_SAFE("rename", oldpath) && \
592 FUNCTION_SANDBOX_SAFE("rename", newpath)) { \
593 check_dlsym(_name); \
594 result = true_ ## _name(oldpath, newpath); \
595 } \
596 \
597 return result; \
598 }
599
600 #define rmdir_decl(_name) \
601 \
602 extern int _name(const char *); \
603 static int (*true_ ## _name) (const char *) = NULL; \
604 \
605 int _name(const char *pathname) \
606 { \
607 int result = -1; \
608 \
609 if FUNCTION_SANDBOX_SAFE("rmdir", pathname) { \
610 check_dlsym(_name); \
611 result = true_ ## _name(pathname); \
612 } \
613 \
614 return result; \
615 }
616
617 #define symlink_decl(_name) \
618 \
619 extern int _name(const char *, const char *); \
620 static int (*true_ ## _name) (const char *, const char *) = NULL; \
621 \
622 int _name(const char *oldpath, const char *newpath) \
623 { \
624 int result = -1; \
625 \
626 if FUNCTION_SANDBOX_SAFE("symlink", newpath) { \
627 check_dlsym(_name); \
628 result = true_ ## _name(oldpath, newpath); \
629 } \
630 \
631 return result; \
632 }
633
634 #define truncate_decl(_name) \
635 \
636 extern int _name(const char *, TRUNCATE_T); \
637 static int (*true_ ## _name) (const char *, TRUNCATE_T) = NULL; \
638 \
639 int _name(const char *path, TRUNCATE_T length) \
640 { \
641 int result = -1; \
642 \
643 if FUNCTION_SANDBOX_SAFE("truncate", path) { \
644 check_dlsym(_name); \
645 result = true_ ## _name(path, length); \
646 } \
647 \
648 return result; \
649 }
650
651 #define unlink_decl(_name) \
652 \
653 extern int _name(const char *); \
654 static int (*true_ ## _name) (const char *) = NULL; \
655 \
656 int _name(const char *pathname) \
657 { \
658 int result = -1; \
659 char canonic[SB_PATH_MAX]; \
660 \
661 if (-1 == canonicalize(pathname, canonic)) \
662 /* Path is too long to canonicalize, do not fail, but just let
663 * the real function handle it (see bug #94630 and #21766). */ \
664 if (ENAMETOOLONG != errno) \
665 return -1; \
666 \
667 /* XXX: Hack to make sure sandboxed process cannot remove
668 * a device node, bug #79836. */ \
669 if ((0 == strncmp(canonic, "/dev/null", 9)) || \
670 (0 == strncmp(canonic, "/dev/zero", 9))) { \
671 errno = EACCES; \
672 return result; \
673 } \
674 \
675 if FUNCTION_SANDBOX_SAFE("unlink", pathname) { \
676 check_dlsym(_name); \
677 result = true_ ## _name(pathname); \
678 } \
679 \
680 return result; \
681 }
682
683 #define getcwd_decl(_name) \
684 \
685 extern char *_name(char *, size_t); \
686 static char * (*true_ ## _name) (char *, size_t) = NULL; \
687 \
688 char *_name(char *buf, size_t size) \
689 { \
690 char *result = NULL; \
691 \
692 /* Need to disable sandbox, as on non-linux libc's, opendir() is
693 * used by some getcwd() implementations and resolves to the sandbox
694 * opendir() wrapper, causing infinit recursion and finially crashes.
695 */ \
696 sandbox_on = 0; \
697 check_dlsym(_name); \
698 result = true_ ## _name(buf, size); \
699 sandbox_on = 1; \
700 \
701 return result; \
702 }
703
704 #define creat64_decl(_name) \
705 \
706 extern int _name(const char *, __mode_t); \
707 /* static int (*true_ ## _name) (const char *, __mode_t) = NULL; */ \
708 \
709 int _name(const char *pathname, __mode_t mode) \
710 { \
711 int result = -1; \
712 \
713 if FUNCTION_SANDBOX_SAFE("creat64", pathname) { \
714 check_dlsym(open64_DEFAULT); \
715 result = true_open64_DEFAULT(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode); \
716 } \
717 \
718 return result; \
719 }
720
721 #define fopen64_decl(_name) \
722 \
723 extern FILE *_name(const char *, const char *); \
724 static FILE * (*true_ ## _name) (const char *, const char *) = NULL; \
725 \
726 FILE *_name(const char *pathname, const char *mode) \
727 { \
728 FILE *result = NULL; \
729 \
730 if FUNCTION_SANDBOX_SAFE_OPEN_CHAR("fopen64", pathname, mode) { \
731 check_dlsym(_name); \
732 result = true_ ## _name(pathname, mode); \
733 } \
734 \
735 return result; \
736 }
737
738 #define open64_decl(_name) \
739 \
740 extern int _name(const char *, int, ...); \
741 static int (*true_ ## _name) (const char *, int, ...) = NULL; \
742 \
743 /* Eventually, there is a third parameter: it's mode_t mode */ \
744 int _name(const char *pathname, int flags, ...) \
745 { \
746 va_list ap; \
747 int mode = 0; \
748 int result = -1; \
749 \
750 if (flags & O_CREAT) { \
751 va_start(ap, flags); \
752 mode = va_arg(ap, int); \
753 va_end(ap); \
754 } \
755 \
756 if FUNCTION_SANDBOX_SAFE_OPEN_INT("open64", pathname, flags) { \
757 check_dlsym(_name); \
758 if (flags & O_CREAT) \
759 result = true_ ## _name(pathname, flags, mode); \
760 else \
761 result = true_ ## _name(pathname, flags); \
762 } \
763 \
764 return result; \
765 }
766
767 #define truncate64_decl(_name) \
768 \
769 extern int _name(const char *, __off64_t); \
770 static int (*true_ ## _name) (const char *, __off64_t) = NULL; \
771 \
772 int _name(const char *path, __off64_t length) \
773 { \
774 int result = -1; \
775 \
776 if FUNCTION_SANDBOX_SAFE("truncate64", path) { \
777 check_dlsym(_name); \
778 result = true_ ## _name(path, length); \
779 } \
780 \
781 return result; \
782 }
783
784 /*
785 * Exec Wrappers
786 */
787
788 #define execve_decl(_name) \
789 \
790 extern int _name(const char *, char *const[], char *const[]); \
791 static int (*true_ ## _name) (const char *, char *const[], char *const[]) = NULL; \
792 \
793 int _name(const char *filename, char *const argv[], char *const envp[]) \
794 { \
795 int old_errno = errno; \
796 int result = -1; \
797 int count = 0; \
798 int env_len = 0; \
799 char **my_env = NULL; \
800 int kill_env = 1; \
801 /* We limit the size LD_PRELOAD can be here, but it should be enough */ \
802 char tmp_str[SB_BUF_LEN]; \
803 \
804 if FUNCTION_SANDBOX_SAFE("execve", filename) { \
805 while (envp[count] != NULL) { \
806 /* Check if we do not have to do anything */ \
807 if (strstr(envp[count], LD_PRELOAD_EQ) == envp[count]) { \
808 if (NULL != strstr(envp[count], sandbox_lib)) { \
809 my_env = (char **)envp; \
810 kill_env = 0; \
811 goto end_loop; \
812 } \
813 } \
814 \
815 /* If LD_PRELOAD is set and sandbox_lib not in it */ \
816 if (((strstr(envp[count], LD_PRELOAD_EQ) == envp[count]) && \
817 (NULL == strstr(envp[count], sandbox_lib))) || \
818 /* Or LD_PRELOAD is not set, and this is the last loop */ \
819 ((strstr(envp[count], LD_PRELOAD_EQ) != envp[count]) && \
820 (NULL == envp[count + 1]))) { \
821 int i = 0; \
822 int add_ldpreload = 0; \
823 const int max_envp_len = strlen(envp[count]) + strlen(sandbox_lib) + 1; \
824 \
825 /* Fail safe ... */ \
826 if (max_envp_len > SB_BUF_LEN) { \
827 fprintf(stderr, "libsandbox: max_envp_len too big!\n"); \
828 errno = ENOMEM; \
829 return result; \
830 } \
831 \
832 /* Calculate envp size */ \
833 my_env = (char **)envp; \
834 do \
835 env_len++; \
836 while (NULL != *my_env++); \
837 \
838 /* Should we add LD_PRELOAD ? */ \
839 if (strstr(envp[count], LD_PRELOAD_EQ) != envp[count]) \
840 add_ldpreload = 1; \
841 \
842 my_env = (char **)calloc(env_len + add_ldpreload, sizeof(char *)); \
843 if (NULL == my_env) { \
844 errno = ENOMEM; \
845 return result; \
846 } \
847 /* Copy envp to my_env */ \
848 do \
849 /* Leave a space for LD_PRELOAD if needed */ \
850 my_env[i + add_ldpreload] = envp[i]; \
851 while (NULL != envp[i++]); \
852 \
853 /* Add 'LD_PRELOAD=' to the beginning of our new string */ \
854 snprintf(tmp_str, max_envp_len, "%s%s", LD_PRELOAD_EQ, sandbox_lib); \
855 \
856 /* LD_PRELOAD already have variables other than sandbox_lib,
857 * thus we have to add sandbox_lib seperated via a whitespace. */ \
858 if (0 == add_ldpreload) { \
859 snprintf((char *)(tmp_str + strlen(tmp_str)), \
860 max_envp_len - strlen(tmp_str) + 1, " %s", \
861 (char *)(envp[count] + strlen(LD_PRELOAD_EQ))); \
862 } \
863 \
864 /* Valid string? */ \
865 tmp_str[max_envp_len] = '\0'; \
866 \
867 /* Ok, replace my_env[count] with our version that contains
868 * sandbox_lib ... */ \
869 if (1 == add_ldpreload) \
870 /* We reserved a space for LD_PRELOAD above */ \
871 my_env[0] = tmp_str; \
872 else \
873 my_env[count] = tmp_str; \
874 \
875 goto end_loop; \
876 } \
877 count++; \
878 } \
879 \
880 end_loop: \
881 errno = old_errno; \
882 check_dlsym(_name); \
883 result = true_ ## _name(filename, argv, my_env); \
884 old_errno = errno; \
885 \
886 if (my_env && kill_env) \
887 free(my_env); \
888 } \
889 \
890 errno = old_errno; \
891 \
892 return result; \
893 }
894
895 #include "symbols.h"
896
897 /*
898 * Internal Functions
899 */
900
901 char *egetcwd(char *buf, size_t size)
902 {
903 struct stat st;
904 char *tmpbuf;
905 int old_errno;
906
907 /* Need to disable sandbox, as on non-linux libc's, opendir() is
908 * used by some getcwd() implementations and resolves to the sandbox
909 * opendir() wrapper, causing infinit recursion and finially crashes.
910 */
911 sandbox_on = 0;
912 check_dlsym(getcwd_DEFAULT);
913 errno = 0;
914 tmpbuf = true_getcwd_DEFAULT(buf, size);
915 sandbox_on = 1;
916 if (tmpbuf) {
917 old_errno = errno;
918 lstat(buf, &st);
919
920 if (errno == ENOENT) {
921 /* If lstat() failed with eerror = ENOENT, then its
922 * possible that we are running on an older kernel
923 * which had issues with returning invalid paths if
924 * they got too long.
925 */
926 errno = ENAMETOOLONG;
927 free(tmpbuf);
928 return NULL;
929 } else if (errno != 0) {
930 /* Not sure if we should quit here, but I guess if
931 * lstat() fails, getcwd could have messed up.
932 */
933 free(tmpbuf);
934 return NULL;
935 }
936
937 errno = old_errno;
938 }
939
940 /* Make sure we do not return garbage if the current libc or kernel's
941 * getcwd() is buggy.
942 */
943 if (errno != 0) {
944 if (tmpbuf)
945 free(tmpbuf);
946
947 return NULL;
948 }
949
950 return tmpbuf;
951 }
952
953 static void init_context(sbcontext_t * context)
954 {
955 context->show_access_violation = 1;
956 context->deny_prefixes = NULL;
957 context->num_deny_prefixes = 0;
958 context->read_prefixes = NULL;
959 context->num_read_prefixes = 0;
960 context->write_prefixes = NULL;
961 context->num_write_prefixes = 0;
962 context->predict_prefixes = NULL;
963 context->num_predict_prefixes = 0;
964 context->write_denied_prefixes = NULL;
965 context->num_write_denied_prefixes = 0;
966 }
967
968 static void clean_env_entries(char ***prefixes_array, int *prefixes_num)
969 {
970 int old_errno = errno;
971 int i = 0;
972
973 if (NULL != *prefixes_array) {
974 for (i = 0; i < *prefixes_num; i++) {
975 if (NULL != (*prefixes_array)[i]) {
976 free((*prefixes_array)[i]);
977 (*prefixes_array)[i] = NULL;
978 }
979 }
980 if (NULL != *prefixes_array)
981 free(*prefixes_array);
982 *prefixes_array = NULL;
983 *prefixes_num = 0;
984 }
985
986 errno = old_errno;
987 }
988
989 #define pfx_num (*prefixes_num)
990 #define pfx_array (*prefixes_array)
991 #define pfx_item ((*prefixes_array)[(*prefixes_num)])
992
993 static void init_env_entries(char ***prefixes_array, int *prefixes_num, const char *env, const char *prefixes_env, int warn)
994 {
995 char *token = NULL;
996 char *rpath = NULL;
997 char *buffer = NULL;
998 char *buffer_ptr = NULL;
999 int prefixes_env_length = strlen(prefixes_env);
1000 int num_delimiters = 0;
1001 int i = 0;
1002 int old_errno = errno;
1003
1004 if (NULL == prefixes_env) {
1005 /* Do not warn if this is in init stage, as we might get
1006 * issues due to LD_PRELOAD already set (bug #91431). */
1007 if (1 == sb_init)
1008 fprintf(stderr,
1009 "libsandbox: The '%s' env variable is not defined!\n",
1010 env);
1011 if (pfx_array) {
1012 for (i = 0; i < pfx_num; i++)
1013 free(pfx_item);
1014 free(pfx_array);
1015 }
1016 pfx_num = 0;
1017
1018 goto done;
1019 }
1020
1021 for (i = 0; i < prefixes_env_length; i++) {
1022 if (':' == prefixes_env[i])
1023 num_delimiters++;
1024 }
1025
1026 /* num_delimiters might be 0, and we need 2 entries at least */
1027 pfx_array = malloc(((num_delimiters * 2) + 2) * sizeof(char *));
1028 if (NULL == pfx_array)
1029 goto error;
1030 buffer = gstrndup(prefixes_env, prefixes_env_length);
1031 if (NULL == buffer)
1032 goto error;
1033 buffer_ptr = buffer;
1034
1035 #ifdef HAVE_STRTOK_R
1036 token = strtok_r(buffer_ptr, ":", &buffer_ptr);
1037 #else
1038 token = strtok(buffer_ptr, ":");
1039 #endif
1040
1041 while ((NULL != token) && (strlen(token) > 0)) {
1042 pfx_item = resolve_path(token, 0);
1043 if (NULL != pfx_item) {
1044 pfx_num++;
1045
1046 /* Now add the realpath if it exists and
1047 * are not a duplicate */
1048 rpath = malloc(SB_PATH_MAX * sizeof(char));
1049 if (NULL != rpath) {
1050 pfx_item = realpath(*(&(pfx_item) - 1), rpath);
1051 if ((NULL != pfx_item) &&
1052 (0 != strcmp(*(&(pfx_item) - 1), pfx_item))) {
1053 pfx_num++;
1054 } else {
1055 free(rpath);
1056 pfx_item = NULL;
1057 }
1058 } else {
1059 goto error;
1060 }
1061 }
1062
1063 #ifdef HAVE_STRTOK_R
1064 token = strtok_r(NULL, ":", &buffer_ptr);
1065 #else
1066 token = strtok(NULL, ":");
1067 #endif
1068 }
1069
1070 free(buffer);
1071
1072 done:
1073 errno = old_errno;
1074 return;
1075
1076 error:
1077 perror("libsandbox: Could not initialize environ\n");
1078 exit(EXIT_FAILURE);
1079 }
1080
1081 static int check_prefixes(char **prefixes, int num_prefixes, const char *path)
1082 {
1083 int i = 0;
1084
1085 if (NULL == prefixes)
1086 return 0;
1087
1088 for (i = 0; i < num_prefixes; i++) {
1089 if (NULL != prefixes[i]) {
1090 if (0 == strncmp(path, prefixes[i], strlen(prefixes[i])))
1091 return 1;
1092 }
1093 }
1094
1095 return 0;
1096 }
1097
1098 static int check_access(sbcontext_t * sbcontext, const char *func, const char *abs_path, const char *resolv_path)
1099 {
1100 int old_errno = errno;
1101 int result = 0;
1102 int retval;
1103
1104 retval = check_prefixes(sbcontext->deny_prefixes,
1105 sbcontext->num_deny_prefixes, resolv_path);
1106 if (1 == retval)
1107 /* Fall in a read/write denied path, Deny Access */
1108 goto out;
1109
1110 /* Hardcode denying write to log dir */
1111 if (0 == strncmp(resolv_path, SANDBOX_LOG_LOCATION,
1112 strlen(SANDBOX_LOG_LOCATION)))
1113 goto out;
1114
1115 if ((NULL != sbcontext->read_prefixes) &&
1116 ((0 == strncmp(func, "access_rd", 9)) ||
1117 (0 == strncmp(func, "open_rd", 7)) ||
1118 (0 == strncmp(func, "popen", 5)) ||
1119 (0 == strncmp(func, "opendir", 7)) ||
1120 (0 == strncmp(func, "system", 6)) ||
1121 (0 == strncmp(func, "execl", 5)) ||
1122 (0 == strncmp(func, "execlp", 6)) ||
1123 (0 == strncmp(func, "execle", 6)) ||
1124 (0 == strncmp(func, "execv", 5)) ||
1125 (0 == strncmp(func, "execvp", 6)) ||
1126 (0 == strncmp(func, "execve", 6)))) {
1127 retval = check_prefixes(sbcontext->read_prefixes,
1128 sbcontext->num_read_prefixes, resolv_path);
1129 if (1 == retval) {
1130 /* Fall in a readable path, Grant Access */
1131 result = 1;
1132 goto out;
1133 }
1134
1135 /* If we are here, and still no joy, and its the access() call,
1136 * do not log it, but just return -1 */
1137 if (0 == strncmp(func, "access_rd", 7)) {
1138 sbcontext->show_access_violation = 0;
1139 goto out;
1140 }
1141 }
1142
1143 if ((0 == strncmp(func, "access_wr", 7)) ||
1144 (0 == strncmp(func, "open_wr", 7)) ||
1145 (0 == strncmp(func, "creat", 5)) ||
1146 (0 == strncmp(func, "creat64", 7)) ||
1147 (0 == strncmp(func, "mkdir", 5)) ||
1148 (0 == strncmp(func, "mknod", 5)) ||
1149 (0 == strncmp(func, "mkfifo", 6)) ||
1150 (0 == strncmp(func, "link", 4)) ||
1151 (0 == strncmp(func, "symlink", 7)) ||
1152 (0 == strncmp(func, "rename", 6)) ||
1153 (0 == strncmp(func, "utime", 5)) ||
1154 (0 == strncmp(func, "utimes", 6)) ||
1155 (0 == strncmp(func, "unlink", 6)) ||
1156 (0 == strncmp(func, "rmdir", 5)) ||
1157 (0 == strncmp(func, "chown", 5)) ||
1158 (0 == strncmp(func, "lchown", 6)) ||
1159 (0 == strncmp(func, "chmod", 5)) ||
1160 (0 == strncmp(func, "truncate", 8)) ||
1161 (0 == strncmp(func, "ftruncate", 9)) ||
1162 (0 == strncmp(func, "truncate64", 10)) ||
1163 (0 == strncmp(func, "ftruncate64", 11))) {
1164 struct stat st;
1165 char proc_self_fd[SB_PATH_MAX];
1166
1167 retval = check_prefixes(sbcontext->write_denied_prefixes,
1168 sbcontext->num_write_denied_prefixes,
1169 resolv_path);
1170 if (1 == retval)
1171 /* Falls in a write denied path, Deny Access */
1172 goto out;
1173
1174 retval = check_prefixes(sbcontext->write_prefixes,
1175 sbcontext->num_write_prefixes, resolv_path);
1176 if (1 == retval) {
1177 /* Falls in a writable path, Grant Access */
1178 result = 1;
1179 goto out;
1180 }
1181
1182 /* XXX: Hack to enable us to remove symlinks pointing
1183 * to protected stuff. First we make sure that the
1184 * passed path is writable, and if so, check if its a
1185 * symlink, and give access only if the resolved path
1186 * of the symlink's parent also have write access. */
1187 if (((0 == strncmp(func, "unlink", 6)) ||
1188 (0 == strncmp(func, "lchown", 6)) ||
1189 (0 == strncmp(func, "rename", 6)) ||
1190 (0 == strncmp(func, "symlink", 7))) &&
1191 ((-1 != lstat(abs_path, &st)) && (S_ISLNK(st.st_mode)))) {
1192 /* Check if the symlink unresolved path have access */
1193 retval = check_prefixes(sbcontext->write_prefixes,
1194 sbcontext->num_write_prefixes, abs_path);
1195 if (1 == retval) { /* Does have write access on path */
1196 char tmp_buf[SB_PATH_MAX];
1197 char *dname, *rpath;
1198
1199 snprintf(tmp_buf, SB_PATH_MAX, "%s", abs_path);
1200
1201 dname = dirname(tmp_buf);
1202 /* Get symlink resolved path */
1203 rpath = resolve_path(dname, 1);
1204 if (NULL == rpath)
1205 /* Don't really worry here about
1206 * memory issues */
1207 goto unlink_hack_end;
1208
1209 /* Now check if the symlink resolved path have access */
1210 retval = check_prefixes(sbcontext->write_prefixes,
1211 sbcontext->num_write_prefixes,
1212 rpath);
1213 free(rpath);
1214 if (1 == retval) {
1215 /* Does have write access on path, so
1216 * enable the hack as it is a symlink */
1217 result = 1;
1218 goto out;
1219 }
1220 }
1221 }
1222 unlink_hack_end:
1223
1224 /* XXX: Hack to allow writing to '/proc/self/fd' (bug #91516)
1225 * It needs to be here, as for each process '/proc/self'
1226 * will differ ... */
1227 if ((0 == strncmp(resolv_path, "/proc", strlen("/proc"))) &&
1228 (NULL != realpath("/proc/self/fd", proc_self_fd))) {
1229 if (0 == strncmp(resolv_path, proc_self_fd,
1230 strlen(proc_self_fd))) {
1231 result = 1;
1232 goto out;
1233 }
1234 }
1235
1236 retval = check_prefixes(sbcontext->predict_prefixes,
1237 sbcontext->num_predict_prefixes, resolv_path);
1238 if (1 == retval) {
1239 /* Is a known access violation, so deny access,
1240 * and do not log it */
1241 sbcontext->show_access_violation = 0;
1242 goto out;
1243 }
1244
1245 /* If we are here, and still no joy, and its the access() call,
1246 * do not log it, but just return -1 */
1247 if (0 == strncmp(func, "access_wr", 7)) {
1248 sbcontext->show_access_violation = 0;
1249 goto out;
1250 }
1251 }
1252
1253 out:
1254 errno = old_errno;
1255
1256 return result;
1257 }
1258
1259 static int check_syscall(sbcontext_t * sbcontext, const char *func, const char *file)
1260 {
1261 struct stat log_stat;
1262 char buffer[512];
1263 char *absolute_path = NULL;
1264 char *resolved_path = NULL;
1265 char *log_path = NULL, *debug_log_path = NULL;
1266 int old_errno = errno;
1267 int result = 1;
1268 int log_file = 0, debug_log_file = 0;
1269 int access = 0, debug = 0, verbose = 1;
1270 int color = ((getenv("NOCOLOR") != NULL) ? 0 : 1);
1271
1272 absolute_path = resolve_path(file, 0);
1273 if (NULL == absolute_path)
1274 goto fp_error;
1275 resolved_path = resolve_path(file, 1);
1276 if (NULL == resolved_path)
1277 goto fp_error;
1278
1279 log_path = getenv(ENV_SANDBOX_LOG);
1280 if (NULL != getenv(ENV_SANDBOX_DEBUG)) {
1281 if ((0 == strncasecmp(getenv(ENV_SANDBOX_DEBUG), "1", 1)) ||
1282 (0 == strncasecmp(getenv(ENV_SANDBOX_DEBUG), "yes", 3))) {
1283 debug_log_path = getenv(ENV_SANDBOX_DEBUG_LOG);
1284 debug = 1;
1285 }
1286 }
1287
1288 if (NULL != getenv(ENV_SANDBOX_VERBOSE)) {
1289 if ((0 == strncasecmp(getenv(ENV_SANDBOX_VERBOSE), "0", 1)) ||
1290 (0 == strncasecmp(getenv(ENV_SANDBOX_VERBOSE), "no", 2)))
1291 verbose = 0;
1292 }
1293
1294 result = check_access(sbcontext, func, absolute_path, resolved_path);
1295
1296 if (1 == verbose) {
1297 if ((0 == result) && (1 == sbcontext->show_access_violation)) {
1298 EERROR(color, "ACCESS DENIED", " %s:%*s%s\n",
1299 func, (int)(10 - strlen(func)), "", absolute_path);
1300 } else if ((1 == debug) && (1 == sbcontext->show_access_violation)) {
1301 EINFO(color, "ACCESS ALLOWED", " %s:%*s%s\n",
1302 func, (int)(10 - strlen(func)), "", absolute_path);
1303 } else if ((1 == debug) && (0 == sbcontext->show_access_violation)) {
1304 EWARN(color, "ACCESS PREDICTED", " %s:%*s%s\n",
1305 func, (int)(10 - strlen(func)), "", absolute_path);
1306 }
1307 }
1308
1309 if ((0 == result) && (1 == sbcontext->show_access_violation))
1310 access = 1;
1311
1312 if (((NULL != log_path) && (1 == access)) ||
1313 ((NULL != debug_log_path) && (1 == debug))) {
1314 if (0 != strncmp(absolute_path, resolved_path, strlen(absolute_path))) {
1315 sprintf(buffer, "%s:%*s%s (symlink to %s)\n", func,
1316 (int)(10 - strlen(func)), "",
1317 absolute_path, resolved_path);
1318 } else {
1319 sprintf(buffer, "%s:%*s%s\n", func,
1320 (int)(10 - strlen(func)), "",
1321 absolute_path);
1322 }
1323 if (1 == access) {
1324 if ((0 == lstat(log_path, &log_stat)) &&
1325 (0 == S_ISREG(log_stat.st_mode))) {
1326 EERROR(color, "SECURITY BREACH", " '%s' %s\n", log_path,
1327 "already exists and is not a regular file!");
1328 } else {
1329 check_dlsym(open_DEFAULT);
1330 log_file = true_open_DEFAULT(log_path, O_APPEND | O_WRONLY |
1331 O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP |
1332 S_IROTH);
1333 if (log_file >= 0) {
1334 write(log_file, buffer, strlen(buffer));
1335 close(log_file);
1336 }
1337 }
1338 }
1339 if (1 == debug) {
1340 if ((0 == lstat(debug_log_path, &log_stat)) &&
1341 (0 == S_ISREG(log_stat.st_mode))) {
1342 EERROR(color, "SECURITY BREACH", " '%s' %s\n", debug_log_path,
1343 "already exists and is not a regular file!");
1344 } else {
1345 check_dlsym(open_DEFAULT);
1346 debug_log_file = true_open_DEFAULT(debug_log_path, O_APPEND | O_WRONLY |
1347 O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP |
1348 S_IROTH);
1349 if (debug_log_file >= 0) {
1350 write(debug_log_file, buffer, strlen(buffer));
1351 close(debug_log_file);
1352 }
1353 }
1354 }
1355 }
1356
1357 if (NULL != absolute_path)
1358 free(absolute_path);
1359 if (NULL != resolved_path)
1360 free(resolved_path);
1361
1362 errno = old_errno;
1363
1364 return result;
1365
1366 fp_error:
1367 if (NULL != absolute_path)
1368 free(absolute_path);
1369 if (NULL != resolved_path)
1370 free(resolved_path);
1371
1372 /* The path is too long to be canonicalized, so just warn and let the
1373 * function handle it (see bug #94630 and #21766 for more info) */
1374 if (ENAMETOOLONG == errno) {
1375 if (0 == sb_path_size_warning) {
1376 EWARN(color, "PATH LENGTH", " %s:%*s%s\n",
1377 func, (int)(10 - strlen(func)), "", file);
1378 sb_path_size_warning = 1;
1379 }
1380
1381 return 1;
1382 }
1383
1384 return 0;
1385 }
1386
1387 static int is_sandbox_on()
1388 {
1389 int old_errno = errno;
1390
1391 /* $SANDBOX_ACTIVE is an env variable that should ONLY
1392 * be used internal by sandbox.c and libsanbox.c. External
1393 * sources should NEVER set it, else the sandbox is enabled
1394 * in some cases when run in parallel with another sandbox,
1395 * but not even in the sandbox shell.
1396 *
1397 * Azarah (3 Aug 2002)
1398 */
1399 if ((NULL != getenv(ENV_SANDBOX_ON)) &&
1400 ((0 == strncmp(getenv(ENV_SANDBOX_ON), "1", 1)) ||
1401 (0 == strncmp(getenv(ENV_SANDBOX_ON), "yes", 3))) &&
1402 (1 == sandbox_on) &&
1403 (NULL != getenv(ENV_SANDBOX_ACTIVE)) &&
1404 (0 == strncmp(getenv(ENV_SANDBOX_ACTIVE), SANDBOX_ACTIVE, 13))) {
1405 errno = old_errno;
1406 return 1;
1407 } else {
1408 errno = old_errno;
1409 return 0;
1410 }
1411 }
1412
1413 static int before_syscall(const char *func, const char *file)
1414 {
1415 int old_errno = errno;
1416 int result = 1;
1417 // static sbcontext_t sbcontext;
1418 char *deny = getenv(ENV_SANDBOX_DENY);
1419 char *read = getenv(ENV_SANDBOX_READ);
1420 char *write = getenv(ENV_SANDBOX_WRITE);
1421 char *predict = getenv(ENV_SANDBOX_PREDICT);
1422
1423 if (NULL == file || 0 == strlen(file)) {
1424 /* The file/directory does not exist */
1425 errno = ENOENT;
1426 return 0;
1427 }
1428
1429 if(0 == sb_init) {
1430 init_context(&sbcontext);
1431 cached_env_vars = malloc(sizeof(char *) * 4);
1432 cached_env_vars[0] = cached_env_vars[1] = cached_env_vars[2] = cached_env_vars[3] = NULL;
1433 sb_init = 1;
1434 }
1435
1436 if((NULL == deny && cached_env_vars[0] != deny) || NULL == cached_env_vars[0] ||
1437 strcmp(cached_env_vars[0], deny) != 0) {
1438
1439 clean_env_entries(&(sbcontext.deny_prefixes),
1440 &(sbcontext.num_deny_prefixes));
1441
1442 if(NULL != cached_env_vars[0])
1443 free(cached_env_vars[0]);
1444
1445 if(NULL != deny) {
1446 init_env_entries(&(sbcontext.deny_prefixes),
1447 &(sbcontext.num_deny_prefixes), ENV_SANDBOX_DENY, deny, 1);
1448 cached_env_vars[0] = strdup(deny);
1449 } else {
1450 cached_env_vars[0] = NULL;
1451 }
1452 }
1453
1454 if((NULL == read && cached_env_vars[1] != read) || NULL == cached_env_vars[1] ||
1455 strcmp(cached_env_vars[1], read) != 0) {
1456
1457 clean_env_entries(&(sbcontext.read_prefixes),
1458 &(sbcontext.num_read_prefixes));
1459
1460 if(NULL != cached_env_vars[1])
1461 free(cached_env_vars[1]);
1462
1463 if(NULL != read) {
1464 init_env_entries(&(sbcontext.read_prefixes),
1465 &(sbcontext.num_read_prefixes), ENV_SANDBOX_READ, read, 1);
1466 cached_env_vars[1] = strdup(read);
1467 } else {
1468 cached_env_vars[1] = NULL;
1469 }
1470 }
1471
1472 if((NULL == write && cached_env_vars[2] != write) || NULL == cached_env_vars[2] ||
1473 strcmp(cached_env_vars[2], write) != 0) {
1474
1475 clean_env_entries(&(sbcontext.write_prefixes),
1476 &(sbcontext.num_write_prefixes));
1477
1478 if(NULL != cached_env_vars[2])
1479 free(cached_env_vars[2]);
1480
1481 if(NULL != write) {
1482 init_env_entries(&(sbcontext.write_prefixes),
1483 &(sbcontext.num_write_prefixes), ENV_SANDBOX_WRITE, write, 1);
1484 cached_env_vars[2] = strdup(write);
1485 } else {
1486 cached_env_vars[2] = NULL;
1487 }
1488 }
1489
1490 if((NULL == predict && cached_env_vars[3] != predict) || NULL == cached_env_vars[3] ||
1491 strcmp(cached_env_vars[3], predict) != 0) {
1492
1493 clean_env_entries(&(sbcontext.predict_prefixes),
1494 &(sbcontext.num_predict_prefixes));
1495
1496 if(NULL != cached_env_vars[3])
1497 free(cached_env_vars[3]);
1498
1499 if(NULL != predict) {
1500 init_env_entries(&(sbcontext.predict_prefixes),
1501 &(sbcontext.num_predict_prefixes), ENV_SANDBOX_PREDICT, predict, 1);
1502 cached_env_vars[3] = strdup(predict);
1503 } else {
1504 cached_env_vars[3] = NULL;
1505 }
1506
1507 }
1508
1509 /* Might have been reset in check_access() */
1510 sbcontext.show_access_violation = 1;
1511
1512 result = check_syscall(&sbcontext, func, file);
1513
1514 errno = old_errno;
1515
1516 if (0 == result) {
1517 errno = EACCES;
1518 }
1519
1520 return result;
1521 }
1522
1523 static int before_syscall_access(const char *func, const char *file, int flags)
1524 {
1525 if (flags & W_OK) {
1526 return before_syscall("access_wr", file);
1527 } else {
1528 return before_syscall("access_rd", file);
1529 }
1530 }
1531
1532 static int before_syscall_open_int(const char *func, const char *file, int flags)
1533 {
1534 if ((flags & O_WRONLY) || (flags & O_RDWR)) {
1535 return before_syscall("open_wr", file);
1536 } else {
1537 return before_syscall("open_rd", file);
1538 }
1539 }
1540
1541 static int before_syscall_open_char(const char *func, const char *file, const char *mode)
1542 {
1543 if (*mode == 'r' && (0 == (strcmp(mode, "r")) ||
1544 /* The strspn accept args are known non-writable modifiers */
1545 (strlen(++mode) == strspn(mode, "xbtmc")))) {
1546 return before_syscall("open_rd", file);
1547 } else {
1548 return before_syscall("open_wr", file);
1549 }
1550 }
1551
1552
1553 // 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