diff options
-rw-r--r-- | NEWS | 11 | ||||
-rw-r--r-- | malloc/memusage.c | 2 | ||||
-rw-r--r-- | manual/threads.texi | 8 | ||||
-rw-r--r-- | resolv/Makefile | 6 | ||||
-rw-r--r-- | resolv/res_send.c | 43 | ||||
-rw-r--r-- | resolv/resolv-internal.h | 2 | ||||
-rw-r--r-- | resolv/tst-resolv-semi-failure.c | 133 | ||||
-rw-r--r-- | resolv/tst-resolv-short-response.c | 124 | ||||
-rw-r--r-- | scripts/localplt.awk | 16 | ||||
-rw-r--r-- | stdlib/arc4random.c | 2 | ||||
-rw-r--r-- | stdlib/tst-swapcontext2.c | 4 | ||||
-rw-r--r-- | sysdeps/ieee754/ldbl-64-128/s_copysignl.c | 4 | ||||
-rw-r--r-- | sysdeps/ieee754/ldbl-64-128/s_frexpl.c | 4 | ||||
-rw-r--r-- | sysdeps/ieee754/ldbl-64-128/s_modfl.c | 4 | ||||
-rw-r--r-- | sysdeps/nptl/dl-tls_init_tp.c | 12 | ||||
-rw-r--r-- | sysdeps/s390/wcsncmp-vx.S | 10 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/Makefile | 4 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/____longjmp_chk.c | 2 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/dl-rseq-symbols.S | 64 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/rseq-internal.h | 23 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/tst-rseq.c | 10 |
21 files changed, 436 insertions, 52 deletions
@@ -7,6 +7,11 @@ using `glibc' in the "product" field. Version 2.39.1 +Deprecated and removed features, and other changes affecting compatibility: + +* __rseq_size now denotes the size of the active rseq area (20 bytes + initially), not the size of struct rseq (32 bytes initially). + Security related changes: The following CVEs were fixed in this release: @@ -32,6 +37,7 @@ The following CVEs were fixed in this release: The following bugs are resolved with this release: [19622] network: Support aliasing with struct sockaddr + [30081] resolv: Do not wait for non-existing second DNS response after error [30701] time: getutxent misbehaves on 32-bit x86 when _TIME_BITS=64 [30994] REP MOVSB performance suffers from page aliasing on Zen 4 [31339] libc: arm32 loader crash after cleanup in 2.36 @@ -49,7 +55,10 @@ The following bugs are resolved with this release: [31372] dynamic-link: _dl_tlsdesc_dynamic doesn't preserve all caller- saved registers [31429] build: Glibc failed to build with -march=x86-64-v3 + [31476] resolv: Track single-request fallback via _res._flags [31501] dynamic-link: _dl_tlsdesc_dynamic_xsavec may clobber %rbx + [31612] libc: arc4random fails to fallback to /dev/urandom if + getrandom is not present [31640] dynamic-link: POWER10 ld.so crashes in elf_machine_load_address with GCC 14 [31676] Configuring with CC="gcc -march=x86-64-v3" @@ -75,6 +84,8 @@ The following bugs are resolved with this release: CPUs [31883] build: ISA level support configure check relies on bashism / is otherwise broken for arithmetic + [31890] resolv: Allow short error responses to match any DNS query + [31965] rseq extension mechanism does not work as intended Version 2.39 diff --git a/malloc/memusage.c b/malloc/memusage.c index e8ae80d..f80225b 100644 --- a/malloc/memusage.c +++ b/malloc/memusage.c @@ -172,7 +172,7 @@ update_data (struct header *result, size_t len, size_t old_len) start_sp = __thread_stack_pointer (); uintptr_t sp = __thread_stack_pointer (); -#ifdef _STACK_GROWS_UP +#if _STACK_GROWS_UP /* This can happen in threads where we didn't catch the thread's stack early enough. */ if (__glibc_unlikely (sp < start_sp)) diff --git a/manual/threads.texi b/manual/threads.texi index e5544ff..25e99c9 100644 --- a/manual/threads.texi +++ b/manual/threads.texi @@ -1007,8 +1007,12 @@ This variable is either zero (if restartable sequence registration failed or has been disabled) or the size of the restartable sequence registration. This can be different from the size of @code{struct rseq} if the kernel has extended the size of the registration. If -registration is successful, @code{__rseq_size} is at least 32 (the -initial size of @code{struct rseq}). +registration is successful, @code{__rseq_size} is at least 20 (the +initially active size of @code{struct rseq}). + +Previous versions of @theglibc{} set this to 32 even if the kernel only +supported the initial area of 20 bytes because the value included unused +padding at the end of the restartable sequence area. @end deftypevar @deftypevar {unsigned int} __rseq_flags diff --git a/resolv/Makefile b/resolv/Makefile index 5f44f58..abff7fc 100644 --- a/resolv/Makefile +++ b/resolv/Makefile @@ -106,6 +106,8 @@ tests += \ tst-resolv-nondecimal \ tst-resolv-res_init-multi \ tst-resolv-search \ + tst-resolv-semi-failure \ + tst-resolv-short-response \ tst-resolv-trailing \ # This test calls __res_context_send directly, which is not exported @@ -299,6 +301,10 @@ $(objpfx)tst-resolv-nondecimal: $(objpfx)libresolv.so $(shared-thread-library) $(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library) $(objpfx)tst-resolv-rotate: $(objpfx)libresolv.so $(shared-thread-library) $(objpfx)tst-resolv-search: $(objpfx)libresolv.so $(shared-thread-library) +$(objpfx)tst-resolv-semi-failure: $(objpfx)libresolv.so \ + $(shared-thread-library) +$(objpfx)tst-resolv-short-response: $(objpfx)libresolv.so \ + $(shared-thread-library) $(objpfx)tst-resolv-trailing: $(objpfx)libresolv.so $(shared-thread-library) $(objpfx)tst-resolv-threads: $(objpfx)libresolv.so $(shared-thread-library) $(objpfx)tst-resolv-txnid-collision: $(objpfx)libresolv.a \ diff --git a/resolv/res_send.c b/resolv/res_send.c index fb02172..9c77613 100644 --- a/resolv/res_send.c +++ b/resolv/res_send.c @@ -947,9 +947,11 @@ send_dg(res_state statp, seconds /= statp->nscount; if (seconds <= 0) seconds = 1; - bool single_request_reopen = (statp->options & RES_SNGLKUPREOP) != 0; - bool single_request = (((statp->options & RES_SNGLKUP) != 0) - | single_request_reopen); + bool single_request_reopen = ((statp->options & RES_SNGLKUPREOP) + || (statp->_flags & RES_F_SNGLKUPREOP)); + bool single_request = ((statp->options & RES_SNGLKUP) + || (statp->_flags & RES_F_SNGLKUP) + || single_request_reopen); int save_gotsomewhere = *gotsomewhere; int retval; @@ -1006,14 +1008,14 @@ send_dg(res_state statp, have received the first answer. */ if (!single_request) { - statp->options |= RES_SNGLKUP; + statp->_flags |= RES_F_SNGLKUP; single_request = true; *gotsomewhere = save_gotsomewhere; goto retry; } else if (!single_request_reopen) { - statp->options |= RES_SNGLKUPREOP; + statp->_flags |= RES_F_SNGLKUPREOP; single_request_reopen = true; *gotsomewhere = save_gotsomewhere; __res_iclose (statp, false); @@ -1197,19 +1199,30 @@ send_dg(res_state statp, } /* Check for the correct header layout and a matching - question. */ + question. Some recursive resolvers send REFUSED + without copying back the question section + (producing a response that is only HFIXEDSZ bytes + long). Skip query matching in this case. */ + bool thisansp_error = (anhp->rcode == SERVFAIL || + anhp->rcode == NOTIMP || + anhp->rcode == REFUSED); + bool skip_query_match = (*thisresplenp == HFIXEDSZ + && ntohs (anhp->qdcount) == 0 + && thisansp_error); int matching_query = 0; /* Default to no matching query. */ if (!recvresp1 && anhp->id == hp->id - && __libc_res_queriesmatch (buf, buf + buflen, - *thisansp, - *thisansp + *thisanssizp)) + && (skip_query_match + || __libc_res_queriesmatch (buf, buf + buflen, + *thisansp, + *thisansp + *thisanssizp))) matching_query = 1; if (!recvresp2 && anhp->id == hp2->id - && __libc_res_queriesmatch (buf2, buf2 + buflen2, - *thisansp, - *thisansp + *thisanssizp)) + && (skip_query_match + || __libc_res_queriesmatch (buf2, buf2 + buflen2, + *thisansp, + *thisansp + *thisanssizp))) matching_query = 2; if (matching_query == 0) /* Spurious UDP packet. Drop it and continue @@ -1219,15 +1232,13 @@ send_dg(res_state statp, goto wait; } - if (anhp->rcode == SERVFAIL || - anhp->rcode == NOTIMP || - anhp->rcode == REFUSED) { + if (thisansp_error) { next_ns: if (recvresp1 || (buf2 != NULL && recvresp2)) { *resplen2 = 0; return resplen; } - if (buf2 != NULL) + if (buf2 != NULL && !single_request) { /* No data from the first reply. */ resplen = 0; diff --git a/resolv/resolv-internal.h b/resolv/resolv-internal.h index 24b164f..944af3e 100644 --- a/resolv/resolv-internal.h +++ b/resolv/resolv-internal.h @@ -26,6 +26,8 @@ #define RES_F_VC 0x00000001 /* Socket is TCP. */ #define RES_F_CONN 0x00000002 /* Socket is connected. */ #define RES_F_EDNS0ERR 0x00000004 /* EDNS0 caused errors. */ +#define RES_F_SNGLKUP 0x00200000 /* Private version of RES_SNGLKUP. */ +#define RES_F_SNGLKUPREOP 0x00400000 /* Private version of RES_SNGLKUPREOP. */ /* The structure HEADER is normally aligned on a word boundary. In some code, we need to access this structure when it may be aligned diff --git a/resolv/tst-resolv-semi-failure.c b/resolv/tst-resolv-semi-failure.c new file mode 100644 index 0000000..aa9798b --- /dev/null +++ b/resolv/tst-resolv-semi-failure.c @@ -0,0 +1,133 @@ +/* Test parallel failure/success responses (bug 30081). + Copyright (C) 2024 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <resolv.h> +#include <support/check.h> +#include <support/resolv_test.h> +#include <support/check_nss.h> + +/* The rcode in the initial response. */ +static volatile int rcode; + +/* Whether to fail the initial A query (!fail_aaaa) or the initial + AAAA query (fail_aaaa). */ +static volatile bool fail_aaaa; + +static void +response (const struct resolv_response_context *ctx, + struct resolv_response_builder *b, + const char *qname, uint16_t qclass, uint16_t qtype) +{ + /* Handle the failing query. */ + if ((fail_aaaa && qtype == T_AAAA) && ctx->server_index == 0) + { + struct resolv_response_flags flags = {.rcode = rcode}; + resolv_response_init (b, flags); + return; + } + + /* Otherwise produce a response. */ + resolv_response_init (b, (struct resolv_response_flags) {}); + resolv_response_add_question (b, qname, qclass, qtype); + resolv_response_section (b, ns_s_an); + resolv_response_open_record (b, qname, qclass, qtype, 0); + switch (qtype) + { + case T_A: + { + char ipv4[4] = {192, 0, 2, 17}; + resolv_response_add_data (b, &ipv4, sizeof (ipv4)); + } + break; + case T_AAAA: + { + char ipv6[16] + = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; + resolv_response_add_data (b, &ipv6, sizeof (ipv6)); + } + break; + default: + FAIL_EXIT1 ("unexpected TYPE%d query", qtype); + } + resolv_response_close_record (b); +} + +static void +check_one (void) +{ + + /* The buggy 1-second query timeout results in 30 seconds of delay, + which triggers are test timeout failure. */ + for (int i = 0; i < 30; ++i) + { + static const struct addrinfo hints = + { + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_STREAM, + }; + struct addrinfo *ai; + int ret = getaddrinfo ("www.example", "80", &hints, &ai); + const char *expected; + if (ret == 0 && ai->ai_next != NULL) + expected = ("address: STREAM/TCP 192.0.2.17 80\n" + "address: STREAM/TCP 2001:db8::1 80\n"); + else + /* Only one response because the AAAA lookup failure is + treated as an ignoreable error. */ + expected = "address: STREAM/TCP 192.0.2.17 80\n"; + check_addrinfo ("www.example", ai, ret, expected); + if (ret == 0) + freeaddrinfo (ai); + } +} + +static int +do_test (void) +{ + for (int do_single_lookup = 0; do_single_lookup < 2; ++do_single_lookup) + { + struct resolv_test *aux = resolv_test_start + ((struct resolv_redirect_config) + { + .response_callback = response, + }); + + if (do_single_lookup) + _res.options |= RES_SNGLKUP; + + for (int do_fail_aaaa = 0; do_fail_aaaa < 2; ++do_fail_aaaa) + { + fail_aaaa = do_fail_aaaa; + + rcode = 2; /* SERVFAIL. */ + check_one (); + + rcode = 4; /* NOTIMP. */ + check_one (); + + rcode = 5; /* REFUSED. */ + check_one (); + } + + resolv_test_end (aux); + } + + return 0; +} + +#include <support/test-driver.c> diff --git a/resolv/tst-resolv-short-response.c b/resolv/tst-resolv-short-response.c new file mode 100644 index 0000000..be354ae --- /dev/null +++ b/resolv/tst-resolv-short-response.c @@ -0,0 +1,124 @@ +/* Test for spurious timeouts with short 12-byte responses (bug 31890). + Copyright (C) 2024 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <resolv.h> +#include <support/check.h> +#include <support/resolv_test.h> +#include <support/check_nss.h> + +/* The rcode in the initial response. */ +static volatile int rcode; + +static void +response (const struct resolv_response_context *ctx, + struct resolv_response_builder *b, + const char *qname, uint16_t qclass, uint16_t qtype) +{ + switch (ctx->server_index) + { + case 0: + /* First server times out. */ + struct resolv_response_flags flags = {.rcode = rcode}; + resolv_response_init (b, flags); + break; + case 1: + /* Second server sends reply. */ + resolv_response_init (b, (struct resolv_response_flags) {}); + resolv_response_add_question (b, qname, qclass, qtype); + resolv_response_section (b, ns_s_an); + resolv_response_open_record (b, qname, qclass, qtype, 0); + switch (qtype) + { + case T_A: + { + char ipv4[4] = {192, 0, 2, 17}; + resolv_response_add_data (b, &ipv4, sizeof (ipv4)); + } + break; + case T_AAAA: + { + char ipv6[16] + = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; + resolv_response_add_data (b, &ipv6, sizeof (ipv6)); + } + break; + default: + FAIL_EXIT1 ("unexpected TYPE%d query", qtype); + } + resolv_response_close_record (b); + break; + default: + FAIL_EXIT1 ("unexpected query to server %d", ctx->server_index); + } +} + +static void +check_one (void) +{ + + /* The buggy 1-second query timeout results in 30 seconds of delay, + which triggers a test timeout failure. */ + for (int i = 0; i < 10; ++i) + { + check_hostent ("www.example", gethostbyname ("www.example"), + "name: www.example\n" + "address: 192.0.2.17\n"); + check_hostent ("www.example", gethostbyname2 ("www.example", AF_INET6), + "name: www.example\n" + "address: 2001:db8::1\n"); + static const struct addrinfo hints = + { + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_STREAM, + }; + struct addrinfo *ai; + int ret = getaddrinfo ("www.example", "80", &hints, &ai); + check_addrinfo ("www.example", ai, ret, + "address: STREAM/TCP 192.0.2.17 80\n" + "address: STREAM/TCP 2001:db8::1 80\n"); + if (ret == 0) + freeaddrinfo (ai); + } +} + +static int +do_test (void) +{ + struct resolv_test *aux = resolv_test_start + ((struct resolv_redirect_config) + { + .response_callback = response, + }); + + _res.options |= RES_SNGLKUP; + + rcode = 2; /* SERVFAIL. */ + check_one (); + + rcode = 4; /* NOTIMP. */ + check_one (); + + rcode = 5; /* REFUSED. */ + check_one (); + + resolv_test_end (aux); + + return 0; +} + +#include <support/test-driver.c> diff --git a/scripts/localplt.awk b/scripts/localplt.awk index fe79ca0..621ae7d 100644 --- a/scripts/localplt.awk +++ b/scripts/localplt.awk @@ -10,7 +10,8 @@ BEGIN { } FILENAME != lastfile { - if (lastfile && jmprel_offset == 0 && rela_offset == 0 && rel_offset == 0) { + if (lastfile && jmprel_offset == 0 && rela_offset == 0 && rel_offset == 0 \ + && relr_offset == 0) { print FILENAME ": *** failed to find expected output (readelf -WSdr)"; result = 2; } @@ -22,6 +23,7 @@ FILENAME != lastfile { jmprel_offset = 0; rela_offset = 0; rel_offset = 0; + relr_offset = 0; pltrelsz = -1; delete section_offset_by_address; } @@ -77,6 +79,8 @@ in_relocs && relocs_offset == rel_offset && NF >= 5 { } } +# No need to handle DT_RELR (all packed relocations are relative). + in_relocs { next } $1 == "Relocation" && $2 == "section" && $5 == "offset" { @@ -121,4 +125,14 @@ $2 == "(REL)" { } next } + +$2 == "(RELR)" { + relr_addr = strtonum($3); + if (relr_addr in section_offset_by_address) { + relr_offset = section_offset_by_address[relr_addr]; + } else { + print FILENAME ": *** DT_RELR does not match any section's address"; + result = 2; + } +} END { exit(result) } diff --git a/stdlib/arc4random.c b/stdlib/arc4random.c index 3ae8fc1..7818cb9 100644 --- a/stdlib/arc4random.c +++ b/stdlib/arc4random.c @@ -51,7 +51,7 @@ __arc4random_buf (void *p, size_t n) n -= l; continue; /* Interrupted by a signal; keep going. */ } - else if (l == -ENOSYS) + else if (l < 0 && errno == ENOSYS) break; /* No syscall, so fallback to /dev/urandom. */ arc4random_getrandom_failure (); } diff --git a/stdlib/tst-swapcontext2.c b/stdlib/tst-swapcontext2.c index f679755..a9c1dc8 100644 --- a/stdlib/tst-swapcontext2.c +++ b/stdlib/tst-swapcontext2.c @@ -85,7 +85,7 @@ do_test (void) { /* ____longjmp_chk has */ #if 0 -#ifdef _STACK_GROWS_DOWN +#if _STACK_GROWS_DOWN #define called_from(this, saved) ((this) < (saved)) #else #define called_from(this, saved) ((this) > (saved)) @@ -98,7 +98,7 @@ do_test (void) /* Arrange stacks for uctx_func1 and uctx_func2 so that called_from is true when setjmp is called from uctx_func1 and longjmp is called from uctx_func2. */ -#ifdef _STACK_GROWS_DOWN +#if _STACK_GROWS_DOWN # define UCTX_FUNC1_STACK 1 # define UCTX_FUNC2_STACK 0 #else diff --git a/sysdeps/ieee754/ldbl-64-128/s_copysignl.c b/sysdeps/ieee754/ldbl-64-128/s_copysignl.c index 11b42d0..8013784 100644 --- a/sysdeps/ieee754/ldbl-64-128/s_copysignl.c +++ b/sysdeps/ieee754/ldbl-64-128/s_copysignl.c @@ -1,10 +1,10 @@ #include <math_ldbl_opt.h> #include <libm-alias-ldouble.h> -#if IS_IN (libc) +#if IS_IN (libc) && defined SHARED # undef libm_alias_ldouble # define libm_alias_ldouble(from, to) #endif #include <sysdeps/ieee754/ldbl-128/s_copysignl.c> -#if IS_IN (libc) +#if IS_IN (libc) && defined SHARED long_double_symbol (libc, __copysignl, copysignl); #endif diff --git a/sysdeps/ieee754/ldbl-64-128/s_frexpl.c b/sysdeps/ieee754/ldbl-64-128/s_frexpl.c index 73ac41e..f5f7d34 100644 --- a/sysdeps/ieee754/ldbl-64-128/s_frexpl.c +++ b/sysdeps/ieee754/ldbl-64-128/s_frexpl.c @@ -1,10 +1,10 @@ #include <math_ldbl_opt.h> #include <libm-alias-ldouble.h> -#if IS_IN (libc) +#if IS_IN (libc) && defined SHARED # undef libm_alias_ldouble # define libm_alias_ldouble(from, to) #endif #include <sysdeps/ieee754/ldbl-128/s_frexpl.c> -#if IS_IN (libc) +#if IS_IN (libc) && defined SHARED long_double_symbol (libc, __frexpl, frexpl); #endif diff --git a/sysdeps/ieee754/ldbl-64-128/s_modfl.c b/sysdeps/ieee754/ldbl-64-128/s_modfl.c index 7d7aeae..ba3d313 100644 --- a/sysdeps/ieee754/ldbl-64-128/s_modfl.c +++ b/sysdeps/ieee754/ldbl-64-128/s_modfl.c @@ -1,10 +1,10 @@ #include <math_ldbl_opt.h> #include <libm-alias-ldouble.h> -#if IS_IN (libc) +#if IS_IN (libc) && defined SHARED # undef libm_alias_ldouble # define libm_alias_ldouble(from, to) #endif #include <sysdeps/ieee754/ldbl-128/s_modfl.c> -#if IS_IN (libc) +#if IS_IN (libc) && defined SHARED long_double_symbol (libc, __modfl, modfl); #endif diff --git a/sysdeps/nptl/dl-tls_init_tp.c b/sysdeps/nptl/dl-tls_init_tp.c index 092c274..7803e19 100644 --- a/sysdeps/nptl/dl-tls_init_tp.c +++ b/sysdeps/nptl/dl-tls_init_tp.c @@ -45,8 +45,6 @@ rtld_mutex_dummy (pthread_mutex_t *lock) #endif const unsigned int __rseq_flags; -const unsigned int __rseq_size attribute_relro; -const ptrdiff_t __rseq_offset attribute_relro; void __tls_pre_init_tp (void) @@ -104,12 +102,7 @@ __tls_init_tp (void) bool do_rseq = true; do_rseq = TUNABLE_GET (rseq, int, NULL); if (rseq_register_current_thread (pd, do_rseq)) - { - /* We need a writable view of the variables. They are in - .data.relro and are not yet write-protected. */ - extern unsigned int size __asm__ ("__rseq_size"); - size = sizeof (pd->rseq_area); - } + _rseq_size = RSEQ_AREA_SIZE_INITIAL_USED; #ifdef RSEQ_SIG /* This should be a compile-time constant, but the current @@ -117,8 +110,7 @@ __tls_init_tp (void) all targets support __thread_pointer, so set __rseq_offset only if the rseq registration may have happened because RSEQ_SIG is defined. */ - extern ptrdiff_t offset __asm__ ("__rseq_offset"); - offset = (char *) &pd->rseq_area - (char *) __thread_pointer (); + _rseq_offset = (char *) &pd->rseq_area - (char *) __thread_pointer (); #endif } diff --git a/sysdeps/s390/wcsncmp-vx.S b/sysdeps/s390/wcsncmp-vx.S index bf6dfa6..8b08156 100644 --- a/sysdeps/s390/wcsncmp-vx.S +++ b/sysdeps/s390/wcsncmp-vx.S @@ -59,14 +59,7 @@ ENTRY(WCSNCMP_Z13) sllg %r4,%r4,2 /* Convert character-count to byte-count. */ locgrne %r4,%r1 /* Use max byte-count, if bit 0/1 was one. */ - /* Check first character without vector load. */ - lghi %r5,4 /* current_len = 4 bytes. */ - /* Check s1/2[0]. */ - lt %r0,0(%r2) - l %r1,0(%r3) - je .Lend_cmp_one_char - crjne %r0,%r1,.Lend_cmp_one_char - + lghi %r5,0 /* current_len = 0 bytes. */ .Lloop: vlbb %v17,0(%r5,%r3),6 /* Load s2 to block boundary. */ vlbb %v16,0(%r5,%r2),6 /* Load s1 to block boundary. */ @@ -167,7 +160,6 @@ ENTRY(WCSNCMP_Z13) srl %r4,2 /* And convert it to character-index. */ vlgvf %r0,%v16,0(%r4) /* Load character-values. */ vlgvf %r1,%v17,0(%r4) -.Lend_cmp_one_char: cr %r0,%r1 je .Lend_equal lghi %r2,1 diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile index 415aa1f..6ab9b90 100644 --- a/sysdeps/unix/sysv/linux/Makefile +++ b/sysdeps/unix/sysv/linux/Makefile @@ -615,6 +615,10 @@ tests += \ endif ifeq ($(subdir),elf) +dl-routines += \ + dl-rseq-symbols \ + # dl-routines + sysdep-rtld-routines += \ dl-brk \ dl-getcwd \ diff --git a/sysdeps/unix/sysv/linux/____longjmp_chk.c b/sysdeps/unix/sysv/linux/____longjmp_chk.c index 0896dc5..3c66a46 100644 --- a/sysdeps/unix/sysv/linux/____longjmp_chk.c +++ b/sysdeps/unix/sysv/linux/____longjmp_chk.c @@ -23,7 +23,7 @@ #include <stdio.h> #include <stackinfo.h> -#ifdef _STACK_GROWS_DOWN +#if _STACK_GROWS_DOWN #define called_from(this, saved) ((this) < (saved)) #else #define called_from(this, saved) ((this) > (saved)) diff --git a/sysdeps/unix/sysv/linux/dl-rseq-symbols.S b/sysdeps/unix/sysv/linux/dl-rseq-symbols.S new file mode 100644 index 0000000..b4bba06 --- /dev/null +++ b/sysdeps/unix/sysv/linux/dl-rseq-symbols.S @@ -0,0 +1,64 @@ +/* Define symbols used by rseq. + Copyright (C) 2024 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <sysdep.h> + +#if __WORDSIZE == 64 +#define RSEQ_OFFSET_SIZE 8 +#else +#define RSEQ_OFFSET_SIZE 4 +#endif + +/* Some targets define a macro to denote the zero register. */ +#undef zero + +/* Define 2 symbols: '__rseq_size' is public const and '_rseq_size' (an + alias of '__rseq_size') is hidden and writable for internal use by the + dynamic linker which will initialize the value both symbols point to + before copy relocations take place. */ + + .globl __rseq_size + .type __rseq_size, %object + .size __rseq_size, 4 + .hidden _rseq_size + .globl _rseq_size + .type _rseq_size, %object + .size _rseq_size, 4 + .section .data.rel.ro + .balign 4 +__rseq_size: +_rseq_size: + .zero 4 + +/* Define 2 symbols: '__rseq_offset' is public const and '_rseq_offset' (an + alias of '__rseq_offset') is hidden and writable for internal use by the + dynamic linker which will initialize the value both symbols point to + before copy relocations take place. */ + + .globl __rseq_offset + .type __rseq_offset, %object + .size __rseq_offset, RSEQ_OFFSET_SIZE + .hidden _rseq_offset + .globl _rseq_offset + .type _rseq_offset, %object + .size _rseq_offset, RSEQ_OFFSET_SIZE + .section .data.rel.ro + .balign RSEQ_OFFSET_SIZE +__rseq_offset: +_rseq_offset: + .zero RSEQ_OFFSET_SIZE diff --git a/sysdeps/unix/sysv/linux/rseq-internal.h b/sysdeps/unix/sysv/linux/rseq-internal.h index 48eebc1..7ea935b 100644 --- a/sysdeps/unix/sysv/linux/rseq-internal.h +++ b/sysdeps/unix/sysv/linux/rseq-internal.h @@ -25,15 +25,34 @@ #include <stdio.h> #include <sys/rseq.h> +/* 32 is the initially required value for the area size. The + actually used rseq size may be less (20 bytes initially). */ +#define RSEQ_AREA_SIZE_INITIAL 32 +#define RSEQ_AREA_SIZE_INITIAL_USED 20 + +/* The variables are in .data.relro but are not yet write-protected. */ +extern unsigned int _rseq_size attribute_hidden; +extern ptrdiff_t _rseq_offset attribute_hidden; + #ifdef RSEQ_SIG static inline bool rseq_register_current_thread (struct pthread *self, bool do_rseq) { if (do_rseq) { + unsigned int size; +#if IS_IN (rtld) + /* Use the hidden symbol in ld.so. */ + size = _rseq_size; +#else + size = __rseq_size; +#endif + if (size < RSEQ_AREA_SIZE_INITIAL) + /* The initial implementation used only 20 bytes out of 32, + but still expected size 32. */ + size = RSEQ_AREA_SIZE_INITIAL; int ret = INTERNAL_SYSCALL_CALL (rseq, &self->rseq_area, - sizeof (self->rseq_area), - 0, RSEQ_SIG); + size, 0, RSEQ_SIG); if (!INTERNAL_SYSCALL_ERROR_P (ret)) return true; } diff --git a/sysdeps/unix/sysv/linux/tst-rseq.c b/sysdeps/unix/sysv/linux/tst-rseq.c index 2c90409..08a9533 100644 --- a/sysdeps/unix/sysv/linux/tst-rseq.c +++ b/sysdeps/unix/sysv/linux/tst-rseq.c @@ -29,6 +29,7 @@ # include <stdlib.h> # include <string.h> # include <syscall.h> +# include <sys/auxv.h> # include <thread_pointer.h> # include <tls.h> # include "tst-rseq.h" @@ -42,7 +43,8 @@ do_rseq_main_test (void) TEST_COMPARE (__rseq_flags, 0); TEST_VERIFY ((char *) __thread_pointer () + __rseq_offset == (char *) &pd->rseq_area); - TEST_COMPARE (__rseq_size, sizeof (pd->rseq_area)); + /* The current implementation only supports the initial size. */ + TEST_COMPARE (__rseq_size, 20); } static void @@ -52,6 +54,12 @@ do_rseq_test (void) { FAIL_UNSUPPORTED ("kernel does not support rseq, skipping test"); } + printf ("info: __rseq_size: %u\n", __rseq_size); + printf ("info: __rseq_offset: %td\n", __rseq_offset); + printf ("info: __rseq_flags: %u\n", __rseq_flags); + printf ("info: getauxval (AT_RSEQ_FEATURE_SIZE): %ld\n", + getauxval (AT_RSEQ_FEATURE_SIZE)); + printf ("info: getauxval (AT_RSEQ_ALIGN): %ld\n", getauxval (AT_RSEQ_ALIGN)); do_rseq_main_test (); } #else /* RSEQ_SIG */ |