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