Home | History | Annotate | Download | only in minijail
      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 	/* TODO(ellyjones): this trashes existing preloads, so one can't do:
     75 	 * LD_PRELOAD="/tmp/test.so libminijailpreload.so" prog; the
     76 	 * descendants of prog will have no LD_PRELOAD set at all.
     77 	 */
     78 	unset_in_env(envp, kLdPreloadEnvVar);
     79 	/* Strip out flags meant for the parent. */
     80 	minijail_preenter(j);
     81 	minijail_enter(j);
     82 	minijail_destroy(j);
     83 	dlclose(libc_handle);
     84 	return real_main(argc, argv, envp);
     85 }
     86 
     87 /** @brief LD_PRELOAD override of __libc_start_main.
     88  *
     89  *  It is really best if you do not look too closely at this function.  We need
     90  *  to ensure that some of our code runs before the target program (see the
     91  *  minijail0.1 file in this directory for high-level details about this), and
     92  *  the only available place to hook is this function, which is normally
     93  *  responsible for calling main(). Our LD_PRELOAD will overwrite the real
     94  *  __libc_start_main with this one, so we have to look up the real one from
     95  *  libc and invoke it with a pointer to the fake main() we'd like to run before
     96  *  the real main(). We can't just run our setup code *here* because
     97  *  __libc_start_main is responsible for setting up the C runtime environment,
     98  *  so we can't rely on things like malloc() being available yet.
     99  */
    100 
    101 int API __libc_start_main(int (*main)(int, char **, char **), int argc,
    102 			  char **ubp_av, void (*init)(void), void (*fini)(void),
    103 			  void (*rtld_fini)(void), void(*stack_end))
    104 {
    105 	void *sym;
    106 	/*
    107 	 * This hack is unfortunately required by C99 - casting directly from
    108 	 * void* to function pointers is left undefined. See POSIX.1-2003, the
    109 	 * Rationale for the specification of dlsym(), and dlsym(3). This
    110 	 * deliberately violates strict-aliasing rules, but gcc can't tell.
    111 	 */
    112 	union {
    113 		int (*fn)(int (*main)(int, char **, char **), int argc,
    114 			  char **ubp_av, void (*init)(void), void (*fini)(void),
    115 			  void (*rtld_fini)(void), void(*stack_end));
    116 		void *symval;
    117 	} real_libc_start_main;
    118 
    119 	/*
    120 	 * We hold this handle for the duration of the real __libc_start_main()
    121 	 * and drop it just before calling the real main().
    122 	 */
    123 	libc_handle = dlopen("libc.so.6", RTLD_NOW);
    124 
    125 	if (!libc_handle) {
    126 		syslog(LOG_ERR, "can't dlopen() libc");
    127 		/*
    128 		 * We dare not use abort() here because it will run atexit()
    129 		 * handlers and try to flush stdio.
    130 		 */
    131 		_exit(1);
    132 	}
    133 	sym = dlsym(libc_handle, "__libc_start_main");
    134 	if (!sym) {
    135 		syslog(LOG_ERR, "can't find the real __libc_start_main()");
    136 		_exit(1);
    137 	}
    138 	real_libc_start_main.symval = sym;
    139 	real_main = main;
    140 
    141 	/*
    142 	 * Note that we swap fake_main in for main - fake_main knows that it
    143 	 * should call real_main after it's done.
    144 	 */
    145 	return real_libc_start_main.fn(fake_main, argc, ubp_av, init, fini,
    146 				       rtld_fini, stack_end);
    147 }
    148