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

Contents of /trunk/src/libsandbox.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 216 - (show annotations) (download) (as text)
Mon Dec 5 09:28:34 2005 UTC (8 years, 4 months ago) by azarah
File MIME type: text/x-csrc
File size: 38329 byte(s)
Rename sandbox_futils.c to sandbox_utils.c.  Add gstrndup() and gbasename()
to sandbox_utils.c.  Add check for glibc, and fixup things to not need glibc
only extensions if not needed for versioned symbols.

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