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 		/* 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;
64 
65 	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);
71 
72 	/* 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);
83 }
84 
85 /** @brief LD_PRELOAD override of __libc_start_main.
86  *
87  *  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
90  *  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 
__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))99 int API __libc_start_main(int (*main) (int, char **, char **),
100 		      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;
117 
118 	/* 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);
122 
123 	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;
137 
138 	/* 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);
143 }
144