b1dca6
commit 17796419b5fd694348cceb65c3f77601faae082c
b1dca6
Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
b1dca6
Date:   Tue Jul 7 10:49:11 2020 +0100
b1dca6
b1dca6
    rtld: Account static TLS surplus for audit modules
b1dca6
    
b1dca6
    The new static TLS surplus size computation is
b1dca6
    
b1dca6
      surplus_tls = 192 * (nns-1) + 144 * nns + 512
b1dca6
    
b1dca6
    where nns is controlled via the rtld.nns tunable. This commit
b1dca6
    accounts audit modules too so nns = rtld.nns + audit modules.
b1dca6
    
b1dca6
    rtld.nns should only include the namespaces required by the
b1dca6
    application, namespaces for audit modules are accounted on top
b1dca6
    of that so audit modules don't use up the static TLS that is
b1dca6
    reserved for the application. This allows loading many audit
b1dca6
    modules without tuning rtld.nns or using up static TLS, and it
b1dca6
    fixes
b1dca6
    
b1dca6
    FAIL: elf/tst-auditmany
b1dca6
    
b1dca6
    Note that DL_NNS is currently a hard upper limit for nns, and
b1dca6
    if rtld.nns + audit modules go over the limit that's a fatal
b1dca6
    error. By default rtld.nns is 4 which allows 12 audit modules.
b1dca6
    
b1dca6
    Counting the audit modules is based on existing audit string
b1dca6
    parsing code, we cannot use GLRO(dl_naudit) before the modules
b1dca6
    are actually loaded.
b1dca6
b1dca6
Conflicts:
b1dca6
	elf/rtld.c
b1dca6
	  (Caused by glibc-fedora-__libc_multiple_libcs.patch.)
b1dca6
b1dca6
diff --git a/csu/libc-tls.c b/csu/libc-tls.c
b1dca6
index 08ed2b988b58ac6c..6f2a47dc86222407 100644
b1dca6
--- a/csu/libc-tls.c
b1dca6
+++ b/csu/libc-tls.c
b1dca6
@@ -132,8 +132,8 @@ __libc_setup_tls (void)
b1dca6
 	  break;
b1dca6
 	}
b1dca6
 
b1dca6
-  /* Calculate the size of the static TLS surplus.  */
b1dca6
-  _dl_tls_static_surplus_init ();
b1dca6
+  /* Calculate the size of the static TLS surplus, with 0 auditors.  */
b1dca6
+  _dl_tls_static_surplus_init (0);
b1dca6
 
b1dca6
   /* We have to set up the TCB block which also (possibly) contains
b1dca6
      'errno'.  Therefore we avoid 'malloc' which might touch 'errno'.
b1dca6
diff --git a/elf/dl-tls.c b/elf/dl-tls.c
b1dca6
index ef57a21391bb36fa..cfda76f6de96df57 100644
b1dca6
--- a/elf/dl-tls.c
b1dca6
+++ b/elf/dl-tls.c
b1dca6
@@ -49,7 +49,10 @@
b1dca6
    that affects the size of the static TLS and by default it's small enough
b1dca6
    not to cause problems with existing applications. The limit is not
b1dca6
    enforced or checked: it is the user's responsibility to increase rtld.nns
b1dca6
-   if more dlmopen namespaces are used.  */
b1dca6
+   if more dlmopen namespaces are used.
b1dca6
+
b1dca6
+   Audit modules use their own namespaces, they are not included in rtld.nns,
b1dca6
+   but come on top when computing the number of namespaces.  */
b1dca6
 
b1dca6
 /* Size of initial-exec TLS in libc.so.  */
b1dca6
 #define LIBC_IE_TLS 192
b1dca6
@@ -60,8 +63,11 @@
b1dca6
 /* Size of additional surplus TLS, placeholder for TLS optimizations.  */
b1dca6
 #define OPT_SURPLUS_TLS 512
b1dca6
 
b1dca6
+/* Calculate the size of the static TLS surplus, when the given
b1dca6
+   number of audit modules are loaded.  Must be called after the
b1dca6
+   number of audit modules is known and before static TLS allocation.  */
b1dca6
 void
b1dca6
-_dl_tls_static_surplus_init (void)
b1dca6
+_dl_tls_static_surplus_init (size_t naudit)
b1dca6
 {
b1dca6
   size_t nns;
b1dca6
 
b1dca6
@@ -73,6 +79,11 @@ _dl_tls_static_surplus_init (void)
b1dca6
 #endif
b1dca6
   if (nns > DL_NNS)
b1dca6
     nns = DL_NNS;
b1dca6
+  if (DL_NNS - nns < naudit)
b1dca6
+    _dl_fatal_printf ("Failed loading %lu audit modules, %lu are supported.\n",
b1dca6
+		      (unsigned long) naudit, (unsigned long) (DL_NNS - nns));
b1dca6
+  nns += naudit;
b1dca6
+
b1dca6
   GLRO(dl_tls_static_surplus) = ((nns - 1) * LIBC_IE_TLS
b1dca6
 				 + nns * OTHER_IE_TLS
b1dca6
 				 + OPT_SURPLUS_TLS);
b1dca6
diff --git a/elf/rtld.c b/elf/rtld.c
b1dca6
index a440741f4c1b3c91..67441ac6f252350e 100644
b1dca6
--- a/elf/rtld.c
b1dca6
+++ b/elf/rtld.c
b1dca6
@@ -297,6 +297,23 @@ audit_list_next (struct audit_list *list)
b1dca6
     }
b1dca6
 }
b1dca6
 
b1dca6
+/* Count audit modules before they are loaded so GLRO(dl_naudit)
b1dca6
+   is not yet usable.  */
b1dca6
+static size_t
b1dca6
+audit_list_count (struct audit_list *list)
b1dca6
+{
b1dca6
+  /* Restore the audit_list iterator state at the end.  */
b1dca6
+  const char *saved_tail = list->current_tail;
b1dca6
+  size_t naudit = 0;
b1dca6
+
b1dca6
+  assert (list->current_index == 0);
b1dca6
+  while (audit_list_next (list) != NULL)
b1dca6
+    naudit++;
b1dca6
+  list->current_tail = saved_tail;
b1dca6
+  list->current_index = 0;
b1dca6
+  return naudit;
b1dca6
+}
b1dca6
+
b1dca6
 /* Set nonzero during loading and initialization of executable and
b1dca6
    libraries, cleared before the executable's entry point runs.  This
b1dca6
    must not be initialized to nonzero, because the unused dynamic
b1dca6
@@ -734,7 +751,7 @@ match_version (const char *string, struct link_map *map)
b1dca6
 static bool tls_init_tp_called;
b1dca6
 
b1dca6
 static void *
b1dca6
-init_tls (void)
b1dca6
+init_tls (size_t naudit)
b1dca6
 {
b1dca6
   /* Number of elements in the static TLS block.  */
b1dca6
   GL(dl_tls_static_nelem) = GL(dl_tls_max_dtv_idx);
b1dca6
@@ -777,7 +794,7 @@ init_tls (void)
b1dca6
   assert (i == GL(dl_tls_max_dtv_idx));
b1dca6
 
b1dca6
   /* Calculate the size of the static TLS surplus.  */
b1dca6
-  _dl_tls_static_surplus_init ();
b1dca6
+  _dl_tls_static_surplus_init (naudit);
b1dca6
 
b1dca6
   /* Compute the TLS offsets for the various blocks.  */
b1dca6
   _dl_determine_tlsoffset ();
b1dca6
@@ -1659,9 +1676,11 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
b1dca6
   bool need_security_init = true;
b1dca6
   if (audit_list.length > 0)
b1dca6
     {
b1dca6
+      size_t naudit = audit_list_count (&audit_list);
b1dca6
+
b1dca6
       /* Since we start using the auditing DSOs right away we need to
b1dca6
 	 initialize the data structures now.  */
b1dca6
-      tcbp = init_tls ();
b1dca6
+      tcbp = init_tls (naudit);
b1dca6
 
b1dca6
       /* Initialize security features.  We need to do it this early
b1dca6
 	 since otherwise the constructors of the audit libraries will
b1dca6
@@ -1671,6 +1690,10 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
b1dca6
       need_security_init = false;
b1dca6
 
b1dca6
       load_audit_modules (main_map, &audit_list);
b1dca6
+
b1dca6
+      /* The count based on audit strings may overestimate the number
b1dca6
+	 of audit modules that got loaded, but not underestimate.  */
b1dca6
+      assert (GLRO(dl_naudit) <= naudit);
b1dca6
     }
b1dca6
 
b1dca6
   /* Keep track of the currently loaded modules to count how many
b1dca6
@@ -1914,7 +1937,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
b1dca6
      multiple threads (from a non-TLS-using libpthread).  */
b1dca6
   bool was_tls_init_tp_called = tls_init_tp_called;
b1dca6
   if (tcbp == NULL)
b1dca6
-    tcbp = init_tls ();
b1dca6
+    tcbp = init_tls (0);
b1dca6
 
b1dca6
   if (__glibc_likely (need_security_init))
b1dca6
     /* Initialize security features.  But only if we have not done it
b1dca6
diff --git a/manual/tunables.texi b/manual/tunables.texi
b1dca6
index e092b8e81a18d739..e6a3e9a2cf5c959c 100644
b1dca6
--- a/manual/tunables.texi
b1dca6
+++ b/manual/tunables.texi
b1dca6
@@ -241,9 +241,12 @@ Sets the number of supported dynamic link namespaces (see @code{dlmopen}).
b1dca6
 Currently this limit can be set between 1 and 16 inclusive, the default is 4.
b1dca6
 Each link namespace consumes some memory in all thread, and thus raising the
b1dca6
 limit will increase the amount of memory each thread uses. Raising the limit
b1dca6
-is useful when your application uses more than 4 dynamic linker audit modules
b1dca6
-e.g. @env{LD_AUDIT}, or will use more than 4 dynamic link namespaces as created
b1dca6
-by @code{dlmopen} with an lmid argument of @code{LM_ID_NEWLM}.
b1dca6
+is useful when your application uses more than 4 dynamic link namespaces as
b1dca6
+created by @code{dlmopen} with an lmid argument of @code{LM_ID_NEWLM}.
b1dca6
+Dynamic linker audit modules are loaded in their own dynamic link namespaces,
b1dca6
+but they are not accounted for in @code{glibc.rtld.nns}.  They implicitly
b1dca6
+increase the per-thread memory usage as necessary, so this tunable does
b1dca6
+not need to be changed to allow many audit modules e.g. via @env{LD_AUDIT}.
b1dca6
 @end deftp
b1dca6
 
b1dca6
 @node Elision Tunables
b1dca6
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
b1dca6
index e54105848c3cb7d1..293f3ab5a496afdf 100644
b1dca6
--- a/sysdeps/generic/ldsodefs.h
b1dca6
+++ b/sysdeps/generic/ldsodefs.h
b1dca6
@@ -1104,8 +1104,9 @@ extern size_t _dl_count_modids (void) attribute_hidden;
b1dca6
 /* Calculate offset of the TLS blocks in the static TLS block.  */
b1dca6
 extern void _dl_determine_tlsoffset (void) attribute_hidden;
b1dca6
 
b1dca6
-/* Calculate the size of the static TLS surplus.  */
b1dca6
-void _dl_tls_static_surplus_init (void) attribute_hidden;
b1dca6
+/* Calculate the size of the static TLS surplus, when the given
b1dca6
+   number of audit modules are loaded.  */
b1dca6
+void _dl_tls_static_surplus_init (size_t naudit) attribute_hidden;
b1dca6
 
b1dca6
 #ifndef SHARED
b1dca6
 /* Set up the TCB for statically linked applications.  This is called