118a206c81d9743481e364384affd43306911283dElliott Hughes/*
218a206c81d9743481e364384affd43306911283dElliott Hughes * Copyright (C) 2010 The Android Open Source Project
318a206c81d9743481e364384affd43306911283dElliott Hughes * All rights reserved.
418a206c81d9743481e364384affd43306911283dElliott Hughes *
518a206c81d9743481e364384affd43306911283dElliott Hughes * Redistribution and use in source and binary forms, with or without
618a206c81d9743481e364384affd43306911283dElliott Hughes * modification, are permitted provided that the following conditions
718a206c81d9743481e364384affd43306911283dElliott Hughes * are met:
818a206c81d9743481e364384affd43306911283dElliott Hughes *  * Redistributions of source code must retain the above copyright
918a206c81d9743481e364384affd43306911283dElliott Hughes *    notice, this list of conditions and the following disclaimer.
1018a206c81d9743481e364384affd43306911283dElliott Hughes *  * Redistributions in binary form must reproduce the above copyright
1118a206c81d9743481e364384affd43306911283dElliott Hughes *    notice, this list of conditions and the following disclaimer in
1218a206c81d9743481e364384affd43306911283dElliott Hughes *    the documentation and/or other materials provided with the
1318a206c81d9743481e364384affd43306911283dElliott Hughes *    distribution.
1418a206c81d9743481e364384affd43306911283dElliott Hughes *
1518a206c81d9743481e364384affd43306911283dElliott Hughes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1618a206c81d9743481e364384affd43306911283dElliott Hughes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1718a206c81d9743481e364384affd43306911283dElliott Hughes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
1818a206c81d9743481e364384affd43306911283dElliott Hughes * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
1918a206c81d9743481e364384affd43306911283dElliott Hughes * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2018a206c81d9743481e364384affd43306911283dElliott Hughes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2118a206c81d9743481e364384affd43306911283dElliott Hughes * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
2218a206c81d9743481e364384affd43306911283dElliott Hughes * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2318a206c81d9743481e364384affd43306911283dElliott Hughes * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2418a206c81d9743481e364384affd43306911283dElliott Hughes * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
2518a206c81d9743481e364384affd43306911283dElliott Hughes * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2618a206c81d9743481e364384affd43306911283dElliott Hughes * SUCH DAMAGE.
2718a206c81d9743481e364384affd43306911283dElliott Hughes */
2818a206c81d9743481e364384affd43306911283dElliott Hughes
2918a206c81d9743481e364384affd43306911283dElliott Hughes#include "linker_environ.h"
3018a206c81d9743481e364384affd43306911283dElliott Hughes
3118a206c81d9743481e364384affd43306911283dElliott Hughes#include <linux/auxvec.h>
3218a206c81d9743481e364384affd43306911283dElliott Hughes#include <stddef.h>
3318a206c81d9743481e364384affd43306911283dElliott Hughes#include <stdlib.h>
3418a206c81d9743481e364384affd43306911283dElliott Hughes#include <unistd.h>
3518a206c81d9743481e364384affd43306911283dElliott Hughes
36eb847bc8666842a3cfc9c06e8458ad1abebebaf0Elliott Hughes#include "private/KernelArgumentBlock.h"
3742b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes
3818a206c81d9743481e364384affd43306911283dElliott Hughesstatic char** _envp;
3918a206c81d9743481e364384affd43306911283dElliott Hughesstatic bool _AT_SECURE_value = true;
4018a206c81d9743481e364384affd43306911283dElliott Hughes
4118a206c81d9743481e364384affd43306911283dElliott Hughesbool get_AT_SECURE() {
4218a206c81d9743481e364384affd43306911283dElliott Hughes  return _AT_SECURE_value;
4318a206c81d9743481e364384affd43306911283dElliott Hughes}
4418a206c81d9743481e364384affd43306911283dElliott Hughes
4542b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughesstatic void __init_AT_SECURE(KernelArgumentBlock& args) {
460894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes  // Check auxv for AT_SECURE first to see if program is setuid, setgid,
470894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes  // has file caps, or caused a SELinux/AppArmor domain transition.
4842b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  bool kernel_supplied_AT_SECURE;
4942b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  _AT_SECURE_value = args.getauxval(AT_SECURE, &kernel_supplied_AT_SECURE);
500894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes
510894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes  // We don't support ancient kernels.
5242b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  if (!kernel_supplied_AT_SECURE) {
5342b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes    const char* msg = "FATAL: kernel did not supply AT_SECURE\n";
5442b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes    write(2, msg, strlen(msg));
5542b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes    exit(EXIT_FAILURE);
5642b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  }
570894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes}
5818a206c81d9743481e364384affd43306911283dElliott Hughes
590894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes// Check if the environment variable definition at 'envstr'
600894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes// starts with '<name>=', and if so return the address of the
610894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes// first character after the equal sign. Otherwise return NULL.
620894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughesstatic const char* env_match(const char* envstr, const char* name) {
630894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes  size_t i = 0;
640894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes
650894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes  while (envstr[i] == name[i] && name[i] != '\0') {
660894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes    ++i;
670894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes  }
680894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes
690894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes  if (name[i] == '\0' && envstr[i] == '=') {
700894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes    return envstr + i + 1;
710894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes  }
720894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes
730894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes  return NULL;
740894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes}
750894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes
760894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughesstatic bool __is_valid_environment_variable(const char* name) {
7718a206c81d9743481e364384affd43306911283dElliott Hughes  // According to its sources, the kernel uses 32*PAGE_SIZE by default
7818a206c81d9743481e364384affd43306911283dElliott Hughes  // as the maximum size for an env. variable definition.
7918a206c81d9743481e364384affd43306911283dElliott Hughes  const int MAX_ENV_LEN = 32*4096;
8018a206c81d9743481e364384affd43306911283dElliott Hughes
810894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes  if (name == NULL) {
820894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes    return false;
8318a206c81d9743481e364384affd43306911283dElliott Hughes  }
8418a206c81d9743481e364384affd43306911283dElliott Hughes
8518a206c81d9743481e364384affd43306911283dElliott Hughes  // Parse the string, looking for the first '=' there, and its size.
860894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes  int pos = 0;
870894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes  int first_equal_pos = -1;
8818a206c81d9743481e364384affd43306911283dElliott Hughes  while (pos < MAX_ENV_LEN) {
890894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes    if (name[pos] == '\0') {
9018a206c81d9743481e364384affd43306911283dElliott Hughes      break;
9118a206c81d9743481e364384affd43306911283dElliott Hughes    }
920894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes    if (name[pos] == '=' && first_equal_pos < 0) {
9318a206c81d9743481e364384affd43306911283dElliott Hughes      first_equal_pos = pos;
9418a206c81d9743481e364384affd43306911283dElliott Hughes    }
9518a206c81d9743481e364384affd43306911283dElliott Hughes    pos++;
9618a206c81d9743481e364384affd43306911283dElliott Hughes  }
9718a206c81d9743481e364384affd43306911283dElliott Hughes
980894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes  // Check that it's smaller than MAX_ENV_LEN (to detect non-zero terminated strings).
9918a206c81d9743481e364384affd43306911283dElliott Hughes  if (pos >= MAX_ENV_LEN) {
1000894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes    return false;
10118a206c81d9743481e364384affd43306911283dElliott Hughes  }
10218a206c81d9743481e364384affd43306911283dElliott Hughes
1030894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes  // Check that it contains at least one equal sign that is not the first character
10418a206c81d9743481e364384affd43306911283dElliott Hughes  if (first_equal_pos < 1) {
1050894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes    return false;
10618a206c81d9743481e364384affd43306911283dElliott Hughes  }
10718a206c81d9743481e364384affd43306911283dElliott Hughes
1080894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes  return true;
10918a206c81d9743481e364384affd43306911283dElliott Hughes}
11018a206c81d9743481e364384affd43306911283dElliott Hughes
1110894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughesstatic bool __is_unsafe_environment_variable(const char* name) {
11218a206c81d9743481e364384affd43306911283dElliott Hughes  // None of these should be allowed in setuid programs.
11318a206c81d9743481e364384affd43306911283dElliott Hughes  static const char* const UNSAFE_VARIABLE_NAMES[] = {
11418a206c81d9743481e364384affd43306911283dElliott Hughes      "GCONV_PATH",
11518a206c81d9743481e364384affd43306911283dElliott Hughes      "GETCONF_DIR",
11618a206c81d9743481e364384affd43306911283dElliott Hughes      "HOSTALIASES",
11718a206c81d9743481e364384affd43306911283dElliott Hughes      "LD_AOUT_LIBRARY_PATH",
11818a206c81d9743481e364384affd43306911283dElliott Hughes      "LD_AOUT_PRELOAD",
11918a206c81d9743481e364384affd43306911283dElliott Hughes      "LD_AUDIT",
12018a206c81d9743481e364384affd43306911283dElliott Hughes      "LD_DEBUG",
12118a206c81d9743481e364384affd43306911283dElliott Hughes      "LD_DEBUG_OUTPUT",
12218a206c81d9743481e364384affd43306911283dElliott Hughes      "LD_DYNAMIC_WEAK",
12318a206c81d9743481e364384affd43306911283dElliott Hughes      "LD_LIBRARY_PATH",
12418a206c81d9743481e364384affd43306911283dElliott Hughes      "LD_ORIGIN_PATH",
12518a206c81d9743481e364384affd43306911283dElliott Hughes      "LD_PRELOAD",
12618a206c81d9743481e364384affd43306911283dElliott Hughes      "LD_PROFILE",
12718a206c81d9743481e364384affd43306911283dElliott Hughes      "LD_SHOW_AUXV",
12818a206c81d9743481e364384affd43306911283dElliott Hughes      "LD_USE_LOAD_BIAS",
12918a206c81d9743481e364384affd43306911283dElliott Hughes      "LOCALDOMAIN",
13018a206c81d9743481e364384affd43306911283dElliott Hughes      "LOCPATH",
13118a206c81d9743481e364384affd43306911283dElliott Hughes      "MALLOC_CHECK_",
13218a206c81d9743481e364384affd43306911283dElliott Hughes      "MALLOC_TRACE",
13318a206c81d9743481e364384affd43306911283dElliott Hughes      "NIS_PATH",
13418a206c81d9743481e364384affd43306911283dElliott Hughes      "NLSPATH",
13518a206c81d9743481e364384affd43306911283dElliott Hughes      "RESOLV_HOST_CONF",
13618a206c81d9743481e364384affd43306911283dElliott Hughes      "RES_OPTIONS",
13718a206c81d9743481e364384affd43306911283dElliott Hughes      "TMPDIR",
13818a206c81d9743481e364384affd43306911283dElliott Hughes      "TZDIR",
13918a206c81d9743481e364384affd43306911283dElliott Hughes      NULL
14018a206c81d9743481e364384affd43306911283dElliott Hughes  };
14118a206c81d9743481e364384affd43306911283dElliott Hughes  for (size_t i = 0; UNSAFE_VARIABLE_NAMES[i] != NULL; ++i) {
1420894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes    if (env_match(name, UNSAFE_VARIABLE_NAMES[i]) != NULL) {
1430894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes      return true;
1440894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes    }
14518a206c81d9743481e364384affd43306911283dElliott Hughes  }
1460894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes  return false;
14718a206c81d9743481e364384affd43306911283dElliott Hughes}
14818a206c81d9743481e364384affd43306911283dElliott Hughes
1490894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughesstatic void __sanitize_environment_variables() {
15018a206c81d9743481e364384affd43306911283dElliott Hughes  char** src  = _envp;
15118a206c81d9743481e364384affd43306911283dElliott Hughes  char** dst = _envp;
15218a206c81d9743481e364384affd43306911283dElliott Hughes  for (; src[0] != NULL; ++src) {
1530894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes    if (!__is_valid_environment_variable(src[0])) {
15418a206c81d9743481e364384affd43306911283dElliott Hughes      continue;
15518a206c81d9743481e364384affd43306911283dElliott Hughes    }
1560894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes    // Remove various unsafe environment variables if we're loading a setuid program.
1570894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes    if (get_AT_SECURE() && __is_unsafe_environment_variable(src[0])) {
1580894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes        continue;
1590894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes    }
16018a206c81d9743481e364384affd43306911283dElliott Hughes    dst[0] = src[0];
16118a206c81d9743481e364384affd43306911283dElliott Hughes    ++dst;
16218a206c81d9743481e364384affd43306911283dElliott Hughes  }
16318a206c81d9743481e364384affd43306911283dElliott Hughes  dst[0] = NULL;
16418a206c81d9743481e364384affd43306911283dElliott Hughes}
16518a206c81d9743481e364384affd43306911283dElliott Hughes
16642b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughesvoid linker_env_init(KernelArgumentBlock& args) {
16718a206c81d9743481e364384affd43306911283dElliott Hughes  // Store environment pointer - can't be NULL.
16842b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  _envp = args.envp;
16918a206c81d9743481e364384affd43306911283dElliott Hughes
17042b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  __init_AT_SECURE(args);
1710894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes  __sanitize_environment_variables();
17218a206c81d9743481e364384affd43306911283dElliott Hughes}
17318a206c81d9743481e364384affd43306911283dElliott Hughes
17418a206c81d9743481e364384affd43306911283dElliott Hughesconst char* linker_env_get(const char* name) {
17518a206c81d9743481e364384affd43306911283dElliott Hughes  if (name == NULL || name[0] == '\0') {
17618a206c81d9743481e364384affd43306911283dElliott Hughes    return NULL;
17718a206c81d9743481e364384affd43306911283dElliott Hughes  }
17818a206c81d9743481e364384affd43306911283dElliott Hughes
17918a206c81d9743481e364384affd43306911283dElliott Hughes  for (char** p = _envp; p[0] != NULL; ++p) {
1800894b2c5d35c9c3a7483ed8faaf65fd6d9ffb00bElliott Hughes    const char* val = env_match(p[0], name);
18118a206c81d9743481e364384affd43306911283dElliott Hughes    if (val != NULL) {
18218a206c81d9743481e364384affd43306911283dElliott Hughes      if (val[0] == '\0') {
18318a206c81d9743481e364384affd43306911283dElliott Hughes        return NULL; // Return NULL for empty strings.
18418a206c81d9743481e364384affd43306911283dElliott Hughes      }
18518a206c81d9743481e364384affd43306911283dElliott Hughes      return val;
18618a206c81d9743481e364384affd43306911283dElliott Hughes    }
18718a206c81d9743481e364384affd43306911283dElliott Hughes  }
18818a206c81d9743481e364384affd43306911283dElliott Hughes  return NULL;
18918a206c81d9743481e364384affd43306911283dElliott Hughes}
190