code-intelligence.com/cifuzz@v0.40.0/third-party/minijail/libminijailpreload.c (about) 1 /* libminijailpreload.c - preload hack library 2 * Copyright (c) 2011 The Chromium OS Authors. All rights reserved. 3 * Use of this source code is governed by a BSD-style license that can be 4 * found in the LICENSE file. 5 * 6 * This library is preloaded into every program launched by minijail_run(). 7 * DO NOT EXPORT ANY SYMBOLS FROM THIS LIBRARY. They will replace other symbols 8 * in the programs it is preloaded into and cause impossible-to-debug failures. 9 * See the minijail0.1 for a design explanation. 10 */ 11 12 #include "libminijail.h" 13 #include "libminijail-private.h" 14 15 #include <dlfcn.h> 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <string.h> 19 #include <sys/types.h> 20 #include <syslog.h> 21 #include <unistd.h> 22 23 static int (*real_main) (int, char **, char **); 24 static void *libc_handle; 25 26 static void die(const char *failed) 27 { 28 syslog(LOG_ERR, "libminijail: %s", failed); 29 abort(); 30 } 31 32 static void unset_in_env(char **envp, const char *name) 33 { 34 int i; 35 for (i = 0; envp[i]; i++) 36 if (!strncmp(envp[i], name, strlen(name))) 37 envp[i][0] = '\0'; 38 } 39 40 /** @brief Fake main(), spliced in before the real call to main() by 41 * __libc_start_main (see below). 42 * We get serialized commands from our invoking process over an fd specified 43 * by an environment variable (kFdEnvVar). The environment variable is a list 44 * of key=value pairs (see move_commands_to_env); we use them to construct a 45 * jail, then enter it. 46 */ 47 static int fake_main(int argc, char **argv, char **envp) 48 { 49 char *fd_name = getenv(kFdEnvVar); 50 int fd = -1; 51 struct minijail *j; 52 if (geteuid() != getuid() || getegid() != getgid()) { 53 /* 54 * If we didn't do this check, an attacker could set kFdEnvVar 55 * for any setuid program that uses libminijail to cause it to 56 * get capabilities or a uid it did not expect. 57 */ 58 /* TODO(wad): why would libminijail interact here? */ 59 return MINIJAIL_ERR_PRELOAD; 60 } 61 if (!fd_name) 62 return MINIJAIL_ERR_PRELOAD; 63 fd = atoi(fd_name); 64 if (fd < 0) 65 return MINIJAIL_ERR_PRELOAD; 66 67 j = minijail_new(); 68 if (!j) 69 die("preload: out of memory"); 70 if (minijail_from_fd(fd, j)) 71 die("preload: failed to parse minijail from parent"); 72 close(fd); 73 74 unset_in_env(envp, kFdEnvVar); 75 /* TODO(ellyjones): this trashes existing preloads, so one can't do: 76 * LD_PRELOAD="/tmp/test.so libminijailpreload.so" prog; the 77 * descendants of prog will have no LD_PRELOAD set at all. 78 */ 79 unset_in_env(envp, kLdPreloadEnvVar); 80 /* Strip out flags meant for the parent. */ 81 minijail_preenter(j); 82 minijail_enter(j); 83 minijail_destroy(j); 84 dlclose(libc_handle); 85 return real_main(argc, argv, envp); 86 } 87 88 /** @brief LD_PRELOAD override of __libc_start_main. 89 * 90 * It is really best if you do not look too closely at this function. We need 91 * to ensure that some of our code runs before the target program (see the 92 * minijail0.1 file in this directory for high-level details about this), and 93 * the only available place to hook is this function, which is normally 94 * responsible for calling main(). Our LD_PRELOAD will overwrite the real 95 * __libc_start_main with this one, so we have to look up the real one from 96 * libc and invoke it with a pointer to the fake main() we'd like to run before 97 * the real main(). We can't just run our setup code *here* because 98 * __libc_start_main is responsible for setting up the C runtime environment, 99 * so we can't rely on things like malloc() being available yet. 100 */ 101 102 int API __libc_start_main(int (*main)(int, char **, char **), int argc, 103 char **ubp_av, void (*init)(void), void (*fini)(void), 104 void (*rtld_fini)(void), void(*stack_end)) 105 { 106 void *sym; 107 /* 108 * This hack is unfortunately required by C99 - casting directly from 109 * void* to function pointers is left undefined. See POSIX.1-2003, the 110 * Rationale for the specification of dlsym(), and dlsym(3). This 111 * deliberately violates strict-aliasing rules, but gcc can't tell. 112 */ 113 union { 114 int (*fn)(int (*main)(int, char **, char **), int argc, 115 char **ubp_av, void (*init)(void), void (*fini)(void), 116 void (*rtld_fini)(void), void(*stack_end)); 117 void *symval; 118 } real_libc_start_main; 119 120 /* 121 * We hold this handle for the duration of the real __libc_start_main() 122 * and drop it just before calling the real main(). 123 */ 124 libc_handle = dlopen("libc.so.6", RTLD_NOW); 125 126 if (!libc_handle) { 127 syslog(LOG_ERR, "can't dlopen() libc"); 128 /* 129 * We dare not use abort() here because it will run atexit() 130 * handlers and try to flush stdio. 131 */ 132 _exit(1); 133 } 134 sym = dlsym(libc_handle, "__libc_start_main"); 135 if (!sym) { 136 syslog(LOG_ERR, "can't find the real __libc_start_main()"); 137 _exit(1); 138 } 139 real_libc_start_main.symval = sym; 140 real_main = main; 141 142 /* 143 * Note that we swap fake_main in for main - fake_main knows that it 144 * should call real_main after it's done. 145 */ 146 return real_libc_start_main.fn(fake_main, argc, ubp_av, init, fini, 147 rtld_fini, stack_end); 148 }