[3/3] Add system-wide tunables: Apply tunables part
Checks
Context |
Check |
Description |
linaro-tcwg-bot/tcwg_glibc_build--master-aarch64 |
success
|
Testing passed
|
linaro-tcwg-bot/tcwg_glibc_check--master-aarch64 |
fail
|
Testing failed
|
linaro-tcwg-bot/tcwg_glibc_build--master-arm |
success
|
Testing passed
|
linaro-tcwg-bot/tcwg_glibc_check--master-arm |
success
|
Testing passed
|
redhat-pt-bot/TryBot-apply_patch |
success
|
Patch applied to master at the time it was sent
|
redhat-pt-bot/TryBot-32bit |
fail
|
Patch caused testsuite regressions
|
Commit Message
Load ld.so.cache and fetch the tunables extension. Apply
those tunables to the current program. We do not yet apply
security policies.
---
elf/dl-cache.c | 24 +++++++++++++
elf/dl-tunables.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++
elf/tunconf.h | 3 ++
3 files changed, 112 insertions(+)
Comments
On 19/04/24 00:49, DJ Delorie wrote:
>
> Load ld.so.cache and fetch the tunables extension. Apply
> those tunables to the current program. We do not yet apply
> security policies.
So the idea is to have GLIBC_TUNABLES to override system-wide tunables
and later handle if the tunable can be override or not?
> ---
> elf/dl-cache.c | 24 +++++++++++++
> elf/dl-tunables.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++
> elf/tunconf.h | 3 ++
> 3 files changed, 112 insertions(+)
>
> diff --git a/elf/dl-cache.c b/elf/dl-cache.c
> index d90278889d..7ccb96d1ca 100644
> --- a/elf/dl-cache.c
> +++ b/elf/dl-cache.c
> @@ -28,6 +28,7 @@
> #include <dl-isa-level.h>
> #include <sys/types.h>
> #include <sys/stat.h>
> +#include "tunconf.h"
>
> #ifndef _DL_PLATFORMS_COUNT
> # define _DL_PLATFORMS_COUNT 0
> @@ -616,3 +617,26 @@ _dl_unload_cache (void)
> now. */
> }
> #endif
> +
> +const struct tunable_header_cached *
> +_dl_load_cache_tunables (const char **data)
> +{
> + struct cache_extension_all_loaded ext;
> +
> + /* This loads the cache (temporary). */
> + if (_dl_check_ldsocache_needs_loading ())
> + _dl_maybe_load_ldsocache ();
> +
> + if (cache_new && cache_new != (void *) -1)
> + *data = (const char *) cache_new;
> + else
> + *data = (const char *) &cache->libs[cache->nlibs];
> +
> + 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;
> + return ext.sections[cache_extension_tag_tunables].base;
> +}
> diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c
> index d3ccd2ecd4..5ecddccff6 100644
> --- a/elf/dl-tunables.c
> +++ b/elf/dl-tunables.c
> @@ -35,6 +35,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)
> @@ -264,6 +265,31 @@ parse_tunables (const char *valstring)
> tunables[i].t->name);
> }
>
> +/* We need this functionality before we load the real strcmp function. */
> +static int
> +dl_strcmp(const char *s1, const char *s2)
> +{
> + while (*s1 && *s2)
> + {
> + if (*s1 != *s2)
> + return *s1 - *s2;
> + ++s1;
> + ++s2;
> + }
> + return *s1 - *s2;
> +}
> +static int
> +dl_strlen(const char *s)
> +{
> + int len = 0;
> + while (*s)
> + {
> + ++s;
> + ++len;
> + }
> + return len;
> +}
> +
> /* Initialize the tunables list from the environment. For now we only use the
> ENV_ALIAS to find values. Later we will also use the tunable names to find
> values. */
> @@ -273,6 +299,65 @@ __tunables_init (char **envp)
> char *envname = NULL;
> char *envval = NULL;
> char **prev_envp = envp;
> + 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
> + || dl_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 (dl_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. */
> + tunable_list[tid].val.strval.str = __strdup (value);
> + tunable_list[tid].val.strval.len = strlen (value);
> + }
> + 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, dl_strlen(value));
> + }
> + }
> + }
> + }
>
> /* Ignore tunables for AT_SECURE programs. */
> if (__libc_enable_secure)
> diff --git a/elf/tunconf.h b/elf/tunconf.h
> index a6c5f0dd9a..623fb7546d 100644
> --- a/elf/tunconf.h
> +++ b/elf/tunconf.h
> @@ -38,3 +38,6 @@ void parse_tunconf (const char *filename, int do_chroot, 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);
Adhemerval Zanella Netto <adhemerval.zanella@linaro.org> writes:
> On 19/04/24 00:49, DJ Delorie wrote:
>>
>> Load ld.so.cache and fetch the tunables extension. Apply
>> those tunables to the current program. We do not yet apply
>> security policies.
>
> So the idea is to have GLIBC_TUNABLES to override system-wide tunables
> and later handle if the tunable can be override or not?
At the time GLIBC_TUNABLES is read, each tunable is either applied or
not depending on the policy. It will happen at startup, not "as tunable
values are used". This is similar to other security policies - tunables
are either parsed or not, but the code that uses the tunables values
doesn't have security code in it.
On 29/05/24 14:19, DJ Delorie wrote:
> Adhemerval Zanella Netto <adhemerval.zanella@linaro.org> writes:
>> On 19/04/24 00:49, DJ Delorie wrote:
>>>
>>> Load ld.so.cache and fetch the tunables extension. Apply
>>> those tunables to the current program. We do not yet apply
>>> security policies.
>>
>> So the idea is to have GLIBC_TUNABLES to override system-wide tunables
>> and later handle if the tunable can be override or not?
>
> At the time GLIBC_TUNABLES is read, each tunable is either applied or
> not depending on the policy. It will happen at startup, not "as tunable
> values are used". This is similar to other security policies - tunables
> are either parsed or not, but the code that uses the tunables values
> doesn't have security code in it.
>
So the idea would that on GLIBC_TUNABLES parsing, if a system-wide option
is already set it would depend whether the policy allow overriding? Or
would any GLIBC_TUNABLE would be ignore if a system-wide option is set?
@@ -28,6 +28,7 @@
#include <dl-isa-level.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include "tunconf.h"
#ifndef _DL_PLATFORMS_COUNT
# define _DL_PLATFORMS_COUNT 0
@@ -616,3 +617,26 @@ _dl_unload_cache (void)
now. */
}
#endif
+
+const struct tunable_header_cached *
+_dl_load_cache_tunables (const char **data)
+{
+ struct cache_extension_all_loaded ext;
+
+ /* This loads the cache (temporary). */
+ if (_dl_check_ldsocache_needs_loading ())
+ _dl_maybe_load_ldsocache ();
+
+ if (cache_new && cache_new != (void *) -1)
+ *data = (const char *) cache_new;
+ else
+ *data = (const char *) &cache->libs[cache->nlibs];
+
+ 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;
+ return ext.sections[cache_extension_tag_tunables].base;
+}
@@ -35,6 +35,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)
@@ -264,6 +265,31 @@ parse_tunables (const char *valstring)
tunables[i].t->name);
}
+/* We need this functionality before we load the real strcmp function. */
+static int
+dl_strcmp(const char *s1, const char *s2)
+{
+ while (*s1 && *s2)
+ {
+ if (*s1 != *s2)
+ return *s1 - *s2;
+ ++s1;
+ ++s2;
+ }
+ return *s1 - *s2;
+}
+static int
+dl_strlen(const char *s)
+{
+ int len = 0;
+ while (*s)
+ {
+ ++s;
+ ++len;
+ }
+ return len;
+}
+
/* Initialize the tunables list from the environment. For now we only use the
ENV_ALIAS to find values. Later we will also use the tunable names to find
values. */
@@ -273,6 +299,65 @@ __tunables_init (char **envp)
char *envname = NULL;
char *envval = NULL;
char **prev_envp = envp;
+ 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
+ || dl_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 (dl_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. */
+ tunable_list[tid].val.strval.str = __strdup (value);
+ tunable_list[tid].val.strval.len = strlen (value);
+ }
+ 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, dl_strlen(value));
+ }
+ }
+ }
+ }
/* Ignore tunables for AT_SECURE programs. */
if (__libc_enable_secure)
@@ -38,3 +38,6 @@ void parse_tunconf (const char *filename, int do_chroot, 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);