blob: 90f87330593245a55b2f46d79804cebc5800e9e8 [file] [log] [blame]
Elly Jonescd7a9042011-07-22 13:56:51 -04001/* 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.
Elly Jonese1749eb2011-10-07 13:54:59 -04009 * See the minijail0.1 for a design explanation.
10 */
Elly Jonescd7a9042011-07-22 13:56:51 -040011
12#include "libminijail.h"
13#include "libminijail-private.h"
14
15#include <dlfcn.h>
Will Drewry2f54b6a2011-09-16 13:45:31 -050016#include <stdio.h>
Elly Jonescd7a9042011-07-22 13:56:51 -040017#include <stdlib.h>
18#include <string.h>
19#include <sys/types.h>
20#include <syslog.h>
21#include <unistd.h>
22
Elly Jonese1749eb2011-10-07 13:54:59 -040023static int (*real_main) (int, char **, char **);
24static void *libc_handle;
Elly Jonescd7a9042011-07-22 13:56:51 -040025
Elly Jonese1749eb2011-10-07 13:54:59 -040026static void die(const char *failed)
27{
28 syslog(LOG_ERR, "libminijail: %s", failed);
29 abort();
Elly Jonescd7a9042011-07-22 13:56:51 -040030}
31
Elly Jonese1749eb2011-10-07 13:54:59 -040032static 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';
Elly Jonescd7a9042011-07-22 13:56:51 -040038}
39
Elly Jonescd7a9042011-07-22 13:56:51 -040040/** @brief Fake main(), spliced in before the real call to main() by
41 * __libc_start_main (see below).
Will Drewry2f54b6a2011-09-16 13:45:31 -050042 * 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.
Elly Jonescd7a9042011-07-22 13:56:51 -040046 */
Elly Jonese1749eb2011-10-07 13:54:59 -040047static 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 /* If we didn't do this check, an attacker could set kFdEnvVar
54 * for any setuid program that uses libminijail to cause it to
55 * get capabilities or a uid it did not expect.
56 */
57 /* TODO(wad) why would libminijail interact here? */
58 return MINIJAIL_ERR_PRELOAD;
59 if (!fd_name)
60 return MINIJAIL_ERR_PRELOAD;
61 fd = atoi(fd_name);
62 if (fd < 0)
63 return MINIJAIL_ERR_PRELOAD;
Will Drewry2f54b6a2011-09-16 13:45:31 -050064
Elly Jonese1749eb2011-10-07 13:54:59 -040065 j = minijail_new();
66 if (!j)
67 die("preload: out of memory");
68 if (minijail_from_fd(fd, j))
69 die("preload: failed to parse minijail from parent");
70 close(fd);
Will Drewryfe4a3722011-09-16 14:50:50 -050071
Elly Jonese1749eb2011-10-07 13:54:59 -040072 /* TODO(ellyjones): this trashes existing preloads, so one can't do:
73 * LD_PRELOAD="/tmp/test.so libminijailpreload.so" prog; the
74 * descendants of prog will have no LD_PRELOAD set at all.
75 */
76 unset_in_env(envp, kLdPreloadEnvVar);
77 /* Strip out flags meant for the parent. */
78 minijail_preenter(j);
79 minijail_enter(j);
80 minijail_destroy(j);
81 dlclose(libc_handle);
82 return real_main(argc, argv, envp);
Elly Jonescd7a9042011-07-22 13:56:51 -040083}
84
85/** @brief LD_PRELOAD override of __libc_start_main.
86 *
Elly Jonese1749eb2011-10-07 13:54:59 -040087 * It is really best if you do not look too closely at this function. We need
88 * to ensure that some of our code runs before the target program (see the
89 * minijail0.1 file in this directory for high-level details about this), and
Elly Jonescd7a9042011-07-22 13:56:51 -040090 * the only available place to hook is this function, which is normally
91 * responsible for calling main(). Our LD_PRELOAD will overwrite the real
92 * __libc_start_main with this one, so we have to look up the real one from
93 * libc and invoke it with a pointer to the fake main() we'd like to run before
94 * the real main(). We can't just run our setup code *here* because
95 * __libc_start_main is responsible for setting up the C runtime environment,
96 * so we can't rely on things like malloc() being available yet.
97 */
98
Will Drewry6ac91122011-10-21 16:38:58 -050099int API __libc_start_main(int (*main) (int, char **, char **),
Elly Jonese1749eb2011-10-07 13:54:59 -0400100 int argc, char **ubp_av, void (*init) (void),
101 void (*fini) (void), void (*rtld_fini) (void),
102 void (*stack_end))
103{
104 void *sym;
105 /* This hack is unfortunately required by C99 - casting directly from
106 * void* to function pointers is left undefined. See POSIX.1-2003, the
107 * Rationale for the specification of dlsym(), and dlsym(3). This
108 * deliberately violates strict-aliasing rules, but gcc can't tell.
109 */
110 union {
111 int (*fn) (int (*main) (int, char **, char **), int argc,
112 char **ubp_av, void (*init) (void),
113 void (*fini) (void), void (*rtld_fini) (void),
114 void (*stack_end));
115 void *symval;
116 } real_libc_start_main;
Elly Jonescd7a9042011-07-22 13:56:51 -0400117
Elly Jonese1749eb2011-10-07 13:54:59 -0400118 /* We hold this handle for the duration of the real __libc_start_main()
119 * and drop it just before calling the real main().
120 */
121 libc_handle = dlopen("libc.so.6", RTLD_NOW);
Elly Jonescd7a9042011-07-22 13:56:51 -0400122
Elly Jonese1749eb2011-10-07 13:54:59 -0400123 if (!libc_handle) {
124 syslog(LOG_ERR, "can't dlopen() libc");
125 /* We dare not use abort() here because it will run atexit()
126 * handlers and try to flush stdio.
127 */
128 _exit(1);
129 }
130 sym = dlsym(libc_handle, "__libc_start_main");
131 if (!sym) {
132 syslog(LOG_ERR, "can't find the real __libc_start_main()");
133 _exit(1);
134 }
135 real_libc_start_main.symval = sym;
136 real_main = main;
Elly Jonescd7a9042011-07-22 13:56:51 -0400137
Elly Jonese1749eb2011-10-07 13:54:59 -0400138 /* Note that we swap fake_main in for main - fake_main knows that it
139 * should call real_main after it's done.
140 */
141 return real_libc_start_main.fn(fake_main, argc, ubp_av, init, fini,
142 rtld_fini, stack_end);
Elly Jonescd7a9042011-07-22 13:56:51 -0400143}