diff options
author | Martin Schlemmer <azarah@gentoo.org> | 2006-07-10 07:16:56 +0000 |
---|---|---|
committer | Martin Schlemmer <azarah@gentoo.org> | 2006-07-10 07:16:56 +0000 |
commit | f4dec3394bce65a32a5c26987950d63849d6f3a6 (patch) | |
tree | 259d369321a6f823545ebbf6e1baa2f8f167200e /libsandbox/wrappers.c | |
parent | Add forgotten libsandbox.h. (diff) | |
download | sandbox-f4dec3394bce65a32a5c26987950d63849d6f3a6.tar.gz sandbox-f4dec3394bce65a32a5c26987950d63849d6f3a6.tar.bz2 sandbox-f4dec3394bce65a32a5c26987950d63849d6f3a6.zip |
Move wrappers out of libsandbox.c. Move IO functions to
libsbutil.
Signed-off-by: Martin Schlemmer <azarah@gentoo.org>
Diffstat (limited to 'libsandbox/wrappers.c')
-rw-r--r-- | libsandbox/wrappers.c | 678 |
1 files changed, 678 insertions, 0 deletions
diff --git a/libsandbox/wrappers.c b/libsandbox/wrappers.c new file mode 100644 index 0000000..d23dde6 --- /dev/null +++ b/libsandbox/wrappers.c @@ -0,0 +1,678 @@ +/* + * wrappers.c + * + * Function wrapping functions. + * + * Copyright 1999-2006 Gentoo Foundation + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Header$ + */ + + +#include "config.h" + +/* Better way would be to only define _GNU_SOURCE when __GLIBC__ is defined, + * but including features.h and then defining _GNU_SOURCE do not work */ +#if defined(HAVE_RTLD_NEXT) +# define _GNU_SOURCE +#endif +#include <errno.h> +#include <dlfcn.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <dirent.h> +#include <unistd.h> +#include <fcntl.h> + +#include "localdecls.h" +#include "sbutil.h" +#include "libsandbox.h" +#include "wrappers.h" + +#if !defined(BROKEN_RTLD_NEXT) && defined(HAVE_RTLD_NEXT) +# define USE_RTLD_NEXT +#endif + +static void *libc_handle = NULL; + +extern char sandbox_lib[SB_PATH_MAX]; +extern int sandbox_on; + +void *get_dlsym(const char *symname, const char *symver) +{ + void *symaddr = NULL; + + if (NULL == libc_handle) { +#if !defined(USE_RTLD_NEXT) + libc_handle = dlopen(LIBC_VERSION, RTLD_LAZY); + if (!libc_handle) { + fprintf(stderr, "libsandbox: Can't dlopen libc: %s\n", + dlerror()); + exit(EXIT_FAILURE); + } +#else + libc_handle = RTLD_NEXT; +#endif + } + + if (NULL == symver) + symaddr = dlsym(libc_handle, symname); + else + symaddr = dlvsym(libc_handle, symname, symver); + if (!symaddr) { + fprintf(stderr, "libsandbox: Can't resolve %s: %s\n", + symname, dlerror()); + exit(EXIT_FAILURE); + } + + return symaddr; +} + +/* + * Wrapper Functions + */ + +#define chmod_decl(_name) \ +\ +extern int _name(const char *, mode_t); \ +static int (*true_ ## _name) (const char *, mode_t) = NULL; \ +\ +int _name(const char *path, mode_t mode) \ +{ \ + int result = -1; \ +\ + if FUNCTION_SANDBOX_SAFE("chmod", path) { \ + check_dlsym(_name); \ + result = true_ ## _name(path, mode); \ + } \ +\ + return result; \ +} + +#define chown_decl(_name) \ +\ +extern int _name(const char *, uid_t, gid_t); \ +static int (*true_ ## _name) (const char *, uid_t, gid_t) = NULL; \ +\ +int _name(const char *path, uid_t owner, gid_t group) \ +{ \ + int result = -1; \ +\ + if FUNCTION_SANDBOX_SAFE("chown", path) { \ + check_dlsym(_name); \ + result = true_ ## _name(path, owner, group); \ + } \ +\ + return result; \ +} + +#define creat_decl(_name) \ +\ +extern int _name(const char *, mode_t); \ +/* static int (*true_ ## _name) (const char *, mode_t) = NULL; */ \ +\ +int _name(const char *pathname, mode_t mode) \ +{ \ + int result = -1; \ +\ + if FUNCTION_SANDBOX_SAFE("creat", pathname) { \ + check_dlsym(open_DEFAULT); \ + result = true_open_DEFAULT(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode); \ + } \ +\ + return result; \ +} + +#define fopen_decl(_name) \ +\ +extern FILE *_name(const char *, const char *); \ +static FILE * (*true_ ## _name) (const char *, const char *) = NULL; \ +\ +FILE *_name(const char *pathname, const char *mode) \ +{ \ + FILE *result = NULL; \ +\ + if FUNCTION_SANDBOX_SAFE_OPEN_CHAR("fopen", pathname, mode) { \ + check_dlsym(_name); \ + result = true_ ## _name(pathname, mode); \ + } \ +\ + return result; \ +} + +#define lchown_decl(_name) \ +\ +extern int _name(const char *, uid_t, gid_t); \ +static int (*true_ ## _name) (const char *, uid_t, gid_t) = NULL; \ +\ +int _name(const char *path, uid_t owner, gid_t group) \ +{ \ + int result = -1; \ +\ + if FUNCTION_SANDBOX_SAFE("lchown", path) { \ + check_dlsym(_name); \ + result = true_ ## _name(path, owner, group); \ + } \ +\ + return result; \ +} + +#define link_decl(_name) \ +\ +extern int _name(const char *, const char *); \ +static int (*true_ ## _name) (const char *, const char *) = NULL; \ +\ +int _name(const char *oldpath, const char *newpath) \ +{ \ + int result = -1; \ +\ + if FUNCTION_SANDBOX_SAFE("link", newpath) { \ + check_dlsym(_name); \ + result = true_ ## _name(oldpath, newpath); \ + } \ +\ + return result; \ +} + +#define mkdir_decl(_name) \ +\ +extern int _name(const char *, mode_t); \ +static int (*true_ ## _name) (const char *, mode_t) = NULL; \ +\ +int _name(const char *pathname, mode_t mode) \ +{ \ + struct stat st; \ + int result = -1, my_errno = errno; \ + char canonic[SB_PATH_MAX]; \ +\ + if (-1 == canonicalize(pathname, canonic)) \ + /* Path is too long to canonicalize, do not fail, but just let + * the real function handle it (see bug #94630 and #21766). */ \ + if (ENAMETOOLONG != errno) \ + return -1; \ +\ + /* XXX: Hack to prevent errors if the directory exist, + * and are not writable - we rather return EEXIST rather + * than failing */ \ + if (0 == lstat(canonic, &st)) { \ + errno = EEXIST; \ + return -1; \ + } \ + errno = my_errno; \ +\ + if FUNCTION_SANDBOX_SAFE("mkdir", pathname) { \ + check_dlsym(_name); \ + result = true_ ## _name(pathname, mode); \ + } \ +\ + return result; \ +} + +#define opendir_decl(_name) \ +\ +extern DIR *_name(const char *); \ +static DIR * (*true_ ## _name) (const char *) = NULL; \ +\ +DIR *_name(const char *name) \ +{ \ + DIR *result = NULL; \ +\ + if FUNCTION_SANDBOX_SAFE("opendir", name) { \ + check_dlsym(_name); \ + result = true_ ## _name(name); \ + } \ +\ + return result; \ +} + +#define mknod_decl(_name) \ +\ +extern int _name(const char *, mode_t, dev_t); \ +static int (*true_ ## _name) (const char *, mode_t, dev_t) = NULL; \ +\ +int _name(const char *pathname, mode_t mode, dev_t dev) \ +{ \ + int result = -1; \ +\ + if FUNCTION_SANDBOX_SAFE("mknod", pathname) { \ + check_dlsym(_name); \ + result = true_ ## _name(pathname, mode, dev); \ + } \ +\ + return result; \ +} + +#define __xmknod_decl(_name) \ +\ +extern int _name(int, const char *, __mode_t, __dev_t *); \ +static int (*true_ ## _name) (int, const char *, __mode_t, __dev_t *) = NULL; \ +\ +int _name(int ver, const char *pathname, __mode_t mode, __dev_t *dev) \ +{ \ + int result = -1; \ +\ + if FUNCTION_SANDBOX_SAFE("mknod", pathname) { \ + check_dlsym(_name); \ + result = true_ ## _name(ver, pathname, mode, dev); \ + } \ +\ + return result; \ +} + +#define mkfifo_decl(_name) \ +\ +extern int _name(const char *, mode_t); \ +static int (*true_ ## _name) (const char *, mode_t) = NULL; \ +\ +int _name(const char *pathname, mode_t mode) \ +{ \ + int result = -1; \ +\ + if FUNCTION_SANDBOX_SAFE("mkfifo", pathname) { \ + check_dlsym(_name); \ + result = true_ ## _name(pathname, mode); \ + } \ +\ + return result; \ +} + +#define access_decl(_name) \ +\ +extern int _name(const char *, int); \ +static int (*true_ ## _name) (const char *, int) = NULL; \ +\ +int _name(const char *pathname, int mode) \ +{ \ + int result = -1; \ +\ + if FUNCTION_SANDBOX_SAFE_ACCESS("access", pathname, mode) { \ + check_dlsym(_name); \ + result = true_ ## _name(pathname, mode); \ + } \ +\ + return result; \ +} + +#define open_decl(_name) \ +\ +extern int _name(const char *, int, ...); \ +static int (*true_ ## _name) (const char *, int, ...) = NULL; \ +\ +/* Eventually, there is a third parameter: it's mode_t mode */ \ +int _name(const char *pathname, int flags, ...) \ +{ \ + va_list ap; \ + int mode = 0; \ + int result = -1; \ +\ + if (flags & O_CREAT) { \ + va_start(ap, flags); \ + mode = va_arg(ap, int); \ + va_end(ap); \ + } \ +\ + if FUNCTION_SANDBOX_SAFE_OPEN_INT("open", pathname, flags) { \ + check_dlsym(_name); \ + if (flags & O_CREAT) \ + result = true_ ## _name(pathname, flags, mode); \ + else \ + result = true_ ## _name(pathname, flags); \ + } \ +\ + return result; \ +} + +#define rename_decl(_name) \ +\ +extern int _name(const char *, const char *); \ +static int (*true_ ## _name) (const char *, const char *) = NULL; \ +\ +int _name(const char *oldpath, const char *newpath) \ +{ \ + int result = -1; \ +\ + if (FUNCTION_SANDBOX_SAFE("rename", oldpath) && \ + FUNCTION_SANDBOX_SAFE("rename", newpath)) { \ + check_dlsym(_name); \ + result = true_ ## _name(oldpath, newpath); \ + } \ +\ + return result; \ +} + +#define rmdir_decl(_name) \ +\ +extern int _name(const char *); \ +static int (*true_ ## _name) (const char *) = NULL; \ +\ +int _name(const char *pathname) \ +{ \ + int result = -1; \ +\ + if FUNCTION_SANDBOX_SAFE("rmdir", pathname) { \ + check_dlsym(_name); \ + result = true_ ## _name(pathname); \ + } \ +\ + return result; \ +} + +#define symlink_decl(_name) \ +\ +extern int _name(const char *, const char *); \ +static int (*true_ ## _name) (const char *, const char *) = NULL; \ +\ +int _name(const char *oldpath, const char *newpath) \ +{ \ + int result = -1; \ +\ + if FUNCTION_SANDBOX_SAFE("symlink", newpath) { \ + check_dlsym(_name); \ + result = true_ ## _name(oldpath, newpath); \ + } \ +\ + return result; \ +} + +#define truncate_decl(_name) \ +\ +extern int _name(const char *, TRUNCATE_T); \ +static int (*true_ ## _name) (const char *, TRUNCATE_T) = NULL; \ +\ +int _name(const char *path, TRUNCATE_T length) \ +{ \ + int result = -1; \ +\ + if FUNCTION_SANDBOX_SAFE("truncate", path) { \ + check_dlsym(_name); \ + result = true_ ## _name(path, length); \ + } \ +\ + return result; \ +} + +#define unlink_decl(_name) \ +\ +extern int _name(const char *); \ +static int (*true_ ## _name) (const char *) = NULL; \ +\ +int _name(const char *pathname) \ +{ \ + int result = -1; \ + char canonic[SB_PATH_MAX]; \ +\ + if (-1 == canonicalize(pathname, canonic)) \ + /* Path is too long to canonicalize, do not fail, but just let + * the real function handle it (see bug #94630 and #21766). */ \ + if (ENAMETOOLONG != errno) \ + return -1; \ +\ + /* XXX: Hack to make sure sandboxed process cannot remove + * a device node, bug #79836. */ \ + if ((0 == strncmp(canonic, "/dev/null", 9)) || \ + (0 == strncmp(canonic, "/dev/zero", 9))) { \ + errno = EACCES; \ + return result; \ + } \ +\ + if FUNCTION_SANDBOX_SAFE("unlink", pathname) { \ + check_dlsym(_name); \ + result = true_ ## _name(pathname); \ + } \ +\ + return result; \ +} + +#define getcwd_decl(_name) \ +\ +extern char *_name(char *, size_t); \ +static char * (*true_ ## _name) (char *, size_t) = NULL; \ +\ +char *_name(char *buf, size_t size) \ +{ \ + char *result = NULL; \ +\ + /* Need to disable sandbox, as on non-linux libc's, opendir() is + * used by some getcwd() implementations and resolves to the sandbox + * opendir() wrapper, causing infinit recursion and finially crashes. + */ \ + sandbox_on = 0; \ + check_dlsym(_name); \ + result = true_ ## _name(buf, size); \ + sandbox_on = 1; \ +\ + return result; \ +} + +#define creat64_decl(_name) \ +\ +extern int _name(const char *, __mode_t); \ +/* static int (*true_ ## _name) (const char *, __mode_t) = NULL; */ \ +\ +int _name(const char *pathname, __mode_t mode) \ +{ \ + int result = -1; \ +\ + if FUNCTION_SANDBOX_SAFE("creat64", pathname) { \ + check_dlsym(open64_DEFAULT); \ + result = true_open64_DEFAULT(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode); \ + } \ +\ + return result; \ +} + +#define fopen64_decl(_name) \ +\ +extern FILE *_name(const char *, const char *); \ +static FILE * (*true_ ## _name) (const char *, const char *) = NULL; \ +\ +FILE *_name(const char *pathname, const char *mode) \ +{ \ + FILE *result = NULL; \ +\ + if FUNCTION_SANDBOX_SAFE_OPEN_CHAR("fopen64", pathname, mode) { \ + check_dlsym(_name); \ + result = true_ ## _name(pathname, mode); \ + } \ +\ + return result; \ +} + +#define open64_decl(_name) \ +\ +extern int _name(const char *, int, ...); \ +static int (*true_ ## _name) (const char *, int, ...) = NULL; \ +\ +/* Eventually, there is a third parameter: it's mode_t mode */ \ +int _name(const char *pathname, int flags, ...) \ +{ \ + va_list ap; \ + int mode = 0; \ + int result = -1; \ +\ + if (flags & O_CREAT) { \ + va_start(ap, flags); \ + mode = va_arg(ap, int); \ + va_end(ap); \ + } \ +\ + if FUNCTION_SANDBOX_SAFE_OPEN_INT("open64", pathname, flags) { \ + check_dlsym(_name); \ + if (flags & O_CREAT) \ + result = true_ ## _name(pathname, flags, mode); \ + else \ + result = true_ ## _name(pathname, flags); \ + } \ +\ + return result; \ +} + +#define truncate64_decl(_name) \ +\ +extern int _name(const char *, __off64_t); \ +static int (*true_ ## _name) (const char *, __off64_t) = NULL; \ +\ +int _name(const char *path, __off64_t length) \ +{ \ + int result = -1; \ +\ + if FUNCTION_SANDBOX_SAFE("truncate64", path) { \ + check_dlsym(_name); \ + result = true_ ## _name(path, length); \ + } \ +\ + return result; \ +} + +/* + * Exec Wrappers + */ + +#define execve_decl(_name) \ +\ +extern int _name(const char *, char *const[], char *const[]); \ +static int (*true_ ## _name) (const char *, char *const[], char *const[]) = NULL; \ +\ +int _name(const char *filename, char *const argv[], char *const envp[]) \ +{ \ + int old_errno = errno; \ + int result = -1; \ + int count = 0; \ + int env_len = 0; \ + char **my_env = NULL; \ + int kill_env = 1; \ + /* We limit the size LD_PRELOAD can be here, but it should be enough */ \ + char tmp_str[SB_BUF_LEN]; \ +\ + if FUNCTION_SANDBOX_SAFE("execve", filename) { \ + while (envp[count] != NULL) { \ + /* Check if we do not have to do anything */ \ + if (strstr(envp[count], LD_PRELOAD_EQ) == envp[count]) { \ + if (NULL != strstr(envp[count], sandbox_lib)) { \ + my_env = (char **)envp; \ + kill_env = 0; \ + goto end_loop; \ + } \ + } \ +\ + /* If LD_PRELOAD is set and sandbox_lib not in it */ \ + if (((strstr(envp[count], LD_PRELOAD_EQ) == envp[count]) && \ + (NULL == strstr(envp[count], sandbox_lib))) || \ + /* Or LD_PRELOAD is not set, and this is the last loop */ \ + ((strstr(envp[count], LD_PRELOAD_EQ) != envp[count]) && \ + (NULL == envp[count + 1]))) { \ + int i = 0; \ + int add_ldpreload = 0; \ + const int max_envp_len = strlen(envp[count]) + strlen(sandbox_lib) + 1; \ +\ + /* Fail safe ... */ \ + if (max_envp_len > SB_BUF_LEN) { \ + fprintf(stderr, "libsandbox: max_envp_len too big!\n"); \ + errno = ENOMEM; \ + return result; \ + } \ +\ + /* Calculate envp size */ \ + my_env = (char **)envp; \ + do \ + env_len++; \ + while (NULL != *my_env++); \ +\ + /* Should we add LD_PRELOAD ? */ \ + if (strstr(envp[count], LD_PRELOAD_EQ) != envp[count]) \ + add_ldpreload = 1; \ +\ + my_env = (char **)xcalloc(env_len + add_ldpreload, sizeof(char *)); \ + if (NULL == my_env) \ + return result; \ + /* Copy envp to my_env */ \ + do \ + /* Leave a space for LD_PRELOAD if needed */ \ + my_env[i + add_ldpreload] = envp[i]; \ + while (NULL != envp[i++]); \ +\ + /* Add 'LD_PRELOAD=' to the beginning of our new string */ \ + snprintf(tmp_str, max_envp_len, "%s%s", LD_PRELOAD_EQ, sandbox_lib); \ +\ + /* LD_PRELOAD already have variables other than sandbox_lib, + * thus we have to add sandbox_lib seperated via a whitespace. */ \ + if (0 == add_ldpreload) { \ + snprintf((char *)(tmp_str + strlen(tmp_str)), \ + max_envp_len - strlen(tmp_str) + 1, " %s", \ + (char *)(envp[count] + strlen(LD_PRELOAD_EQ))); \ + } \ +\ + /* Valid string? */ \ + tmp_str[max_envp_len] = '\0'; \ +\ + /* Ok, replace my_env[count] with our version that contains + * sandbox_lib ... */ \ + if (1 == add_ldpreload) \ + /* We reserved a space for LD_PRELOAD above */ \ + my_env[0] = tmp_str; \ + else \ + my_env[count] = tmp_str; \ +\ + goto end_loop; \ + } \ + count++; \ + } \ +\ +end_loop: \ + errno = old_errno; \ + check_dlsym(_name); \ + result = true_ ## _name(filename, argv, my_env); \ + old_errno = errno; \ +\ + if (my_env && kill_env) \ + free(my_env); \ + } \ +\ + errno = old_errno; \ +\ + return result; \ +} + +#include "symbols.h" + + +int libsb_open(const char *pathname, int flags, ...) +{ + va_list ap; + int mode = 0; + int result = -1; + + if (flags & O_CREAT) { + va_start(ap, flags); + mode = va_arg(ap, int); + va_end(ap); + } + + check_dlsym(open_DEFAULT); + if (flags & O_CREAT) + result = true_open_DEFAULT(pathname, flags, mode); + else + result = true_open_DEFAULT(pathname, flags); + + return result; +} + |