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

Contents of /trunk/src/libsandbox.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 257 - (show annotations) (download) (as text)
Fri Jun 30 11:10:35 2006 UTC (8 years ago) by azarah
File MIME type: text/x-csrc
File size: 41393 byte(s)
Fix possible huge overflow with logging code.

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