elf: Add glibc.mem.decorate_maps tunable

The PR_SET_VMA_ANON_NAME support is only enabled through a configurable
kernel switch, mainly because assigning a name to a
anonymous virtual memory area might prevent that area from being
merged with adjacent virtual memory areas.

For instance, with the following code:

   void *p1 = mmap (NULL,
                    1024 * 4096,
                    PROT_READ | PROT_WRITE,
                    MAP_PRIVATE | MAP_ANONYMOUS,
                    -1,
                    0);

   void *p2 = mmap (p1 + (1024 * 4096),
                    1024 * 4096,
                    PROT_READ | PROT_WRITE,
                    MAP_PRIVATE | MAP_ANONYMOUS,
                    -1,
                    0);

The kernel will potentially merge both mappings resulting in only one
segment of size 0x800000.  If the segment is names with
PR_SET_VMA_ANON_NAME with different names, it results in two mappings.

Although this will unlikely be an issue for pthread stacks and malloc
arenas (since for pthread stacks the guard page will result in
a PROT_NONE segment, similar to the alignment requirement for the arena
block), it still might prevent the mmap memory allocated for detail
malloc.

There is also another potential scalability issue, where the prctl
requires
to take the mmap global lock which is still not fully fixed in Linux
[1] (for pthread stacks and arenas, it is mitigated by the stack
cached and the arena reuse).

So this patch disables anonymous mapping annotations as default and
add a new tunable, glibc.mem.decorate_maps, can be used to enable
it.

[1] https://lwn.net/Articles/906852/

Checked on x86_64-linux-gnu and aarch64-linux-gnu.
Reviewed-by: DJ Delorie <dj@redhat.com>
This commit is contained in:
Adhemerval Zanella 2023-11-01 09:56:11 -03:00
parent f10ba2ab25
commit bf033c0072
5 changed files with 38 additions and 6 deletions

5
NEWS
View File

@ -38,6 +38,11 @@ Major new features:
and the wfN format length modifiers for arguments pointing to types
int_fastN_t or uint_fastN_t, as specified in draft ISO C2X.
* A new tunable, glibc.mem.decorate_maps, can be used to add additional
information on underlying memory allocated by the glibc (for instance,
on thread stack created by pthread_create or memory allocated by
malloc).
Deprecated and removed features, and other changes affecting compatibility:
* The ldconfig program now skips file names containing ';' or ending in

View File

@ -2985,5 +2985,5 @@ $(objpfx)tst-dlclose-lazy.out: \
$(objpfx)tst-decorate-maps: $(shared-thread-library)
tst-decorate-maps-ENV = \
GLIBC_TUNABLES=glibc.malloc.arena_max=8:glibc.malloc.mmap_threshold=1024
GLIBC_TUNABLES=glibc.malloc.arena_max=8:glibc.malloc.mmap_threshold=1024:glibc.mem.decorate_maps=1
tst-decorate-maps-ARGS = 8

View File

@ -160,6 +160,11 @@ glibc {
maxval: 255
security_level: SXID_IGNORE
}
decorate_maps {
type: INT_32
minval: 0
maxval: 1
}
}
rtld {

View File

@ -653,6 +653,23 @@ support in the kernel if this tunable has any non-zero value.
The default value is @samp{0}, which disables all memory tagging.
@end deftp
@deftp Tunable glibc.mem.decorate_maps
If the kernel supports naming anonymous virtual memory areas (since
Linux version 5.17, although not always enabled by some kernel
configurations), this tunable can be used to control whether
@theglibc{} decorates the underlying memory obtained from operating
system with a string describing its usage (for instance, on the thread
stack created by @code{ptthread_create} or memory allocated by
@code{malloc}).
The process mappings can be obtained by reading the @code{/proc/<pid>maps}
(with @code{pid} being either the @dfn{process ID} or @code{self} for the
process own mapping).
This tunable takes a value of 0 and 1, where 1 enables the feature.
The default value is @samp{0}, which disables the decoration.
@end deftp
@node gmon Tunables
@section gmon Tunables
@cindex gmon tunables

View File

@ -20,6 +20,7 @@
#include <setvmaname.h>
#include <sys/prctl.h>
#include <sysdep.h>
#include <elf/dl-tunables.h>
/* 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.
@ -34,11 +35,15 @@ __set_vma_name (void *start, size_t len, const char *name)
if (atomic_load_relaxed (&prctl_supported) == 0)
return;
int r = INTERNAL_SYSCALL_CALL (prctl, PR_SET_VMA, PR_SET_VMA_ANON_NAME,
start, len, name);
if (r == 0 || r != -EINVAL)
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)
{
int r = INTERNAL_SYSCALL_CALL (prctl, PR_SET_VMA, PR_SET_VMA_ANON_NAME,
start, len, name);
if (r == 0 || r != -EINVAL)
return;
}
atomic_store_relaxed (&prctl_supported, 0);
return;
}