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

Contents of /trunk/src/libsandbox.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 189 - (show annotations) (download) (as text)
Thu Dec 1 09:46:17 2005 UTC (8 years, 9 months ago) by azarah
File MIME type: text/x-csrc
File size: 37833 byte(s)
Remove the SB_STATIC and including of getcwd.c, etc voodoo, as we new use a
symbol map, and all non-exported symbols are local.  Cleanup getcwd.c, as
the generic getcwd for older 2.4 kernels do not work properly anyhow, and
just makes things slower.  Some other warning fixes.

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