Commit | Line | Data |
---|---|---|
d42e7319 JB |
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 | } |