powerpc: Fix strncat ifunc selection
[glibc.git] / elf / dl-tunables.c
blobebf48bb38988a4518b63bb2596bb1567e91997dd
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 /* A stripped down strtoul-like implementation for very early use. It does not
106 set errno if the result is outside bounds because it gets called before
107 errno may have been set up. */
108 static unsigned long int
109 tunables_strtoul (const char *nptr)
111 unsigned long int result = 0;
112 long int sign = 1;
113 unsigned max_digit;
115 while (*nptr == ' ' || *nptr == '\t')
116 ++nptr;
118 if (*nptr == '-')
120 sign = -1;
121 ++nptr;
123 else if (*nptr == '+')
124 ++nptr;
126 if (*nptr < '0' || *nptr > '9')
127 return 0UL;
129 int base = 10;
130 max_digit = 9;
131 if (*nptr == '0')
133 if (nptr[1] == 'x' || nptr[1] == 'X')
135 base = 16;
136 nptr += 2;
138 else
140 base = 8;
141 max_digit = 7;
145 while (1)
147 unsigned long int digval;
148 if (*nptr >= '0' && *nptr <= '0' + max_digit)
149 digval = *nptr - '0';
150 else if (base == 16)
152 if (*nptr >= 'a' && *nptr <= 'f')
153 digval = *nptr - 'a' + 10;
154 else if (*nptr >= 'A' && *nptr <= 'F')
155 digval = *nptr - 'A' + 10;
156 else
157 break;
159 else
160 break;
162 if (result > ULONG_MAX / base
163 || (result == ULONG_MAX / base && digval > ULONG_MAX % base))
164 return ULONG_MAX;
165 result *= base;
166 result += digval;
167 ++nptr;
170 return result * sign;
173 /* Initialize the internal type if the value validates either using the
174 explicit constraints of the tunable or with the implicit constraints of its
175 type. */
176 static void
177 tunable_set_val_if_valid_range_signed (tunable_t *cur, const char *strval,
178 int64_t default_min, int64_t default_max)
180 int64_t val = (int64_t) tunables_strtoul (strval);
182 int64_t min = cur->type.min;
183 int64_t max = cur->type.max;
185 if (min == max)
187 min = default_min;
188 max = default_max;
191 if (val >= min && val <= max)
193 cur->val.numval = val;
194 cur->strval = strval;
198 static void
199 tunable_set_val_if_valid_range_unsigned (tunable_t *cur, const char *strval,
200 uint64_t default_min, uint64_t default_max)
202 uint64_t val = (uint64_t) tunables_strtoul (strval);
204 uint64_t min = cur->type.min;
205 uint64_t max = cur->type.max;
207 if (min == max)
209 min = default_min;
210 max = default_max;
213 if (val >= min && val <= max)
215 cur->val.numval = val;
216 cur->strval = strval;
220 /* Validate range of the input value and initialize the tunable CUR if it looks
221 good. */
222 static void
223 tunable_initialize (tunable_t *cur, const char *strval)
225 switch (cur->type.type_code)
227 case TUNABLE_TYPE_INT_32:
229 tunable_set_val_if_valid_range_signed (cur, strval, INT32_MIN, INT32_MAX);
230 break;
232 case TUNABLE_TYPE_SIZE_T:
234 tunable_set_val_if_valid_range_unsigned (cur, strval, 0, SIZE_MAX);
235 break;
237 case TUNABLE_TYPE_STRING:
239 cur->val.strval = cur->strval = strval;
240 break;
242 default:
243 __builtin_unreachable ();
247 #if TUNABLES_FRONTEND == TUNABLES_FRONTEND_valstring
248 /* Parse the tunable string TUNESTR and adjust it to drop any tunables that may
249 be unsafe for AT_SECURE processes so that it can be used as the new
250 environment variable value for GLIBC_TUNABLES. VALSTRING is the original
251 environment variable string which we use to make NULL terminated values so
252 that we don't have to allocate memory again for it. */
253 static void
254 parse_tunables (char *tunestr, char *valstring)
256 if (tunestr == NULL || *tunestr == '\0')
257 return;
259 char *p = tunestr;
261 while (true)
263 char *name = p;
264 size_t len = 0;
266 /* First, find where the name ends. */
267 while (p[len] != '=' && p[len] != ':' && p[len] != '\0')
268 len++;
270 /* If we reach the end of the string before getting a valid name-value
271 pair, bail out. */
272 if (p[len] == '\0')
273 return;
275 /* We did not find a valid name-value pair before encountering the
276 colon. */
277 if (p[len]== ':')
279 p += len + 1;
280 continue;
283 p += len + 1;
285 /* Take the value from the valstring since we need to NULL terminate it. */
286 char *value = &valstring[p - tunestr];
287 len = 0;
289 while (p[len] != ':' && p[len] != '\0')
290 len++;
292 /* Add the tunable if it exists. */
293 for (size_t i = 0; i < sizeof (tunable_list) / sizeof (tunable_t); i++)
295 tunable_t *cur = &tunable_list[i];
297 if (is_name (cur->name, name))
299 /* If we are in a secure context (AT_SECURE) then ignore the tunable
300 unless it is explicitly marked as secure. Tunable values take
301 precendence over their envvar aliases. */
302 if (__libc_enable_secure)
304 if (cur->security_level == TUNABLE_SECLEVEL_SXID_ERASE)
306 if (p[len] == '\0')
308 /* Last tunable in the valstring. Null-terminate and
309 return. */
310 *name = '\0';
311 return;
313 else
315 /* Remove the current tunable from the string. We do
316 this by overwriting the string starting from NAME
317 (which is where the current tunable begins) with
318 the remainder of the string. We then have P point
319 to NAME so that we continue in the correct
320 position in the valstring. */
321 char *q = &p[len + 1];
322 p = name;
323 while (*q != '\0')
324 *name++ = *q++;
325 name[0] = '\0';
326 len = 0;
330 if (cur->security_level != TUNABLE_SECLEVEL_NONE)
331 break;
334 value[len] = '\0';
335 tunable_initialize (cur, value);
336 break;
340 if (p[len] == '\0')
341 return;
342 else
343 p += len + 1;
346 #endif
348 /* Enable the glibc.malloc.check tunable in SETUID/SETGID programs only when
349 the system administrator has created the /etc/suid-debug file. This is a
350 special case where we want to conditionally enable/disable a tunable even
351 for setuid binaries. We use the special version of access() to avoid
352 setting ERRNO, which is a TLS variable since TLS has not yet been set
353 up. */
354 static inline void
355 __always_inline
356 maybe_enable_malloc_check (void)
358 tunable_id_t id = TUNABLE_ENUM_NAME (glibc, malloc, check);
359 if (__libc_enable_secure && __access_noerrno ("/etc/suid-debug", F_OK) == 0)
360 tunable_list[id].security_level = TUNABLE_SECLEVEL_NONE;
363 /* Initialize the tunables list from the environment. For now we only use the
364 ENV_ALIAS to find values. Later we will also use the tunable names to find
365 values. */
366 void
367 __tunables_init (char **envp)
369 char *envname = NULL;
370 char *envval = NULL;
371 size_t len = 0;
372 char **prev_envp = envp;
374 maybe_enable_malloc_check ();
376 while ((envp = get_next_env (envp, &envname, &len, &envval,
377 &prev_envp)) != NULL)
379 #if TUNABLES_FRONTEND == TUNABLES_FRONTEND_valstring
380 if (is_name (GLIBC_TUNABLES, envname))
382 char *new_env = tunables_strdup (envname);
383 if (new_env != NULL)
384 parse_tunables (new_env + len + 1, envval);
385 /* Put in the updated envval. */
386 *prev_envp = new_env;
387 continue;
389 #endif
391 for (int i = 0; i < sizeof (tunable_list) / sizeof (tunable_t); i++)
393 tunable_t *cur = &tunable_list[i];
395 /* Skip over tunables that have either been set already or should be
396 skipped. */
397 if (cur->strval != NULL || cur->env_alias == NULL)
398 continue;
400 const char *name = cur->env_alias;
402 /* We have a match. Initialize and move on to the next line. */
403 if (is_name (name, envname))
405 /* For AT_SECURE binaries, we need to check the security settings of
406 the tunable and decide whether we read the value and also whether
407 we erase the value so that child processes don't inherit them in
408 the environment. */
409 if (__libc_enable_secure)
411 if (cur->security_level == TUNABLE_SECLEVEL_SXID_ERASE)
413 /* Erase the environment variable. */
414 char **ep = prev_envp;
416 while (*ep != NULL)
418 if (is_name (name, *ep))
420 char **dp = ep;
423 dp[0] = dp[1];
424 while (*dp++);
426 else
427 ++ep;
429 /* Reset the iterator so that we read the environment again
430 from the point we erased. */
431 envp = prev_envp;
434 if (cur->security_level != TUNABLE_SECLEVEL_NONE)
435 continue;
438 tunable_initialize (cur, envval);
439 break;
445 /* Set the tunable value. This is called by the module that the tunable exists
446 in. */
447 void
448 __tunable_set_val (tunable_id_t id, void *valp, tunable_callback_t callback)
450 tunable_t *cur = &tunable_list[id];
452 /* Don't do anything if our tunable was not set during initialization or if
453 it failed validation. */
454 if (cur->strval == NULL)
455 return;
457 /* Caller does not need the value, just call the callback with our tunable
458 value. */
459 if (valp == NULL)
460 goto cb;
462 switch (cur->type.type_code)
464 case TUNABLE_TYPE_INT_32:
466 *((int32_t *) valp) = (int32_t) cur->val.numval;
467 break;
469 case TUNABLE_TYPE_SIZE_T:
471 *((size_t *) valp) = (size_t) cur->val.numval;
472 break;
474 case TUNABLE_TYPE_STRING:
476 *((const char **)valp) = cur->val.strval;
477 break;
479 default:
480 __builtin_unreachable ();
484 if (callback)
485 callback (&cur->val);