• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
_is_valid_definition(const char * str)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*
linker_env_init(unsigned * vecs)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*
env_match(char * envstr,const char * name)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*
linker_env_get(const char * name)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
linker_env_unset(const char * name)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
linker_env_secure(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         NULL
196     };
197 
198     int count;
199     for (count = 0; unsec_vars[count] != NULL; count++) {
200         linker_env_unset(unsec_vars[count]);
201     }
202 }
203