diff mbox series

[3/3] Add system-wide tunables: Apply tunables part

Message ID xna5lq2er9.fsf@greed.delorie.com
State New
Headers show
Series [1/3] Add system-wide tunables: ldconfig part | expand

Commit Message

DJ Delorie April 19, 2024, 3:49 a.m. UTC
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

Adhemerval Zanella Netto May 29, 2024, 1:18 p.m. UTC | #1
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);
diff mbox series

Patch

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);