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  }