Use '%z' instead of '%Z' on printf functions
[glibc.git] / elf / dl-tunables.c
bloba3e399fda2504890ceab317925881291cd724a5b
1 /* The tunable framework. See the README.tunables to know how to use the
2 tunable in a glibc module.
4 Copyright (C) 2016-2022 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>
34 #include <dl-minimal-malloc.h>
36 #define TUNABLES_INTERNAL 1
37 #include "dl-tunables.h"
39 #include <not-errno.h>
41 #if TUNABLES_FRONTEND == TUNABLES_FRONTEND_valstring
42 # define GLIBC_TUNABLES "GLIBC_TUNABLES"
43 #endif
45 #if TUNABLES_FRONTEND == TUNABLES_FRONTEND_valstring
46 static char *
47 tunables_strdup (const char *in)
49 size_t i = 0;
51 while (in[i++] != '\0');
52 char *out = __minimal_malloc (i + 1);
54 /* For most of the tunables code, we ignore user errors. However,
55 this is a system error - and running out of memory at program
56 startup should be reported, so we do. */
57 if (out == NULL)
58 _dl_fatal_printf ("failed to allocate memory to process tunables\n");
60 while (i-- > 0)
61 out[i] = in[i];
63 return out;
65 #endif
67 static char **
68 get_next_env (char **envp, char **name, size_t *namelen, char **val,
69 char ***prev_envp)
71 while (envp != NULL && *envp != NULL)
73 char **prev = envp;
74 char *envline = *envp++;
75 int len = 0;
77 while (envline[len] != '\0' && envline[len] != '=')
78 len++;
80 /* Just the name and no value, go to the next one. */
81 if (envline[len] == '\0')
82 continue;
84 *name = envline;
85 *namelen = len;
86 *val = &envline[len + 1];
87 *prev_envp = prev;
89 return envp;
92 return NULL;
95 static void
96 do_tunable_update_val (tunable_t *cur, const tunable_val_t *valp,
97 const tunable_num_t *minp,
98 const tunable_num_t *maxp)
100 tunable_num_t val, min, max;
102 if (cur->type.type_code == TUNABLE_TYPE_STRING)
104 cur->val.strval = valp->strval;
105 cur->initialized = true;
106 return;
109 bool unsigned_cmp = unsigned_tunable_type (cur->type.type_code);
111 val = valp->numval;
112 min = minp != NULL ? *minp : cur->type.min;
113 max = maxp != NULL ? *maxp : cur->type.max;
115 /* We allow only increasingly restrictive bounds. */
116 if (tunable_val_lt (min, cur->type.min, unsigned_cmp))
117 min = cur->type.min;
119 if (tunable_val_gt (max, cur->type.max, unsigned_cmp))
120 max = cur->type.max;
122 /* Skip both bounds if they're inconsistent. */
123 if (tunable_val_gt (min, max, unsigned_cmp))
125 min = cur->type.min;
126 max = cur->type.max;
129 /* Bail out if the bounds are not valid. */
130 if (tunable_val_lt (val, min, unsigned_cmp)
131 || tunable_val_lt (max, val, unsigned_cmp))
132 return;
134 cur->val.numval = val;
135 cur->type.min = min;
136 cur->type.max = max;
137 cur->initialized = true;
140 /* Validate range of the input value and initialize the tunable CUR if it looks
141 good. */
142 static void
143 tunable_initialize (tunable_t *cur, const char *strval)
145 tunable_val_t val;
147 if (cur->type.type_code != TUNABLE_TYPE_STRING)
148 val.numval = (tunable_num_t) _dl_strtoul (strval, NULL);
149 else
150 val.strval = strval;
151 do_tunable_update_val (cur, &val, NULL, NULL);
154 void
155 __tunable_set_val (tunable_id_t id, tunable_val_t *valp, tunable_num_t *minp,
156 tunable_num_t *maxp)
158 tunable_t *cur = &tunable_list[id];
160 do_tunable_update_val (cur, valp, minp, maxp);
163 #if TUNABLES_FRONTEND == TUNABLES_FRONTEND_valstring
164 /* Parse the tunable string TUNESTR and adjust it to drop any tunables that may
165 be unsafe for AT_SECURE processes so that it can be used as the new
166 environment variable value for GLIBC_TUNABLES. VALSTRING is the original
167 environment variable string which we use to make NULL terminated values so
168 that we don't have to allocate memory again for it. */
169 static void
170 parse_tunables (char *tunestr, char *valstring)
172 if (tunestr == NULL || *tunestr == '\0')
173 return;
175 char *p = tunestr;
176 size_t off = 0;
178 while (true)
180 char *name = p;
181 size_t len = 0;
183 /* First, find where the name ends. */
184 while (p[len] != '=' && p[len] != ':' && p[len] != '\0')
185 len++;
187 /* If we reach the end of the string before getting a valid name-value
188 pair, bail out. */
189 if (p[len] == '\0')
191 if (__libc_enable_secure)
192 tunestr[off] = '\0';
193 return;
196 /* We did not find a valid name-value pair before encountering the
197 colon. */
198 if (p[len]== ':')
200 p += len + 1;
201 continue;
204 p += len + 1;
206 /* Take the value from the valstring since we need to NULL terminate it. */
207 char *value = &valstring[p - tunestr];
208 len = 0;
210 while (p[len] != ':' && p[len] != '\0')
211 len++;
213 /* Add the tunable if it exists. */
214 for (size_t i = 0; i < sizeof (tunable_list) / sizeof (tunable_t); i++)
216 tunable_t *cur = &tunable_list[i];
218 if (tunable_is_name (cur->name, name))
220 /* If we are in a secure context (AT_SECURE) then ignore the
221 tunable unless it is explicitly marked as secure. Tunable
222 values take precedence over their envvar aliases. We write
223 the tunables that are not SXID_ERASE back to TUNESTR, thus
224 dropping all SXID_ERASE tunables and any invalid or
225 unrecognized tunables. */
226 if (__libc_enable_secure)
228 if (cur->security_level != TUNABLE_SECLEVEL_SXID_ERASE)
230 if (off > 0)
231 tunestr[off++] = ':';
233 const char *n = cur->name;
235 while (*n != '\0')
236 tunestr[off++] = *n++;
238 tunestr[off++] = '=';
240 for (size_t j = 0; j < len; j++)
241 tunestr[off++] = value[j];
244 if (cur->security_level != TUNABLE_SECLEVEL_NONE)
245 break;
248 value[len] = '\0';
249 tunable_initialize (cur, value);
250 break;
254 if (p[len] != '\0')
255 p += len + 1;
258 #endif
260 /* Enable the glibc.malloc.check tunable in SETUID/SETGID programs only when
261 the system administrator has created the /etc/suid-debug file. This is a
262 special case where we want to conditionally enable/disable a tunable even
263 for setuid binaries. We use the special version of access() to avoid
264 setting ERRNO, which is a TLS variable since TLS has not yet been set
265 up. */
266 static __always_inline void
267 maybe_enable_malloc_check (void)
269 tunable_id_t id = TUNABLE_ENUM_NAME (glibc, malloc, check);
270 if (__libc_enable_secure && __access_noerrno ("/etc/suid-debug", F_OK) == 0)
271 tunable_list[id].security_level = TUNABLE_SECLEVEL_NONE;
274 /* Initialize the tunables list from the environment. For now we only use the
275 ENV_ALIAS to find values. Later we will also use the tunable names to find
276 values. */
277 void
278 __tunables_init (char **envp)
280 char *envname = NULL;
281 char *envval = NULL;
282 size_t len = 0;
283 char **prev_envp = envp;
285 maybe_enable_malloc_check ();
287 while ((envp = get_next_env (envp, &envname, &len, &envval,
288 &prev_envp)) != NULL)
290 #if TUNABLES_FRONTEND == TUNABLES_FRONTEND_valstring
291 if (tunable_is_name (GLIBC_TUNABLES, envname))
293 char *new_env = tunables_strdup (envname);
294 if (new_env != NULL)
295 parse_tunables (new_env + len + 1, envval);
296 /* Put in the updated envval. */
297 *prev_envp = new_env;
298 continue;
300 #endif
302 for (int i = 0; i < sizeof (tunable_list) / sizeof (tunable_t); i++)
304 tunable_t *cur = &tunable_list[i];
306 /* Skip over tunables that have either been set already or should be
307 skipped. */
308 if (cur->initialized || cur->env_alias[0] == '\0')
309 continue;
311 const char *name = cur->env_alias;
313 /* We have a match. Initialize and move on to the next line. */
314 if (tunable_is_name (name, envname))
316 /* For AT_SECURE binaries, we need to check the security settings of
317 the tunable and decide whether we read the value and also whether
318 we erase the value so that child processes don't inherit them in
319 the environment. */
320 if (__libc_enable_secure)
322 if (cur->security_level == TUNABLE_SECLEVEL_SXID_ERASE)
324 /* Erase the environment variable. */
325 char **ep = prev_envp;
327 while (*ep != NULL)
329 if (tunable_is_name (name, *ep))
331 char **dp = ep;
334 dp[0] = dp[1];
335 while (*dp++);
337 else
338 ++ep;
340 /* Reset the iterator so that we read the environment again
341 from the point we erased. */
342 envp = prev_envp;
345 if (cur->security_level != TUNABLE_SECLEVEL_NONE)
346 continue;
349 tunable_initialize (cur, envval);
350 break;
356 void
357 __tunables_print (void)
359 for (int i = 0; i < array_length (tunable_list); i++)
361 const tunable_t *cur = &tunable_list[i];
362 if (cur->type.type_code == TUNABLE_TYPE_STRING
363 && cur->val.strval == NULL)
364 _dl_printf ("%s:\n", cur->name);
365 else
367 _dl_printf ("%s: ", cur->name);
368 switch (cur->type.type_code)
370 case TUNABLE_TYPE_INT_32:
371 _dl_printf ("%d (min: %d, max: %d)\n",
372 (int) cur->val.numval,
373 (int) cur->type.min,
374 (int) cur->type.max);
375 break;
376 case TUNABLE_TYPE_UINT_64:
377 _dl_printf ("0x%lx (min: 0x%lx, max: 0x%lx)\n",
378 (long int) cur->val.numval,
379 (long int) cur->type.min,
380 (long int) cur->type.max);
381 break;
382 case TUNABLE_TYPE_SIZE_T:
383 _dl_printf ("0x%zx (min: 0x%zx, max: 0x%zx)\n",
384 (size_t) cur->val.numval,
385 (size_t) cur->type.min,
386 (size_t) cur->type.max);
387 break;
388 case TUNABLE_TYPE_STRING:
389 _dl_printf ("%s\n", cur->val.strval);
390 break;
391 default:
392 __builtin_unreachable ();
398 /* Set the tunable value. This is called by the module that the tunable exists
399 in. */
400 void
401 __tunable_get_val (tunable_id_t id, void *valp, tunable_callback_t callback)
403 tunable_t *cur = &tunable_list[id];
405 switch (cur->type.type_code)
407 case TUNABLE_TYPE_UINT_64:
409 *((uint64_t *) valp) = (uint64_t) cur->val.numval;
410 break;
412 case TUNABLE_TYPE_INT_32:
414 *((int32_t *) valp) = (int32_t) cur->val.numval;
415 break;
417 case TUNABLE_TYPE_SIZE_T:
419 *((size_t *) valp) = (size_t) cur->val.numval;
420 break;
422 case TUNABLE_TYPE_STRING:
424 *((const char **)valp) = cur->val.strval;
425 break;
427 default:
428 __builtin_unreachable ();
431 if (cur->initialized && callback != NULL)
432 callback (&cur->val);
435 rtld_hidden_def (__tunable_get_val)