summary refs log tree commit diff
path: root/misc
diff options
context:
space:
mode:
authorFlorian Weimer <fweimer@redhat.com>2020-12-16 15:09:52 +0100
committerFlorian Weimer <fweimer@redhat.com>2020-12-16 15:13:40 +0100
commite7570f4131a6af9405af7b4fd1c31de807e7cf68 (patch)
tree0f11050a7a1b768fb0d683dc60412bc2a101c3a5 /misc
parent9459fe9da0f981f77ba931790f82e43ac552b73c (diff)
downloadglibc-e7570f4131a6af9405af7b4fd1c31de807e7cf68.tar.gz
glibc-e7570f4131a6af9405af7b4fd1c31de807e7cf68.tar.xz
glibc-e7570f4131a6af9405af7b4fd1c31de807e7cf68.zip
Replace __libc_multiple_libcs with __libc_initial flag
Change sbrk to fail for !__libc_initial (in the generic
implementation).  As a result, sbrk is (relatively) safe to use
for the __libc_initial case (from the main libc).  It is therefore
no longer necessary to avoid using it in that case (or updating the
brk cache), and the __libc_initial flag does not need to be updated
as part of dlmopen or static dlopen.

As before, direct brk system calls on Linux may lead to memory
corruption.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
Diffstat (limited to 'misc')
-rw-r--r--misc/sbrk.c34
1 files changed, 24 insertions, 10 deletions
diff --git a/misc/sbrk.c b/misc/sbrk.c
index ba3322fba6..a6929d736d 100644
--- a/misc/sbrk.c
+++ b/misc/sbrk.c
@@ -16,9 +16,10 @@
    <https://www.gnu.org/licenses/>.  */
 
 #include <errno.h>
+#include <libc-internal.h>
+#include <stdbool.h>
 #include <stdint.h>
 #include <unistd.h>
-#include <libc-internal.h>
 
 /* Defined in brk.c.  */
 extern void *__curbrk;
@@ -30,21 +31,34 @@ extern int __brk (void *addr);
 void *
 __sbrk (intptr_t increment)
 {
-  void *oldbrk;
-
-  /* If this is not part of the dynamic library or the library is used
-     via dynamic loading in a statically linked program update
-     __curbrk from the kernel's brk value.  That way two separate
-     instances of __brk and __sbrk can share the heap, returning
-     interleaved pieces of it.  */
-  if (__curbrk == NULL || __libc_multiple_libcs)
+  /* Controls whether __brk (0) is called to read the brk value from
+     the kernel.  */
+  bool update_brk = __curbrk == NULL;
+
+#if defined (SHARED) && ! IS_IN (rtld)
+  if (!__libc_initial)
+    {
+      if (increment != 0)
+	{
+	  /* Do not allow changing the brk from an inner libc because
+	     it cannot be synchronized with the outer libc's brk.  */
+	  __set_errno (ENOMEM);
+	  return (void *) -1;
+	}
+      /* Querying the kernel's brk value from an inner namespace is
+	 fine.  */
+      update_brk = true;
+    }
+#endif
+
+  if (update_brk)
     if (__brk (0) < 0)		/* Initialize the break.  */
       return (void *) -1;
 
   if (increment == 0)
     return __curbrk;
 
-  oldbrk = __curbrk;
+  void *oldbrk = __curbrk;
   if (increment > 0
       ? ((uintptr_t) oldbrk + (uintptr_t) increment < (uintptr_t) oldbrk)
       : ((uintptr_t) oldbrk < (uintptr_t) -increment))