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