[PATCH 1/4] csu: randomize location of TCB
Topi Miettinen
toiwoton@gmail.com
Sun Nov 29 14:13:42 GMT 2020
On 28.11.2020 13.59, Topi Miettinen wrote:
> Use mmap() for allocating TCB except if instructed by tunable
> glibc.malloc.use_sbrk. This makes the location of TCB random instead
> of always staying predictably next to data segment. When using mmap(),
> improve the logic so that allocation of TCB can be assumed to fail
> insted of segfaulting.
insted -> instead
>
> --
> v2: introduce a tunable to use sbrk()
> v3:
> - refactor mmap() (Adhemerval Zanella)
> - rename mmap_internal to mmap_noerrno
> ---
> csu/libc-tls.c | 40 ++++++++++++++++----
> elf/dl-tunables.list | 7 ++++
> include/sys/mman.h | 5 +++
> manual/tunables.texi | 5 +++
> sysdeps/mach/hurd/dl-sysdep.c | 18 +++++++--
> sysdeps/unix/sysv/linux/mmap.c | 30 ++++++++++++---
> sysdeps/unix/sysv/linux/mmap64.c | 23 ++++++++---
> sysdeps/unix/sysv/linux/mmap_internal.h | 2 +-
> sysdeps/unix/sysv/linux/s390/mmap_internal.h | 2 +-
> 9 files changed, 109 insertions(+), 23 deletions(-)
>
> diff --git a/csu/libc-tls.c b/csu/libc-tls.c
> index c3589f0a7d..0cb6cb2e42 100644
> --- a/csu/libc-tls.c
> +++ b/csu/libc-tls.c
> @@ -25,11 +25,18 @@
> #include <sys/param.h>
> #include <array_length.h>
> #include <list.h>
> +#include <sys/mman.h>
> +#include <sysdep.h>
>
> #ifdef SHARED
> #error makefile bug, this file is for static only
> #endif
>
> +#if HAVE_TUNABLES
> +# define TUNABLE_NAMESPACE malloc
> +#endif
> +#include <elf/dl-tunables.h>
> +
> dtv_t _dl_static_dtv[2 + TLS_SLOTINFO_SURPLUS];
>
>
> @@ -135,26 +142,45 @@ __libc_setup_tls (void)
>
> /* We have to set up the TCB block which also (possibly) contains
> 'errno'. Therefore we avoid 'malloc' which might touch 'errno'.
> - Instead we use 'sbrk' which would only uses 'errno' if it fails.
> - In this case we are right away out of memory and the user gets
> - what she/he deserves. */
> + Instead we use '__mmap_noerrno' (when available) which does not
> + use 'errno', except if instructed by tunable
> + glibc.malloc.use_sbrk to use 'sbrk()' instead. If 'sbrk()' fails,
> + it will access 'errno' with catastrophic results. */
> +
> + size_t tlsblock_size;
> #if TLS_TCB_AT_TP
> /* Align the TCB offset to the maximum alignment, as
> _dl_allocate_tls_storage (in elf/dl-tls.c) does using __libc_memalign
> and dl_tls_static_align. */
> tcb_offset = roundup (memsz + GLRO(dl_tls_static_surplus), max_align);
> - tlsblock = __sbrk (tcb_offset + TLS_INIT_TCB_SIZE + max_align);
> + tlsblock_size = tcb_offset + TLS_INIT_TCB_SIZE + max_align;
> #elif TLS_DTV_AT_TP
> tcb_offset = roundup (TLS_INIT_TCB_SIZE, align ?: 1);
> - tlsblock = __sbrk (tcb_offset + memsz + max_align
> - + TLS_PRE_TCB_SIZE + GLRO(dl_tls_static_surplus));
> - tlsblock += TLS_PRE_TCB_SIZE;
> + tlsblock_size = tcb_offset + memsz + max_align
> + + TLS_PRE_TCB_SIZE + GLRO(dl_tls_static_surplus);
> #else
> /* In case a model with a different layout for the TCB and DTV
> is defined add another #elif here and in the following #ifs. */
> # error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
> #endif
>
> +#if HAVE_TUNABLES
> + if (!TUNABLE_GET (use_sbrk, int32_t, NULL))
> + {
> + int error = 0;
> + tlsblock = __mmap_noerrno (NULL, tlsblock_size, PROT_READ | PROT_WRITE,
Forgot to add ALIGN_UP (tlsblock_size, GLRO(dl_pagesize)).
> + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0, &error);
> + if (error || tlsblock == MAP_FAILED)
> + _startup_fatal ("Cannot allocate TCB");
> + }
> + else
> +#endif
> + tlsblock = __sbrk (tlsblock_size);
> +
> +#if TLS_DTV_AT_TP
> + tlsblock += TLS_PRE_TCB_SIZE;
> +#endif
> +
> /* Align the TLS block. */
> tlsblock = (void *) (((uintptr_t) tlsblock + max_align - 1)
> & ~(max_align - 1));
This probably is not necessary for the mmap() case since it returns page
aligned pointers, except if the addition above tlsblock +=
TLS_PRE_TCB_SIZE makes the alignment worse than needed.
> diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list
> index e1d8225128..777ebee788 100644
> --- a/elf/dl-tunables.list
> +++ b/elf/dl-tunables.list
> @@ -91,6 +91,13 @@ glibc {
> minval: 0
> security_level: SXID_IGNORE
> }
> + use_sbrk {
> + type: INT_32
> + minval: 0
> + maxval: 1
> + default: 0
> + security_level: SXID_IGNORE
> + }
> }
> cpu {
> hwcap_mask {
> diff --git a/include/sys/mman.h b/include/sys/mman.h
> index 503edaae88..d2fc5608c3 100644
> --- a/include/sys/mman.h
> +++ b/include/sys/mman.h
> @@ -22,6 +22,11 @@ extern void *__mremap (void *__addr, size_t __old_len,
> size_t __new_len, int __flags, ...);
> libc_hidden_proto (__mremap)
>
> +/* Internal version of mmap() which doesn't attempt to access errno */
> +extern void *__mmap_noerrno (void *addr, size_t len, int prot, int flags,
> + int fd, off_t offset, int *err);
> +libc_hidden_proto (__mmap_noerrno)
> +
> # if IS_IN (rtld)
> # include <dl-mman.h>
> # endif
> diff --git a/manual/tunables.texi b/manual/tunables.texi
> index d72d7a5ec0..46132900e3 100644
> --- a/manual/tunables.texi
> +++ b/manual/tunables.texi
> @@ -227,6 +227,11 @@ pointer, so add 4 on 32-bit systems or 8 on 64-bit systems to the size
> passed to @code{malloc} for the largest bin size to enable.
> @end deftp
>
> +@deftp Tunable glibc.malloc.use_sbrk
> +A value of 1 instructs @theglibc{} to use @code{sbrk()} for memory
> +allocation instead of @code{mmap()}.
> +@end deftp
> +
> @node Dynamic Linking Tunables
> @section Dynamic Linking Tunables
> @cindex dynamic linking tunables
> diff --git a/sysdeps/mach/hurd/dl-sysdep.c b/sysdeps/mach/hurd/dl-sysdep.c
> index 370495710e..40e2919b9d 100644
> --- a/sysdeps/mach/hurd/dl-sysdep.c
> +++ b/sysdeps/mach/hurd/dl-sysdep.c
> @@ -482,9 +482,9 @@ __libc_lseek64 (int fd, off64_t offset, int whence)
> return offset;
> }
>
> -check_no_hidden(__mmap);
> +check_no_hidden(__mmap_noerrno);
> void *weak_function
> -__mmap (void *addr, size_t len, int prot, int flags, int fd, off_t offset)
> +__mmap_noerrno (void *addr, size_t len, int prot, int flags, int fd, off_t offset, int *error)
> {
> error_t err;
> vm_prot_t vmprot;
> @@ -541,10 +541,22 @@ __mmap (void *addr, size_t len, int prot, int flags, int fd, off_t offset)
> __mach_port_deallocate (__mach_task_self (), memobj_rd);
>
> if (err)
> - return __hurd_fail (err), MAP_FAILED;
> + *error = err;
> return (void *) mapaddr;
> }
>
> +check_no_hidden(__mmap);
> +void *weak_function
> +__mmap (void *addr, size_t len, int prot, int flags, int fd, off_t offset)
> +{
> + int err = 0;
> +
> + void *r = __mmap_noerrno (addr, len, prot, flags, fd, offset, &err);
> + if (err)
> + return __hurd_fail (err), MAP_FAILED;
> + return r;
> +}
> +
> check_no_hidden(__fstat64);
> int weak_function
> __fstat64 (int fd, struct stat64 *buf)
> diff --git a/sysdeps/unix/sysv/linux/mmap.c b/sysdeps/unix/sysv/linux/mmap.c
> index 22f276bb14..19eca3fe18 100644
> --- a/sysdeps/unix/sysv/linux/mmap.c
> +++ b/sysdeps/unix/sysv/linux/mmap.c
> @@ -31,20 +31,38 @@
> # endif
>
> void *
> -__mmap (void *addr, size_t len, int prot, int flags, int fd, off_t offset)
> +__mmap_noerrno (void *addr, size_t len, int prot, int flags, int fd, off_t offset, int *err)
> {
> MMAP_CHECK_PAGE_UNIT ();
>
> if (offset & MMAP_OFF_LOW_MASK)
> - return (void *) INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
> + return (void *) -EINVAL;
>
> #ifdef __NR_mmap2
> - return (void *) MMAP_CALL (mmap2, addr, len, prot, flags, fd,
> - offset / (uint32_t) MMAP2_PAGE_UNIT);
> + long int r = MMAP_CALL (mmap2, addr, len, prot, flags, fd,
> + offset / (uint32_t) MMAP2_PAGE_UNIT);
> #else
> - return (void *) MMAP_CALL (mmap, addr, len, prot, flags, fd,
> - MMAP_ADJUST_OFFSET (offset));
> + long int r = MMAP_CALL (mmap, addr, len, prot, flags, fd,
> + MMAP_ADJUST_OFFSET (offset));
> #endif
> + if (INTERNAL_SYSCALL_ERROR_P (r))
> + {
> + *err = (INTERNAL_SYSCALL_ERRNO (r));
> + return MAP_FAILED;
> + }
> + return (void*) r;
> +}
> +libc_hidden_def (__mmap_noerrno)
> +
> +void *
> +__mmap (void *addr, size_t len, int prot, int flags, int fd, off_t offset)
> +{
> + int error = 0;
> +
> + void *r = __mmap_noerrno (addr, len, prot, flags, fd, offset, &error);
> + if (error)
> + __set_errno(error);
I suppose errno should be cleared if there's no error, so remove the check.
-Topi
> + return r;
> }
> weak_alias (__mmap, mmap)
> libc_hidden_def (__mmap)
> diff --git a/sysdeps/unix/sysv/linux/mmap64.c b/sysdeps/unix/sysv/linux/mmap64.c
> index 8074deb466..3d6557734b 100644
> --- a/sysdeps/unix/sysv/linux/mmap64.c
> +++ b/sysdeps/unix/sysv/linux/mmap64.c
> @@ -44,25 +44,38 @@
> #endif
>
> void *
> -__mmap64 (void *addr, size_t len, int prot, int flags, int fd, off64_t offset)
> +__mmap64_noerrno (void *addr, size_t len, int prot, int flags, int fd, off64_t offset, int *err)
> {
> MMAP_CHECK_PAGE_UNIT ();
>
> if (offset & MMAP_OFF_MASK)
> - return (void *) INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
> + return (void *) -EINVAL;
>
> MMAP_PREPARE (addr, len, prot, flags, fd, offset);
> #ifdef __NR_mmap2
> - return (void *) MMAP_CALL (mmap2, addr, len, prot, flags, fd,
> - (off_t) (offset / MMAP2_PAGE_UNIT));
> + long int r = MMAP_CALL (mmap2, addr, len, prot, flags, fd,
> + (off_t) (offset / MMAP2_PAGE_UNIT));
> #else
> - return (void *) MMAP_CALL (mmap, addr, len, prot, flags, fd, offset);
> + long int r = MMAP_CALL (mmap, addr, len, prot, flags, fd, offset);
> #endif
> + if (INTERNAL_SYSCALL_ERROR_P (r))
> + {
> + *err = INTERNAL_SYSCALL_ERRNO (r);
> + return MAP_FAILED;
> + }
> + return (void *) r;
> +}
> +
> +void *
> +__mmap64 (void *addr, size_t len, int prot, int flags, int fd, off64_t offset)
> +{
> + return __mmap64_noerrno (addr, len, prot, flags, fd, offset, &errno);
> }
> weak_alias (__mmap64, mmap64)
> libc_hidden_def (__mmap64)
>
> #ifdef __OFF_T_MATCHES_OFF64_T
> +weak_alias (__mmap64_noerrno, __mmap_noerrno)
> weak_alias (__mmap64, mmap)
> weak_alias (__mmap64, __mmap)
> libc_hidden_def (__mmap)
> diff --git a/sysdeps/unix/sysv/linux/mmap_internal.h b/sysdeps/unix/sysv/linux/mmap_internal.h
> index d53f0c642a..5386b5eb63 100644
> --- a/sysdeps/unix/sysv/linux/mmap_internal.h
> +++ b/sysdeps/unix/sysv/linux/mmap_internal.h
> @@ -43,7 +43,7 @@ static uint64_t page_unit;
> /* An architecture may override this. */
> #ifndef MMAP_CALL
> # define MMAP_CALL(__nr, __addr, __len, __prot, __flags, __fd, __offset) \
> - INLINE_SYSCALL_CALL (__nr, __addr, __len, __prot, __flags, __fd, __offset)
> + INTERNAL_SYSCALL_CALL (__nr, __addr, __len, __prot, __flags, __fd, __offset)
> #endif
>
> #endif /* MMAP_INTERNAL_LINUX_H */
> diff --git a/sysdeps/unix/sysv/linux/s390/mmap_internal.h b/sysdeps/unix/sysv/linux/s390/mmap_internal.h
> index 2884f2844b..d2289f311c 100644
> --- a/sysdeps/unix/sysv/linux/s390/mmap_internal.h
> +++ b/sysdeps/unix/sysv/linux/s390/mmap_internal.h
> @@ -24,7 +24,7 @@
> long int __args[6] = { (long int) (__addr), (long int) (__len), \
> (long int) (__prot), (long int) (__flags), \
> (long int) (__fd), (long int) (__offset) }; \
> - INLINE_SYSCALL_CALL (__nr, __args); \
> + INTERNAL_SYSCALL_CALL (__nr, __args); \
> })
>
> #include_next <mmap_internal.h>
>
More information about the Libc-alpha
mailing list