1be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner/* 2be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner * Copyright (C) 2010 The Android Open Source Project 3be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner * All rights reserved. 4be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner * 5be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner * Redistribution and use in source and binary forms, with or without 6be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner * modification, are permitted provided that the following conditions 7be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner * are met: 8be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner * * Redistributions of source code must retain the above copyright 9be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner * notice, this list of conditions and the following disclaimer. 10be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner * * Redistributions in binary form must reproduce the above copyright 11be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner * notice, this list of conditions and the following disclaimer in 12be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner * the documentation and/or other materials provided with the 13be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner * distribution. 14be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner * 15be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner * SUCH DAMAGE. 27be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner */ 28be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner#include "linker_environ.h" 29be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner#include <stddef.h> 30be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 31be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turnerstatic char** _envp; 32be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 33be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner/* Returns 1 if 'str' points to a valid environment variable definition. 34be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner * For now, we check that: 35be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner * - It is smaller than MAX_ENV_LEN (to detect non-zero terminated strings) 36be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner * - It contains at least one equal sign that is not the first character 37be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner */ 38be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turnerstatic int 39be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner_is_valid_definition(const char* str) 40be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner{ 41be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner int pos = 0; 42be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner int first_equal_pos = -1; 43be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 44be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner /* According to its sources, the kernel uses 32*PAGE_SIZE by default 45be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner * as the maximum size for an env. variable definition. 46be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner */ 47be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner const int MAX_ENV_LEN = 32*4096; 48be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 49be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner if (str == NULL) 50be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner return 0; 51be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 52be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner /* Parse the string, looking for the first '=' there, and its size */ 53be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner do { 54be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner if (str[pos] == '\0') 55be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner break; 56be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner if (str[pos] == '=' && first_equal_pos < 0) 57be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner first_equal_pos = pos; 58be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner pos++; 59be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner } while (pos < MAX_ENV_LEN); 60be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 61be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner if (pos >= MAX_ENV_LEN) /* Too large */ 62be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner return 0; 63be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 64be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner if (first_equal_pos < 1) /* No equal sign, or it is the first character */ 65be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner return 0; 66be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 67be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner return 1; 68be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner} 69be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 70be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turnerunsigned* 71be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turnerlinker_env_init(unsigned* vecs) 72be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner{ 73be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner /* Store environment pointer - can't be NULL */ 74be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner _envp = (char**) vecs; 75be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 76be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner /* Skip over all definitions */ 77be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner while (vecs[0] != 0) 78be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner vecs++; 79be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner /* The end of the environment block is marked by two NULL pointers */ 80be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner vecs++; 81be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 82be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner /* As a sanity check, we're going to remove all invalid variable 83be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner * definitions from the environment array. 84be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner */ 85be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner { 86be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner char** readp = _envp; 87be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner char** writep = _envp; 88be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner for ( ; readp[0] != NULL; readp++ ) { 89be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner if (!_is_valid_definition(readp[0])) 90be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner continue; 91be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner writep[0] = readp[0]; 92be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner writep++; 93be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner } 94be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner writep[0] = NULL; 95be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner } 96be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 97be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner /* Return the address of the aux vectors table */ 98be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner return vecs; 99be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner} 100be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 101be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner/* Check if the environment variable definition at 'envstr' 102be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner * starts with '<name>=', and if so return the address of the 103be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner * first character after the equal sign. Otherwise return NULL. 104be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner */ 105be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turnerstatic char* 106be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turnerenv_match(char* envstr, const char* name) 107be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner{ 108be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner size_t cnt = 0; 109be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 110be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner while (envstr[cnt] == name[cnt] && name[cnt] != '\0') 111be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner cnt++; 112be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 113b3cdf7fef86eb17dba5640e9a1b158510326b9b7tedbo if (name[cnt] == '\0' && envstr[cnt] == '=') 114be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner return envstr + cnt + 1; 115be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 116be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner return NULL; 117be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner} 118be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 119be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner#define MAX_ENV_LEN (16*4096) 120be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 121be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turnerconst char* 122be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turnerlinker_env_get(const char* name) 123be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner{ 124be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner char** readp = _envp; 125be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 126be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner if (name == NULL || name[0] == '\0') 127be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner return NULL; 128be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 129be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner for ( ; readp[0] != NULL; readp++ ) { 130be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner char* val = env_match(readp[0], name); 131be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner if (val != NULL) { 132be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner /* Return NULL for empty strings, or if it is too large */ 133be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner if (val[0] == '\0') 134be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner val = NULL; 135be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner return val; 136be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner } 137be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner } 138be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner return NULL; 139be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner} 140be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 141be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 142be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turnervoid 143be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turnerlinker_env_unset(const char* name) 144be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner{ 145be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner char** readp = _envp; 146be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner char** writep = readp; 147be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 148be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner if (name == NULL || name[0] == '\0') 149be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner return; 150be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 151be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner for ( ; readp[0] != NULL; readp++ ) { 152be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner if (env_match(readp[0], name)) 153be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner continue; 154be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner writep[0] = readp[0]; 155be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner writep++; 156be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner } 157be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner /* end list with a NULL */ 158be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner writep[0] = NULL; 159be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner} 160be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 161be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 162be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 163be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner/* Remove unsafe environment variables. This should be used when 164be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner * running setuid programs. */ 165be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turnervoid 166be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turnerlinker_env_secure(void) 167be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner{ 168be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner /* The same list than GLibc at this point */ 169be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner static const char* const unsec_vars[] = { 170be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner "GCONV_PATH", 171be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner "GETCONF_DIR", 172be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner "HOSTALIASES", 173be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner "LD_AUDIT", 174be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner "LD_DEBUG", 175be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner "LD_DEBUG_OUTPUT", 176be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner "LD_DYNAMIC_WEAK", 177be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner "LD_LIBRARY_PATH", 178be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner "LD_ORIGIN_PATH", 179be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner "LD_PRELOAD", 180be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner "LD_PROFILE", 181be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner "LD_SHOW_AUXV", 182be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner "LD_USE_LOAD_BIAS", 183be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner "LOCALDOMAIN", 184be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner "LOCPATH", 185be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner "MALLOC_TRACE", 186be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner "MALLOC_CHECK_", 187be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner "NIS_PATH", 188be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner "NLSPATH", 189be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner "RESOLV_HOST_CONF", 190be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner "RES_OPTIONS", 191be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner "TMPDIR", 192be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner "TZDIR", 193be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner "LD_AOUT_LIBRARY_PATH", 194be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner "LD_AOUT_PRELOAD", 19516084168111cd7d2ac8a6b92e6fa6df5696928a5David 'Digit' Turner NULL 196be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner }; 197be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 19816084168111cd7d2ac8a6b92e6fa6df5696928a5David 'Digit' Turner int count; 19916084168111cd7d2ac8a6b92e6fa6df5696928a5David 'Digit' Turner for (count = 0; unsec_vars[count] != NULL; count++) { 20016084168111cd7d2ac8a6b92e6fa6df5696928a5David 'Digit' Turner linker_env_unset(unsec_vars[count]); 201be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner } 202be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner} 203