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

Contents of /trunk/libsandbox.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 36 - (show annotations) (download) (as text)
Sun Mar 13 23:29:28 2005 UTC (13 years, 7 months ago) by azarah
File MIME type: text/x-csrc
File size: 37496 byte(s)
Also rename the _init() and _fini() declarations.

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