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

Contents of /trunk/src/libsandbox.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 235 - (show annotations) (download) (as text)
Mon Dec 5 22:49:20 2005 UTC (13 years ago) by azarah
File MIME type: text/x-csrc
File size: 39751 byte(s)
More configure related cleanups. Define HAVE_RTLD_NEXT
via config.h.

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
906 /* Need to disable sandbox, as on non-linux libc's, opendir() is
907 * used by some getcwd() implementations and resolves to the sandbox
908 * opendir() wrapper, causing infinit recursion and finially crashes.
909 */
910 sandbox_on = 0;
911 check_dlsym(getcwd_DEFAULT);
912 errno = 0;
913 tmpbuf = true_getcwd_DEFAULT(buf, size);
914 sandbox_on = 1;
915 if (tmpbuf)
916 lstat(buf, &st);
917
918 if ((tmpbuf) && (errno == ENOENT)) {
919 /* If lstat() failed with eerror = ENOENT, then its
920 * possible that we are running on an older kernel
921 * which had issues with returning invalid paths if
922 * they got too long.
923 */
924 free(tmpbuf);
925
926 return NULL;
927 }
928
929 return tmpbuf;
930 }
931
932 static void init_context(sbcontext_t * context)
933 {
934 context->show_access_violation = 1;
935 context->deny_prefixes = NULL;
936 context->num_deny_prefixes = 0;
937 context->read_prefixes = NULL;
938 context->num_read_prefixes = 0;
939 context->write_prefixes = NULL;
940 context->num_write_prefixes = 0;
941 context->predict_prefixes = NULL;
942 context->num_predict_prefixes = 0;
943 context->write_denied_prefixes = NULL;
944 context->num_write_denied_prefixes = 0;
945 }
946
947 static void clean_env_entries(char ***prefixes_array, int *prefixes_num)
948 {
949 int old_errno = errno;
950 int i = 0;
951
952 if (NULL != *prefixes_array) {
953 for (i = 0; i < *prefixes_num; i++) {
954 if (NULL != (*prefixes_array)[i]) {
955 free((*prefixes_array)[i]);
956 (*prefixes_array)[i] = NULL;
957 }
958 }
959 if (NULL != *prefixes_array)
960 free(*prefixes_array);
961 *prefixes_array = NULL;
962 *prefixes_num = 0;
963 }
964
965 errno = old_errno;
966 }
967
968 #define pfx_num (*prefixes_num)
969 #define pfx_array (*prefixes_array)
970 #define pfx_item ((*prefixes_array)[(*prefixes_num)])
971
972 static void init_env_entries(char ***prefixes_array, int *prefixes_num, const char *env, const char *prefixes_env, int warn)
973 {
974 char *token = NULL;
975 char *rpath = NULL;
976 char *buffer = NULL;
977 char *buffer_ptr = NULL;
978 int prefixes_env_length = strlen(prefixes_env);
979 int num_delimiters = 0;
980 int i = 0;
981 int old_errno = errno;
982
983 if (NULL == prefixes_env) {
984 /* Do not warn if this is in init stage, as we might get
985 * issues due to LD_PRELOAD already set (bug #91431). */
986 if (1 == sb_init)
987 fprintf(stderr,
988 "libsandbox: The '%s' env variable is not defined!\n",
989 env);
990 if (pfx_array) {
991 for (i = 0; i < pfx_num; i++)
992 free(pfx_item);
993 free(pfx_array);
994 }
995 pfx_num = 0;
996
997 goto done;
998 }
999
1000 for (i = 0; i < prefixes_env_length; i++) {
1001 if (':' == prefixes_env[i])
1002 num_delimiters++;
1003 }
1004
1005 /* num_delimiters might be 0, and we need 2 entries at least */
1006 pfx_array = malloc(((num_delimiters * 2) + 2) * sizeof(char *));
1007 if (NULL == pfx_array)
1008 goto error;
1009 buffer = gstrndup(prefixes_env, prefixes_env_length);
1010 if (NULL == buffer)
1011 goto error;
1012 buffer_ptr = buffer;
1013
1014 #ifdef HAVE_STRTOK_R
1015 token = strtok_r(buffer_ptr, ":", &buffer_ptr);
1016 #else
1017 token = strtok(buffer_ptr, ":");
1018 #endif
1019
1020 while ((NULL != token) && (strlen(token) > 0)) {
1021 pfx_item = resolve_path(token, 0);
1022 if (NULL != pfx_item) {
1023 pfx_num++;
1024
1025 /* Now add the realpath if it exists and
1026 * are not a duplicate */
1027 rpath = malloc(SB_PATH_MAX * sizeof(char));
1028 if (NULL != rpath) {
1029 pfx_item = realpath(*(&(pfx_item) - 1), rpath);
1030 if ((NULL != pfx_item) &&
1031 (0 != strcmp(*(&(pfx_item) - 1), pfx_item))) {
1032 pfx_num++;
1033 } else {
1034 free(rpath);
1035 pfx_item = NULL;
1036 }
1037 } else {
1038 goto error;
1039 }
1040 }
1041
1042 #ifdef HAVE_STRTOK_R
1043 token = strtok_r(NULL, ":", &buffer_ptr);
1044 #else
1045 token = strtok(NULL, ":");
1046 #endif
1047 }
1048
1049 free(buffer);
1050
1051 done:
1052 errno = old_errno;
1053 return;
1054
1055 error:
1056 perror("libsandbox: Could not initialize environ\n");
1057 exit(EXIT_FAILURE);
1058 }
1059
1060 static int check_prefixes(char **prefixes, int num_prefixes, const char *path)
1061 {
1062 int i = 0;
1063
1064 if (NULL == prefixes)
1065 return 0;
1066
1067 for (i = 0; i < num_prefixes; i++) {
1068 if (NULL != prefixes[i]) {
1069 if (0 == strncmp(path, prefixes[i], strlen(prefixes[i])))
1070 return 1;
1071 }
1072 }
1073
1074 return 0;
1075 }
1076
1077 static int check_access(sbcontext_t * sbcontext, const char *func, const char *abs_path, const char *resolv_path)
1078 {
1079 int old_errno = errno;
1080 int result = 0;
1081 int retval;
1082
1083 retval = check_prefixes(sbcontext->deny_prefixes,
1084 sbcontext->num_deny_prefixes, resolv_path);
1085 if (1 == retval)
1086 /* Fall in a read/write denied path, Deny Access */
1087 goto out;
1088
1089 /* Hardcode denying write to log dir */
1090 if (0 == strncmp(resolv_path, SANDBOX_LOG_LOCATION,
1091 strlen(SANDBOX_LOG_LOCATION)))
1092 goto out;
1093
1094 if ((NULL != sbcontext->read_prefixes) &&
1095 ((0 == strncmp(func, "access_rd", 9)) ||
1096 (0 == strncmp(func, "open_rd", 7)) ||
1097 (0 == strncmp(func, "popen", 5)) ||
1098 (0 == strncmp(func, "opendir", 7)) ||
1099 (0 == strncmp(func, "system", 6)) ||
1100 (0 == strncmp(func, "execl", 5)) ||
1101 (0 == strncmp(func, "execlp", 6)) ||
1102 (0 == strncmp(func, "execle", 6)) ||
1103 (0 == strncmp(func, "execv", 5)) ||
1104 (0 == strncmp(func, "execvp", 6)) ||
1105 (0 == strncmp(func, "execve", 6)))) {
1106 retval = check_prefixes(sbcontext->read_prefixes,
1107 sbcontext->num_read_prefixes, resolv_path);
1108 if (1 == retval) {
1109 /* Fall in a readable path, Grant Access */
1110 result = 1;
1111 goto out;
1112 }
1113
1114 /* If we are here, and still no joy, and its the access() call,
1115 * do not log it, but just return -1 */
1116 if (0 == strncmp(func, "access_rd", 7)) {
1117 sbcontext->show_access_violation = 0;
1118 goto out;
1119 }
1120 }
1121
1122 if ((0 == strncmp(func, "access_wr", 7)) ||
1123 (0 == strncmp(func, "open_wr", 7)) ||
1124 (0 == strncmp(func, "creat", 5)) ||
1125 (0 == strncmp(func, "creat64", 7)) ||
1126 (0 == strncmp(func, "mkdir", 5)) ||
1127 (0 == strncmp(func, "mknod", 5)) ||
1128 (0 == strncmp(func, "mkfifo", 6)) ||
1129 (0 == strncmp(func, "link", 4)) ||
1130 (0 == strncmp(func, "symlink", 7)) ||
1131 (0 == strncmp(func, "rename", 6)) ||
1132 (0 == strncmp(func, "utime", 5)) ||
1133 (0 == strncmp(func, "utimes", 6)) ||
1134 (0 == strncmp(func, "unlink", 6)) ||
1135 (0 == strncmp(func, "rmdir", 5)) ||
1136 (0 == strncmp(func, "chown", 5)) ||
1137 (0 == strncmp(func, "lchown", 6)) ||
1138 (0 == strncmp(func, "chmod", 5)) ||
1139 (0 == strncmp(func, "truncate", 8)) ||
1140 (0 == strncmp(func, "ftruncate", 9)) ||
1141 (0 == strncmp(func, "truncate64", 10)) ||
1142 (0 == strncmp(func, "ftruncate64", 11))) {
1143 struct stat st;
1144 char proc_self_fd[SB_PATH_MAX];
1145
1146 retval = check_prefixes(sbcontext->write_denied_prefixes,
1147 sbcontext->num_write_denied_prefixes,
1148 resolv_path);
1149 if (1 == retval)
1150 /* Falls in a write denied path, Deny Access */
1151 goto out;
1152
1153 retval = check_prefixes(sbcontext->write_prefixes,
1154 sbcontext->num_write_prefixes, resolv_path);
1155 if (1 == retval) {
1156 /* Falls in a writable path, Grant Access */
1157 result = 1;
1158 goto out;
1159 }
1160
1161 /* XXX: Hack to enable us to remove symlinks pointing
1162 * to protected stuff. First we make sure that the
1163 * passed path is writable, and if so, check if its a
1164 * symlink, and give access only if the resolved path
1165 * of the symlink's parent also have write access. */
1166 if (((0 == strncmp(func, "unlink", 6)) ||
1167 (0 == strncmp(func, "lchown", 6)) ||
1168 (0 == strncmp(func, "rename", 6)) ||
1169 (0 == strncmp(func, "symlink", 7))) &&
1170 ((-1 != lstat(abs_path, &st)) && (S_ISLNK(st.st_mode)))) {
1171 /* Check if the symlink unresolved path have access */
1172 retval = check_prefixes(sbcontext->write_prefixes,
1173 sbcontext->num_write_prefixes, abs_path);
1174 if (1 == retval) { /* Does have write access on path */
1175 char tmp_buf[SB_PATH_MAX];
1176 char *dname, *rpath;
1177
1178 snprintf(tmp_buf, SB_PATH_MAX, "%s", abs_path);
1179
1180 dname = dirname(tmp_buf);
1181 /* Get symlink resolved path */
1182 rpath = resolve_path(dname, 1);
1183 if (NULL == rpath)
1184 /* Don't really worry here about
1185 * memory issues */
1186 goto unlink_hack_end;
1187
1188 /* Now check if the symlink resolved path have access */
1189 retval = check_prefixes(sbcontext->write_prefixes,
1190 sbcontext->num_write_prefixes,
1191 rpath);
1192 free(rpath);
1193 if (1 == retval) {
1194 /* Does have write access on path, so
1195 * enable the hack as it is a symlink */
1196 result = 1;
1197 goto out;
1198 }
1199 }
1200 }
1201 unlink_hack_end:
1202
1203 /* XXX: Hack to allow writing to '/proc/self/fd' (bug #91516)
1204 * It needs to be here, as for each process '/proc/self'
1205 * will differ ... */
1206 if ((0 == strncmp(resolv_path, "/proc", strlen("/proc"))) &&
1207 (NULL != realpath("/proc/self/fd", proc_self_fd))) {
1208 if (0 == strncmp(resolv_path, proc_self_fd,
1209 strlen(proc_self_fd))) {
1210 result = 1;
1211 goto out;
1212 }
1213 }
1214
1215 retval = check_prefixes(sbcontext->predict_prefixes,
1216 sbcontext->num_predict_prefixes, resolv_path);
1217 if (1 == retval) {
1218 /* Is a known access violation, so deny access,
1219 * and do not log it */
1220 sbcontext->show_access_violation = 0;
1221 goto out;
1222 }
1223
1224 /* If we are here, and still no joy, and its the access() call,
1225 * do not log it, but just return -1 */
1226 if (0 == strncmp(func, "access_wr", 7)) {
1227 sbcontext->show_access_violation = 0;
1228 goto out;
1229 }
1230 }
1231
1232 out:
1233 errno = old_errno;
1234
1235 return result;
1236 }
1237
1238 static int check_syscall(sbcontext_t * sbcontext, const char *func, const char *file)
1239 {
1240 struct stat log_stat;
1241 char buffer[512];
1242 char *absolute_path = NULL;
1243 char *resolved_path = NULL;
1244 char *log_path = NULL, *debug_log_path = NULL;
1245 int old_errno = errno;
1246 int result = 1;
1247 int log_file = 0, debug_log_file = 0;
1248 int access = 0, debug = 0, verbose = 1;
1249 int color = ((getenv("NOCOLOR") != NULL) ? 0 : 1);
1250
1251 absolute_path = resolve_path(file, 0);
1252 if (NULL == absolute_path)
1253 goto fp_error;
1254 resolved_path = resolve_path(file, 1);
1255 if (NULL == resolved_path)
1256 goto fp_error;
1257
1258 log_path = getenv(ENV_SANDBOX_LOG);
1259 if (NULL != getenv(ENV_SANDBOX_DEBUG)) {
1260 if ((0 == strncasecmp(getenv(ENV_SANDBOX_DEBUG), "1", 1)) ||
1261 (0 == strncasecmp(getenv(ENV_SANDBOX_DEBUG), "yes", 3))) {
1262 debug_log_path = getenv(ENV_SANDBOX_DEBUG_LOG);
1263 debug = 1;
1264 }
1265 }
1266
1267 if (NULL != getenv(ENV_SANDBOX_VERBOSE)) {
1268 if ((0 == strncasecmp(getenv(ENV_SANDBOX_VERBOSE), "0", 1)) ||
1269 (0 == strncasecmp(getenv(ENV_SANDBOX_VERBOSE), "no", 2)))
1270 verbose = 0;
1271 }
1272
1273 result = check_access(sbcontext, func, absolute_path, resolved_path);
1274
1275 if (1 == verbose) {
1276 if ((0 == result) && (1 == sbcontext->show_access_violation)) {
1277 EERROR(color, "ACCESS DENIED", " %s:%*s%s\n",
1278 func, (int)(10 - strlen(func)), "", absolute_path);
1279 } else if ((1 == debug) && (1 == sbcontext->show_access_violation)) {
1280 EINFO(color, "ACCESS ALLOWED", " %s:%*s%s\n",
1281 func, (int)(10 - strlen(func)), "", absolute_path);
1282 } else if ((1 == debug) && (0 == sbcontext->show_access_violation)) {
1283 EWARN(color, "ACCESS PREDICTED", " %s:%*s%s\n",
1284 func, (int)(10 - strlen(func)), "", absolute_path);
1285 }
1286 }
1287
1288 if ((0 == result) && (1 == sbcontext->show_access_violation))
1289 access = 1;
1290
1291 if (((NULL != log_path) && (1 == access)) ||
1292 ((NULL != debug_log_path) && (1 == debug))) {
1293 if (0 != strncmp(absolute_path, resolved_path, strlen(absolute_path))) {
1294 sprintf(buffer, "%s:%*s%s (symlink to %s)\n", func,
1295 (int)(10 - strlen(func)), "",
1296 absolute_path, resolved_path);
1297 } else {
1298 sprintf(buffer, "%s:%*s%s\n", func,
1299 (int)(10 - strlen(func)), "",
1300 absolute_path);
1301 }
1302 if (1 == access) {
1303 if ((0 == lstat(log_path, &log_stat)) &&
1304 (0 == S_ISREG(log_stat.st_mode))) {
1305 EERROR(color, "SECURITY BREACH", " '%s' %s\n", log_path,
1306 "already exists and is not a regular file!");
1307 } else {
1308 check_dlsym(open_DEFAULT);
1309 log_file = true_open_DEFAULT(log_path, O_APPEND | O_WRONLY |
1310 O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP |
1311 S_IROTH);
1312 if (log_file >= 0) {
1313 write(log_file, buffer, strlen(buffer));
1314 close(log_file);
1315 }
1316 }
1317 }
1318 if (1 == debug) {
1319 if ((0 == lstat(debug_log_path, &log_stat)) &&
1320 (0 == S_ISREG(log_stat.st_mode))) {
1321 EERROR(color, "SECURITY BREACH", " '%s' %s\n", debug_log_path,
1322 "already exists and is not a regular file!");
1323 } else {
1324 check_dlsym(open_DEFAULT);
1325 debug_log_file = true_open_DEFAULT(debug_log_path, O_APPEND | O_WRONLY |
1326 O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP |
1327 S_IROTH);
1328 if (debug_log_file >= 0) {
1329 write(debug_log_file, buffer, strlen(buffer));
1330 close(debug_log_file);
1331 }
1332 }
1333 }
1334 }
1335
1336 if (NULL != absolute_path)
1337 free(absolute_path);
1338 if (NULL != resolved_path)
1339 free(resolved_path);
1340
1341 errno = old_errno;
1342
1343 return result;
1344
1345 fp_error:
1346 if (NULL != absolute_path)
1347 free(absolute_path);
1348 if (NULL != resolved_path)
1349 free(resolved_path);
1350
1351 /* The path is too long to be canonicalized, so just warn and let the
1352 * function handle it (see bug #94630 and #21766 for more info) */
1353 if (ENAMETOOLONG == errno) {
1354 if (0 == sb_path_size_warning) {
1355 EWARN(color, "PATH LENGTH", " %s:%*s%s\n",
1356 func, (int)(10 - strlen(func)), "", file);
1357 sb_path_size_warning = 1;
1358 }
1359
1360 return 1;
1361 }
1362
1363 return 0;
1364 }
1365
1366 static int is_sandbox_on()
1367 {
1368 int old_errno = errno;
1369
1370 /* $SANDBOX_ACTIVE is an env variable that should ONLY
1371 * be used internal by sandbox.c and libsanbox.c. External
1372 * sources should NEVER set it, else the sandbox is enabled
1373 * in some cases when run in parallel with another sandbox,
1374 * but not even in the sandbox shell.
1375 *
1376 * Azarah (3 Aug 2002)
1377 */
1378 if ((NULL != getenv(ENV_SANDBOX_ON)) &&
1379 ((0 == strncmp(getenv(ENV_SANDBOX_ON), "1", 1)) ||
1380 (0 == strncmp(getenv(ENV_SANDBOX_ON), "yes", 3))) &&
1381 (1 == sandbox_on) &&
1382 (NULL != getenv(ENV_SANDBOX_ACTIVE)) &&
1383 (0 == strncmp(getenv(ENV_SANDBOX_ACTIVE), SANDBOX_ACTIVE, 13))) {
1384 errno = old_errno;
1385 return 1;
1386 } else {
1387 errno = old_errno;
1388 return 0;
1389 }
1390 }
1391
1392 static int before_syscall(const char *func, const char *file)
1393 {
1394 int old_errno = errno;
1395 int result = 1;
1396 // static sbcontext_t sbcontext;
1397 char *deny = getenv(ENV_SANDBOX_DENY);
1398 char *read = getenv(ENV_SANDBOX_READ);
1399 char *write = getenv(ENV_SANDBOX_WRITE);
1400 char *predict = getenv(ENV_SANDBOX_PREDICT);
1401
1402 if (NULL == file || 0 == strlen(file)) {
1403 /* The file/directory does not exist */
1404 errno = ENOENT;
1405 return 0;
1406 }
1407
1408 if(0 == sb_init) {
1409 init_context(&sbcontext);
1410 cached_env_vars = malloc(sizeof(char *) * 4);
1411 cached_env_vars[0] = cached_env_vars[1] = cached_env_vars[2] = cached_env_vars[3] = NULL;
1412 sb_init = 1;
1413 }
1414
1415 if((NULL == deny && cached_env_vars[0] != deny) || NULL == cached_env_vars[0] ||
1416 strcmp(cached_env_vars[0], deny) != 0) {
1417
1418 clean_env_entries(&(sbcontext.deny_prefixes),
1419 &(sbcontext.num_deny_prefixes));
1420
1421 if(NULL != cached_env_vars[0])
1422 free(cached_env_vars[0]);
1423
1424 if(NULL != deny) {
1425 init_env_entries(&(sbcontext.deny_prefixes),
1426 &(sbcontext.num_deny_prefixes), ENV_SANDBOX_DENY, deny, 1);
1427 cached_env_vars[0] = strdup(deny);
1428 } else {
1429 cached_env_vars[0] = NULL;
1430 }
1431 }
1432
1433 if((NULL == read && cached_env_vars[1] != read) || NULL == cached_env_vars[1] ||
1434 strcmp(cached_env_vars[1], read) != 0) {
1435
1436 clean_env_entries(&(sbcontext.read_prefixes),
1437 &(sbcontext.num_read_prefixes));
1438
1439 if(NULL != cached_env_vars[1])
1440 free(cached_env_vars[1]);
1441
1442 if(NULL != read) {
1443 init_env_entries(&(sbcontext.read_prefixes),
1444 &(sbcontext.num_read_prefixes), ENV_SANDBOX_READ, read, 1);
1445 cached_env_vars[1] = strdup(read);
1446 } else {
1447 cached_env_vars[1] = NULL;
1448 }
1449 }
1450
1451 if((NULL == write && cached_env_vars[2] != write) || NULL == cached_env_vars[2] ||
1452 strcmp(cached_env_vars[2], write) != 0) {
1453
1454 clean_env_entries(&(sbcontext.write_prefixes),
1455 &(sbcontext.num_write_prefixes));
1456
1457 if(NULL != cached_env_vars[2])
1458 free(cached_env_vars[2]);
1459
1460 if(NULL != write) {
1461 init_env_entries(&(sbcontext.write_prefixes),
1462 &(sbcontext.num_write_prefixes), ENV_SANDBOX_WRITE, write, 1);
1463 cached_env_vars[2] = strdup(write);
1464 } else {
1465 cached_env_vars[2] = NULL;
1466 }
1467 }
1468
1469 if((NULL == predict && cached_env_vars[3] != predict) || NULL == cached_env_vars[3] ||
1470 strcmp(cached_env_vars[3], predict) != 0) {
1471
1472 clean_env_entries(&(sbcontext.predict_prefixes),
1473 &(sbcontext.num_predict_prefixes));
1474
1475 if(NULL != cached_env_vars[3])
1476 free(cached_env_vars[3]);
1477
1478 if(NULL != predict) {
1479 init_env_entries(&(sbcontext.predict_prefixes),
1480 &(sbcontext.num_predict_prefixes), ENV_SANDBOX_PREDICT, predict, 1);
1481 cached_env_vars[3] = strdup(predict);
1482 } else {
1483 cached_env_vars[3] = NULL;
1484 }
1485
1486 }
1487
1488 /* Might have been reset in check_access() */
1489 sbcontext.show_access_violation = 1;
1490
1491 result = check_syscall(&sbcontext, func, file);
1492
1493 errno = old_errno;
1494
1495 if (0 == result) {
1496 errno = EACCES;
1497 }
1498
1499 return result;
1500 }
1501
1502 static int before_syscall_access(const char *func, const char *file, int flags)
1503 {
1504 if (flags & W_OK) {
1505 return before_syscall("access_wr", file);
1506 } else {
1507 return before_syscall("access_rd", file);
1508 }
1509 }
1510
1511 static int before_syscall_open_int(const char *func, const char *file, int flags)
1512 {
1513 if ((flags & O_WRONLY) || (flags & O_RDWR)) {
1514 return before_syscall("open_wr", file);
1515 } else {
1516 return before_syscall("open_rd", file);
1517 }
1518 }
1519
1520 static int before_syscall_open_char(const char *func, const char *file, const char *mode)
1521 {
1522 if (*mode == 'r' && (0 == (strcmp(mode, "r")) ||
1523 /* The strspn accept args are known non-writable modifiers */
1524 (strlen(++mode) == strspn(mode, "xbtmc")))) {
1525 return before_syscall("open_rd", file);
1526 } else {
1527 return before_syscall("open_wr", file);
1528 }
1529 }
1530
1531
1532 // 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