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

Contents of /trunk/libsandbox.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 156 - (show annotations) (download) (as text)
Fri Aug 5 13:33:54 2005 UTC (8 years, 8 months ago) by azarah
File MIME type: text/x-csrc
File size: 37211 byte(s)
Do not give an access violation if the access() system call do not have
write/read access - it does not actually modify, so we only need to return
not being able to write/read.  Noted by Andres Loeh <kosmikus@gentoo.org>,
bug #101433.

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