aarch64: Move and update the definition of MTE_ENABLED
[glibc.git] / elf / dl-tunables.c
blobb1a50b84693d15de59eaedb4cd5b7db24e223845
1 /* The tunable framework. See the README.tunables to know how to use the
2 tunable in a glibc module.
4 Copyright (C) 2016-2021 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 <https://www.gnu.org/licenses/>. */
21 /* Mark symbols hidden in static PIE for early self relocation to work. */
22 #if BUILD_PIE_DEFAULT
23 # pragma GCC visibility push(hidden)
24 #endif
25 #include <startup.h>
26 #include <stdint.h>
27 #include <stdbool.h>
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <sysdep.h>
31 #include <fcntl.h>
32 #include <ldsodefs.h>
33 #include <array_length.h>
35 #define TUNABLES_INTERNAL 1
36 #include "dl-tunables.h"
38 #include <not-errno.h>
40 #if TUNABLES_FRONTEND == TUNABLES_FRONTEND_valstring
41 # define GLIBC_TUNABLES "GLIBC_TUNABLES"
42 #endif
44 #if TUNABLES_FRONTEND == TUNABLES_FRONTEND_valstring
45 static char *
46 tunables_strdup (const char *in)
48 size_t i = 0;
50 while (in[i++] != '\0');
51 char *out = __sbrk (i);
53 /* For most of the tunables code, we ignore user errors. However,
54 this is a system error - and running out of memory at program
55 startup should be reported, so we do. */
56 if (out == (void *)-1)
57 _dl_fatal_printf ("sbrk() failure while processing tunables\n");
59 i--;
61 while (i-- > 0)
62 out[i] = in[i];
64 return out;
66 #endif
68 static char **
69 get_next_env (char **envp, char **name, size_t *namelen, char **val,
70 char ***prev_envp)
72 while (envp != NULL && *envp != NULL)
74 char **prev = envp;
75 char *envline = *envp++;
76 int len = 0;
78 while (envline[len] != '\0' && envline[len] != '=')
79 len++;
81 /* Just the name and no value, go to the next one. */
82 if (envline[len] == '\0')
83 continue;
85 *name = envline;
86 *namelen = len;
87 *val = &envline[len + 1];
88 *prev_envp = prev;
90 return envp;
93 return NULL;
96 #define TUNABLE_SET_VAL_IF_VALID_RANGE(__cur, __val, __type) \
97 ({ \
98 __type min = (__cur)->type.min; \
99 __type max = (__cur)->type.max; \
101 if ((__type) (__val) >= min && (__type) (__val) <= max) \
103 (__cur)->val.numval = (__val); \
104 (__cur)->initialized = true; \
108 #define TUNABLE_SET_BOUNDS_IF_VALID(__cur, __minp, __maxp, __type) \
109 ({ \
110 if (__minp != NULL) \
112 /* MIN is specified. */ \
113 __type min = *((__type *) __minp); \
114 if (__maxp != NULL) \
116 /* Both MIN and MAX are specified. */ \
117 __type max = *((__type *) __maxp); \
118 if (max >= min \
119 && max <= (__cur)->type.max \
120 && min >= (__cur)->type.min) \
122 (__cur)->type.min = min; \
123 (__cur)->type.max = max; \
126 else if (min > (__cur)->type.min && min <= (__cur)->type.max) \
128 /* Only MIN is specified. */ \
129 (__cur)->type.min = min; \
132 else if (__maxp != NULL) \
134 /* Only MAX is specified. */ \
135 __type max = *((__type *) __maxp); \
136 if (max < (__cur)->type.max && max >= (__cur)->type.min) \
137 (__cur)->type.max = max; \
141 static void
142 do_tunable_update_val (tunable_t *cur, const void *valp,
143 const void *minp, const void *maxp)
145 uint64_t val;
147 if (cur->type.type_code != TUNABLE_TYPE_STRING)
148 val = *((int64_t *) valp);
150 switch (cur->type.type_code)
152 case TUNABLE_TYPE_INT_32:
154 TUNABLE_SET_BOUNDS_IF_VALID (cur, minp, maxp, int64_t);
155 TUNABLE_SET_VAL_IF_VALID_RANGE (cur, val, int64_t);
156 break;
158 case TUNABLE_TYPE_UINT_64:
160 TUNABLE_SET_BOUNDS_IF_VALID (cur, minp, maxp, uint64_t);
161 TUNABLE_SET_VAL_IF_VALID_RANGE (cur, val, uint64_t);
162 break;
164 case TUNABLE_TYPE_SIZE_T:
166 TUNABLE_SET_BOUNDS_IF_VALID (cur, minp, maxp, uint64_t);
167 TUNABLE_SET_VAL_IF_VALID_RANGE (cur, val, uint64_t);
168 break;
170 case TUNABLE_TYPE_STRING:
172 cur->val.strval = valp;
173 break;
175 default:
176 __builtin_unreachable ();
180 /* Validate range of the input value and initialize the tunable CUR if it looks
181 good. */
182 static void
183 tunable_initialize (tunable_t *cur, const char *strval)
185 uint64_t val;
186 const void *valp;
188 if (cur->type.type_code != TUNABLE_TYPE_STRING)
190 val = _dl_strtoul (strval, NULL);
191 valp = &val;
193 else
195 cur->initialized = true;
196 valp = strval;
198 do_tunable_update_val (cur, valp, NULL, NULL);
201 void
202 __tunable_set_val (tunable_id_t id, void *valp, void *minp, void *maxp)
204 tunable_t *cur = &tunable_list[id];
206 do_tunable_update_val (cur, valp, minp, maxp);
209 #if TUNABLES_FRONTEND == TUNABLES_FRONTEND_valstring
210 /* Parse the tunable string TUNESTR and adjust it to drop any tunables that may
211 be unsafe for AT_SECURE processes so that it can be used as the new
212 environment variable value for GLIBC_TUNABLES. VALSTRING is the original
213 environment variable string which we use to make NULL terminated values so
214 that we don't have to allocate memory again for it. */
215 static void
216 parse_tunables (char *tunestr, char *valstring)
218 if (tunestr == NULL || *tunestr == '\0')
219 return;
221 char *p = tunestr;
223 while (true)
225 char *name = p;
226 size_t len = 0;
228 /* First, find where the name ends. */
229 while (p[len] != '=' && p[len] != ':' && p[len] != '\0')
230 len++;
232 /* If we reach the end of the string before getting a valid name-value
233 pair, bail out. */
234 if (p[len] == '\0')
235 return;
237 /* We did not find a valid name-value pair before encountering the
238 colon. */
239 if (p[len]== ':')
241 p += len + 1;
242 continue;
245 p += len + 1;
247 /* Take the value from the valstring since we need to NULL terminate it. */
248 char *value = &valstring[p - tunestr];
249 len = 0;
251 while (p[len] != ':' && p[len] != '\0')
252 len++;
254 /* Add the tunable if it exists. */
255 for (size_t i = 0; i < sizeof (tunable_list) / sizeof (tunable_t); i++)
257 tunable_t *cur = &tunable_list[i];
259 if (tunable_is_name (cur->name, name))
261 /* If we are in a secure context (AT_SECURE) then ignore the tunable
262 unless it is explicitly marked as secure. Tunable values take
263 precedence over their envvar aliases. */
264 if (__libc_enable_secure)
266 if (cur->security_level == TUNABLE_SECLEVEL_SXID_ERASE)
268 if (p[len] == '\0')
270 /* Last tunable in the valstring. Null-terminate and
271 return. */
272 *name = '\0';
273 return;
275 else
277 /* Remove the current tunable from the string. We do
278 this by overwriting the string starting from NAME
279 (which is where the current tunable begins) with
280 the remainder of the string. We then have P point
281 to NAME so that we continue in the correct
282 position in the valstring. */
283 char *q = &p[len + 1];
284 p = name;
285 while (*q != '\0')
286 *name++ = *q++;
287 name[0] = '\0';
288 len = 0;
292 if (cur->security_level != TUNABLE_SECLEVEL_NONE)
293 break;
296 value[len] = '\0';
297 tunable_initialize (cur, value);
298 break;
302 if (p[len] == '\0')
303 return;
304 else
305 p += len + 1;
308 #endif
310 /* Enable the glibc.malloc.check tunable in SETUID/SETGID programs only when
311 the system administrator has created the /etc/suid-debug file. This is a
312 special case where we want to conditionally enable/disable a tunable even
313 for setuid binaries. We use the special version of access() to avoid
314 setting ERRNO, which is a TLS variable since TLS has not yet been set
315 up. */
316 static __always_inline void
317 maybe_enable_malloc_check (void)
319 tunable_id_t id = TUNABLE_ENUM_NAME (glibc, malloc, check);
320 if (__libc_enable_secure && __access_noerrno ("/etc/suid-debug", F_OK) == 0)
321 tunable_list[id].security_level = TUNABLE_SECLEVEL_NONE;
324 /* Initialize the tunables list from the environment. For now we only use the
325 ENV_ALIAS to find values. Later we will also use the tunable names to find
326 values. */
327 void
328 __tunables_init (char **envp)
330 char *envname = NULL;
331 char *envval = NULL;
332 size_t len = 0;
333 char **prev_envp = envp;
335 maybe_enable_malloc_check ();
337 while ((envp = get_next_env (envp, &envname, &len, &envval,
338 &prev_envp)) != NULL)
340 #if TUNABLES_FRONTEND == TUNABLES_FRONTEND_valstring
341 if (tunable_is_name (GLIBC_TUNABLES, envname))
343 char *new_env = tunables_strdup (envname);
344 if (new_env != NULL)
345 parse_tunables (new_env + len + 1, envval);
346 /* Put in the updated envval. */
347 *prev_envp = new_env;
348 continue;
350 #endif
352 for (int i = 0; i < sizeof (tunable_list) / sizeof (tunable_t); i++)
354 tunable_t *cur = &tunable_list[i];
356 /* Skip over tunables that have either been set already or should be
357 skipped. */
358 if (cur->initialized || cur->env_alias[0] == '\0')
359 continue;
361 const char *name = cur->env_alias;
363 /* We have a match. Initialize and move on to the next line. */
364 if (tunable_is_name (name, envname))
366 /* For AT_SECURE binaries, we need to check the security settings of
367 the tunable and decide whether we read the value and also whether
368 we erase the value so that child processes don't inherit them in
369 the environment. */
370 if (__libc_enable_secure)
372 if (cur->security_level == TUNABLE_SECLEVEL_SXID_ERASE)
374 /* Erase the environment variable. */
375 char **ep = prev_envp;
377 while (*ep != NULL)
379 if (tunable_is_name (name, *ep))
381 char **dp = ep;
384 dp[0] = dp[1];
385 while (*dp++);
387 else
388 ++ep;
390 /* Reset the iterator so that we read the environment again
391 from the point we erased. */
392 envp = prev_envp;
395 if (cur->security_level != TUNABLE_SECLEVEL_NONE)
396 continue;
399 tunable_initialize (cur, envval);
400 break;
406 void
407 __tunables_print (void)
409 for (int i = 0; i < array_length (tunable_list); i++)
411 const tunable_t *cur = &tunable_list[i];
412 if (cur->type.type_code == TUNABLE_TYPE_STRING
413 && cur->val.strval == NULL)
414 _dl_printf ("%s:\n", cur->name);
415 else
417 _dl_printf ("%s: ", cur->name);
418 switch (cur->type.type_code)
420 case TUNABLE_TYPE_INT_32:
421 _dl_printf ("%d (min: %d, max: %d)\n",
422 (int) cur->val.numval,
423 (int) cur->type.min,
424 (int) cur->type.max);
425 break;
426 case TUNABLE_TYPE_UINT_64:
427 _dl_printf ("0x%lx (min: 0x%lx, max: 0x%lx)\n",
428 (long int) cur->val.numval,
429 (long int) cur->type.min,
430 (long int) cur->type.max);
431 break;
432 case TUNABLE_TYPE_SIZE_T:
433 _dl_printf ("0x%Zx (min: 0x%Zx, max: 0x%Zx)\n",
434 (size_t) cur->val.numval,
435 (size_t) cur->type.min,
436 (size_t) cur->type.max);
437 break;
438 case TUNABLE_TYPE_STRING:
439 _dl_printf ("%s\n", cur->val.strval);
440 break;
441 default:
442 __builtin_unreachable ();
448 /* Set the tunable value. This is called by the module that the tunable exists
449 in. */
450 void
451 __tunable_get_val (tunable_id_t id, void *valp, tunable_callback_t callback)
453 tunable_t *cur = &tunable_list[id];
455 switch (cur->type.type_code)
457 case TUNABLE_TYPE_UINT_64:
459 *((uint64_t *) valp) = (uint64_t) cur->val.numval;
460 break;
462 case TUNABLE_TYPE_INT_32:
464 *((int32_t *) valp) = (int32_t) cur->val.numval;
465 break;
467 case TUNABLE_TYPE_SIZE_T:
469 *((size_t *) valp) = (size_t) cur->val.numval;
470 break;
472 case TUNABLE_TYPE_STRING:
474 *((const char **)valp) = cur->val.strval;
475 break;
477 default:
478 __builtin_unreachable ();
481 if (cur->initialized && callback != NULL)
482 callback (&cur->val);
485 rtld_hidden_def (__tunable_get_val)