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

Contents of /trunk/libsandbox/wrappers.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 318 - (show annotations) (download) (as text)
Mon Jul 10 07:21:53 2006 UTC (12 years, 4 months ago) by azarah
File MIME type: text/x-csrc
File size: 16246 byte(s)
Add wrapper for internal use of getcwd().

1 /*
2 * wrappers.c
3 *
4 * Function wrapping functions.
5 *
6 * Copyright 1999-2006 Gentoo Foundation
7 *
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation version 2 of the License.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 * $Header$
23 */
24
25
26 #include "config.h"
27
28 /* Better way would be to only define _GNU_SOURCE when __GLIBC__ is defined,
29 * but including features.h and then defining _GNU_SOURCE do not work */
30 #if defined(HAVE_RTLD_NEXT)
31 # define _GNU_SOURCE
32 #endif
33 #include <errno.h>
34 #include <dlfcn.h>
35 #include <stdarg.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <limits.h>
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <dirent.h>
43 #include <unistd.h>
44 #include <fcntl.h>
45
46 #include "localdecls.h"
47 #include "sbutil.h"
48 #include "libsandbox.h"
49 #include "wrappers.h"
50
51 #if !defined(BROKEN_RTLD_NEXT) && defined(HAVE_RTLD_NEXT)
52 # define USE_RTLD_NEXT
53 #endif
54
55 static void *libc_handle = NULL;
56
57 extern char sandbox_lib[SB_PATH_MAX];
58 extern int sandbox_on;
59
60 void *get_dlsym(const char *symname, const char *symver)
61 {
62 void *symaddr = NULL;
63
64 if (NULL == libc_handle) {
65 #if !defined(USE_RTLD_NEXT)
66 libc_handle = dlopen(LIBC_VERSION, RTLD_LAZY);
67 if (!libc_handle) {
68 fprintf(stderr, "libsandbox: Can't dlopen libc: %s\n",
69 dlerror());
70 exit(EXIT_FAILURE);
71 }
72 #else
73 libc_handle = RTLD_NEXT;
74 #endif
75 }
76
77 if (NULL == symver)
78 symaddr = dlsym(libc_handle, symname);
79 else
80 symaddr = dlvsym(libc_handle, symname, symver);
81 if (!symaddr) {
82 fprintf(stderr, "libsandbox: Can't resolve %s: %s\n",
83 symname, dlerror());
84 exit(EXIT_FAILURE);
85 }
86
87 return symaddr;
88 }
89
90 /*
91 * Wrapper Functions
92 */
93
94 #define chmod_decl(_name) \
95 \
96 extern int _name(const char *, mode_t); \
97 static int (*true_ ## _name) (const char *, mode_t) = NULL; \
98 \
99 int _name(const char *path, mode_t mode) \
100 { \
101 int result = -1; \
102 \
103 if FUNCTION_SANDBOX_SAFE("chmod", path) { \
104 check_dlsym(_name); \
105 result = true_ ## _name(path, mode); \
106 } \
107 \
108 return result; \
109 }
110
111 #define chown_decl(_name) \
112 \
113 extern int _name(const char *, uid_t, gid_t); \
114 static int (*true_ ## _name) (const char *, uid_t, gid_t) = NULL; \
115 \
116 int _name(const char *path, uid_t owner, gid_t group) \
117 { \
118 int result = -1; \
119 \
120 if FUNCTION_SANDBOX_SAFE("chown", path) { \
121 check_dlsym(_name); \
122 result = true_ ## _name(path, owner, group); \
123 } \
124 \
125 return result; \
126 }
127
128 #define creat_decl(_name) \
129 \
130 extern int _name(const char *, mode_t); \
131 /* static int (*true_ ## _name) (const char *, mode_t) = NULL; */ \
132 \
133 int _name(const char *pathname, mode_t mode) \
134 { \
135 int result = -1; \
136 \
137 if FUNCTION_SANDBOX_SAFE("creat", pathname) { \
138 check_dlsym(open_DEFAULT); \
139 result = true_open_DEFAULT(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode); \
140 } \
141 \
142 return result; \
143 }
144
145 #define fopen_decl(_name) \
146 \
147 extern FILE *_name(const char *, const char *); \
148 static FILE * (*true_ ## _name) (const char *, const char *) = NULL; \
149 \
150 FILE *_name(const char *pathname, const char *mode) \
151 { \
152 FILE *result = NULL; \
153 \
154 if FUNCTION_SANDBOX_SAFE_OPEN_CHAR("fopen", pathname, mode) { \
155 check_dlsym(_name); \
156 result = true_ ## _name(pathname, mode); \
157 } \
158 \
159 return result; \
160 }
161
162 #define lchown_decl(_name) \
163 \
164 extern int _name(const char *, uid_t, gid_t); \
165 static int (*true_ ## _name) (const char *, uid_t, gid_t) = NULL; \
166 \
167 int _name(const char *path, uid_t owner, gid_t group) \
168 { \
169 int result = -1; \
170 \
171 if FUNCTION_SANDBOX_SAFE("lchown", path) { \
172 check_dlsym(_name); \
173 result = true_ ## _name(path, owner, group); \
174 } \
175 \
176 return result; \
177 }
178
179 #define link_decl(_name) \
180 \
181 extern int _name(const char *, const char *); \
182 static int (*true_ ## _name) (const char *, const char *) = NULL; \
183 \
184 int _name(const char *oldpath, const char *newpath) \
185 { \
186 int result = -1; \
187 \
188 if FUNCTION_SANDBOX_SAFE("link", newpath) { \
189 check_dlsym(_name); \
190 result = true_ ## _name(oldpath, newpath); \
191 } \
192 \
193 return result; \
194 }
195
196 #define mkdir_decl(_name) \
197 \
198 extern int _name(const char *, mode_t); \
199 static int (*true_ ## _name) (const char *, mode_t) = NULL; \
200 \
201 int _name(const char *pathname, mode_t mode) \
202 { \
203 struct stat st; \
204 int result = -1, my_errno = errno; \
205 char canonic[SB_PATH_MAX]; \
206 \
207 if (-1 == canonicalize(pathname, canonic)) \
208 /* Path is too long to canonicalize, do not fail, but just let
209 * the real function handle it (see bug #94630 and #21766). */ \
210 if (ENAMETOOLONG != errno) \
211 return -1; \
212 \
213 /* XXX: Hack to prevent errors if the directory exist,
214 * and are not writable - we rather return EEXIST rather
215 * than failing */ \
216 if (0 == lstat(canonic, &st)) { \
217 errno = EEXIST; \
218 return -1; \
219 } \
220 errno = my_errno; \
221 \
222 if FUNCTION_SANDBOX_SAFE("mkdir", pathname) { \
223 check_dlsym(_name); \
224 result = true_ ## _name(pathname, mode); \
225 } \
226 \
227 return result; \
228 }
229
230 #define opendir_decl(_name) \
231 \
232 extern DIR *_name(const char *); \
233 static DIR * (*true_ ## _name) (const char *) = NULL; \
234 \
235 DIR *_name(const char *name) \
236 { \
237 DIR *result = NULL; \
238 \
239 if FUNCTION_SANDBOX_SAFE("opendir", name) { \
240 check_dlsym(_name); \
241 result = true_ ## _name(name); \
242 } \
243 \
244 return result; \
245 }
246
247 #define mknod_decl(_name) \
248 \
249 extern int _name(const char *, mode_t, dev_t); \
250 static int (*true_ ## _name) (const char *, mode_t, dev_t) = NULL; \
251 \
252 int _name(const char *pathname, mode_t mode, dev_t dev) \
253 { \
254 int result = -1; \
255 \
256 if FUNCTION_SANDBOX_SAFE("mknod", pathname) { \
257 check_dlsym(_name); \
258 result = true_ ## _name(pathname, mode, dev); \
259 } \
260 \
261 return result; \
262 }
263
264 #define __xmknod_decl(_name) \
265 \
266 extern int _name(int, const char *, __mode_t, __dev_t *); \
267 static int (*true_ ## _name) (int, const char *, __mode_t, __dev_t *) = NULL; \
268 \
269 int _name(int ver, const char *pathname, __mode_t mode, __dev_t *dev) \
270 { \
271 int result = -1; \
272 \
273 if FUNCTION_SANDBOX_SAFE("mknod", pathname) { \
274 check_dlsym(_name); \
275 result = true_ ## _name(ver, pathname, mode, dev); \
276 } \
277 \
278 return result; \
279 }
280
281 #define mkfifo_decl(_name) \
282 \
283 extern int _name(const char *, mode_t); \
284 static int (*true_ ## _name) (const char *, mode_t) = NULL; \
285 \
286 int _name(const char *pathname, mode_t mode) \
287 { \
288 int result = -1; \
289 \
290 if FUNCTION_SANDBOX_SAFE("mkfifo", pathname) { \
291 check_dlsym(_name); \
292 result = true_ ## _name(pathname, mode); \
293 } \
294 \
295 return result; \
296 }
297
298 #define access_decl(_name) \
299 \
300 extern int _name(const char *, int); \
301 static int (*true_ ## _name) (const char *, int) = NULL; \
302 \
303 int _name(const char *pathname, int mode) \
304 { \
305 int result = -1; \
306 \
307 if FUNCTION_SANDBOX_SAFE_ACCESS("access", pathname, mode) { \
308 check_dlsym(_name); \
309 result = true_ ## _name(pathname, mode); \
310 } \
311 \
312 return result; \
313 }
314
315 #define open_decl(_name) \
316 \
317 extern int _name(const char *, int, ...); \
318 static int (*true_ ## _name) (const char *, int, ...) = NULL; \
319 \
320 /* Eventually, there is a third parameter: it's mode_t mode */ \
321 int _name(const char *pathname, int flags, ...) \
322 { \
323 va_list ap; \
324 int mode = 0; \
325 int result = -1; \
326 \
327 if (flags & O_CREAT) { \
328 va_start(ap, flags); \
329 mode = va_arg(ap, int); \
330 va_end(ap); \
331 } \
332 \
333 if FUNCTION_SANDBOX_SAFE_OPEN_INT("open", pathname, flags) { \
334 check_dlsym(_name); \
335 if (flags & O_CREAT) \
336 result = true_ ## _name(pathname, flags, mode); \
337 else \
338 result = true_ ## _name(pathname, flags); \
339 } \
340 \
341 return result; \
342 }
343
344 #define rename_decl(_name) \
345 \
346 extern int _name(const char *, const char *); \
347 static int (*true_ ## _name) (const char *, const char *) = NULL; \
348 \
349 int _name(const char *oldpath, const char *newpath) \
350 { \
351 int result = -1; \
352 \
353 if (FUNCTION_SANDBOX_SAFE("rename", oldpath) && \
354 FUNCTION_SANDBOX_SAFE("rename", newpath)) { \
355 check_dlsym(_name); \
356 result = true_ ## _name(oldpath, newpath); \
357 } \
358 \
359 return result; \
360 }
361
362 #define rmdir_decl(_name) \
363 \
364 extern int _name(const char *); \
365 static int (*true_ ## _name) (const char *) = NULL; \
366 \
367 int _name(const char *pathname) \
368 { \
369 int result = -1; \
370 \
371 if FUNCTION_SANDBOX_SAFE("rmdir", pathname) { \
372 check_dlsym(_name); \
373 result = true_ ## _name(pathname); \
374 } \
375 \
376 return result; \
377 }
378
379 #define symlink_decl(_name) \
380 \
381 extern int _name(const char *, const char *); \
382 static int (*true_ ## _name) (const char *, const char *) = NULL; \
383 \
384 int _name(const char *oldpath, const char *newpath) \
385 { \
386 int result = -1; \
387 \
388 if FUNCTION_SANDBOX_SAFE("symlink", newpath) { \
389 check_dlsym(_name); \
390 result = true_ ## _name(oldpath, newpath); \
391 } \
392 \
393 return result; \
394 }
395
396 #define truncate_decl(_name) \
397 \
398 extern int _name(const char *, TRUNCATE_T); \
399 static int (*true_ ## _name) (const char *, TRUNCATE_T) = NULL; \
400 \
401 int _name(const char *path, TRUNCATE_T length) \
402 { \
403 int result = -1; \
404 \
405 if FUNCTION_SANDBOX_SAFE("truncate", path) { \
406 check_dlsym(_name); \
407 result = true_ ## _name(path, length); \
408 } \
409 \
410 return result; \
411 }
412
413 #define unlink_decl(_name) \
414 \
415 extern int _name(const char *); \
416 static int (*true_ ## _name) (const char *) = NULL; \
417 \
418 int _name(const char *pathname) \
419 { \
420 int result = -1; \
421 char canonic[SB_PATH_MAX]; \
422 \
423 if (-1 == canonicalize(pathname, canonic)) \
424 /* Path is too long to canonicalize, do not fail, but just let
425 * the real function handle it (see bug #94630 and #21766). */ \
426 if (ENAMETOOLONG != errno) \
427 return -1; \
428 \
429 /* XXX: Hack to make sure sandboxed process cannot remove
430 * a device node, bug #79836. */ \
431 if ((0 == strncmp(canonic, "/dev/null", 9)) || \
432 (0 == strncmp(canonic, "/dev/zero", 9))) { \
433 errno = EACCES; \
434 return result; \
435 } \
436 \
437 if FUNCTION_SANDBOX_SAFE("unlink", pathname) { \
438 check_dlsym(_name); \
439 result = true_ ## _name(pathname); \
440 } \
441 \
442 return result; \
443 }
444
445 #define getcwd_decl(_name) \
446 \
447 extern char *_name(char *, size_t); \
448 static char * (*true_ ## _name) (char *, size_t) = NULL; \
449 \
450 char *_name(char *buf, size_t size) \
451 { \
452 char *result = NULL; \
453 \
454 /* Need to disable sandbox, as on non-linux libc's, opendir() is
455 * used by some getcwd() implementations and resolves to the sandbox
456 * opendir() wrapper, causing infinit recursion and finially crashes.
457 */ \
458 sandbox_on = 0; \
459 check_dlsym(_name); \
460 result = true_ ## _name(buf, size); \
461 sandbox_on = 1; \
462 \
463 return result; \
464 }
465
466 #define creat64_decl(_name) \
467 \
468 extern int _name(const char *, __mode_t); \
469 /* static int (*true_ ## _name) (const char *, __mode_t) = NULL; */ \
470 \
471 int _name(const char *pathname, __mode_t mode) \
472 { \
473 int result = -1; \
474 \
475 if FUNCTION_SANDBOX_SAFE("creat64", pathname) { \
476 check_dlsym(open64_DEFAULT); \
477 result = true_open64_DEFAULT(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode); \
478 } \
479 \
480 return result; \
481 }
482
483 #define fopen64_decl(_name) \
484 \
485 extern FILE *_name(const char *, const char *); \
486 static FILE * (*true_ ## _name) (const char *, const char *) = NULL; \
487 \
488 FILE *_name(const char *pathname, const char *mode) \
489 { \
490 FILE *result = NULL; \
491 \
492 if FUNCTION_SANDBOX_SAFE_OPEN_CHAR("fopen64", pathname, mode) { \
493 check_dlsym(_name); \
494 result = true_ ## _name(pathname, mode); \
495 } \
496 \
497 return result; \
498 }
499
500 #define open64_decl(_name) \
501 \
502 extern int _name(const char *, int, ...); \
503 static int (*true_ ## _name) (const char *, int, ...) = NULL; \
504 \
505 /* Eventually, there is a third parameter: it's mode_t mode */ \
506 int _name(const char *pathname, int flags, ...) \
507 { \
508 va_list ap; \
509 int mode = 0; \
510 int result = -1; \
511 \
512 if (flags & O_CREAT) { \
513 va_start(ap, flags); \
514 mode = va_arg(ap, int); \
515 va_end(ap); \
516 } \
517 \
518 if FUNCTION_SANDBOX_SAFE_OPEN_INT("open64", pathname, flags) { \
519 check_dlsym(_name); \
520 if (flags & O_CREAT) \
521 result = true_ ## _name(pathname, flags, mode); \
522 else \
523 result = true_ ## _name(pathname, flags); \
524 } \
525 \
526 return result; \
527 }
528
529 #define truncate64_decl(_name) \
530 \
531 extern int _name(const char *, __off64_t); \
532 static int (*true_ ## _name) (const char *, __off64_t) = NULL; \
533 \
534 int _name(const char *path, __off64_t length) \
535 { \
536 int result = -1; \
537 \
538 if FUNCTION_SANDBOX_SAFE("truncate64", path) { \
539 check_dlsym(_name); \
540 result = true_ ## _name(path, length); \
541 } \
542 \
543 return result; \
544 }
545
546 /*
547 * Exec Wrappers
548 */
549
550 #define execve_decl(_name) \
551 \
552 extern int _name(const char *, char *const[], char *const[]); \
553 static int (*true_ ## _name) (const char *, char *const[], char *const[]) = NULL; \
554 \
555 int _name(const char *filename, char *const argv[], char *const envp[]) \
556 { \
557 int old_errno = errno; \
558 int result = -1; \
559 int count = 0; \
560 int env_len = 0; \
561 char **my_env = NULL; \
562 int kill_env = 1; \
563 /* We limit the size LD_PRELOAD can be here, but it should be enough */ \
564 char tmp_str[SB_BUF_LEN]; \
565 \
566 if FUNCTION_SANDBOX_SAFE("execve", filename) { \
567 while (envp[count] != NULL) { \
568 /* Check if we do not have to do anything */ \
569 if (strstr(envp[count], LD_PRELOAD_EQ) == envp[count]) { \
570 if (NULL != strstr(envp[count], sandbox_lib)) { \
571 my_env = (char **)envp; \
572 kill_env = 0; \
573 goto end_loop; \
574 } \
575 } \
576 \
577 /* If LD_PRELOAD is set and sandbox_lib not in it */ \
578 if (((strstr(envp[count], LD_PRELOAD_EQ) == envp[count]) && \
579 (NULL == strstr(envp[count], sandbox_lib))) || \
580 /* Or LD_PRELOAD is not set, and this is the last loop */ \
581 ((strstr(envp[count], LD_PRELOAD_EQ) != envp[count]) && \
582 (NULL == envp[count + 1]))) { \
583 int i = 0; \
584 int add_ldpreload = 0; \
585 const int max_envp_len = strlen(envp[count]) + strlen(sandbox_lib) + 1; \
586 \
587 /* Fail safe ... */ \
588 if (max_envp_len > SB_BUF_LEN) { \
589 fprintf(stderr, "libsandbox: max_envp_len too big!\n"); \
590 errno = ENOMEM; \
591 return result; \
592 } \
593 \
594 /* Calculate envp size */ \
595 my_env = (char **)envp; \
596 do \
597 env_len++; \
598 while (NULL != *my_env++); \
599 \
600 /* Should we add LD_PRELOAD ? */ \
601 if (strstr(envp[count], LD_PRELOAD_EQ) != envp[count]) \
602 add_ldpreload = 1; \
603 \
604 my_env = (char **)xcalloc(env_len + add_ldpreload, sizeof(char *)); \
605 if (NULL == my_env) \
606 return result; \
607 /* Copy envp to my_env */ \
608 do \
609 /* Leave a space for LD_PRELOAD if needed */ \
610 my_env[i + add_ldpreload] = envp[i]; \
611 while (NULL != envp[i++]); \
612 \
613 /* Add 'LD_PRELOAD=' to the beginning of our new string */ \
614 snprintf(tmp_str, max_envp_len, "%s%s", LD_PRELOAD_EQ, sandbox_lib); \
615 \
616 /* LD_PRELOAD already have variables other than sandbox_lib,
617 * thus we have to add sandbox_lib seperated via a whitespace. */ \
618 if (0 == add_ldpreload) { \
619 snprintf((char *)(tmp_str + strlen(tmp_str)), \
620 max_envp_len - strlen(tmp_str) + 1, " %s", \
621 (char *)(envp[count] + strlen(LD_PRELOAD_EQ))); \
622 } \
623 \
624 /* Valid string? */ \
625 tmp_str[max_envp_len] = '\0'; \
626 \
627 /* Ok, replace my_env[count] with our version that contains
628 * sandbox_lib ... */ \
629 if (1 == add_ldpreload) \
630 /* We reserved a space for LD_PRELOAD above */ \
631 my_env[0] = tmp_str; \
632 else \
633 my_env[count] = tmp_str; \
634 \
635 goto end_loop; \
636 } \
637 count++; \
638 } \
639 \
640 end_loop: \
641 errno = old_errno; \
642 check_dlsym(_name); \
643 result = true_ ## _name(filename, argv, my_env); \
644 old_errno = errno; \
645 \
646 if (my_env && kill_env) \
647 free(my_env); \
648 } \
649 \
650 errno = old_errno; \
651 \
652 return result; \
653 }
654
655 #include "symbols.h"
656
657
658 int libsb_open(const char *pathname, int flags, ...)
659 {
660 va_list ap;
661 int mode = 0;
662 int result = -1;
663
664 if (flags & O_CREAT) {
665 va_start(ap, flags);
666 mode = va_arg(ap, int);
667 va_end(ap);
668 }
669
670 check_dlsym(open_DEFAULT);
671 if (flags & O_CREAT)
672 result = true_open_DEFAULT(pathname, flags, mode);
673 else
674 result = true_open_DEFAULT(pathname, flags);
675
676 return result;
677 }
678
679 char *libsb_getcwd(char *buf, size_t size)
680 {
681 check_dlsym(getcwd_DEFAULT);
682
683 return true_getcwd_DEFAULT(buf, size);
684 }
685

  ViewVC Help
Powered by ViewVC 1.1.20