Use ASCII in LC_TIME of om_ET for better readability
[glibc.git] / elf / dl-tunables.c
blobb964a09413dded0fd622419299b79dc384c1bcb3
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 <startup.h>
22 #include <stdint.h>
23 #include <stdbool.h>
24 #include <unistd.h>
25 #include <stdlib.h>
26 #include <sysdep.h>
27 #include <fcntl.h>
28 #include <ldsodefs.h>
30 #define TUNABLES_INTERNAL 1
31 #include "dl-tunables.h"
33 #include <not-errno.h>
35 #if TUNABLES_FRONTEND == TUNABLES_FRONTEND_valstring
36 # define GLIBC_TUNABLES "GLIBC_TUNABLES"
37 #endif
39 #if TUNABLES_FRONTEND == TUNABLES_FRONTEND_valstring
40 static char *
41 tunables_strdup (const char *in)
43 size_t i = 0;
45 while (in[i++] != '\0');
46 char *out = __sbrk (i);
48 /* FIXME: In reality if the allocation fails, __sbrk will crash attempting to
49 set the thread-local errno since the TCB has not yet been set up. This
50 needs to be fixed with an __sbrk implementation that does not set
51 errno. */
52 if (out == (void *)-1)
53 return NULL;
55 i--;
57 while (i-- > 0)
58 out[i] = in[i];
60 return out;
62 #endif
64 static char **
65 get_next_env (char **envp, char **name, size_t *namelen, char **val,
66 char ***prev_envp)
68 while (envp != NULL && *envp != NULL)
70 char **prev = envp;
71 char *envline = *envp++;
72 int len = 0;
74 while (envline[len] != '\0' && envline[len] != '=')
75 len++;
77 /* Just the name and no value, go to the next one. */
78 if (envline[len] == '\0')
79 continue;
81 *name = envline;
82 *namelen = len;
83 *val = &envline[len + 1];
84 *prev_envp = prev;
86 return envp;
89 return NULL;
92 #define TUNABLE_SET_VAL_IF_VALID_RANGE(__cur, __val, __type, __default_min, \
93 __default_max) \
94 ({ \
95 __type min = (__cur)->type.min; \
96 __type max = (__cur)->type.max; \
98 if (min == max) \
99 { \
100 min = __default_min; \
101 max = __default_max; \
104 if ((__type) (__val) >= min && (__type) (val) <= max) \
106 (__cur)->val.numval = val; \
107 (__cur)->initialized = true; \
111 static void
112 do_tunable_update_val (tunable_t *cur, const void *valp)
114 uint64_t val;
116 if (cur->type.type_code != TUNABLE_TYPE_STRING)
117 val = *((int64_t *) valp);
119 switch (cur->type.type_code)
121 case TUNABLE_TYPE_INT_32:
123 TUNABLE_SET_VAL_IF_VALID_RANGE (cur, val, int64_t, INT32_MIN, INT32_MAX);
124 break;
126 case TUNABLE_TYPE_UINT_64:
128 TUNABLE_SET_VAL_IF_VALID_RANGE (cur, val, uint64_t, 0, UINT64_MAX);
129 break;
131 case TUNABLE_TYPE_SIZE_T:
133 TUNABLE_SET_VAL_IF_VALID_RANGE (cur, val, uint64_t, 0, SIZE_MAX);
134 break;
136 case TUNABLE_TYPE_STRING:
138 cur->val.strval = valp;
139 break;
141 default:
142 __builtin_unreachable ();
146 /* Validate range of the input value and initialize the tunable CUR if it looks
147 good. */
148 static void
149 tunable_initialize (tunable_t *cur, const char *strval)
151 uint64_t val;
152 const void *valp;
154 if (cur->type.type_code != TUNABLE_TYPE_STRING)
156 val = _dl_strtoul (strval, NULL);
157 valp = &val;
159 else
161 cur->initialized = true;
162 valp = strval;
164 do_tunable_update_val (cur, valp);
167 void
168 __tunable_set_val (tunable_id_t id, void *valp)
170 tunable_t *cur = &tunable_list[id];
172 do_tunable_update_val (cur, valp);
175 #if TUNABLES_FRONTEND == TUNABLES_FRONTEND_valstring
176 /* Parse the tunable string TUNESTR and adjust it to drop any tunables that may
177 be unsafe for AT_SECURE processes so that it can be used as the new
178 environment variable value for GLIBC_TUNABLES. VALSTRING is the original
179 environment variable string which we use to make NULL terminated values so
180 that we don't have to allocate memory again for it. */
181 static void
182 parse_tunables (char *tunestr, char *valstring)
184 if (tunestr == NULL || *tunestr == '\0')
185 return;
187 char *p = tunestr;
189 while (true)
191 char *name = p;
192 size_t len = 0;
194 /* First, find where the name ends. */
195 while (p[len] != '=' && p[len] != ':' && p[len] != '\0')
196 len++;
198 /* If we reach the end of the string before getting a valid name-value
199 pair, bail out. */
200 if (p[len] == '\0')
201 return;
203 /* We did not find a valid name-value pair before encountering the
204 colon. */
205 if (p[len]== ':')
207 p += len + 1;
208 continue;
211 p += len + 1;
213 /* Take the value from the valstring since we need to NULL terminate it. */
214 char *value = &valstring[p - tunestr];
215 len = 0;
217 while (p[len] != ':' && p[len] != '\0')
218 len++;
220 /* Add the tunable if it exists. */
221 for (size_t i = 0; i < sizeof (tunable_list) / sizeof (tunable_t); i++)
223 tunable_t *cur = &tunable_list[i];
225 if (tunable_is_name (cur->name, name))
227 /* If we are in a secure context (AT_SECURE) then ignore the tunable
228 unless it is explicitly marked as secure. Tunable values take
229 precendence over their envvar aliases. */
230 if (__libc_enable_secure)
232 if (cur->security_level == TUNABLE_SECLEVEL_SXID_ERASE)
234 if (p[len] == '\0')
236 /* Last tunable in the valstring. Null-terminate and
237 return. */
238 *name = '\0';
239 return;
241 else
243 /* Remove the current tunable from the string. We do
244 this by overwriting the string starting from NAME
245 (which is where the current tunable begins) with
246 the remainder of the string. We then have P point
247 to NAME so that we continue in the correct
248 position in the valstring. */
249 char *q = &p[len + 1];
250 p = name;
251 while (*q != '\0')
252 *name++ = *q++;
253 name[0] = '\0';
254 len = 0;
258 if (cur->security_level != TUNABLE_SECLEVEL_NONE)
259 break;
262 value[len] = '\0';
263 tunable_initialize (cur, value);
264 break;
268 if (p[len] == '\0')
269 return;
270 else
271 p += len + 1;
274 #endif
276 /* Enable the glibc.malloc.check tunable in SETUID/SETGID programs only when
277 the system administrator has created the /etc/suid-debug file. This is a
278 special case where we want to conditionally enable/disable a tunable even
279 for setuid binaries. We use the special version of access() to avoid
280 setting ERRNO, which is a TLS variable since TLS has not yet been set
281 up. */
282 static inline void
283 __always_inline
284 maybe_enable_malloc_check (void)
286 tunable_id_t id = TUNABLE_ENUM_NAME (glibc, malloc, check);
287 if (__libc_enable_secure && __access_noerrno ("/etc/suid-debug", F_OK) == 0)
288 tunable_list[id].security_level = TUNABLE_SECLEVEL_NONE;
291 /* Initialize the tunables list from the environment. For now we only use the
292 ENV_ALIAS to find values. Later we will also use the tunable names to find
293 values. */
294 void
295 __tunables_init (char **envp)
297 char *envname = NULL;
298 char *envval = NULL;
299 size_t len = 0;
300 char **prev_envp = envp;
302 maybe_enable_malloc_check ();
304 while ((envp = get_next_env (envp, &envname, &len, &envval,
305 &prev_envp)) != NULL)
307 #if TUNABLES_FRONTEND == TUNABLES_FRONTEND_valstring
308 if (tunable_is_name (GLIBC_TUNABLES, envname))
310 char *new_env = tunables_strdup (envname);
311 if (new_env != NULL)
312 parse_tunables (new_env + len + 1, envval);
313 /* Put in the updated envval. */
314 *prev_envp = new_env;
315 continue;
317 #endif
319 for (int i = 0; i < sizeof (tunable_list) / sizeof (tunable_t); i++)
321 tunable_t *cur = &tunable_list[i];
323 /* Skip over tunables that have either been set already or should be
324 skipped. */
325 if (cur->initialized || cur->env_alias == NULL)
326 continue;
328 const char *name = cur->env_alias;
330 /* We have a match. Initialize and move on to the next line. */
331 if (tunable_is_name (name, envname))
333 /* For AT_SECURE binaries, we need to check the security settings of
334 the tunable and decide whether we read the value and also whether
335 we erase the value so that child processes don't inherit them in
336 the environment. */
337 if (__libc_enable_secure)
339 if (cur->security_level == TUNABLE_SECLEVEL_SXID_ERASE)
341 /* Erase the environment variable. */
342 char **ep = prev_envp;
344 while (*ep != NULL)
346 if (tunable_is_name (name, *ep))
348 char **dp = ep;
351 dp[0] = dp[1];
352 while (*dp++);
354 else
355 ++ep;
357 /* Reset the iterator so that we read the environment again
358 from the point we erased. */
359 envp = prev_envp;
362 if (cur->security_level != TUNABLE_SECLEVEL_NONE)
363 continue;
366 tunable_initialize (cur, envval);
367 break;
373 /* Set the tunable value. This is called by the module that the tunable exists
374 in. */
375 void
376 __tunable_get_val (tunable_id_t id, void *valp, tunable_callback_t callback)
378 tunable_t *cur = &tunable_list[id];
380 switch (cur->type.type_code)
382 case TUNABLE_TYPE_UINT_64:
384 *((uint64_t *) valp) = (uint64_t) cur->val.numval;
385 break;
387 case TUNABLE_TYPE_INT_32:
389 *((int32_t *) valp) = (int32_t) cur->val.numval;
390 break;
392 case TUNABLE_TYPE_SIZE_T:
394 *((size_t *) valp) = (size_t) cur->val.numval;
395 break;
397 case TUNABLE_TYPE_STRING:
399 *((const char **)valp) = cur->val.strval;
400 break;
402 default:
403 __builtin_unreachable ();
406 if (cur->initialized && callback != NULL)
407 callback (&cur->val);
410 rtld_hidden_def (__tunable_get_val)