rtld: properly handle root directory in load path (bug 30435)
[platform/upstream/glibc.git] / elf / dl-tunables.c
1 /* The tunable framework.  See the README.tunables to know how to use the
2    tunable in a glibc module.
3
4    Copyright (C) 2016-2023 Free Software Foundation, Inc.
5    This file is part of the GNU C Library.
6
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.
11
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.
16
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/>.  */
20
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>
35
36 #define TUNABLES_INTERNAL 1
37 #include "dl-tunables.h"
38
39 #include <not-errno.h>
40
41 static char *
42 tunables_strdup (const char *in)
43 {
44   size_t i = 0;
45
46   while (in[i++] != '\0');
47   char *out = __minimal_malloc (i + 1);
48
49   /* For most of the tunables code, we ignore user errors.  However,
50      this is a system error - and running out of memory at program
51      startup should be reported, so we do.  */
52   if (out == NULL)
53     _dl_fatal_printf ("failed to allocate memory to process tunables\n");
54
55   while (i-- > 0)
56     out[i] = in[i];
57
58   return out;
59 }
60
61 static char **
62 get_next_env (char **envp, char **name, size_t *namelen, char **val,
63               char ***prev_envp)
64 {
65   while (envp != NULL && *envp != NULL)
66     {
67       char **prev = envp;
68       char *envline = *envp++;
69       int len = 0;
70
71       while (envline[len] != '\0' && envline[len] != '=')
72         len++;
73
74       /* Just the name and no value, go to the next one.  */
75       if (envline[len] == '\0')
76         continue;
77
78       *name = envline;
79       *namelen = len;
80       *val = &envline[len + 1];
81       *prev_envp = prev;
82
83       return envp;
84     }
85
86   return NULL;
87 }
88
89 static void
90 do_tunable_update_val (tunable_t *cur, const tunable_val_t *valp,
91                        const tunable_num_t *minp,
92                        const tunable_num_t *maxp)
93 {
94   tunable_num_t val, min, max;
95
96   if (cur->type.type_code == TUNABLE_TYPE_STRING)
97     {
98       cur->val.strval = valp->strval;
99       cur->initialized = true;
100       return;
101     }
102
103   bool unsigned_cmp = unsigned_tunable_type (cur->type.type_code);
104
105   val = valp->numval;
106   min = minp != NULL ? *minp : cur->type.min;
107   max = maxp != NULL ? *maxp : cur->type.max;
108
109   /* We allow only increasingly restrictive bounds.  */
110   if (tunable_val_lt (min, cur->type.min, unsigned_cmp))
111     min = cur->type.min;
112
113   if (tunable_val_gt (max, cur->type.max, unsigned_cmp))
114     max = cur->type.max;
115
116   /* Skip both bounds if they're inconsistent.  */
117   if (tunable_val_gt (min, max, unsigned_cmp))
118     {
119       min = cur->type.min;
120       max = cur->type.max;
121     }
122
123   /* Bail out if the bounds are not valid.  */
124   if (tunable_val_lt (val, min, unsigned_cmp)
125       || tunable_val_lt (max, val, unsigned_cmp))
126     return;
127
128   cur->val.numval = val;
129   cur->type.min = min;
130   cur->type.max = max;
131   cur->initialized = true;
132 }
133
134 /* Validate range of the input value and initialize the tunable CUR if it looks
135    good.  */
136 static void
137 tunable_initialize (tunable_t *cur, const char *strval)
138 {
139   tunable_val_t val;
140
141   if (cur->type.type_code != TUNABLE_TYPE_STRING)
142     val.numval = (tunable_num_t) _dl_strtoul (strval, NULL);
143   else
144     val.strval = strval;
145   do_tunable_update_val (cur, &val, NULL, NULL);
146 }
147
148 void
149 __tunable_set_val (tunable_id_t id, tunable_val_t *valp, tunable_num_t *minp,
150                    tunable_num_t *maxp)
151 {
152   tunable_t *cur = &tunable_list[id];
153
154   do_tunable_update_val (cur, valp, minp, maxp);
155 }
156
157 /* Parse the tunable string TUNESTR and adjust it to drop any tunables that may
158    be unsafe for AT_SECURE processes so that it can be used as the new
159    environment variable value for GLIBC_TUNABLES.  VALSTRING is the original
160    environment variable string which we use to make NULL terminated values so
161    that we don't have to allocate memory again for it.  */
162 static void
163 parse_tunables (char *tunestr, char *valstring)
164 {
165   if (tunestr == NULL || *tunestr == '\0')
166     return;
167
168   char *p = tunestr;
169   size_t off = 0;
170
171   while (true)
172     {
173       char *name = p;
174       size_t len = 0;
175
176       /* First, find where the name ends.  */
177       while (p[len] != '=' && p[len] != ':' && p[len] != '\0')
178         len++;
179
180       /* If we reach the end of the string before getting a valid name-value
181          pair, bail out.  */
182       if (p[len] == '\0')
183         {
184           if (__libc_enable_secure)
185             tunestr[off] = '\0';
186           return;
187         }
188
189       /* We did not find a valid name-value pair before encountering the
190          colon.  */
191       if (p[len]== ':')
192         {
193           p += len + 1;
194           continue;
195         }
196
197       p += len + 1;
198
199       /* Take the value from the valstring since we need to NULL terminate it.  */
200       char *value = &valstring[p - tunestr];
201       len = 0;
202
203       while (p[len] != ':' && p[len] != '\0')
204         len++;
205
206       /* Add the tunable if it exists.  */
207       for (size_t i = 0; i < sizeof (tunable_list) / sizeof (tunable_t); i++)
208         {
209           tunable_t *cur = &tunable_list[i];
210
211           if (tunable_is_name (cur->name, name))
212             {
213               /* If we are in a secure context (AT_SECURE) then ignore the
214                  tunable unless it is explicitly marked as secure.  Tunable
215                  values take precedence over their envvar aliases.  We write
216                  the tunables that are not SXID_ERASE back to TUNESTR, thus
217                  dropping all SXID_ERASE tunables and any invalid or
218                  unrecognized tunables.  */
219               if (__libc_enable_secure)
220                 {
221                   if (cur->security_level != TUNABLE_SECLEVEL_SXID_ERASE)
222                     {
223                       if (off > 0)
224                         tunestr[off++] = ':';
225
226                       const char *n = cur->name;
227
228                       while (*n != '\0')
229                         tunestr[off++] = *n++;
230
231                       tunestr[off++] = '=';
232
233                       for (size_t j = 0; j < len; j++)
234                         tunestr[off++] = value[j];
235                     }
236
237                   if (cur->security_level != TUNABLE_SECLEVEL_NONE)
238                     break;
239                 }
240
241               value[len] = '\0';
242               tunable_initialize (cur, value);
243               break;
244             }
245         }
246
247       if (p[len] != '\0')
248         p += len + 1;
249     }
250 }
251
252 /* Enable the glibc.malloc.check tunable in SETUID/SETGID programs only when
253    the system administrator has created the /etc/suid-debug file.  This is a
254    special case where we want to conditionally enable/disable a tunable even
255    for setuid binaries.  We use the special version of access() to avoid
256    setting ERRNO, which is a TLS variable since TLS has not yet been set
257    up.  */
258 static __always_inline void
259 maybe_enable_malloc_check (void)
260 {
261   tunable_id_t id = TUNABLE_ENUM_NAME (glibc, malloc, check);
262   if (__libc_enable_secure && __access_noerrno ("/etc/suid-debug", F_OK) == 0)
263     tunable_list[id].security_level = TUNABLE_SECLEVEL_NONE;
264 }
265
266 /* Initialize the tunables list from the environment.  For now we only use the
267    ENV_ALIAS to find values.  Later we will also use the tunable names to find
268    values.  */
269 void
270 __tunables_init (char **envp)
271 {
272   char *envname = NULL;
273   char *envval = NULL;
274   size_t len = 0;
275   char **prev_envp = envp;
276
277   maybe_enable_malloc_check ();
278
279   while ((envp = get_next_env (envp, &envname, &len, &envval,
280                                &prev_envp)) != NULL)
281     {
282       if (tunable_is_name ("GLIBC_TUNABLES", envname))
283         {
284           char *new_env = tunables_strdup (envname);
285           if (new_env != NULL)
286             parse_tunables (new_env + len + 1, envval);
287           /* Put in the updated envval.  */
288           *prev_envp = new_env;
289           continue;
290         }
291
292       for (int i = 0; i < sizeof (tunable_list) / sizeof (tunable_t); i++)
293         {
294           tunable_t *cur = &tunable_list[i];
295
296           /* Skip over tunables that have either been set already or should be
297              skipped.  */
298           if (cur->initialized || cur->env_alias[0] == '\0')
299             continue;
300
301           const char *name = cur->env_alias;
302
303           /* We have a match.  Initialize and move on to the next line.  */
304           if (tunable_is_name (name, envname))
305             {
306               /* For AT_SECURE binaries, we need to check the security settings of
307                  the tunable and decide whether we read the value and also whether
308                  we erase the value so that child processes don't inherit them in
309                  the environment.  */
310               if (__libc_enable_secure)
311                 {
312                   if (cur->security_level == TUNABLE_SECLEVEL_SXID_ERASE)
313                     {
314                       /* Erase the environment variable.  */
315                       char **ep = prev_envp;
316
317                       while (*ep != NULL)
318                         {
319                           if (tunable_is_name (name, *ep))
320                             {
321                               char **dp = ep;
322
323                               do
324                                 dp[0] = dp[1];
325                               while (*dp++);
326                             }
327                           else
328                             ++ep;
329                         }
330                       /* Reset the iterator so that we read the environment again
331                          from the point we erased.  */
332                       envp = prev_envp;
333                     }
334
335                   if (cur->security_level != TUNABLE_SECLEVEL_NONE)
336                     continue;
337                 }
338
339               tunable_initialize (cur, envval);
340               break;
341             }
342         }
343     }
344 }
345
346 void
347 __tunables_print (void)
348 {
349   for (int i = 0; i < array_length (tunable_list); i++)
350     {
351       const tunable_t *cur = &tunable_list[i];
352       if (cur->type.type_code == TUNABLE_TYPE_STRING
353           && cur->val.strval == NULL)
354         _dl_printf ("%s:\n", cur->name);
355       else
356         {
357           _dl_printf ("%s: ", cur->name);
358           switch (cur->type.type_code)
359             {
360             case TUNABLE_TYPE_INT_32:
361               _dl_printf ("%d (min: %d, max: %d)\n",
362                           (int) cur->val.numval,
363                           (int) cur->type.min,
364                           (int) cur->type.max);
365               break;
366             case TUNABLE_TYPE_UINT_64:
367               _dl_printf ("0x%lx (min: 0x%lx, max: 0x%lx)\n",
368                           (long int) cur->val.numval,
369                           (long int) cur->type.min,
370                           (long int) cur->type.max);
371               break;
372             case TUNABLE_TYPE_SIZE_T:
373               _dl_printf ("0x%zx (min: 0x%zx, max: 0x%zx)\n",
374                           (size_t) cur->val.numval,
375                           (size_t) cur->type.min,
376                           (size_t) cur->type.max);
377               break;
378             case TUNABLE_TYPE_STRING:
379               _dl_printf ("%s\n", cur->val.strval);
380               break;
381             default:
382               __builtin_unreachable ();
383             }
384         }
385     }
386 }
387
388 /* Set the tunable value.  This is called by the module that the tunable exists
389    in. */
390 void
391 __tunable_get_val (tunable_id_t id, void *valp, tunable_callback_t callback)
392 {
393   tunable_t *cur = &tunable_list[id];
394
395   switch (cur->type.type_code)
396     {
397     case TUNABLE_TYPE_UINT_64:
398         {
399           *((uint64_t *) valp) = (uint64_t) cur->val.numval;
400           break;
401         }
402     case TUNABLE_TYPE_INT_32:
403         {
404           *((int32_t *) valp) = (int32_t) cur->val.numval;
405           break;
406         }
407     case TUNABLE_TYPE_SIZE_T:
408         {
409           *((size_t *) valp) = (size_t) cur->val.numval;
410           break;
411         }
412     case TUNABLE_TYPE_STRING:
413         {
414           *((const char **)valp) = cur->val.strval;
415           break;
416         }
417     default:
418       __builtin_unreachable ();
419     }
420
421   if (cur->initialized && callback != NULL)
422     callback (&cur->val);
423 }
424
425 rtld_hidden_def (__tunable_get_val)