diff --git a/elf/dl-map-segments.h b/elf/dl-map-segments.h index 203b6c7b0b..ee68dda550 100644 --- a/elf/dl-map-segments.h +++ b/elf/dl-map-segments.h @@ -18,6 +18,7 @@ . */ #include +#include /* Map a segment and align it properly. */ @@ -182,12 +183,41 @@ _dl_map_segments (struct link_map *l, int fd, if (zeroend > zeropage) { /* Map the remaining zero pages in from the zero fill FD. */ + char bssname[ANON_VMA_NAME_MAX_LEN] = " glibc: .bss"; + caddr_t mapat; mapat = __mmap ((caddr_t) zeropage, zeroend - zeropage, c->prot, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0); if (__glibc_unlikely (mapat == MAP_FAILED)) return DL_MAP_SEGMENTS_ERROR_MAP_ZERO_FILL; + if (__is_decorate_maps_enabled ()) + { + if (l->l_name != NULL && *l->l_name != '\0') + { + int i = strlen (bssname), j = 0; + int namelen = strlen (l->l_name); + + bssname[i++] = ' '; + if (namelen > sizeof (bssname) - i - 1) + for (j = namelen - 1; j > 0; j--) + if (l->l_name[j - 1] == '/') + break; + + for (; l->l_name[j] != '\0' && i < sizeof (bssname) - 1; + i++, j++) + { + char ch = l->l_name[j]; + /* Replace non-printable characters and + \, `, $, [ and ]. */ + if (ch <= 0x1f || ch >= 0x7f || strchr("\\`$[]", ch)) + ch = '!'; + bssname[i] = ch; + } + bssname[i] = 0; + } + __set_vma_name ((void*)zeropage, zeroend - zeropage, bssname); + } } } diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c index cffcd3d421..800ca89720 100644 --- a/nptl/allocatestack.c +++ b/nptl/allocatestack.c @@ -638,10 +638,6 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp, return 0; } -/* Maximum supported name from initial kernel support, not exported - by user API. */ -#define ANON_VMA_NAME_MAX_LEN 80 - #define SET_STACK_NAME(__prefix, __stack, __stacksize, __tid) \ ({ \ char __stack_name[sizeof (__prefix) + \ diff --git a/sysdeps/generic/setvmaname.h b/sysdeps/generic/setvmaname.h index baca984a54..496fcca33b 100644 --- a/sysdeps/generic/setvmaname.h +++ b/sysdeps/generic/setvmaname.h @@ -19,6 +19,18 @@ #ifndef __SETVMANAME_H #define __SETVMANAME_H +#include + +/* Set this to small value to not waste memory on systems, which do + * not support VMA name. */ +#define ANON_VMA_NAME_MAX_LEN 16 + +static inline bool +__is_decorate_maps_enabled (void) +{ + return false; +} + static inline void __set_vma_name (void *start, size_t len, const char *name) { diff --git a/sysdeps/unix/sysv/linux/setvmaname.c b/sysdeps/unix/sysv/linux/setvmaname.c index 749c587f12..ea93a5ffbe 100644 --- a/sysdeps/unix/sysv/linux/setvmaname.c +++ b/sysdeps/unix/sysv/linux/setvmaname.c @@ -22,6 +22,33 @@ #include #include +static enum { + decorate_unknown = -1, + decorate_off, + decorate_on +} decorate_maps = decorate_unknown; + +bool +__is_decorate_maps_enabled (void) +{ + switch (atomic_load_relaxed (&decorate_maps)) + { + case decorate_unknown: + if (TUNABLE_GET (glibc, mem, decorate_maps, int32_t, NULL) != 0) + { + atomic_store_relaxed (&decorate_maps, decorate_on); + return true; + } + atomic_store_relaxed (&decorate_maps, decorate_off); + return false; + case decorate_off: + return false; + case decorate_on: + return true; + } + __builtin_unreachable (); +} + /* If PR_SET_VMA_ANON_NAME is not supported by the kernel, prctl returns EINVAL. However, it also returns the same error for invalid argument. Since it is an internal-only API, it assumes well formatted input: @@ -31,19 +58,13 @@ void __set_vma_name (void *start, size_t len, const char *name) { - static int prctl_supported = 1; - if (atomic_load_relaxed (&prctl_supported) == 0) - return; - - /* Set the prctl as not supported to avoid checking the tunable on every - call. */ - if (TUNABLE_GET (glibc, mem, decorate_maps, int32_t, NULL) != 0) + if (__is_decorate_maps_enabled ()) { int r = INTERNAL_SYSCALL_CALL (prctl, PR_SET_VMA, PR_SET_VMA_ANON_NAME, - start, len, name); - if (r == 0 || r != -EINVAL) - return; + start, len, name); + + /* Disable further attempts if not supported by the kernel. */ + if (r == -EINVAL) + atomic_store_relaxed (&decorate_maps, decorate_off); } - atomic_store_relaxed (&prctl_supported, 0); - return; } diff --git a/sysdeps/unix/sysv/linux/setvmaname.h b/sysdeps/unix/sysv/linux/setvmaname.h index 715b096799..48643d0dad 100644 --- a/sysdeps/unix/sysv/linux/setvmaname.h +++ b/sysdeps/unix/sysv/linux/setvmaname.h @@ -19,9 +19,17 @@ #ifndef __SETVMANAME_H #define __SETVMANAME_H +/* Maximum supported name from initial kernel support, not exported + by user API. */ +#define ANON_VMA_NAME_MAX_LEN 80 + /* Set the NAME to the anonymous memory map START with size of LEN. It assumes well-formatted input. */ #if IS_IN(libc) || IS_IN(rtld) +#include + +bool __is_decorate_maps_enabled (void) attribute_hidden; + void __set_vma_name (void *start, size_t len, const char *name) attribute_hidden; #else