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
die(const char * failed)26 static void die(const char *failed)
27 {
28 syslog(LOG_ERR, "libminijail: %s", failed);
29 abort();
30 }
31
unset_in_env(char ** envp,const char * name)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 */
fake_main(int argc,char ** argv,char ** envp)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
__libc_start_main(int (* main)(int,char **,char **),int argc,char ** ubp_av,void (* init)(void),void (* fini)(void),void (* rtld_fini)(void),void (* stack_end))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 }
149