localedata: CLDRv29: update LC_ADDRESS.lang_name translations
[glibc.git] / elf / dl-tunables.c
blobb3c1392ce4a80f74113ddff7475f08e53b37daf2
1 /* The tunable framework. See the README.tunables to know how to use the
2 tunable in a glibc module.
4 Copyright (C) 2016-2017 Free Software Foundation, Inc.
5 This file is part of the GNU C Library.
7 The GNU C Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
12 The GNU C Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with the GNU C Library; if not, see
19 <http://www.gnu.org/licenses/>. */
21 #include <stdint.h>
22 #include <stdbool.h>
23 #include <unistd.h>
24 #include <stdlib.h>
25 #include <sysdep.h>
26 #include <fcntl.h>
27 #include <ldsodefs.h>
29 #define TUNABLES_INTERNAL 1
30 #include "dl-tunables.h"
32 #if TUNABLES_FRONTEND == TUNABLES_FRONTEND_valstring
33 # define GLIBC_TUNABLES "GLIBC_TUNABLES"
34 #endif
36 /* Compare environment or tunable names, bounded by the name hardcoded in
37 glibc. */
38 static bool
39 is_name (const char *orig, const char *envname)
41 for (;*orig != '\0' && *envname != '\0'; envname++, orig++)
42 if (*orig != *envname)
43 break;
45 /* The ENVNAME is immediately followed by a value. */
46 if (*orig == '\0' && *envname == '=')
47 return true;
48 else
49 return false;
52 #if TUNABLES_FRONTEND == TUNABLES_FRONTEND_valstring
53 static char *
54 tunables_strdup (const char *in)
56 size_t i = 0;
58 while (in[i++] != '\0');
59 char *out = __sbrk (i);
61 /* FIXME: In reality if the allocation fails, __sbrk will crash attempting to
62 set the thread-local errno since the TCB has not yet been set up. This
63 needs to be fixed with an __sbrk implementation that does not set
64 errno. */
65 if (out == (void *)-1)
66 return NULL;
68 i--;
70 while (i-- > 0)
71 out[i] = in[i];
73 return out;
75 #endif
77 static char **
78 get_next_env (char **envp, char **name, size_t *namelen, char **val,
79 char ***prev_envp)
81 while (envp != NULL && *envp != NULL)
83 char **prev = envp;
84 char *envline = *envp++;
85 int len = 0;
87 while (envline[len] != '\0' && envline[len] != '=')
88 len++;
90 /* Just the name and no value, go to the next one. */
91 if (envline[len] == '\0')
92 continue;
94 *name = envline;
95 *namelen = len;
96 *val = &envline[len + 1];
97 *prev_envp = prev;
99 return envp;
102 return NULL;
105 #define TUNABLE_SET_VAL_IF_VALID_RANGE(__cur, __val, __type, __default_min, \
106 __default_max) \
107 ({ \
108 __type min = (__cur)->type.min; \
109 __type max = (__cur)->type.max; \
111 if (min == max) \
113 min = __default_min; \
114 max = __default_max; \
117 if ((__type) (__val) >= min && (__type) (val) <= max) \
119 (__cur)->val.numval = val; \
120 (__cur)->initialized = true; \
124 static void
125 do_tunable_update_val (tunable_t *cur, const void *valp)
127 uint64_t val;
129 if (cur->type.type_code != TUNABLE_TYPE_STRING)
130 val = *((int64_t *) valp);
132 switch (cur->type.type_code)
134 case TUNABLE_TYPE_INT_32:
136 TUNABLE_SET_VAL_IF_VALID_RANGE (cur, val, int64_t, INT32_MIN, INT32_MAX);
137 break;
139 case TUNABLE_TYPE_UINT_64:
141 TUNABLE_SET_VAL_IF_VALID_RANGE (cur, val, uint64_t, 0, UINT64_MAX);
142 break;
144 case TUNABLE_TYPE_SIZE_T:
146 TUNABLE_SET_VAL_IF_VALID_RANGE (cur, val, uint64_t, 0, SIZE_MAX);
147 break;
149 case TUNABLE_TYPE_STRING:
151 cur->val.strval = valp;
152 break;
154 default:
155 __builtin_unreachable ();
159 /* Validate range of the input value and initialize the tunable CUR if it looks
160 good. */
161 static void
162 tunable_initialize (tunable_t *cur, const char *strval)
164 uint64_t val;
165 const void *valp;
167 if (cur->type.type_code != TUNABLE_TYPE_STRING)
169 val = _dl_strtoul (strval, NULL);
170 valp = &val;
172 else
174 cur->initialized = true;
175 valp = strval;
177 do_tunable_update_val (cur, valp);
180 void
181 __tunable_set_val (tunable_id_t id, void *valp)
183 tunable_t *cur = &tunable_list[id];
185 do_tunable_update_val (cur, valp);
188 #if TUNABLES_FRONTEND == TUNABLES_FRONTEND_valstring
189 /* Parse the tunable string TUNESTR and adjust it to drop any tunables that may
190 be unsafe for AT_SECURE processes so that it can be used as the new
191 environment variable value for GLIBC_TUNABLES. VALSTRING is the original
192 environment variable string which we use to make NULL terminated values so
193 that we don't have to allocate memory again for it. */
194 static void
195 parse_tunables (char *tunestr, char *valstring)
197 if (tunestr == NULL || *tunestr == '\0')
198 return;
200 char *p = tunestr;
202 while (true)
204 char *name = p;
205 size_t len = 0;
207 /* First, find where the name ends. */
208 while (p[len] != '=' && p[len] != ':' && p[len] != '\0')
209 len++;
211 /* If we reach the end of the string before getting a valid name-value
212 pair, bail out. */
213 if (p[len] == '\0')
214 return;
216 /* We did not find a valid name-value pair before encountering the
217 colon. */
218 if (p[len]== ':')
220 p += len + 1;
221 continue;
224 p += len + 1;
226 /* Take the value from the valstring since we need to NULL terminate it. */
227 char *value = &valstring[p - tunestr];
228 len = 0;
230 while (p[len] != ':' && p[len] != '\0')
231 len++;
233 /* Add the tunable if it exists. */
234 for (size_t i = 0; i < sizeof (tunable_list) / sizeof (tunable_t); i++)
236 tunable_t *cur = &tunable_list[i];
238 if (is_name (cur->name, name))
240 /* If we are in a secure context (AT_SECURE) then ignore the tunable
241 unless it is explicitly marked as secure. Tunable values take
242 precendence over their envvar aliases. */
243 if (__libc_enable_secure)
245 if (cur->security_level == TUNABLE_SECLEVEL_SXID_ERASE)
247 if (p[len] == '\0')
249 /* Last tunable in the valstring. Null-terminate and
250 return. */
251 *name = '\0';
252 return;
254 else
256 /* Remove the current tunable from the string. We do
257 this by overwriting the string starting from NAME
258 (which is where the current tunable begins) with
259 the remainder of the string. We then have P point
260 to NAME so that we continue in the correct
261 position in the valstring. */
262 char *q = &p[len + 1];
263 p = name;
264 while (*q != '\0')
265 *name++ = *q++;
266 name[0] = '\0';
267 len = 0;
271 if (cur->security_level != TUNABLE_SECLEVEL_NONE)
272 break;
275 value[len] = '\0';
276 tunable_initialize (cur, value);
277 break;
281 if (p[len] == '\0')
282 return;
283 else
284 p += len + 1;
287 #endif
289 /* Enable the glibc.malloc.check tunable in SETUID/SETGID programs only when
290 the system administrator has created the /etc/suid-debug file. This is a
291 special case where we want to conditionally enable/disable a tunable even
292 for setuid binaries. We use the special version of access() to avoid
293 setting ERRNO, which is a TLS variable since TLS has not yet been set
294 up. */
295 static inline void
296 __always_inline
297 maybe_enable_malloc_check (void)
299 tunable_id_t id = TUNABLE_ENUM_NAME (glibc, malloc, check);
300 if (__libc_enable_secure && __access_noerrno ("/etc/suid-debug", F_OK) == 0)
301 tunable_list[id].security_level = TUNABLE_SECLEVEL_NONE;
304 /* Initialize the tunables list from the environment. For now we only use the
305 ENV_ALIAS to find values. Later we will also use the tunable names to find
306 values. */
307 void
308 __tunables_init (char **envp)
310 char *envname = NULL;
311 char *envval = NULL;
312 size_t len = 0;
313 char **prev_envp = envp;
315 maybe_enable_malloc_check ();
317 while ((envp = get_next_env (envp, &envname, &len, &envval,
318 &prev_envp)) != NULL)
320 #if TUNABLES_FRONTEND == TUNABLES_FRONTEND_valstring
321 if (is_name (GLIBC_TUNABLES, envname))
323 char *new_env = tunables_strdup (envname);
324 if (new_env != NULL)
325 parse_tunables (new_env + len + 1, envval);
326 /* Put in the updated envval. */
327 *prev_envp = new_env;
328 continue;
330 #endif
332 for (int i = 0; i < sizeof (tunable_list) / sizeof (tunable_t); i++)
334 tunable_t *cur = &tunable_list[i];
336 /* Skip over tunables that have either been set already or should be
337 skipped. */
338 if (cur->initialized || cur->env_alias == NULL)
339 continue;
341 const char *name = cur->env_alias;
343 /* We have a match. Initialize and move on to the next line. */
344 if (is_name (name, envname))
346 /* For AT_SECURE binaries, we need to check the security settings of
347 the tunable and decide whether we read the value and also whether
348 we erase the value so that child processes don't inherit them in
349 the environment. */
350 if (__libc_enable_secure)
352 if (cur->security_level == TUNABLE_SECLEVEL_SXID_ERASE)
354 /* Erase the environment variable. */
355 char **ep = prev_envp;
357 while (*ep != NULL)
359 if (is_name (name, *ep))
361 char **dp = ep;
364 dp[0] = dp[1];
365 while (*dp++);
367 else
368 ++ep;
370 /* Reset the iterator so that we read the environment again
371 from the point we erased. */
372 envp = prev_envp;
375 if (cur->security_level != TUNABLE_SECLEVEL_NONE)
376 continue;
379 tunable_initialize (cur, envval);
380 break;
386 /* Set the tunable value. This is called by the module that the tunable exists
387 in. */
388 void
389 __tunable_get_val (tunable_id_t id, void *valp, tunable_callback_t callback)
391 tunable_t *cur = &tunable_list[id];
393 switch (cur->type.type_code)
395 case TUNABLE_TYPE_UINT_64:
397 *((uint64_t *) valp) = (uint64_t) cur->val.numval;
398 break;
400 case TUNABLE_TYPE_INT_32:
402 *((int32_t *) valp) = (int32_t) cur->val.numval;
403 break;
405 case TUNABLE_TYPE_SIZE_T:
407 *((size_t *) valp) = (size_t) cur->val.numval;
408 break;
410 case TUNABLE_TYPE_STRING:
412 *((const char **)valp) = cur->val.strval;
413 break;
415 default:
416 __builtin_unreachable ();
419 if (cur->initialized && callback != NULL)
420 callback (&cur->val);
423 rtld_hidden_def (__tunable_get_val)