[PATCH v8 3/5] Add system-wide tunables: Apply tunables part
Arjun Shankar
arjun@redhat.com
Wed Jun 24 01:19:14 GMT 2026
Hi DJ,
> Load ld.so.cache and fetch the tunables extension. Apply
> those tunables to the current program. We do not yet apply
> security policies.
Only two notes for this one. Otherwise OK.
Reviewed-by: Arjun Shankar <arjun@redhat.com>
> ---
> elf/dl-cache.c | 50 ++++++++++++++++++++++++++++++++++++
> elf/dl-tunables.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++
> elf/tunconf.h | 3 +++
> 3 files changed, 118 insertions(+)
>
> diff --git a/elf/dl-cache.c b/elf/dl-cache.c
> index 07c7e639f5..b18cf58905 100644
> --- a/elf/dl-cache.c
> +++ b/elf/dl-cache.c
> @@ -28,6 +28,7 @@
> #include <dl-isa-level.h>
> #include <fcntl.h>
> #include <sys/stat.h>
> +#include "tunconf.h"
>
> /* This is the starting address and the size of the mmap()ed file. */
> static struct cache_file *cache;
> @@ -613,3 +614,52 @@ _dl_unload_cache (void)
> now. */
> }
> #endif
> +
> +const struct tunable_header_cached *
> +_dl_load_cache_tunables (const char **data)
> +{
> + struct cache_extension_all_loaded ext;
> + struct tunable_header_cached *thc;
> + struct tunable_entry_cached *tec;
> + int i, count;
> +
> + if (_dl_check_ldsocache_needs_loading ())
> + _dl_maybe_load_ldsocache ();
> +
> + if (cache_new)
> + *data = (const char *) cache_new;
> + else
> + return NULL;
> +
> + if (!cache_extension_load (cache_new, cache, cachesize, &ext))
> + return NULL;
> +
> + /* Validate length/contents here. */
> + if (ext.sections[cache_extension_tag_tunables].size
> + < sizeof(struct tunable_header_cached))
> + return NULL;
> +
> + thc = (struct tunable_header_cached *)
> + ext.sections[cache_extension_tag_tunables].base;
> + tec = thc->tunables;
> + count = thc->num_tunables;
> +
> + if (ext.sections[cache_extension_tag_tunables].base
> + + ext.sections[cache_extension_tag_tunables].size
> + < (void *) & tec[count])
> + return NULL;
This could be exact, like the assert in patch #1.
> +
> + /* Validate each entry. */
> + int s_start = (const char *) (&cache_new->libs[cache_new->nlibs]) - *data;
> + int s_end = s_start + cache_new->len_strings;
> + for (i = 0; i < count; i ++)
> + {
> + if (thc->tunables[i].name_offset < s_start
> + || thc->tunables[i].name_offset >= s_end
> + || thc->tunables[i].value_offset < s_start
> + || thc->tunables[i].value_offset >= s_end)
> + return NULL;
> + }
Offset validation. flag_offset can also be checked here (except when it's zero).
> +
> + return thc;
> +}
> diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c
> index 5c65e8b458..f183e99855 100644
> --- a/elf/dl-tunables.c
> +++ b/elf/dl-tunables.c
> @@ -37,6 +37,7 @@
>
> #define TUNABLES_INTERNAL 1
> #include "dl-tunables.h"
> +#include "tunconf.h"
>
> static char **
> get_next_env (char **envp, char **name, char **val, char ***prev_envp)
> @@ -302,6 +303,70 @@ __tunables_init (char **envp)
> if (MALLOC_DEFAULT_THP_PAGESIZE > 0)
> TUNABLE_SET (glibc, malloc, hugetlb, 1);
>
> +#if defined(SHARED) && defined (USE_LDCONFIG)
> + const struct tunable_header_cached *thc;
> + const char *td;
> +
> + thc = _dl_load_cache_tunables (&td);
> + if (thc != NULL)
> + {
> + for (int t = 0; t < thc->num_tunables; ++ t)
> + {
> + const struct tunable_entry_cached *tec = &( thc->tunables[t] );
> + int tid = tec->tunable_id;
> + const char *name = td + tec->name_offset;
> + const char *value = td + tec->value_offset;
> +
> + /* Check that we have the correct tunable, and search by
> + name if needed. We rely on order of operations here to
> + avoid mis-indexing tunables[]. */
> + if (tid < 0 || tid >= tunables_list_size
> + || strcmp (name, tunable_list[tid].name) != 0)
> + {
> + /* It does not, search by name instead. */
> + tid = -1;
> + for (int i = 0; i < tunables_list_size; i++)
> + {
> + if (strcmp (name, tunable_list[i].name) == 0)
> + {
> + tid = i;
> + break;
> + }
> + }
> + if (tid == -1)
> + continue;
> + }
> + /* At this point, TID is valid for the tunable we want. See
> + if the parsed type matches the desired type. */
> +
> + if (tunable_list[tid].type.type_code == TUNABLE_TYPE_STRING)
> + {
> + /* This is a memory leak but there's no easy way around
> + it, as the mapping will go away if the disk file is
> + updated and the cache is reloaded. */
> + tunable_list[tid].val.strval.str = __strdup (value);
> + tunable_list[tid].val.strval.len = strlen (value);
> + tunable_list[tid].initialized = true;
OK. Setting initialized.
> + }
> + else
> + {
> + tunable_val_t tval;
> + if (tec->flags & TUNCONF_FLAG_PARSED)
> + {
> + tval.numval = tec->parsed_value;
> + do_tunable_update_val (& tunable_list[tid],
> + &tval, NULL, NULL);
> + }
> + else
> + {
> + tunable_initialize (& tunable_list[tid],
> + value, strlen (value));
> + }
> + }
> + }
> + }
> +#endif /* defined(SHARED) && defined (USE_LDCONFIG) */
> +
> /* Ignore tunables for AT_SECURE programs. */
> if (__libc_enable_secure)
> return;
> diff --git a/elf/tunconf.h b/elf/tunconf.h
> index 85e1c142fa..b063c1bc96 100644
> --- a/elf/tunconf.h
> +++ b/elf/tunconf.h
> @@ -36,3 +36,6 @@ void parse_tunconf (const char *filename, char *opt_chroot);
> struct tunable_header_cached * get_tunconf_ext (uint32_t str_offset);
> #define TUNCONF_SIZE(thc_p) (sizeof(struct tunable_header_cached) \
> + thc_p->num_tunables * sizeof (struct tunable_entry_cached))
> +
> +extern const struct tunable_header_cached *
> +_dl_load_cache_tunables (const char **data);
> --
> 2.47.3
>
--
Arjun Shankar
he/him/his
More information about the Libc-alpha
mailing list