From ffa0667ada1101ba8fb9f7f6ec0739681463c375 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Tue, 21 Jan 2020 14:14:46 -0500 Subject: [PATCH] import glibc-2.28-100.el8 --- SOURCES/glibc-rh1361965.patch | 49 ++ SOURCES/glibc-rh1410154-1.patch | 185 +++++ SOURCES/glibc-rh1410154-10.patch | 42 + SOURCES/glibc-rh1410154-11.patch | 27 + SOURCES/glibc-rh1410154-12.patch | 1229 ++++++++++++++++++++++++++++++ SOURCES/glibc-rh1410154-13.patch | 328 ++++++++ SOURCES/glibc-rh1410154-14.patch | 134 ++++ SOURCES/glibc-rh1410154-2.patch | 33 + SOURCES/glibc-rh1410154-3.patch | 54 ++ SOURCES/glibc-rh1410154-4.patch | 42 + SOURCES/glibc-rh1410154-5.patch | 343 +++++++++ SOURCES/glibc-rh1410154-6.patch | 308 ++++++++ SOURCES/glibc-rh1410154-7.patch | 490 ++++++++++++ SOURCES/glibc-rh1410154-8.patch | 619 +++++++++++++++ SOURCES/glibc-rh1410154-9.patch | 104 +++ SOURCES/glibc-rh1682954.patch | 545 +++++++++++++ SOURCES/glibc-rh1717438.patch | 71 ++ SOURCES/glibc-rh1722215.patch | 186 +++++ SOURCES/glibc-rh1724975.patch | 1013 ++++++++++++++++++++++++ SOURCES/glibc-rh1726638-1.patch | 35 + SOURCES/glibc-rh1726638-2.patch | 138 ++++ SOURCES/glibc-rh1726638-3.patch | 49 ++ SOURCES/glibc-rh1727152.patch | 22 + SOURCES/glibc-rh1727241-1.patch | 221 ++++++ SOURCES/glibc-rh1727241-2.patch | 80 ++ SOURCES/glibc-rh1727241-3.patch | 698 +++++++++++++++++ SOURCES/glibc-rh1735747-1.patch | 25 + SOURCES/glibc-rh1735747-2.patch | 35 + SOURCES/glibc-rh1746928.patch | 117 +++ SOURCES/glibc-rh1746933-1.patch | 60 ++ SOURCES/glibc-rh1746933-2.patch | 37 + SOURCES/glibc-rh1746933-3.patch | 92 +++ SOURCES/glibc-rh1747453.patch | 156 ++++ SOURCES/glibc-rh1747502-1.patch | 168 ++++ SOURCES/glibc-rh1747502-2.patch | 48 ++ SOURCES/glibc-rh1747502-3.patch | 40 + SOURCES/glibc-rh1747502-4.patch | 31 + SOURCES/glibc-rh1747502-5.patch | 56 ++ SOURCES/glibc-rh1747502-6.patch | 56 ++ SOURCES/glibc-rh1747502-7.patch | 46 ++ SOURCES/glibc-rh1747502-8.patch | 50 ++ SOURCES/glibc-rh1747502-9.patch | 86 +++ SOURCES/glibc-rh1747502.patch | 268 +++++++ SOURCES/glibc-rh1747505-1.patch | 196 +++++ SOURCES/glibc-rh1747505-2.patch | 38 + SOURCES/glibc-rh1747505-3.patch | 40 + SOURCES/glibc-rh1747505-4.patch | 27 + SOURCES/glibc-rh1749439-1.patch | 512 +++++++++++++ SOURCES/glibc-rh1749439-10.patch | 389 ++++++++++ SOURCES/glibc-rh1749439-11.patch | 138 ++++ SOURCES/glibc-rh1749439-12.patch | 114 +++ SOURCES/glibc-rh1749439-13.patch | 307 ++++++++ SOURCES/glibc-rh1749439-2.patch | 676 ++++++++++++++++ SOURCES/glibc-rh1749439-3.patch | 260 +++++++ SOURCES/glibc-rh1749439-4.patch | 155 ++++ SOURCES/glibc-rh1749439-5.patch | 33 + SOURCES/glibc-rh1749439-6.patch | 204 +++++ SOURCES/glibc-rh1749439-7.patch | 309 ++++++++ SOURCES/glibc-rh1749439-8.patch | 86 +++ SOURCES/glibc-rh1749439-9.patch | 26 + SOURCES/glibc-rh1764214.patch | 305 ++++++++ SOURCES/glibc-rh1764218-1.patch | 192 +++++ SOURCES/glibc-rh1764218-2.patch | 72 ++ SOURCES/glibc-rh1764218-3.patch | 31 + SOURCES/glibc-rh1764223.patch | 142 ++++ SOURCES/glibc-rh1764226-1.patch | 82 ++ SOURCES/glibc-rh1764226-2.patch | 159 ++++ SOURCES/glibc-rh1764226-3.patch | 112 +++ SOURCES/glibc-rh1764231-1.patch | 49 ++ SOURCES/glibc-rh1764231-2.patch | 342 +++++++++ SOURCES/glibc-rh1764234-1.patch | 40 + SOURCES/glibc-rh1764234-2.patch | 43 ++ SOURCES/glibc-rh1764234-3.patch | 181 +++++ SOURCES/glibc-rh1764234-4.patch | 58 ++ SOURCES/glibc-rh1764234-5.patch | 30 + SOURCES/glibc-rh1764234-6.patch | 52 ++ SOURCES/glibc-rh1764234-7.patch | 24 + SOURCES/glibc-rh1764234-8.patch | 47 ++ SOURCES/glibc-rh1764235.patch | 165 ++++ SOURCES/glibc-rh1764238-1.patch | 92 +++ SOURCES/glibc-rh1764238-2.patch | 56 ++ SOURCES/glibc-rh1764241.patch | 544 +++++++++++++ SOURCES/glibc-rh1764242.patch | 81 ++ SOURCES/glibc-rh1769304.patch | 740 ++++++++++++++++++ SOURCES/glibc-rh1774021.patch | 24 + SOURCES/glibc-rh1775294.patch | 70 ++ SOURCES/glibc-rh1777241.patch | 88 +++ SOURCES/nsswitch.conf | 56 -- SPECS/glibc.spec | 213 +++++- 89 files changed, 15954 insertions(+), 62 deletions(-) create mode 100644 SOURCES/glibc-rh1361965.patch create mode 100644 SOURCES/glibc-rh1410154-1.patch create mode 100644 SOURCES/glibc-rh1410154-10.patch create mode 100644 SOURCES/glibc-rh1410154-11.patch create mode 100644 SOURCES/glibc-rh1410154-12.patch create mode 100644 SOURCES/glibc-rh1410154-13.patch create mode 100644 SOURCES/glibc-rh1410154-14.patch create mode 100644 SOURCES/glibc-rh1410154-2.patch create mode 100644 SOURCES/glibc-rh1410154-3.patch create mode 100644 SOURCES/glibc-rh1410154-4.patch create mode 100644 SOURCES/glibc-rh1410154-5.patch create mode 100644 SOURCES/glibc-rh1410154-6.patch create mode 100644 SOURCES/glibc-rh1410154-7.patch create mode 100644 SOURCES/glibc-rh1410154-8.patch create mode 100644 SOURCES/glibc-rh1410154-9.patch create mode 100644 SOURCES/glibc-rh1682954.patch create mode 100644 SOURCES/glibc-rh1717438.patch create mode 100644 SOURCES/glibc-rh1722215.patch create mode 100644 SOURCES/glibc-rh1724975.patch create mode 100644 SOURCES/glibc-rh1726638-1.patch create mode 100644 SOURCES/glibc-rh1726638-2.patch create mode 100644 SOURCES/glibc-rh1726638-3.patch create mode 100644 SOURCES/glibc-rh1727152.patch create mode 100644 SOURCES/glibc-rh1727241-1.patch create mode 100644 SOURCES/glibc-rh1727241-2.patch create mode 100644 SOURCES/glibc-rh1727241-3.patch create mode 100644 SOURCES/glibc-rh1735747-1.patch create mode 100644 SOURCES/glibc-rh1735747-2.patch create mode 100644 SOURCES/glibc-rh1746928.patch create mode 100644 SOURCES/glibc-rh1746933-1.patch create mode 100644 SOURCES/glibc-rh1746933-2.patch create mode 100644 SOURCES/glibc-rh1746933-3.patch create mode 100644 SOURCES/glibc-rh1747453.patch create mode 100644 SOURCES/glibc-rh1747502-1.patch create mode 100644 SOURCES/glibc-rh1747502-2.patch create mode 100644 SOURCES/glibc-rh1747502-3.patch create mode 100644 SOURCES/glibc-rh1747502-4.patch create mode 100644 SOURCES/glibc-rh1747502-5.patch create mode 100644 SOURCES/glibc-rh1747502-6.patch create mode 100644 SOURCES/glibc-rh1747502-7.patch create mode 100644 SOURCES/glibc-rh1747502-8.patch create mode 100644 SOURCES/glibc-rh1747502-9.patch create mode 100644 SOURCES/glibc-rh1747502.patch create mode 100644 SOURCES/glibc-rh1747505-1.patch create mode 100644 SOURCES/glibc-rh1747505-2.patch create mode 100644 SOURCES/glibc-rh1747505-3.patch create mode 100644 SOURCES/glibc-rh1747505-4.patch create mode 100644 SOURCES/glibc-rh1749439-1.patch create mode 100644 SOURCES/glibc-rh1749439-10.patch create mode 100644 SOURCES/glibc-rh1749439-11.patch create mode 100644 SOURCES/glibc-rh1749439-12.patch create mode 100644 SOURCES/glibc-rh1749439-13.patch create mode 100644 SOURCES/glibc-rh1749439-2.patch create mode 100644 SOURCES/glibc-rh1749439-3.patch create mode 100644 SOURCES/glibc-rh1749439-4.patch create mode 100644 SOURCES/glibc-rh1749439-5.patch create mode 100644 SOURCES/glibc-rh1749439-6.patch create mode 100644 SOURCES/glibc-rh1749439-7.patch create mode 100644 SOURCES/glibc-rh1749439-8.patch create mode 100644 SOURCES/glibc-rh1749439-9.patch create mode 100644 SOURCES/glibc-rh1764214.patch create mode 100644 SOURCES/glibc-rh1764218-1.patch create mode 100644 SOURCES/glibc-rh1764218-2.patch create mode 100644 SOURCES/glibc-rh1764218-3.patch create mode 100644 SOURCES/glibc-rh1764223.patch create mode 100644 SOURCES/glibc-rh1764226-1.patch create mode 100644 SOURCES/glibc-rh1764226-2.patch create mode 100644 SOURCES/glibc-rh1764226-3.patch create mode 100644 SOURCES/glibc-rh1764231-1.patch create mode 100644 SOURCES/glibc-rh1764231-2.patch create mode 100644 SOURCES/glibc-rh1764234-1.patch create mode 100644 SOURCES/glibc-rh1764234-2.patch create mode 100644 SOURCES/glibc-rh1764234-3.patch create mode 100644 SOURCES/glibc-rh1764234-4.patch create mode 100644 SOURCES/glibc-rh1764234-5.patch create mode 100644 SOURCES/glibc-rh1764234-6.patch create mode 100644 SOURCES/glibc-rh1764234-7.patch create mode 100644 SOURCES/glibc-rh1764234-8.patch create mode 100644 SOURCES/glibc-rh1764235.patch create mode 100644 SOURCES/glibc-rh1764238-1.patch create mode 100644 SOURCES/glibc-rh1764238-2.patch create mode 100644 SOURCES/glibc-rh1764241.patch create mode 100644 SOURCES/glibc-rh1764242.patch create mode 100644 SOURCES/glibc-rh1769304.patch create mode 100644 SOURCES/glibc-rh1774021.patch create mode 100644 SOURCES/glibc-rh1775294.patch create mode 100644 SOURCES/glibc-rh1777241.patch delete mode 100644 SOURCES/nsswitch.conf diff --git a/SOURCES/glibc-rh1361965.patch b/SOURCES/glibc-rh1361965.patch new file mode 100644 index 0000000..cfbf09c --- /dev/null +++ b/SOURCES/glibc-rh1361965.patch @@ -0,0 +1,49 @@ +Backport of this Fedora Rawhide commit but split out into a distinct +patch. + +commit 72195d44855ab96875f117acb75c37f98dcb26a9 +Author: Carlos O'Donell +Date: Thu Jun 6 23:58:21 2019 -0400 + + locale: Fix C.UTF-8 ranges. + + The ellipsis range support only allows or as + valid unicode code points, otherwise it treats it as a symbol and + since we don't define the symbol the entire range is unused. + +diff --git a/localedata/locales/C b/localedata/locales/C +index b2c2d1dc417cde69..30d9563213b8cb0f 100644 +--- a/localedata/locales/C ++++ b/localedata/locales/C +@@ -43,21 +43,21 @@ order_start forward + + .. + +- ++ + .. +- +- ++ ++ + .. +- +- ++ ++ + .. +- +- ++ ++ + .. +- +- ++ ++ + .. +- ++ + UNDEFINED + order_end + END LC_COLLATE diff --git a/SOURCES/glibc-rh1410154-1.patch b/SOURCES/glibc-rh1410154-1.patch new file mode 100644 index 0000000..6acd167 --- /dev/null +++ b/SOURCES/glibc-rh1410154-1.patch @@ -0,0 +1,185 @@ +commit 96cd0558bcd69481ccc42e1b392f0c0b36fce2b0 +Author: Florian Weimer +Date: Wed Nov 28 19:59:45 2018 +0100 + + support: Add signal support to support_capture_subprocess_check + + Signal zero does not terminate a process, so it is safe to use negative + values for signal numbers. + + Adjust libio/tst-vtables-common.c to use this new functionality, + instead of determining the termination status for a signal indirectly. + +diff --git a/libio/tst-vtables-common.c b/libio/tst-vtables-common.c +index 5e3101206919fa1b..85e246cd1131f8e8 100644 +--- a/libio/tst-vtables-common.c ++++ b/libio/tst-vtables-common.c +@@ -380,21 +380,6 @@ without_compatibility_fflush (void *closure) + _exit (1); + } + +-/* Exit status after abnormal termination. */ +-static int termination_status; +- +-static void +-init_termination_status (void) +-{ +- pid_t pid = xfork (); +- if (pid == 0) +- abort (); +- xwaitpid (pid, &termination_status, 0); +- +- TEST_VERIFY (WIFSIGNALED (termination_status)); +- TEST_COMPARE (WTERMSIG (termination_status), SIGABRT); +-} +- + static void + check_for_termination (const char *name, void (*callback) (void *)) + { +@@ -404,7 +389,7 @@ check_for_termination (const char *name, void (*callback) (void *)) + shared->calls = 0; + struct support_capture_subprocess proc + = support_capture_subprocess (callback, NULL); +- support_capture_subprocess_check (&proc, name, termination_status, ++ support_capture_subprocess_check (&proc, name, -SIGABRT, + sc_allow_stderr); + const char *message + = "Fatal error: glibc detected an invalid stdio handle\n"; +@@ -491,7 +476,6 @@ run_tests (bool initially_disabled) + + shared = support_shared_allocate (sizeof (*shared)); + shared->initially_disabled = initially_disabled; +- init_termination_status (); + + if (initially_disabled) + { +diff --git a/support/capture_subprocess.h b/support/capture_subprocess.h +index d5eac84d09ae325f..2d2384e73df0d2d0 100644 +--- a/support/capture_subprocess.h ++++ b/support/capture_subprocess.h +@@ -55,13 +55,16 @@ enum support_capture_allow + sc_allow_stderr = 0x04, + }; + +-/* Check that the subprocess exited with STATUS and that only the +- allowed outputs happened. ALLOWED is a combination of +- support_capture_allow flags. Report errors under the CONTEXT +- message. */ ++/* Check that the subprocess exited and that only the allowed outputs ++ happened. If STATUS_OR_SIGNAL is nonnegative, it is the expected ++ (decoded) exit status of the process, as returned by WEXITSTATUS. ++ If STATUS_OR_SIGNAL is negative, -STATUS_OR_SIGNAL is the expected ++ termination signal, as returned by WTERMSIG. ALLOWED is a ++ combination of support_capture_allow flags. Report errors under ++ the CONTEXT message. */ + void support_capture_subprocess_check (struct support_capture_subprocess *, +- const char *context, int status, +- int allowed) ++ const char *context, ++ int status_or_signal, int allowed) + __attribute__ ((nonnull (1, 2))); + + #endif /* SUPPORT_CAPTURE_SUBPROCESS_H */ +diff --git a/support/support_capture_subprocess_check.c b/support/support_capture_subprocess_check.c +index ff5ee89fb02599ae..8b4c352c96227b78 100644 +--- a/support/support_capture_subprocess_check.c ++++ b/support/support_capture_subprocess_check.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + + static void + print_context (const char *context, bool *failed) +@@ -31,9 +32,22 @@ print_context (const char *context, bool *failed) + printf ("error: subprocess failed: %s\n", context); + } + ++static void ++print_actual_status (struct support_capture_subprocess *proc) ++{ ++ if (WIFEXITED (proc->status)) ++ printf ("error: actual exit status: %d [0x%x]\n", ++ WEXITSTATUS (proc->status), proc->status); ++ else if (WIFSIGNALED (proc->status)) ++ printf ("error: actual termination signal: %d [0x%x]\n", ++ WTERMSIG (proc->status), proc->status); ++ else ++ printf ("error: actual undecoded exit status: [0x%x]\n", proc->status); ++} ++ + void + support_capture_subprocess_check (struct support_capture_subprocess *proc, +- const char *context, int status, ++ const char *context, int status_or_signal, + int allowed) + { + TEST_VERIFY ((allowed & sc_allow_none) +@@ -44,11 +58,28 @@ support_capture_subprocess_check (struct support_capture_subprocess *proc, + || (allowed & sc_allow_stderr)))); + + bool failed = false; +- if (proc->status != status) ++ if (status_or_signal >= 0) + { +- print_context (context, &failed); +- printf ("error: expected exit status: %d\n", status); +- printf ("error: actual exit status: %d\n", proc->status); ++ /* Expect regular termination. */ ++ if (!(WIFEXITED (proc->status) ++ && WEXITSTATUS (proc->status) == status_or_signal)) ++ { ++ print_context (context, &failed); ++ printf ("error: expected exit status: %d\n", status_or_signal); ++ print_actual_status (proc); ++ } ++ } ++ else ++ { ++ /* status_or_signal < 0. Expect termination by signal. */ ++ if (!(WIFSIGNALED (proc->status) ++ && WTERMSIG (proc->status) == -status_or_signal)) ++ { ++ print_context (context, &failed); ++ printf ("error: expected termination signal: %d\n", ++ -status_or_signal); ++ print_actual_status (proc); ++ } + } + if (!(allowed & sc_allow_stdout) && proc->out.length != 0) + { +diff --git a/support/tst-support_capture_subprocess.c b/support/tst-support_capture_subprocess.c +index 63b6699622f97fcc..99570879eedd65b1 100644 +--- a/support/tst-support_capture_subprocess.c ++++ b/support/tst-support_capture_subprocess.c +@@ -285,15 +285,29 @@ do_multiple_tests (enum test_type type) + + check_stream ("stdout", &result.out, test.out); + check_stream ("stderr", &result.err, test.err); ++ ++ /* Allowed output for support_capture_subprocess_check. */ ++ int check_allow = 0; ++ if (lengths[length_idx_stdout] > 0) ++ check_allow |= sc_allow_stdout; ++ if (lengths[length_idx_stderr] > 0) ++ check_allow |= sc_allow_stderr; ++ if (check_allow == 0) ++ check_allow = sc_allow_none; ++ + if (test.signal != 0) + { + TEST_VERIFY (WIFSIGNALED (result.status)); + TEST_VERIFY (WTERMSIG (result.status) == test.signal); ++ support_capture_subprocess_check (&result, "signal", ++ -SIGTERM, check_allow); + } + else + { + TEST_VERIFY (WIFEXITED (result.status)); + TEST_VERIFY (WEXITSTATUS (result.status) == test.status); ++ support_capture_subprocess_check (&result, "exit", ++ test.status, check_allow); + } + support_capture_subprocess_free (&result); + free (test.out); diff --git a/SOURCES/glibc-rh1410154-10.patch b/SOURCES/glibc-rh1410154-10.patch new file mode 100644 index 0000000..9025c9e --- /dev/null +++ b/SOURCES/glibc-rh1410154-10.patch @@ -0,0 +1,42 @@ +commit e37c2cf299b61ce18f62852f6c5624c27829b610 +Author: Florian Weimer +Date: Thu Oct 31 18:48:43 2019 +0100 + + Move _dl_open_check to its original place in dl_open_worker + + This reverts the non-test change from commit d0093c5cefb7f7a4143f + ("Call _dl_open_check after relocation [BZ #24259]"), given that + the underlying bug has been fixed properly in commit 61b74477fa7f63 + ("Remove all loaded objects if dlopen fails, ignoring NODELETE + [BZ #20839]"). + + Tested on x86-64-linux-gnu, with and without --enable-cet. + + Change-Id: I995a6cfb89f25d2b0cf5e606428c2a93eb48fc33 + +diff --git a/elf/dl-open.c b/elf/dl-open.c +index 25838b073ac1edaf..e13968d4d7c4c83f 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -619,6 +619,8 @@ dl_open_worker (void *a) + _dl_debug_state (); + LIBC_PROBE (map_complete, 3, args->nsid, r, new); + ++ _dl_open_check (new); ++ + /* Print scope information. */ + if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES)) + _dl_show_scope (new, 0); +@@ -699,12 +701,6 @@ dl_open_worker (void *a) + _dl_relocate_object (l, l->l_scope, reloc_mode, 0); + } + +- /* NB: Workaround for [BZ #20839] which doesn't remove the NODELETE +- object when _dl_open_check throws an exception. Move it after +- relocation to avoid leaving the NODELETE object mapped without +- relocation. */ +- _dl_open_check (new); +- + /* This only performs the memory allocations. The actual update of + the scopes happens below, after failure is impossible. */ + resize_scopes (new); diff --git a/SOURCES/glibc-rh1410154-11.patch b/SOURCES/glibc-rh1410154-11.patch new file mode 100644 index 0000000..c3a16f3 --- /dev/null +++ b/SOURCES/glibc-rh1410154-11.patch @@ -0,0 +1,27 @@ +commit 61a7c9df71ee4e6f94b56c20f0d37c6e17d5f284 +Author: Florian Weimer +Date: Mon Dec 2 14:53:16 2019 +0100 + + elf/tst-dlopenfail: Disable --no-as-needed for tst-dlopenfailmod1.so + + Otherwise, the shared object dependency which triggers the load + failure is dropped, invalidating the test. + +diff --git a/elf/Makefile b/elf/Makefile +index bf7c41f38be42184..467e810e784bb96d 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -1543,8 +1543,11 @@ LDFLAGS-tst-finilazyfailmod.so = \ + $(objpfx)tst-dlopenfail: $(libdl) + $(objpfx)tst-dlopenfail.out: \ + $(objpfx)tst-dlopenfailmod1.so $(objpfx)tst-dlopenfailmod2.so +-# Order matters here. tst-dlopenfaillinkmod.so's soname ensures +-# a run-time loader failure. ++# Order matters here. tst-dlopenfaillinkmod.so's soname ensures a ++# run-time loader failure. --as-needed breaks this test because ++# nothing actually references tst-dlopenfailmod2.so (with its soname ++# tst-dlopenfail-missingmod.so). ++LDFLAGS-tst-dlopenfailmod1.so = -Wl,--no-as-needed + $(objpfx)tst-dlopenfailmod1.so: \ + $(shared-thread-library) $(objpfx)tst-dlopenfaillinkmod.so + LDFLAGS-tst-dlopenfaillinkmod.so = -Wl,-soname,tst-dlopenfail-missingmod.so diff --git a/SOURCES/glibc-rh1410154-12.patch b/SOURCES/glibc-rh1410154-12.patch new file mode 100644 index 0000000..48dcfc3 --- /dev/null +++ b/SOURCES/glibc-rh1410154-12.patch @@ -0,0 +1,1229 @@ +commit 365624e2d2a342cdb693b4cc35d2312169959e28 +Author: Florian Weimer +Date: Fri Dec 13 10:18:24 2019 +0100 + + dlopen: Fix issues related to NODELETE handling and relocations + + The assumption behind the assert in activate_nodelete was wrong: + + Inconsistency detected by ld.so: dl-open.c: 459: activate_nodelete: + Assertion `!imap->l_init_called || imap->l_type != lt_loaded' failed! (edit) + + It can happen that an already-loaded object that is in the local + scope is promoted to NODELETE status, via binding to a unique + symbol. + + Similarly, it is possible that such NODELETE promotion occurs to + an already-loaded object from the global scope. This is why the + loop in activate_nodelete has to cover all objects in the namespace + of the new object. + + In do_lookup_unique, it could happen that the NODELETE status of + an already-loaded object was overwritten with a pending NODELETE + status. As a result, if dlopen fails, this could cause a loss of + the NODELETE status of the affected object, eventually resulting + in an incorrect unload. + + Fixes commit f63b73814f74032c0e5d0a83300e3d864ef905e5 ("Remove all + loaded objects if dlopen fails, ignoring NODELETE [BZ #20839]"). + +diff --git a/elf/Makefile b/elf/Makefile +index 467e810e784bb96d..16a3e8dcda19b4ba 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -185,7 +185,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + tst-audit1 tst-audit2 tst-audit8 tst-audit9 \ + tst-addr1 tst-thrlock \ + tst-unique1 tst-unique2 $(if $(CXX),tst-unique3 tst-unique4 \ +- tst-nodelete) \ ++ tst-nodelete tst-dlopen-nodelete-reloc) \ + tst-initorder tst-initorder2 tst-relsort1 tst-null-argv \ + tst-tlsalign tst-tlsalign-extern tst-nodelete-opened \ + tst-nodelete2 tst-audit11 tst-audit12 tst-dlsym-error tst-noload \ +@@ -266,7 +266,24 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + tst-auditmod9a tst-auditmod9b \ + $(if $(CXX),tst-unique3lib tst-unique3lib2 tst-unique4lib \ + tst-nodelete-uniquemod tst-nodelete-rtldmod \ +- tst-nodelete-zmod) \ ++ tst-nodelete-zmod \ ++ tst-dlopen-nodelete-reloc-mod1 \ ++ tst-dlopen-nodelete-reloc-mod2 \ ++ tst-dlopen-nodelete-reloc-mod3 \ ++ tst-dlopen-nodelete-reloc-mod4 \ ++ tst-dlopen-nodelete-reloc-mod5 \ ++ tst-dlopen-nodelete-reloc-mod6 \ ++ tst-dlopen-nodelete-reloc-mod7 \ ++ tst-dlopen-nodelete-reloc-mod8 \ ++ tst-dlopen-nodelete-reloc-mod9 \ ++ tst-dlopen-nodelete-reloc-mod10 \ ++ tst-dlopen-nodelete-reloc-mod11 \ ++ tst-dlopen-nodelete-reloc-mod12 \ ++ tst-dlopen-nodelete-reloc-mod13 \ ++ tst-dlopen-nodelete-reloc-mod14 \ ++ tst-dlopen-nodelete-reloc-mod15 \ ++ tst-dlopen-nodelete-reloc-mod16 \ ++ tst-dlopen-nodelete-reloc-mod17) \ + tst-initordera1 tst-initorderb1 \ + tst-initordera2 tst-initorderb2 \ + tst-initordera3 tst-initordera4 \ +@@ -1552,3 +1569,48 @@ $(objpfx)tst-dlopenfailmod1.so: \ + $(shared-thread-library) $(objpfx)tst-dlopenfaillinkmod.so + LDFLAGS-tst-dlopenfaillinkmod.so = -Wl,-soname,tst-dlopenfail-missingmod.so + $(objpfx)tst-dlopenfailmod2.so: $(shared-thread-library) ++ ++$(objpfx)tst-dlopen-nodelete-reloc: $(libdl) ++$(objpfx)tst-dlopen-nodelete-reloc.out: \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod1.so \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod2.so \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod3.so \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod4.so \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod5.so \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod6.so \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod7.so \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod8.so \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod9.so \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod10.so \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod11.so \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod12.so \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod13.so \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod14.so \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod15.so \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod16.so \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod17.so ++tst-dlopen-nodelete-reloc-mod2.so-no-z-defs = yes ++LDFLAGS-tst-dlopen-nodelete-reloc-mod2.so = -Wl,-z,nodelete ++$(objpfx)tst-dlopen-nodelete-reloc-mod4.so: \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod3.so ++LDFLAGS-tst-dlopen-nodelete-reloc-mod4.so = -Wl,--no-as-needed ++$(objpfx)tst-dlopen-nodelete-reloc-mod5.so: \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod4.so ++LDFLAGS-tst-dlopen-nodelete-reloc-mod5.so = -Wl,-z,nodelete,--no-as-needed ++tst-dlopen-nodelete-reloc-mod5.so-no-z-defs = yes ++tst-dlopen-nodelete-reloc-mod7.so-no-z-defs = yes ++$(objpfx)tst-dlopen-nodelete-reloc-mod8.so: $(libdl) ++$(objpfx)tst-dlopen-nodelete-reloc-mod10.so: $(libdl) ++tst-dlopen-nodelete-reloc-mod11.so-no-z-defs = yes ++$(objpfx)tst-dlopen-nodelete-reloc-mod13.so: \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod12.so ++$(objpfx)tst-dlopen-nodelete-reloc-mod15.so: \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod14.so ++tst-dlopen-nodelete-reloc-mod16.so-no-z-defs = yes ++$(objpfx)tst-dlopen-nodelete-reloc-mod16.so: \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod15.so ++LDFLAGS-tst-dlopen-nodelete-reloc-mod16.so = -Wl,--no-as-needed ++$(objpfx)tst-dlopen-nodelete-reloc-mod17.so: \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod15.so \ ++ $(objpfx)tst-dlopen-nodelete-reloc-mod16.so ++LDFLAGS-tst-dlopen-nodelete-reloc-mod17.so = -Wl,--no-as-needed +diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c +index c5e5857fb1fe2808..35a3f96a6296294a 100644 +--- a/elf/dl-lookup.c ++++ b/elf/dl-lookup.c +@@ -311,12 +311,12 @@ do_lookup_unique (const char *undef_name, uint_fast32_t new_hash, + enter_unique_sym (entries, size, + new_hash, strtab + sym->st_name, sym, map); + +- if (map->l_type == lt_loaded) ++ if (map->l_type == lt_loaded ++ && map->l_nodelete == link_map_nodelete_inactive) + { + /* Make sure we don't unload this object by + setting the appropriate flag. */ +- if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_BINDINGS) +- && map->l_nodelete == link_map_nodelete_inactive) ++ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_BINDINGS)) + _dl_debug_printf ("\ + marking %s [%lu] as NODELETE due to unique symbol\n", + map->l_name, map->l_ns); +diff --git a/elf/dl-open.c b/elf/dl-open.c +index e13968d4d7c4c83f..c7ed85b7ee99a296 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -433,34 +433,21 @@ TLS generation counter wrapped! Please report this.")); + after dlopen failure is not possible, so that _dl_close can clean + up objects if necessary. */ + static void +-activate_nodelete (struct link_map *new, int mode) ++activate_nodelete (struct link_map *new) + { +- if (mode & RTLD_NODELETE || new->l_nodelete == link_map_nodelete_pending) +- { +- if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_FILES)) +- _dl_debug_printf ("activating NODELETE for %s [%lu]\n", +- new->l_name, new->l_ns); +- new->l_nodelete = link_map_nodelete_active; +- } +- +- for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i) +- { +- struct link_map *imap = new->l_searchlist.r_list[i]; +- if (imap->l_nodelete == link_map_nodelete_pending) +- { +- if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_FILES)) +- _dl_debug_printf ("activating NODELETE for %s [%lu]\n", +- imap->l_name, imap->l_ns); +- +- /* Only new objects should have set +- link_map_nodelete_pending. Existing objects should not +- have gained any new dependencies and therefore cannot +- reach NODELETE status. */ +- assert (!imap->l_init_called || imap->l_type != lt_loaded); ++ /* It is necessary to traverse the entire namespace. References to ++ objects in the global scope and unique symbol bindings can force ++ NODELETE status for objects outside the local scope. */ ++ for (struct link_map *l = GL (dl_ns)[new->l_ns]._ns_loaded; l != NULL; ++ l = l->l_next) ++ if (l->l_nodelete == link_map_nodelete_pending) ++ { ++ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_FILES)) ++ _dl_debug_printf ("activating NODELETE for %s [%lu]\n", ++ l->l_name, l->l_ns); + +- imap->l_nodelete = link_map_nodelete_active; +- } +- } ++ l->l_nodelete = link_map_nodelete_active; ++ } + } + + /* struct dl_init_args and call_dl_init are used to call _dl_init with +@@ -718,7 +705,7 @@ dl_open_worker (void *a) + All memory allocations for new objects must have happened + before. */ + +- activate_nodelete (new, mode); ++ activate_nodelete (new); + + /* Second stage after resize_scopes: Actually perform the scope + update. After this, dlsym and lazy binding can bind to new +diff --git a/elf/tst-dlopen-nodelete-reloc-mod1.c b/elf/tst-dlopen-nodelete-reloc-mod1.c +new file mode 100644 +index 0000000000000000..397d60a2d5ea62d9 +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc-mod1.c +@@ -0,0 +1,39 @@ ++/* Test propagation of NODELETE to an already-loaded object via relocation. ++ Non-NODELETE helper module. ++ Copyright (C) 2019 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 ++ . */ ++ ++#include ++#include ++#include ++ ++/* Globally exported. Set by the main program to true before ++ termination, and used by tst-dlopen-nodelete-reloc-mod2.so to ++ trigger marking this module as NODELETE (and also for its destructor ++ check). */ ++bool may_finalize_mod1 = false; ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ if (!may_finalize_mod1) ++ { ++ puts ("error: tst-dlopen-nodelete-reloc-mod1.so destructor" ++ " called too early"); ++ _exit (1); ++ } ++} +diff --git a/elf/tst-dlopen-nodelete-reloc-mod10.c b/elf/tst-dlopen-nodelete-reloc-mod10.c +new file mode 100644 +index 0000000000000000..30748b73ec7daed3 +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc-mod10.c +@@ -0,0 +1,41 @@ ++/* Helper module to load tst-dlopen-nodelete-reloc-mod11.so. ++ Copyright (C) 2019 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++static void *handle; ++ ++static void __attribute__ ((constructor)) ++init (void) ++{ ++ handle = dlopen ("tst-dlopen-nodelete-reloc-mod11.so", RTLD_NOW); ++ if (handle == NULL) ++ { ++ printf ("error: dlopen in module 10: %s\n", dlerror ()); ++ _exit (1); ++ } ++} ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ dlclose (handle); ++} +diff --git a/elf/tst-dlopen-nodelete-reloc-mod11.cc b/elf/tst-dlopen-nodelete-reloc-mod11.cc +new file mode 100644 +index 0000000000000000..48c910403e782c83 +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc-mod11.cc +@@ -0,0 +1,49 @@ ++/* Second module defining a unique symbol (loaded indirectly). ++ Copyright (C) 2019 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 ++ . */ ++ ++#include "tst-dlopen-nodelete-reloc.h" ++ ++#include ++#include ++#include ++ ++/* Just a flag here, not used for NODELETE processing. */ ++bool may_finalize_mod11 = false; ++ ++/* Trigger the creation of a unique symbol reference. This should ++ cause tst-dlopen-nodelete-reloc-mod9.so to be marked as ++ NODELETE. */ ++ ++extern template struct unique_symbol<9>; ++ ++int ++global_function_mod11 (void) ++{ ++ return unique_symbol<9>::value; ++} ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ if (!may_finalize_mod11) ++ { ++ puts ("error: tst-dlopen-nodelete-reloc-mod11.so destructor" ++ " called too early"); ++ _exit (1); ++ } ++} +diff --git a/elf/tst-dlopen-nodelete-reloc-mod12.cc b/elf/tst-dlopen-nodelete-reloc-mod12.cc +new file mode 100644 +index 0000000000000000..5c093fd02d1fd0c7 +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc-mod12.cc +@@ -0,0 +1,42 @@ ++/* First module for NODELETE test defining a unique symbol (with DT_NEEDED). ++ Copyright (C) 2019 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 ++ . */ ++ ++#include "tst-dlopen-nodelete-reloc.h" ++ ++#include ++#include ++#include ++ ++/* Just a flag here, not used for NODELETE processing. */ ++bool may_finalize_mod12 = false; ++ ++/* Explicit instantiation. This produces a unique symbol definition ++ which is not referenced by the library itself, so the library is ++ not marked NODELETE. */ ++template struct unique_symbol<12>; ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ if (!may_finalize_mod12) ++ { ++ puts ("error: tst-dlopen-nodelete-reloc-mod12.so destructor" ++ " called too early"); ++ _exit (1); ++ } ++} +diff --git a/elf/tst-dlopen-nodelete-reloc-mod13.cc b/elf/tst-dlopen-nodelete-reloc-mod13.cc +new file mode 100644 +index 0000000000000000..caf4fd1cc9e1c1e1 +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc-mod13.cc +@@ -0,0 +1,48 @@ ++/* Second module for NODELETE test defining a unique symbol (with DT_NEEDED). ++ Copyright (C) 2019 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 ++ . */ ++ ++#include "tst-dlopen-nodelete-reloc.h" ++ ++#include ++#include ++#include ++ ++/* Just a flag here, not used for NODELETE processing. */ ++bool may_finalize_mod13 = false; ++ ++extern template struct unique_symbol<12>; ++ ++/* Trigger the creation of a unique symbol reference. This should ++ cause tst-dlopen-nodelete-reloc-mod12.so to be marked as ++ NODELETE. */ ++int ++global_function_mod13 (void) ++{ ++ return unique_symbol<12>::value; ++} ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ if (!may_finalize_mod13) ++ { ++ puts ("error: tst-dlopen-nodelete-reloc-mod13.so destructor" ++ " called too early"); ++ _exit (1); ++ } ++} +diff --git a/elf/tst-dlopen-nodelete-reloc-mod13.h b/elf/tst-dlopen-nodelete-reloc-mod13.h +new file mode 100644 +index 0000000000000000..5d338481a34a5714 +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc-mod13.h +@@ -0,0 +1,24 @@ ++/* Inline function which produces a unique symbol. ++ Copyright (C) 2019 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 ++ . */ ++ ++inline char * ++third_function_with_local_static (void) ++{ ++ static char local; ++ return &local; ++} +diff --git a/elf/tst-dlopen-nodelete-reloc-mod14.cc b/elf/tst-dlopen-nodelete-reloc-mod14.cc +new file mode 100644 +index 0000000000000000..e67621a2a2f8509a +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc-mod14.cc +@@ -0,0 +1,42 @@ ++/* This object must retain NODELETE status after a dlopen failure. ++ Copyright (C) 2019 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 ++ . */ ++ ++#include "tst-dlopen-nodelete-reloc.h" ++ ++#include ++#include ++#include ++ ++/* Just a flag here, not used for NODELETE processing. */ ++bool may_finalize_mod14 = false; ++ ++/* Explicit instantiation. This produces a unique symbol definition ++ which is not referenced by the library itself, so the library is ++ not marked NODELETE. */ ++template struct unique_symbol<14>; ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ if (!may_finalize_mod14) ++ { ++ puts ("error: tst-dlopen-nodelete-reloc-mod14.so destructor" ++ " called too early"); ++ _exit (1); ++ } ++} +diff --git a/elf/tst-dlopen-nodelete-reloc-mod15.cc b/elf/tst-dlopen-nodelete-reloc-mod15.cc +new file mode 100644 +index 0000000000000000..ead362bfdbb90eef +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc-mod15.cc +@@ -0,0 +1,42 @@ ++/* Helper object to mark tst-dlopen-nodelete-reloc-mod14.so as NODELETE. ++ Copyright (C) 2019 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 ++ . */ ++ ++#include "tst-dlopen-nodelete-reloc.h" ++ ++#include ++#include ++#include ++ ++extern template struct unique_symbol<14>; ++ ++/* Trigger the creation of a unique symbol reference. This should ++ cause tst-dlopen-nodelete-reloc-mod14.so to be marked as ++ NODELETE. */ ++int ++global_function_mod15 (void) ++{ ++ return unique_symbol<14>::value; ++} ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ /* This object is never loaded completely. */ ++ puts ("error: tst-dlopen-nodelete-reloc-mod15.so destructor invoked"); ++ _exit (1); ++} +diff --git a/elf/tst-dlopen-nodelete-reloc-mod16.c b/elf/tst-dlopen-nodelete-reloc-mod16.c +new file mode 100644 +index 0000000000000000..fa2ed1461b42c82c +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc-mod16.c +@@ -0,0 +1,27 @@ ++/* Object with an undefined symbol to trigger a relocation failure. ++ Copyright (C) 2019 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 ++ . */ ++ ++/* The reference to undefined_mod16 triggers a relocation failure. */ ++ ++extern int undefined_mod16; ++ ++int ++global_function_mod16 (void) ++{ ++ return undefined_mod16; ++} +diff --git a/elf/tst-dlopen-nodelete-reloc-mod17.c b/elf/tst-dlopen-nodelete-reloc-mod17.c +new file mode 100644 +index 0000000000000000..426562edd9a3ffee +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc-mod17.c +@@ -0,0 +1,19 @@ ++/* Top-level object with dependency on an object that fails relocation. ++ Copyright (C) 2019 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 ++ . */ ++ ++/* The dependencies do all the work. */ +diff --git a/elf/tst-dlopen-nodelete-reloc-mod2.c b/elf/tst-dlopen-nodelete-reloc-mod2.c +new file mode 100644 +index 0000000000000000..81ea8e5af2d00b93 +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc-mod2.c +@@ -0,0 +1,38 @@ ++/* Test propagation of NODELETE to an already-loaded object via relocation. ++ NODELETE helper module. ++ Copyright (C) 2019 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 ++ . */ ++ ++#include ++#include ++#include ++ ++/* Defined in tst-dlopen-nodelete-reloc-mod1.so. This dependency is ++ not expressed via DT_NEEDED, so this reference marks the other ++ object as NODELETE dynamically, during initially relocation. */ ++extern bool may_finalize_mod1; ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ if (!may_finalize_mod1) ++ { ++ puts ("error: tst-dlopen-nodelete-reloc-mod2.so destructor" ++ " called too early"); ++ _exit (1); ++ } ++} +diff --git a/elf/tst-dlopen-nodelete-reloc-mod3.c b/elf/tst-dlopen-nodelete-reloc-mod3.c +new file mode 100644 +index 0000000000000000..d33f4ec7630c6a1e +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc-mod3.c +@@ -0,0 +1,38 @@ ++/* Test propagation of NODELETE to an already-loaded object via relocation. ++ Non-NODELETE helper module. ++ Copyright (C) 2019 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 ++ . */ ++ ++#include ++#include ++#include ++ ++/* Globally exported. Set by the main program to true before ++ termination, and used by tst-dlopen-nodelete-reloc-mod4.so, ++ tst-dlopen-nodelete-reloc-mod5.so. */ ++bool may_finalize_mod3 = false; ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ if (!may_finalize_mod3) ++ { ++ puts ("error: tst-dlopen-nodelete-reloc-mod3.so destructor" ++ " called too early"); ++ _exit (1); ++ } ++} +diff --git a/elf/tst-dlopen-nodelete-reloc-mod4.c b/elf/tst-dlopen-nodelete-reloc-mod4.c +new file mode 100644 +index 0000000000000000..7e6633aebb1e2f00 +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc-mod4.c +@@ -0,0 +1,37 @@ ++/* Test propagation of NODELETE to an already-loaded object via relocation. ++ Intermediate helper module. ++ Copyright (C) 2019 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 ++ . */ ++ ++#include ++#include ++#include ++ ++/* Defined in tst-dlopen-nodelete-reloc-mod3.so. The dependency is ++ expressed via DT_NEEDED. */ ++extern bool may_finalize_mod3; ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ if (!may_finalize_mod3) ++ { ++ puts ("error: tst-dlopen-nodelete-reloc-mod4.so destructor" ++ " called too early"); ++ _exit (1); ++ } ++} +diff --git a/elf/tst-dlopen-nodelete-reloc-mod5.c b/elf/tst-dlopen-nodelete-reloc-mod5.c +new file mode 100644 +index 0000000000000000..22aa16f855dc75a8 +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc-mod5.c +@@ -0,0 +1,38 @@ ++/* Test propagation of NODELETE to an already-loaded object via relocation. ++ NODELETE helper module. ++ Copyright (C) 2019 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 ++ . */ ++ ++#include ++#include ++#include ++ ++/* Defined in tst-dlopen-nodelete-reloc-mod3.so. The dependency is ++ expressed via DT_NEEDED on the intermediate DSO ++ tst-dlopen-nodelete-reloc-mod3.so. */ ++extern bool may_finalize_mod3; ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ if (!may_finalize_mod3) ++ { ++ puts ("error: tst-dlopen-nodelete-reloc-mod5.so destructor" ++ " called too early"); ++ _exit (1); ++ } ++} +diff --git a/elf/tst-dlopen-nodelete-reloc-mod6.cc b/elf/tst-dlopen-nodelete-reloc-mod6.cc +new file mode 100644 +index 0000000000000000..180f5b5842f1c2b0 +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc-mod6.cc +@@ -0,0 +1,42 @@ ++/* First module for NODELETE test defining a unique symbol. ++ Copyright (C) 2019 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 ++ . */ ++ ++#include "tst-dlopen-nodelete-reloc.h" ++ ++#include ++#include ++#include ++ ++/* Just a flag here, not used for NODELETE processing. */ ++bool may_finalize_mod6 = false; ++ ++/* Explicit instantiation. This produces a unique symbol definition ++ which is not referenced by the library itself, so the library is ++ not marked NODELETE. */ ++template struct unique_symbol<6>; ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ if (!may_finalize_mod6) ++ { ++ puts ("error: tst-dlopen-nodelete-reloc-mod6.so destructor" ++ " called too early"); ++ _exit (1); ++ } ++} +diff --git a/elf/tst-dlopen-nodelete-reloc-mod7.cc b/elf/tst-dlopen-nodelete-reloc-mod7.cc +new file mode 100644 +index 0000000000000000..c85e7c991b098bf5 +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc-mod7.cc +@@ -0,0 +1,48 @@ ++/* Second module for NODELETE test defining a unique symbol. ++ Copyright (C) 2019 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 ++ . */ ++ ++#include "tst-dlopen-nodelete-reloc.h" ++ ++#include ++#include ++#include ++ ++/* Just a flag here, not used for NODELETE processing. */ ++bool may_finalize_mod7 = false; ++ ++extern template struct unique_symbol<6>; ++ ++/* Trigger the creation of a unique symbol reference. This should ++ cause tst-dlopen-nodelete-reloc-mod6.so to be marked as ++ NODELETE. */ ++int ++global_function_mod7 (void) ++{ ++ return unique_symbol<6>::value; ++} ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ if (!may_finalize_mod7) ++ { ++ puts ("error: tst-dlopen-nodelete-reloc-mod7.so destructor" ++ " called too early"); ++ _exit (1); ++ } ++} +diff --git a/elf/tst-dlopen-nodelete-reloc-mod8.c b/elf/tst-dlopen-nodelete-reloc-mod8.c +new file mode 100644 +index 0000000000000000..ebb1c35fab57e319 +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc-mod8.c +@@ -0,0 +1,41 @@ ++/* Helper module to load tst-dlopen-nodelete-reloc-mod9.so. ++ Copyright (C) 2019 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++static void *handle; ++ ++static void __attribute__ ((constructor)) ++init (void) ++{ ++ handle = dlopen ("tst-dlopen-nodelete-reloc-mod9.so", RTLD_NOW); ++ if (handle == NULL) ++ { ++ printf ("error: dlopen in module 8: %s\n", dlerror ()); ++ _exit (1); ++ } ++} ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ dlclose (handle); ++} +diff --git a/elf/tst-dlopen-nodelete-reloc-mod9.cc b/elf/tst-dlopen-nodelete-reloc-mod9.cc +new file mode 100644 +index 0000000000000000..06fb49cdf753cb41 +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc-mod9.cc +@@ -0,0 +1,42 @@ ++/* First module defining a unique symbol (loaded indirectly). ++ Copyright (C) 2019 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 ++ . */ ++ ++#include "tst-dlopen-nodelete-reloc.h" ++ ++#include ++#include ++#include ++ ++/* Just a flag here, not used for NODELETE processing. */ ++bool may_finalize_mod9 = false; ++ ++/* Explicit instantiation. This produces a unique symbol definition ++ which is not referenced by the library itself, so the library is ++ not marked NODELETE. */ ++template struct unique_symbol<9>; ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ if (!may_finalize_mod9) ++ { ++ puts ("error: tst-dlopen-nodelete-reloc-mod9.so destructor" ++ " called too early"); ++ _exit (1); ++ } ++} +diff --git a/elf/tst-dlopen-nodelete-reloc.c b/elf/tst-dlopen-nodelete-reloc.c +new file mode 100644 +index 0000000000000000..291ac9eb8385a92e +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc.c +@@ -0,0 +1,179 @@ ++/* Test interactions of dlopen, NODELETE, and relocations. ++ Copyright (C) 2019 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 ++ . */ ++ ++/* This test exercises NODELETE propagation due to data relocations ++ and unique symbols, and the interaction with already-loaded ++ objects. Some test objects are written in C++, to produce unique ++ symbol definitions. ++ ++ First test: Global scope variant, data relocation as the NODELETE ++ trigger. mod1 is loaded first with a separate dlopen call. ++ ++ mod2 ---(may_finalize_mod1 relocation dependency)---> mod1 ++ (NODELETE) (marked as NODELETE) ++ ++ Second test: Local scope variant, data relocation. mod3 is loaded ++ first, then mod5. ++ ++ mod5 ---(DT_NEEDED)---> mod4 ---(DT_NEEDED)---> mod3 ++ (NODELETE) (not NODELETE) ^ ++ \ / (marked as ++ `--(may_finalize_mod3 relocation dependency)--/ NODELETE) ++ ++ Third test: Shared local scope with unique symbol. mod6 is loaded ++ first, then mod7. No explicit dependencies between the two ++ objects, so first object has to be opened with RTLD_GLOBAL. ++ ++ mod7 ---(unique symbol)---> mod6 ++ (marked as NODELETE) ++ ++ Forth test: Non-shared scopes with unique symbol. mod8 and mod10 ++ are loaded from the main program. mod8 loads mod9 from an ELF ++ constructor, mod10 loads mod11. There are no DT_NEEDED ++ dependencies. mod9 is promoted to the global scope form the main ++ program. The unique symbol dependency is: ++ ++ mod9 ---(unique symbol)---> mod11 ++ (marked as NODELETE) ++ ++ Fifth test: Shared local scope with unique symbol, like test 3, but ++ this time, there is also a DT_NEEDED dependency (so no RTLD_GLOBAL ++ needed): ++ ++ DT_NEEDED ++ mod13 ---(unique symbol)---> mod12 ++ (marked as NODELETE) ++ ++ Sixth test: NODELETE status is retained after relocation failure ++ with unique symbol dependency. The object graph ensures that the ++ unique symbol binding is processed before the dlopen failure. ++ ++ DT_NEEDED ++ mod17 --(DT_NEEDED)--> mod15 --(unique symbol)--> mod14 ++ \ ^ (RTLD_NODELETE) ++ \ (DT_NEEDED) ++ \ | ++ `---(DT_NEEDED)--> mod16 ++ (fails to relocate) ++ ++ mod14 is loaded first, and the loading mod17 is attempted. ++ mod14 must remain NODELETE after opening mod17 failed. */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ /* First case: global scope, regular data symbol. Open the object ++ which is not NODELETE initially. */ ++ void *mod1 = xdlopen ("tst-dlopen-nodelete-reloc-mod1.so", ++ RTLD_NOW | RTLD_GLOBAL); ++ /* This is used to indicate that the ELF destructor may be ++ called. */ ++ bool *may_finalize_mod1 = xdlsym (mod1, "may_finalize_mod1"); ++ /* Open the NODELETE object. */ ++ void *mod2 = xdlopen ("tst-dlopen-nodelete-reloc-mod2.so", RTLD_NOW); ++ /* This has no effect because the DSO is directly marked as ++ NODELETE. */ ++ xdlclose (mod2); ++ /* This has no effect because the DSO has been indirectly marked as ++ NODELETE due to a relocation dependency. */ ++ xdlclose (mod1); ++ ++ /* Second case: local scope, regular data symbol. Open the object ++ which is not NODELETE initially. */ ++ void *mod3 = xdlopen ("tst-dlopen-nodelete-reloc-mod3.so", RTLD_NOW); ++ bool *may_finalize_mod3 = xdlsym (mod3, "may_finalize_mod3"); ++ /* Open the NODELETE object. */ ++ void *mod5 = xdlopen ("tst-dlopen-nodelete-reloc-mod5.so", RTLD_NOW); ++ /* Again those have no effect because of NODELETE. */ ++ xdlclose (mod5); ++ xdlclose (mod3); ++ ++ /* Third case: Unique symbol. */ ++ void *mod6 = xdlopen ("tst-dlopen-nodelete-reloc-mod6.so", ++ RTLD_NOW | RTLD_GLOBAL); ++ bool *may_finalize_mod6 = xdlsym (mod6, "may_finalize_mod6"); ++ void *mod7 = xdlopen ("tst-dlopen-nodelete-reloc-mod7.so", RTLD_NOW); ++ bool *may_finalize_mod7 = xdlsym (mod7, "may_finalize_mod7"); ++ /* This should not have any effect because of the unique symbol and ++ the resulting NODELETE status. */ ++ xdlclose (mod6); ++ /* mod7 is not NODELETE and can be closed. */ ++ *may_finalize_mod7 = true; ++ xdlclose (mod7); ++ ++ /* Fourth case: Unique symbol, indirect loading. */ ++ void *mod8 = xdlopen ("tst-dlopen-nodelete-reloc-mod8.so", RTLD_NOW); ++ /* Also promote to global scope. */ ++ void *mod9 = xdlopen ("tst-dlopen-nodelete-reloc-mod9.so", ++ RTLD_NOW | RTLD_NOLOAD | RTLD_GLOBAL); ++ bool *may_finalize_mod9 = xdlsym (mod9, "may_finalize_mod9"); ++ xdlclose (mod9); /* Drop mod9 reference. */ ++ void *mod10 = xdlopen ("tst-dlopen-nodelete-reloc-mod10.so", RTLD_NOW); ++ void *mod11 = xdlopen ("tst-dlopen-nodelete-reloc-mod11.so", ++ RTLD_NOW | RTLD_NOLOAD); ++ bool *may_finalize_mod11 = xdlsym (mod11, "may_finalize_mod11"); ++ xdlclose (mod11); /* Drop mod11 reference. */ ++ /* mod11 is not NODELETE and can be closed. */ ++ *may_finalize_mod11 = true; ++ /* Trigger closing of mod11, too. */ ++ xdlclose (mod10); ++ /* Does not trigger closing of mod9. */ ++ xdlclose (mod8); ++ ++ /* Fifth case: Unique symbol, with DT_NEEDED dependency. */ ++ void *mod12 = xdlopen ("tst-dlopen-nodelete-reloc-mod12.so", RTLD_NOW); ++ bool *may_finalize_mod12 = xdlsym (mod12, "may_finalize_mod12"); ++ void *mod13 = xdlopen ("tst-dlopen-nodelete-reloc-mod13.so", RTLD_NOW); ++ bool *may_finalize_mod13 = xdlsym (mod13, "may_finalize_mod13"); ++ /* This should not have any effect because of the unique symbol. */ ++ xdlclose (mod12); ++ /* mod13 is not NODELETE and can be closed. */ ++ *may_finalize_mod13 = true; ++ xdlclose (mod13); ++ ++ /* Sixth case: Unique symbol binding must not cause loss of NODELETE ++ status. */ ++ void *mod14 = xdlopen ("tst-dlopen-nodelete-reloc-mod14.so", ++ RTLD_NOW | RTLD_NODELETE); ++ bool *may_finalize_mod14 = xdlsym (mod14, "may_finalize_mod14"); ++ TEST_VERIFY (dlopen ("tst-dlopen-nodelete-reloc-mod17.so", RTLD_NOW) ++ == NULL); ++ const char *message = dlerror (); ++ printf ("info: test 6 message: %s\n", message); ++ /* This must not close the object, it must still be NODELETE. */ ++ xdlclose (mod14); ++ xdlopen ("tst-dlopen-nodelete-reloc-mod14.so", RTLD_NOW | RTLD_NOLOAD); ++ ++ /* Prepare for process exit. Destructors for NODELETE objects will ++ be invoked. */ ++ *may_finalize_mod1 = true; ++ *may_finalize_mod3 = true; ++ *may_finalize_mod6 = true; ++ *may_finalize_mod9 = true; ++ *may_finalize_mod12 = true; ++ *may_finalize_mod14 = true; ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-dlopen-nodelete-reloc.h b/elf/tst-dlopen-nodelete-reloc.h +new file mode 100644 +index 0000000000000000..8844de622631f575 +--- /dev/null ++++ b/elf/tst-dlopen-nodelete-reloc.h +@@ -0,0 +1,35 @@ ++/* Template to produce unique symbols. ++ Copyright (C) 2019 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 ++ . */ ++ ++/* This template produces a unique symbol definition for an explicit ++ template instantiation (without also incorporating a reference), ++ and an extern template declaration can be used to reference that ++ symbol from another object. The modid parameter is just a ++ placeholder to create different symbols (because it affects the ++ name mangling of the static value member). By convention, it ++ should match the number of the module that contains the ++ definition. */ ++ ++template ++struct unique_symbol ++{ ++ static int value; ++}; ++ ++template ++int unique_symbol::value; diff --git a/SOURCES/glibc-rh1410154-13.patch b/SOURCES/glibc-rh1410154-13.patch new file mode 100644 index 0000000..1ec1768 --- /dev/null +++ b/SOURCES/glibc-rh1410154-13.patch @@ -0,0 +1,328 @@ +commit f8ed116aa574435c6e28260f21963233682d3b57 +Author: Florian Weimer +Date: Fri Dec 13 10:18:46 2019 +0100 + + dlopen: Rework handling of pending NODELETE status + + Commit a2e8aa0d9ea648068d8be52dd7b15f1b6a008e23 ("Block signals during + the initial part of dlopen") was deemed necessary because of + read-modify-write operations like the one in add_dependency in + elf/dl-lookup.c. In the old code, we check for any kind of NODELETE + status and bail out: + + /* Redo the NODELETE check, as when dl_load_lock wasn't held + yet this could have changed. */ + if (map->l_nodelete != link_map_nodelete_inactive) + goto out; + + And then set pending status (during relocation): + + if (flags & DL_LOOKUP_FOR_RELOCATE) + map->l_nodelete = link_map_nodelete_pending; + else + map->l_nodelete = link_map_nodelete_active; + + If a signal arrives during relocation and the signal handler, through + lazy binding, adds a global scope dependency on the same map, it will + set map->l_nodelete to link_map_nodelete_active. This will be + overwritten with link_map_nodelete_pending by the dlopen relocation + code. + + To avoid such problems in relation to the l_nodelete member, this + commit introduces two flags for active NODELETE status (irrevocable) + and pending NODELETE status (revocable until activate_nodelete is + invoked). As a result, NODELETE processing in dlopen does not + introduce further reasons why lazy binding from signal handlers + is unsafe during dlopen, and a subsequent commit can remove signal + blocking from dlopen. + + This does not address pre-existing issues (unrelated to the NODELETE + changes) which make lazy binding in a signal handler during dlopen + unsafe, such as the use of malloc in both cases. + + Reviewed-by: Adhemerval Zanella + Reviewed-by: Carlos O'Donell + +diff --git a/elf/dl-close.c b/elf/dl-close.c +index 243a028c443173c1..fa7f3e8174576e46 100644 +--- a/elf/dl-close.c ++++ b/elf/dl-close.c +@@ -197,7 +197,7 @@ _dl_close_worker (struct link_map *map, bool force) + /* Check whether this object is still used. */ + if (l->l_type == lt_loaded + && l->l_direct_opencount == 0 +- && l->l_nodelete != link_map_nodelete_active ++ && !l->l_nodelete_active + /* See CONCURRENCY NOTES in cxa_thread_atexit_impl.c to know why + acquire is sufficient and correct. */ + && atomic_load_acquire (&l->l_tls_dtor_count) == 0 +@@ -279,8 +279,7 @@ _dl_close_worker (struct link_map *map, bool force) + + if (!used[i]) + { +- assert (imap->l_type == lt_loaded +- && imap->l_nodelete != link_map_nodelete_active); ++ assert (imap->l_type == lt_loaded && !imap->l_nodelete_active); + + /* Call its termination function. Do not do it for + half-cooked objects. Temporarily disable exception +@@ -820,7 +819,7 @@ _dl_close (void *_map) + before we took the lock. There is no way to detect this (see below) + so we proceed assuming this isn't the case. First see whether we + can remove the object at all. */ +- if (__glibc_unlikely (map->l_nodelete == link_map_nodelete_active)) ++ if (__glibc_unlikely (map->l_nodelete_active)) + { + /* Nope. Do nothing. */ + __rtld_lock_unlock_recursive (GL(dl_load_lock)); +diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c +index 35a3f96a6296294a..01724a54f8840f9f 100644 +--- a/elf/dl-lookup.c ++++ b/elf/dl-lookup.c +@@ -187,6 +187,28 @@ enter_unique_sym (struct unique_sym *table, size_t size, + table[idx].map = map; + } + ++/* Mark MAP as NODELETE according to the lookup mode in FLAGS. During ++ initial relocation, NODELETE state is pending only. */ ++static void ++mark_nodelete (struct link_map *map, int flags) ++{ ++ if (flags & DL_LOOKUP_FOR_RELOCATE) ++ map->l_nodelete_pending = true; ++ else ++ map->l_nodelete_active = true; ++} ++ ++/* Return true if MAP is marked as NODELETE according to the lookup ++ mode in FLAGS> */ ++static bool ++is_nodelete (struct link_map *map, int flags) ++{ ++ /* Non-pending NODELETE always counts. Pending NODELETE only counts ++ during initial relocation processing. */ ++ return map->l_nodelete_active ++ || ((flags & DL_LOOKUP_FOR_RELOCATE) && map->l_nodelete_pending); ++} ++ + /* Utility function for do_lookup_x. Lookup an STB_GNU_UNIQUE symbol + in the unique symbol table, creating a new entry if necessary. + Return the matching symbol in RESULT. */ +@@ -311,8 +333,7 @@ do_lookup_unique (const char *undef_name, uint_fast32_t new_hash, + enter_unique_sym (entries, size, + new_hash, strtab + sym->st_name, sym, map); + +- if (map->l_type == lt_loaded +- && map->l_nodelete == link_map_nodelete_inactive) ++ if (map->l_type == lt_loaded && !is_nodelete (map, flags)) + { + /* Make sure we don't unload this object by + setting the appropriate flag. */ +@@ -320,10 +341,7 @@ do_lookup_unique (const char *undef_name, uint_fast32_t new_hash, + _dl_debug_printf ("\ + marking %s [%lu] as NODELETE due to unique symbol\n", + map->l_name, map->l_ns); +- if (flags & DL_LOOKUP_FOR_RELOCATE) +- map->l_nodelete = link_map_nodelete_pending; +- else +- map->l_nodelete = link_map_nodelete_active; ++ mark_nodelete (map, flags); + } + } + ++tab->n_elements; +@@ -586,7 +604,7 @@ add_dependency (struct link_map *undef_map, struct link_map *map, int flags) + dependencies may pick an dependency which can be dlclose'd, but + such IFUNC resolvers are undefined anyway. */ + assert (map->l_type == lt_loaded); +- if (map->l_nodelete != link_map_nodelete_inactive) ++ if (is_nodelete (map, flags)) + return 0; + + struct link_map_reldeps *l_reldeps +@@ -694,17 +712,16 @@ add_dependency (struct link_map *undef_map, struct link_map *map, int flags) + + /* Redo the NODELETE check, as when dl_load_lock wasn't held + yet this could have changed. */ +- if (map->l_nodelete != link_map_nodelete_inactive) ++ if (is_nodelete (map, flags)) + goto out; + + /* If the object with the undefined reference cannot be removed ever + just make sure the same is true for the object which contains the + definition. */ +- if (undef_map->l_type != lt_loaded +- || (undef_map->l_nodelete != link_map_nodelete_inactive)) ++ if (undef_map->l_type != lt_loaded || is_nodelete (map, flags)) + { + if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_BINDINGS) +- && map->l_nodelete == link_map_nodelete_inactive) ++ && !is_nodelete (map, flags)) + { + if (undef_map->l_name[0] == '\0') + _dl_debug_printf ("\ +@@ -716,11 +733,7 @@ marking %s [%lu] as NODELETE due to reference to %s [%lu]\n", + map->l_name, map->l_ns, + undef_map->l_name, undef_map->l_ns); + } +- +- if (flags & DL_LOOKUP_FOR_RELOCATE) +- map->l_nodelete = link_map_nodelete_pending; +- else +- map->l_nodelete = link_map_nodelete_active; ++ mark_nodelete (map, flags); + goto out; + } + +@@ -746,17 +759,14 @@ marking %s [%lu] as NODELETE due to reference to %s [%lu]\n", + cannot be unloaded. This is semantically the correct + behavior. */ + if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_BINDINGS) +- && map->l_nodelete == link_map_nodelete_inactive) ++ && !is_nodelete (map, flags)) + _dl_debug_printf ("\ + marking %s [%lu] as NODELETE due to memory allocation failure\n", + map->l_name, map->l_ns); +- if (flags & DL_LOOKUP_FOR_RELOCATE) +- /* In case of non-lazy binding, we could actually +- report the memory allocation error, but for now, we +- use the conservative approximation as well. */ +- map->l_nodelete = link_map_nodelete_pending; +- else +- map->l_nodelete = link_map_nodelete_active; ++ /* In case of non-lazy binding, we could actually report ++ the memory allocation error, but for now, we use the ++ conservative approximation as well. */ ++ mark_nodelete (map, flags); + goto out; + } + else +diff --git a/elf/dl-open.c b/elf/dl-open.c +index c7ed85b7ee99a296..a382bfae8aa3a2f8 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -440,13 +440,17 @@ activate_nodelete (struct link_map *new) + NODELETE status for objects outside the local scope. */ + for (struct link_map *l = GL (dl_ns)[new->l_ns]._ns_loaded; l != NULL; + l = l->l_next) +- if (l->l_nodelete == link_map_nodelete_pending) ++ if (l->l_nodelete_pending) + { + if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_FILES)) + _dl_debug_printf ("activating NODELETE for %s [%lu]\n", + l->l_name, l->l_ns); + +- l->l_nodelete = link_map_nodelete_active; ++ l->l_nodelete_active = true; ++ ++ /* This is just a debugging aid, to indicate that ++ activate_nodelete has run for this map. */ ++ l->l_nodelete_pending = false; + } + } + +@@ -549,10 +553,10 @@ dl_open_worker (void *a) + if (__glibc_unlikely (mode & RTLD_NODELETE)) + { + if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_FILES) +- && new->l_nodelete == link_map_nodelete_inactive) ++ && !new->l_nodelete_active) + _dl_debug_printf ("marking %s [%lu] as NODELETE\n", + new->l_name, new->l_ns); +- new->l_nodelete = link_map_nodelete_active; ++ new->l_nodelete_active = true; + } + + /* Finalize the addition to the global scope. */ +@@ -568,7 +572,7 @@ dl_open_worker (void *a) + /* Schedule NODELETE marking for the directly loaded object if + requested. */ + if (__glibc_unlikely (mode & RTLD_NODELETE)) +- new->l_nodelete = link_map_nodelete_pending; ++ new->l_nodelete_pending = true; + + /* Load that object's dependencies. */ + _dl_map_object_deps (new, NULL, 0, 0, +@@ -680,7 +684,7 @@ dl_open_worker (void *a) + _dl_start_profile (); + + /* Prevent unloading the object. */ +- GL(dl_profile_map)->l_nodelete = link_map_nodelete_active; ++ GL(dl_profile_map)->l_nodelete_active = true; + } + } + else +@@ -879,9 +883,9 @@ no more namespaces available for dlmopen()")); + happens inside dl_open_worker. */ + __libc_signal_restore_set (&args.original_signal_mask); + +- /* All link_map_nodelete_pending objects should have been +- deleted at this point, which is why it is not necessary +- to reset the flag here. */ ++ /* All l_nodelete_pending objects should have been deleted ++ at this point, which is why it is not necessary to reset ++ the flag here. */ + } + else + __libc_signal_restore_set (&args.original_signal_mask); +diff --git a/elf/get-dynamic-info.h b/elf/get-dynamic-info.h +index ea286abaea0128d1..78ba7e76db9706cc 100644 +--- a/elf/get-dynamic-info.h ++++ b/elf/get-dynamic-info.h +@@ -164,7 +164,7 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp) + { + l->l_flags_1 = info[VERSYMIDX (DT_FLAGS_1)]->d_un.d_val; + if (l->l_flags_1 & DF_1_NODELETE) +- l->l_nodelete = link_map_nodelete_pending; ++ l->l_nodelete_pending = true; + + /* Only DT_1_SUPPORTED_MASK bits are supported, and we would like + to assert this, but we can't. Users have been setting +diff --git a/include/link.h b/include/link.h +index a277b77cad6b52b1..e90fa79a0b332087 100644 +--- a/include/link.h ++++ b/include/link.h +@@ -79,22 +79,6 @@ struct r_search_path_struct + int malloced; + }; + +-/* Type used by the l_nodelete member. */ +-enum link_map_nodelete +-{ +- /* This link map can be deallocated. */ +- link_map_nodelete_inactive = 0, /* Zero-initialized in _dl_new_object. */ +- +- /* This link map cannot be deallocated. */ +- link_map_nodelete_active, +- +- /* This link map cannot be deallocated after dlopen has succeded. +- dlopen turns this into link_map_nodelete_active. dlclose treats +- this intermediate state as link_map_nodelete_active. */ +- link_map_nodelete_pending, +-}; +- +- + /* Structure describing a loaded shared object. The `l_next' and `l_prev' + members form a chain of all the shared objects loaded at startup. + +@@ -218,10 +202,17 @@ struct link_map + freed, ie. not allocated with + the dummy malloc in ld.so. */ + +- /* Actually of type enum link_map_nodelete. Separate byte due to +- a read in add_dependency in elf/dl-lookup.c outside the loader +- lock. Only valid for l_type == lt_loaded. */ +- unsigned char l_nodelete; ++ /* NODELETE status of the map. Only valid for maps of type ++ lt_loaded. Lazy binding sets l_nodelete_active directly, ++ potentially from signal handlers. Initial loading of an ++ DF_1_NODELETE object set l_nodelete_pending. Relocation may ++ set l_nodelete_pending as well. l_nodelete_pending maps are ++ promoted to l_nodelete_active status in the final stages of ++ dlopen, prior to calling ELF constructors. dlclose only ++ refuses to unload l_nodelete_active maps, the pending status is ++ ignored. */ ++ bool l_nodelete_active; ++ bool l_nodelete_pending; + + #include + diff --git a/SOURCES/glibc-rh1410154-14.patch b/SOURCES/glibc-rh1410154-14.patch new file mode 100644 index 0000000..ac4d1e2 --- /dev/null +++ b/SOURCES/glibc-rh1410154-14.patch @@ -0,0 +1,134 @@ +commit f7649d5780aa4682393b9daedd653e4d9c12784c +Author: Florian Weimer +Date: Fri Dec 13 10:23:10 2019 +0100 + + dlopen: Do not block signals + + Blocking signals causes issues with certain anti-malware solutions + which rely on an unblocked SIGSYS signal for system calls they + intercept. + + This reverts commit a2e8aa0d9ea648068d8be52dd7b15f1b6a008e23 + ("Block signals during the initial part of dlopen") and adds + comments related to async signal safety to active_nodelete and + its caller. + + Note that this does not make lazy binding async-signal-safe with regards + to dlopen. It merely avoids introducing new async-signal-safety hazards + as part of the NODELETE changes. + + Reviewed-by: Adhemerval Zanella + Reviewed-by: Carlos O'Donell + +diff --git a/elf/dl-open.c b/elf/dl-open.c +index a382bfae8aa3a2f8..d834b89754d2b073 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -34,7 +34,6 @@ + #include + #include + #include +-#include + + #include + #include +@@ -53,10 +52,6 @@ struct dl_open_args + /* Namespace ID. */ + Lmid_t nsid; + +- /* Original signal mask. Used for unblocking signal handlers before +- running ELF constructors. */ +- sigset_t original_signal_mask; +- + /* Original value of _ns_global_scope_pending_adds. Set by + dl_open_worker. Only valid if nsid is a real namespace + (non-negative). */ +@@ -446,6 +441,9 @@ activate_nodelete (struct link_map *new) + _dl_debug_printf ("activating NODELETE for %s [%lu]\n", + l->l_name, l->l_ns); + ++ /* The flag can already be true at this point, e.g. a signal ++ handler may have triggered lazy binding and set NODELETE ++ status immediately. */ + l->l_nodelete_active = true; + + /* This is just a debugging aid, to indicate that +@@ -520,16 +518,12 @@ dl_open_worker (void *a) + if (new == NULL) + { + assert (mode & RTLD_NOLOAD); +- __libc_signal_restore_set (&args->original_signal_mask); + return; + } + + if (__glibc_unlikely (mode & __RTLD_SPROF)) +- { +- /* This happens only if we load a DSO for 'sprof'. */ +- __libc_signal_restore_set (&args->original_signal_mask); +- return; +- } ++ /* This happens only if we load a DSO for 'sprof'. */ ++ return; + + /* This object is directly loaded. */ + ++new->l_direct_opencount; +@@ -565,7 +559,6 @@ dl_open_worker (void *a) + + assert (_dl_debug_initialize (0, args->nsid)->r_state == RT_CONSISTENT); + +- __libc_signal_restore_set (&args->original_signal_mask); + return; + } + +@@ -709,6 +702,12 @@ dl_open_worker (void *a) + All memory allocations for new objects must have happened + before. */ + ++ /* Finalize the NODELETE status first. This comes before ++ update_scopes, so that lazy binding will not see pending NODELETE ++ state for newly loaded objects. There is a compiler barrier in ++ update_scopes which ensures that the changes from ++ activate_nodelete are visible before new objects show up in the ++ local scope. */ + activate_nodelete (new); + + /* Second stage after resize_scopes: Actually perform the scope +@@ -742,10 +741,6 @@ dl_open_worker (void *a) + if (mode & RTLD_GLOBAL) + add_to_global_resize (new); + +- /* Unblock signals. Data structures are now consistent, and +- application code may run. */ +- __libc_signal_restore_set (&args->original_signal_mask); +- + /* Run the initializer functions of new objects. Temporarily + disable the exception handler, so that lazy binding failures are + fatal. */ +@@ -835,10 +830,6 @@ no more namespaces available for dlmopen()")); + args.argv = argv; + args.env = env; + +- /* Recursive lazy binding during manipulation of the dynamic loader +- structures may result in incorrect behavior. */ +- __libc_signal_block_all (&args.original_signal_mask); +- + struct dl_exception exception; + int errcode = _dl_catch_exception (&exception, dl_open_worker, &args); + +@@ -879,16 +870,10 @@ no more namespaces available for dlmopen()")); + + _dl_close_worker (args.map, true); + +- /* Restore the signal mask. In the success case, this +- happens inside dl_open_worker. */ +- __libc_signal_restore_set (&args.original_signal_mask); +- + /* All l_nodelete_pending objects should have been deleted + at this point, which is why it is not necessary to reset + the flag here. */ + } +- else +- __libc_signal_restore_set (&args.original_signal_mask); + + assert (_dl_debug_initialize (0, args.nsid)->r_state == RT_CONSISTENT); + diff --git a/SOURCES/glibc-rh1410154-2.patch b/SOURCES/glibc-rh1410154-2.patch new file mode 100644 index 0000000..84269e7 --- /dev/null +++ b/SOURCES/glibc-rh1410154-2.patch @@ -0,0 +1,33 @@ +commit ca136bb0a36d0a7056c926bfe5126873566efe40 +Author: Florian Weimer +Date: Thu Oct 31 13:28:26 2019 +0100 + + Clarify purpose of assert in _dl_lookup_symbol_x + + Only one of the currently defined flags is incompatible with versioned + symbol lookups, so it makes sense to check for that flag and not its + complement. + + Reviewed-by: Carlos O'Donell + Reviewed-by: Gabriel F. T. Gomes + Change-Id: I3384349cef90cfd91862ebc34a4053f0c0a99404 + +diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c +index 1d046caf017b582b..efbdb8deb3c0a9d4 100644 +--- a/elf/dl-lookup.c ++++ b/elf/dl-lookup.c +@@ -792,11 +792,9 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map, + + bump_num_relocations (); + +- /* No other flag than DL_LOOKUP_ADD_DEPENDENCY or DL_LOOKUP_GSCOPE_LOCK +- is allowed if we look up a versioned symbol. */ +- assert (version == NULL +- || (flags & ~(DL_LOOKUP_ADD_DEPENDENCY | DL_LOOKUP_GSCOPE_LOCK)) +- == 0); ++ /* DL_LOOKUP_RETURN_NEWEST does not make sense for versioned ++ lookups. */ ++ assert (version == NULL || !(flags & DL_LOOKUP_RETURN_NEWEST)); + + size_t i = 0; + if (__glibc_unlikely (skip_map != NULL)) diff --git a/SOURCES/glibc-rh1410154-3.patch b/SOURCES/glibc-rh1410154-3.patch new file mode 100644 index 0000000..34afb62 --- /dev/null +++ b/SOURCES/glibc-rh1410154-3.patch @@ -0,0 +1,54 @@ +commit 2a764c6ee848dfe92cb2921ed3b14085f15d9e79 +Author: Florian Weimer +Date: Thu Oct 31 13:23:06 2019 +0100 + + Enhance _dl_catch_exception to allow disabling exception handling + + In some cases, it is necessary to introduce noexcept regions + where raised dynamic loader exceptions (e.g., from lazy binding) + are fatal, despite being nested in a code region with an active + exception handler. This change enhances _dl_catch_exception with + to provide such a capability. The existing function is reused, + so that it is not necessary to introduce yet another function with + a similar purpose. + + Change-Id: Iec1bf642ff95a349fdde8040e9baf851ac7b8904 + +diff --git a/elf/dl-error-skeleton.c b/elf/dl-error-skeleton.c +index d5f418ab1848f0c4..9cb002ccfed2c7b4 100644 +--- a/elf/dl-error-skeleton.c ++++ b/elf/dl-error-skeleton.c +@@ -173,6 +173,18 @@ int + _dl_catch_exception (struct dl_exception *exception, + void (*operate) (void *), void *args) + { ++ /* If exception is NULL, temporarily disable exception handling. ++ Exceptions during operate (args) are fatal. */ ++ if (exception == NULL) ++ { ++ struct catch *const old = catch_hook; ++ catch_hook = NULL; ++ operate (args); ++ /* If we get here, the operation was successful. */ ++ catch_hook = old; ++ return 0; ++ } ++ + /* We need not handle `receiver' since setting a `catch' is handled + before it. */ + +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 95dc87519b80e0ec..cc2484033fe0d902 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -852,7 +852,9 @@ libc_hidden_proto (_dl_catch_error) + + /* Call OPERATE (ARGS). If no error occurs, set *EXCEPTION to zero. + Otherwise, store a copy of the raised exception in *EXCEPTION, +- which has to be freed by _dl_exception_free. */ ++ which has to be freed by _dl_exception_free. As a special case, if ++ EXCEPTION is null, call OPERATE (ARGS) with exception handling ++ disabled (so that exceptions are fatal). */ + int _dl_catch_exception (struct dl_exception *exception, + void (*operate) (void *), void *args); + libc_hidden_proto (_dl_catch_exception) diff --git a/SOURCES/glibc-rh1410154-4.patch b/SOURCES/glibc-rh1410154-4.patch new file mode 100644 index 0000000..fa3cc53 --- /dev/null +++ b/SOURCES/glibc-rh1410154-4.patch @@ -0,0 +1,42 @@ +commit fcb04b9aed26a737159ef7be9c5a6ad0994437dc +Author: Florian Weimer +Date: Thu Oct 31 13:28:49 2019 +0100 + + Introduce DL_LOOKUP_FOR_RELOCATE flag for _dl_lookup_symbol_x + + This will allow changes in dependency processing during non-lazy + binding, for more precise processing of NODELETE objects: During + initial relocation in dlopen, the fate of NODELETE objects is still + unclear, so objects which are depended upon by NODELETE objects + cannot immediately be marked as NODELETE. + + Change-Id: Ic7b94a3f7c4719a00ca8e6018088567824da0658 + +diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c +index 053916eeae50467c..afeace4d3e49180c 100644 +--- a/elf/dl-reloc.c ++++ b/elf/dl-reloc.c +@@ -248,7 +248,8 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[], + v = (version); \ + _lr = _dl_lookup_symbol_x (strtab + (*ref)->st_name, l, (ref), \ + scope, v, _tc, \ +- DL_LOOKUP_ADD_DEPENDENCY, NULL); \ ++ DL_LOOKUP_ADD_DEPENDENCY \ ++ | DL_LOOKUP_FOR_RELOCATE, NULL); \ + l->l_lookup_cache.ret = (*ref); \ + l->l_lookup_cache.value = _lr; })) \ + : l) +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index cc2484033fe0d902..6c5298a80bff8e96 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -908,6 +908,9 @@ enum + DL_LOOKUP_RETURN_NEWEST = 2, + /* Set if dl_lookup* called with GSCOPE lock held. */ + DL_LOOKUP_GSCOPE_LOCK = 4, ++ /* Set if dl_lookup is called for non-lazy relocation processing ++ from _dl_relocate_object in elf/dl-reloc.c. */ ++ DL_LOOKUP_FOR_RELOCATE = 8, + }; + + /* Lookup versioned symbol. */ diff --git a/SOURCES/glibc-rh1410154-5.patch b/SOURCES/glibc-rh1410154-5.patch new file mode 100644 index 0000000..6879fb3 --- /dev/null +++ b/SOURCES/glibc-rh1410154-5.patch @@ -0,0 +1,343 @@ +commit 79e0cd7b3c997e211fad44a81fd839dc5b2546e8 +Author: Florian Weimer +Date: Wed Nov 27 16:20:47 2019 +0100 + + Lazy binding failures during dlopen/dlclose must be fatal [BZ #24304] + + If a lazy binding failure happens during the execution of an ELF + constructor or destructor, the dynamic loader catches the error + and reports it using the dlerror mechanism. This is undesirable + because there could be other constructors and destructors that + need processing (which are skipped), and the process is in an + inconsistent state at this point. Therefore, we have to issue + a fatal dynamic loader error error and terminate the process. + + Note that the _dl_catch_exception in _dl_open is just an inner catch, + to roll back some state locally. If called from dlopen, there is + still an outer catch, which is why calling _dl_init via call_dl_init + and a no-exception is required and cannot be avoiding by moving the + _dl_init call directly into _dl_open. + + _dl_fini does not need changes because it does not install an error + handler, so errors are already fatal there. + + Change-Id: I6b1addfe2e30f50a1781595f046f44173db9491a + +Conflicts: + elf/Makefile + (Usual conflicts due to test backport differences.) + +diff --git a/elf/Makefile b/elf/Makefile +index 74a240b3a68ff5e2..b752f6366400d221 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -191,7 +191,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + tst-nodelete2 tst-audit11 tst-audit12 tst-dlsym-error tst-noload \ + tst-latepthread tst-tls-manydynamic tst-nodelete-dlclose \ + tst-debug1 tst-main1 tst-absolute-sym tst-absolute-zero tst-big-note \ +- tst-sonamemove-link tst-sonamemove-dlopen ++ tst-sonamemove-link tst-sonamemove-dlopen tst-initfinilazyfail + # reldep9 + tests-internal += loadtest unload unload2 circleload1 \ + neededtest neededtest2 neededtest3 neededtest4 \ +@@ -281,7 +281,8 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + tst-main1mod tst-libc_dlvsym-dso tst-absolute-sym-lib \ + tst-absolute-zero-lib tst-big-note-lib \ + tst-sonamemove-linkmod1 \ +- tst-sonamemove-runmod1 tst-sonamemove-runmod2 ++ tst-sonamemove-runmod1 tst-sonamemove-runmod2 \ ++ tst-initlazyfailmod tst-finilazyfailmod + + ifeq (yes,$(have-mtls-dialect-gnu2)) + tests += tst-gnu2-tls1 +@@ -1526,3 +1527,13 @@ tst-libc_dlvsym-static-ENV = \ + $(objpfx)tst-libc_dlvsym-static.out: $(objpfx)tst-libc_dlvsym-dso.so + + $(objpfx)tst-big-note: $(objpfx)tst-big-note-lib.so ++ ++$(objpfx)tst-initfinilazyfail: $(libdl) ++$(objpfx)tst-initfinilazyfail.out: \ ++ $(objpfx)tst-initlazyfailmod.so $(objpfx)tst-finilazyfailmod.so ++# Override -z defs, so that we can reference an undefined symbol. ++# Force lazy binding for the same reason. ++LDFLAGS-tst-initlazyfailmod.so = \ ++ -Wl,-z,lazy -Wl,--unresolved-symbols=ignore-all ++LDFLAGS-tst-finilazyfailmod.so = \ ++ -Wl,-z,lazy -Wl,--unresolved-symbols=ignore-all +diff --git a/elf/dl-close.c b/elf/dl-close.c +index ecd6729704ea3294..88aeea25839a34e0 100644 +--- a/elf/dl-close.c ++++ b/elf/dl-close.c +@@ -106,6 +106,30 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp, + return false; + } + ++/* Invoke dstructors for CLOSURE (a struct link_map *). Called with ++ exception handling temporarily disabled, to make errors fatal. */ ++static void ++call_destructors (void *closure) ++{ ++ struct link_map *map = closure; ++ ++ if (map->l_info[DT_FINI_ARRAY] != NULL) ++ { ++ ElfW(Addr) *array = ++ (ElfW(Addr) *) (map->l_addr ++ + map->l_info[DT_FINI_ARRAY]->d_un.d_ptr); ++ unsigned int sz = (map->l_info[DT_FINI_ARRAYSZ]->d_un.d_val ++ / sizeof (ElfW(Addr))); ++ ++ while (sz-- > 0) ++ ((fini_t) array[sz]) (); ++ } ++ ++ /* Next try the old-style destructor. */ ++ if (map->l_info[DT_FINI] != NULL) ++ DL_CALL_DT_FINI (map, ((void *) map->l_addr ++ + map->l_info[DT_FINI]->d_un.d_ptr)); ++} + + void + _dl_close_worker (struct link_map *map, bool force) +@@ -267,7 +291,8 @@ _dl_close_worker (struct link_map *map, bool force) + && (imap->l_flags_1 & DF_1_NODELETE) == 0); + + /* Call its termination function. Do not do it for +- half-cooked objects. */ ++ half-cooked objects. Temporarily disable exception ++ handling, so that errors are fatal. */ + if (imap->l_init_called) + { + /* When debugging print a message first. */ +@@ -276,22 +301,9 @@ _dl_close_worker (struct link_map *map, bool force) + _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n", + imap->l_name, nsid); + +- if (imap->l_info[DT_FINI_ARRAY] != NULL) +- { +- ElfW(Addr) *array = +- (ElfW(Addr) *) (imap->l_addr +- + imap->l_info[DT_FINI_ARRAY]->d_un.d_ptr); +- unsigned int sz = (imap->l_info[DT_FINI_ARRAYSZ]->d_un.d_val +- / sizeof (ElfW(Addr))); +- +- while (sz-- > 0) +- ((fini_t) array[sz]) (); +- } +- +- /* Next try the old-style destructor. */ +- if (imap->l_info[DT_FINI] != NULL) +- DL_CALL_DT_FINI (imap, ((void *) imap->l_addr +- + imap->l_info[DT_FINI]->d_un.d_ptr)); ++ if (imap->l_info[DT_FINI_ARRAY] != NULL ++ || imap->l_info[DT_FINI] != NULL) ++ _dl_catch_exception (NULL, call_destructors, imap); + } + + #ifdef SHARED +diff --git a/elf/dl-open.c b/elf/dl-open.c +index 518a6cad699ec6d0..c9c0254ee74c4f4b 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -177,6 +177,23 @@ _dl_find_dso_for_object (const ElfW(Addr) addr) + } + rtld_hidden_def (_dl_find_dso_for_object); + ++/* struct dl_init_args and call_dl_init are used to call _dl_init with ++ exception handling disabled. */ ++struct dl_init_args ++{ ++ struct link_map *new; ++ int argc; ++ char **argv; ++ char **env; ++}; ++ ++static void ++call_dl_init (void *closure) ++{ ++ struct dl_init_args *args = closure; ++ _dl_init (args->new, args->argc, args->argv, args->env); ++} ++ + static void + dl_open_worker (void *a) + { +@@ -506,8 +523,19 @@ TLS generation counter wrapped! Please report this.")); + DL_STATIC_INIT (new); + #endif + +- /* Run the initializer functions of new objects. */ +- _dl_init (new, args->argc, args->argv, args->env); ++ /* Run the initializer functions of new objects. Temporarily ++ disable the exception handler, so that lazy binding failures are ++ fatal. */ ++ { ++ struct dl_init_args init_args = ++ { ++ .new = new, ++ .argc = args->argc, ++ .argv = args->argv, ++ .env = args->env ++ }; ++ _dl_catch_exception (NULL, call_dl_init, &init_args); ++ } + + /* Now we can make the new map available in the global scope. */ + if (mode & RTLD_GLOBAL) +diff --git a/elf/tst-finilazyfailmod.c b/elf/tst-finilazyfailmod.c +new file mode 100644 +index 0000000000000000..2670bd1a9400d0ef +--- /dev/null ++++ b/elf/tst-finilazyfailmod.c +@@ -0,0 +1,27 @@ ++/* Helper module for tst-initfinilazyfail: lazy binding failure in destructor. ++ Copyright (C) 2019 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 ++ . */ ++ ++/* An undefined function. Calling it will cause a lazy binding ++ failure. */ ++void undefined_function (void); ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ undefined_function (); ++} +diff --git a/elf/tst-initfinilazyfail.c b/elf/tst-initfinilazyfail.c +new file mode 100644 +index 0000000000000000..9b4a3d0c0ffbb7c6 +--- /dev/null ++++ b/elf/tst-initfinilazyfail.c +@@ -0,0 +1,84 @@ ++/* Test that lazy binding failures in constructors and destructors are fatal. ++ Copyright (C) 2019 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++static void ++test_constructor (void *closure) ++{ ++ void *handle = dlopen ("tst-initlazyfailmod.so", RTLD_LAZY); ++ if (handle == NULL) ++ FAIL_EXIT (2, "dlopen did not terminate the process: %s", dlerror ()); ++ else ++ FAIL_EXIT (2, "dlopen did not terminate the process (%p)", handle); ++} ++ ++static void ++test_destructor (void *closure) ++{ ++ void *handle = xdlopen ("tst-finilazyfailmod.so", RTLD_LAZY); ++ int ret = dlclose (handle); ++ const char *message = dlerror (); ++ if (message != NULL) ++ FAIL_EXIT (2, "dlclose did not terminate the process: %d, %s", ++ ret, message); ++ else ++ FAIL_EXIT (2, "dlopen did not terminate the process: %d", ret); ++} ++ ++static int ++do_test (void) ++{ ++ { ++ struct support_capture_subprocess proc ++ = support_capture_subprocess (test_constructor, NULL); ++ support_capture_subprocess_check (&proc, "constructor", 127, ++ sc_allow_stderr); ++ printf ("info: constructor failure output: [[%s]]\n", proc.err.buffer); ++ TEST_VERIFY (strstr (proc.err.buffer, ++ "tst-initfinilazyfail: symbol lookup error: ") ++ != NULL); ++ TEST_VERIFY (strstr (proc.err.buffer, ++ "tst-initlazyfailmod.so: undefined symbol:" ++ " undefined_function\n") != NULL); ++ support_capture_subprocess_free (&proc); ++ } ++ ++ { ++ struct support_capture_subprocess proc ++ = support_capture_subprocess (test_destructor, NULL); ++ support_capture_subprocess_check (&proc, "destructor", 127, ++ sc_allow_stderr); ++ printf ("info: destructor failure output: [[%s]]\n", proc.err.buffer); ++ TEST_VERIFY (strstr (proc.err.buffer, ++ "tst-initfinilazyfail: symbol lookup error: ") ++ != NULL); ++ TEST_VERIFY (strstr (proc.err.buffer, ++ "tst-finilazyfailmod.so: undefined symbol:" ++ " undefined_function\n") != NULL); ++ support_capture_subprocess_free (&proc); ++ } ++ ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-initlazyfailmod.c b/elf/tst-initlazyfailmod.c +new file mode 100644 +index 0000000000000000..36348b58d634d2bb +--- /dev/null ++++ b/elf/tst-initlazyfailmod.c +@@ -0,0 +1,27 @@ ++/* Helper module for tst-initfinilazyfail: lazy binding failure in constructor. ++ Copyright (C) 2019 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 ++ . */ ++ ++/* An undefined function. Calling it will cause a lazy binding ++ failure. */ ++void undefined_function (void); ++ ++static void __attribute__ ((constructor)) ++init (void) ++{ ++ undefined_function (); ++} diff --git a/SOURCES/glibc-rh1410154-6.patch b/SOURCES/glibc-rh1410154-6.patch new file mode 100644 index 0000000..3b05076 --- /dev/null +++ b/SOURCES/glibc-rh1410154-6.patch @@ -0,0 +1,308 @@ +commit 440b7f8653e4ed8f6e1425145208050b795e9a6c +Author: Florian Weimer +Date: Thu Oct 31 18:25:39 2019 +0100 + + Avoid late failure in dlopen in global scope update [BZ #25112] + + The call to add_to_global in dl_open_worker happens after running ELF + constructors for new objects. At this point, proper recovery from + malloc failure would be quite complicated: We would have to run the + ELF destructors and close all opened objects, something that we + currently do not do. + + Instead, this change splits add_to_global into two phases, + add_to_global_resize (which can raise an exception, called before ELF + constructors run), and add_to_global_update (which cannot, called + after ELF constructors). A complication arises due to recursive + dlopen: After the inner dlopen consumes some space, the pre-allocation + in the outer dlopen may no longer be sufficient. A new member in the + namespace structure, _ns_global_scope_pending_adds keeps track of the + maximum number of objects that need to be added to the global scope. + This enables the inner add_to_global_resize call to take into account + the needs of an outer dlopen. + + Most code in the dynamic linker assumes that the number of global + scope entries fits into an unsigned int (matching the r_nlist member + of struct r_scop_elem). Therefore, change the type of + _ns_global_scope_alloc to unsigned int (from size_t), and add overflow + checks. + + Change-Id: Ie08e2f318510d5a6a4bcb1c315f46791b5b77524 + +diff --git a/elf/dl-open.c b/elf/dl-open.c +index c9c0254ee74c4f4b..85db4f0ecb5f29ce 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -50,22 +50,38 @@ struct dl_open_args + struct link_map *map; + /* Namespace ID. */ + Lmid_t nsid; ++ ++ /* Original value of _ns_global_scope_pending_adds. Set by ++ dl_open_worker. Only valid if nsid is a real namespace ++ (non-negative). */ ++ unsigned int original_global_scope_pending_adds; ++ + /* Original parameters to the program and the current environment. */ + int argc; + char **argv; + char **env; + }; + ++/* Called in case the global scope cannot be extended. */ ++static void __attribute__ ((noreturn)) ++add_to_global_resize_failure (struct link_map *new) ++{ ++ _dl_signal_error (ENOMEM, new->l_libname->name, NULL, ++ N_ ("cannot extend global scope")); ++} + +-static int +-add_to_global (struct link_map *new) ++/* Grow the global scope array for the namespace, so that all the new ++ global objects can be added later in add_to_global_update, without ++ risk of memory allocation failure. add_to_global_resize raises ++ exceptions for memory allocation errors. */ ++static void ++add_to_global_resize (struct link_map *new) + { +- struct link_map **new_global; +- unsigned int to_add = 0; +- unsigned int cnt; ++ struct link_namespaces *ns = &GL (dl_ns)[new->l_ns]; + + /* Count the objects we have to put in the global scope. */ +- for (cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt) ++ unsigned int to_add = 0; ++ for (unsigned int cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt) + if (new->l_searchlist.r_list[cnt]->l_global == 0) + ++to_add; + +@@ -83,47 +99,51 @@ add_to_global (struct link_map *new) + in an realloc() call. Therefore we allocate a completely new + array the first time we have to add something to the locale scope. */ + +- struct link_namespaces *ns = &GL(dl_ns)[new->l_ns]; ++ if (__builtin_add_overflow (ns->_ns_global_scope_pending_adds, to_add, ++ &ns->_ns_global_scope_pending_adds)) ++ add_to_global_resize_failure (new); ++ ++ unsigned int new_size = 0; /* 0 means no new allocation. */ ++ void *old_global = NULL; /* Old allocation if free-able. */ ++ ++ /* Minimum required element count for resizing. Adjusted below for ++ an exponential resizing policy. */ ++ size_t required_new_size; ++ if (__builtin_add_overflow (ns->_ns_main_searchlist->r_nlist, ++ ns->_ns_global_scope_pending_adds, ++ &required_new_size)) ++ add_to_global_resize_failure (new); ++ + if (ns->_ns_global_scope_alloc == 0) + { +- /* This is the first dynamic object given global scope. */ +- ns->_ns_global_scope_alloc +- = ns->_ns_main_searchlist->r_nlist + to_add + 8; +- new_global = (struct link_map **) +- malloc (ns->_ns_global_scope_alloc * sizeof (struct link_map *)); +- if (new_global == NULL) +- { +- ns->_ns_global_scope_alloc = 0; +- nomem: +- _dl_signal_error (ENOMEM, new->l_libname->name, NULL, +- N_("cannot extend global scope")); +- return 1; +- } ++ if (__builtin_add_overflow (required_new_size, 8, &new_size)) ++ add_to_global_resize_failure (new); ++ } ++ else if (required_new_size > ns->_ns_global_scope_alloc) ++ { ++ if (__builtin_mul_overflow (required_new_size, 2, &new_size)) ++ add_to_global_resize_failure (new); + +- /* Copy over the old entries. */ +- ns->_ns_main_searchlist->r_list +- = memcpy (new_global, ns->_ns_main_searchlist->r_list, +- (ns->_ns_main_searchlist->r_nlist +- * sizeof (struct link_map *))); ++ /* The old array was allocated with our malloc, not the minimal ++ malloc. */ ++ old_global = ns->_ns_main_searchlist->r_list; + } +- else if (ns->_ns_main_searchlist->r_nlist + to_add +- > ns->_ns_global_scope_alloc) ++ ++ if (new_size > 0) + { +- /* We have to extend the existing array of link maps in the +- main map. */ +- struct link_map **old_global +- = GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list; +- size_t new_nalloc = ((ns->_ns_global_scope_alloc + to_add) * 2); +- +- new_global = (struct link_map **) +- malloc (new_nalloc * sizeof (struct link_map *)); ++ size_t allocation_size; ++ if (__builtin_mul_overflow (new_size, sizeof (struct link_map *), ++ &allocation_size)) ++ add_to_global_resize_failure (new); ++ struct link_map **new_global = malloc (allocation_size); + if (new_global == NULL) +- goto nomem; ++ add_to_global_resize_failure (new); + +- memcpy (new_global, old_global, +- ns->_ns_global_scope_alloc * sizeof (struct link_map *)); ++ /* Copy over the old entries. */ ++ memcpy (new_global, ns->_ns_main_searchlist->r_list, ++ ns->_ns_main_searchlist->r_nlist * sizeof (struct link_map *)); + +- ns->_ns_global_scope_alloc = new_nalloc; ++ ns->_ns_global_scope_alloc = new_size; + ns->_ns_main_searchlist->r_list = new_global; + + if (!RTLD_SINGLE_THREAD_P) +@@ -131,16 +151,28 @@ add_to_global (struct link_map *new) + + free (old_global); + } ++} ++ ++/* Actually add the new global objects to the global scope. Must be ++ called after add_to_global_resize. This function cannot fail. */ ++static void ++add_to_global_update (struct link_map *new) ++{ ++ struct link_namespaces *ns = &GL (dl_ns)[new->l_ns]; + + /* Now add the new entries. */ + unsigned int new_nlist = ns->_ns_main_searchlist->r_nlist; +- for (cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt) ++ for (unsigned int cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt) + { + struct link_map *map = new->l_searchlist.r_list[cnt]; + + if (map->l_global == 0) + { + map->l_global = 1; ++ ++ /* The array has been resized by add_to_global_resize. */ ++ assert (new_nlist < ns->_ns_global_scope_alloc); ++ + ns->_ns_main_searchlist->r_list[new_nlist++] = map; + + /* We modify the global scope. Report this. */ +@@ -149,10 +181,15 @@ add_to_global (struct link_map *new) + map->l_name, map->l_ns); + } + } ++ ++ /* Some of the pending adds have been performed by the loop above. ++ Adjust the counter accordingly. */ ++ unsigned int added = new_nlist - ns->_ns_main_searchlist->r_nlist; ++ assert (added <= ns->_ns_global_scope_pending_adds); ++ ns->_ns_global_scope_pending_adds -= added; ++ + atomic_write_barrier (); + ns->_ns_main_searchlist->r_nlist = new_nlist; +- +- return 0; + } + + /* Search link maps in all namespaces for the DSO that contains the object at +@@ -225,6 +262,10 @@ dl_open_worker (void *a) + args->nsid = call_map->l_ns; + } + ++ /* Retain the old value, so that it can be restored. */ ++ args->original_global_scope_pending_adds ++ = GL (dl_ns)[args->nsid]._ns_global_scope_pending_adds; ++ + /* One might be tempted to assert that we are RT_CONSISTENT at this point, but that + may not be true if this is a recursive call to dlopen. */ + _dl_debug_initialize (0, args->nsid); +@@ -266,7 +307,10 @@ dl_open_worker (void *a) + /* If the user requested the object to be in the global namespace + but it is not so far, add it now. */ + if ((mode & RTLD_GLOBAL) && new->l_global == 0) +- (void) add_to_global (new); ++ { ++ add_to_global_resize (new); ++ add_to_global_update (new); ++ } + + assert (_dl_debug_initialize (0, args->nsid)->r_state == RT_CONSISTENT); + +@@ -523,6 +567,11 @@ TLS generation counter wrapped! Please report this.")); + DL_STATIC_INIT (new); + #endif + ++ /* Perform the necessary allocations for adding new global objects ++ to the global scope below, via add_to_global_update. */ ++ if (mode & RTLD_GLOBAL) ++ add_to_global_resize (new); ++ + /* Run the initializer functions of new objects. Temporarily + disable the exception handler, so that lazy binding failures are + fatal. */ +@@ -539,10 +588,7 @@ TLS generation counter wrapped! Please report this.")); + + /* Now we can make the new map available in the global scope. */ + if (mode & RTLD_GLOBAL) +- /* Move the object in the global namespace. */ +- if (add_to_global (new) != 0) +- /* It failed. */ +- return; ++ add_to_global_update (new); + + #ifndef SHARED + /* We must be the static _dl_open in libc.a. A static program that +@@ -556,7 +602,6 @@ TLS generation counter wrapped! Please report this.")); + new->l_name, new->l_ns, new->l_direct_opencount); + } + +- + void * + _dl_open (const char *file, int mode, const void *caller_dlopen, Lmid_t nsid, + int argc, char *argv[], char *env[]) +@@ -624,6 +669,19 @@ no more namespaces available for dlmopen()")); + _dl_unload_cache (); + #endif + ++ /* Do this for both the error and success cases. The old value has ++ only been determined if the namespace ID was assigned (i.e., it ++ is not __LM_ID_CALLER). In the success case, we actually may ++ have consumed more pending adds than planned (because the local ++ scopes overlap in case of a recursive dlopen, the inner dlopen ++ doing some of the globalization work of the outer dlopen), so the ++ old pending adds value is larger than absolutely necessary. ++ Since it is just a conservative upper bound, this is harmless. ++ The top-level dlopen call will restore the field to zero. */ ++ if (args.nsid >= 0) ++ GL (dl_ns)[args.nsid]._ns_global_scope_pending_adds ++ = args.original_global_scope_pending_adds; ++ + /* See if an error occurred during loading. */ + if (__glibc_unlikely (exception.errstring != NULL)) + { +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 6c5298a80bff8e96..57fbefea3cb841e9 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -311,7 +311,14 @@ struct rtld_global + /* This is zero at program start to signal that the global scope map is + allocated by rtld. Later it keeps the size of the map. It might be + reset if in _dl_close if the last global object is removed. */ +- size_t _ns_global_scope_alloc; ++ unsigned int _ns_global_scope_alloc; ++ ++ /* During dlopen, this is the number of objects that still need to ++ be added to the global scope map. It has to be taken into ++ account when resizing the map, for future map additions after ++ recursive dlopen calls from ELF constructors. */ ++ unsigned int _ns_global_scope_pending_adds; ++ + /* Search table for unique objects. */ + struct unique_sym_table + { diff --git a/SOURCES/glibc-rh1410154-7.patch b/SOURCES/glibc-rh1410154-7.patch new file mode 100644 index 0000000..977a011 --- /dev/null +++ b/SOURCES/glibc-rh1410154-7.patch @@ -0,0 +1,490 @@ +commit a509eb117fac1d764b15eba64993f4bdb63d7f3c +Author: Florian Weimer +Date: Wed Nov 27 16:37:17 2019 +0100 + + Avoid late dlopen failure due to scope, TLS slotinfo updates [BZ #25112] + + This change splits the scope and TLS slotinfo updates in dlopen into + two parts: one to resize the data structures, and one to actually apply + the update. The call to add_to_global_resize in dl_open_worker is moved + before the demarcation point at which no further memory allocations are + allowed. + + _dl_add_to_slotinfo is adjusted to make the list update optional. There + is some optimization possibility here because we could grow the slotinfo + list of arrays in a single call, one the largest TLS modid is known. + + This commit does not fix the fatal meory allocation failure in + _dl_update_slotinfo. Ideally, this error during dlopen should be + recoverable. + + The update order of scopes and TLS data structures is retained, although + it appears to be more correct to fully initialize TLS first, and then + expose symbols in the newly loaded objects via the scope update. + + Tested on x86_64-linux-gnu. + + Change-Id: I240c58387dabda3ca1bcab48b02115175fa83d6c + +diff --git a/elf/dl-open.c b/elf/dl-open.c +index 85db4f0ecb5f29ce..b330cff7d349224a 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -214,6 +215,215 @@ _dl_find_dso_for_object (const ElfW(Addr) addr) + } + rtld_hidden_def (_dl_find_dso_for_object); + ++/* Return true if NEW is found in the scope for MAP. */ ++static size_t ++scope_has_map (struct link_map *map, struct link_map *new) ++{ ++ size_t cnt; ++ for (cnt = 0; map->l_scope[cnt] != NULL; ++cnt) ++ if (map->l_scope[cnt] == &new->l_searchlist) ++ return true; ++ return false; ++} ++ ++/* Return the length of the scope for MAP. */ ++static size_t ++scope_size (struct link_map *map) ++{ ++ size_t cnt; ++ for (cnt = 0; map->l_scope[cnt] != NULL; ) ++ ++cnt; ++ return cnt; ++} ++ ++/* Resize the scopes of depended-upon objects, so that the new object ++ can be added later without further allocation of memory. This ++ function can raise an exceptions due to malloc failure. */ ++static void ++resize_scopes (struct link_map *new) ++{ ++ /* If the file is not loaded now as a dependency, add the search ++ list of the newly loaded object to the scope. */ ++ for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i) ++ { ++ struct link_map *imap = new->l_searchlist.r_list[i]; ++ ++ /* If the initializer has been called already, the object has ++ not been loaded here and now. */ ++ if (imap->l_init_called && imap->l_type == lt_loaded) ++ { ++ if (scope_has_map (imap, new)) ++ /* Avoid duplicates. */ ++ continue; ++ ++ size_t cnt = scope_size (imap); ++ if (__glibc_unlikely (cnt + 1 >= imap->l_scope_max)) ++ { ++ /* The l_scope array is too small. Allocate a new one ++ dynamically. */ ++ size_t new_size; ++ struct r_scope_elem **newp; ++ ++ if (imap->l_scope != imap->l_scope_mem ++ && imap->l_scope_max < array_length (imap->l_scope_mem)) ++ { ++ /* If the current l_scope memory is not pointing to ++ the static memory in the structure, but the ++ static memory in the structure is large enough to ++ use for cnt + 1 scope entries, then switch to ++ using the static memory. */ ++ new_size = array_length (imap->l_scope_mem); ++ newp = imap->l_scope_mem; ++ } ++ else ++ { ++ new_size = imap->l_scope_max * 2; ++ newp = (struct r_scope_elem **) ++ malloc (new_size * sizeof (struct r_scope_elem *)); ++ if (newp == NULL) ++ _dl_signal_error (ENOMEM, "dlopen", NULL, ++ N_("cannot create scope list")); ++ } ++ ++ /* Copy the array and the terminating NULL. */ ++ memcpy (newp, imap->l_scope, ++ (cnt + 1) * sizeof (imap->l_scope[0])); ++ struct r_scope_elem **old = imap->l_scope; ++ ++ imap->l_scope = newp; ++ ++ if (old != imap->l_scope_mem) ++ _dl_scope_free (old); ++ ++ imap->l_scope_max = new_size; ++ } ++ } ++ } ++} ++ ++/* Second stage of resize_scopes: Add NEW to the scopes. Also print ++ debugging information about scopes if requested. ++ ++ This function cannot raise an exception because all required memory ++ has been allocated by a previous call to resize_scopes. */ ++static void ++update_scopes (struct link_map *new) ++{ ++ for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i) ++ { ++ struct link_map *imap = new->l_searchlist.r_list[i]; ++ int from_scope = 0; ++ ++ if (imap->l_init_called && imap->l_type == lt_loaded) ++ { ++ if (scope_has_map (imap, new)) ++ /* Avoid duplicates. */ ++ continue; ++ ++ size_t cnt = scope_size (imap); ++ /* Assert that resize_scopes has sufficiently enlarged the ++ array. */ ++ assert (cnt + 1 < imap->l_scope_max); ++ ++ /* First terminate the extended list. Otherwise a thread ++ might use the new last element and then use the garbage ++ at offset IDX+1. */ ++ imap->l_scope[cnt + 1] = NULL; ++ atomic_write_barrier (); ++ imap->l_scope[cnt] = &new->l_searchlist; ++ ++ from_scope = cnt; ++ } ++ ++ /* Print scope information. */ ++ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES)) ++ _dl_show_scope (imap, from_scope); ++ } ++} ++ ++/* Call _dl_add_to_slotinfo with DO_ADD set to false, to allocate ++ space in GL (dl_tls_dtv_slotinfo_list). This can raise an ++ exception. The return value is true if any of the new objects use ++ TLS. */ ++static bool ++resize_tls_slotinfo (struct link_map *new) ++{ ++ bool any_tls = false; ++ for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i) ++ { ++ struct link_map *imap = new->l_searchlist.r_list[i]; ++ ++ /* Only add TLS memory if this object is loaded now and ++ therefore is not yet initialized. */ ++ if (! imap->l_init_called && imap->l_tls_blocksize > 0) ++ { ++ _dl_add_to_slotinfo (imap, false); ++ any_tls = true; ++ } ++ } ++ return any_tls; ++} ++ ++/* Second stage of TLS update, after resize_tls_slotinfo. This ++ function does not raise any exception. It should only be called if ++ resize_tls_slotinfo returned true. */ ++static void ++update_tls_slotinfo (struct link_map *new) ++{ ++ unsigned int first_static_tls = new->l_searchlist.r_nlist; ++ for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i) ++ { ++ struct link_map *imap = new->l_searchlist.r_list[i]; ++ ++ /* Only add TLS memory if this object is loaded now and ++ therefore is not yet initialized. */ ++ if (! imap->l_init_called && imap->l_tls_blocksize > 0) ++ { ++ _dl_add_to_slotinfo (imap, true); ++ ++ if (imap->l_need_tls_init ++ && first_static_tls == new->l_searchlist.r_nlist) ++ first_static_tls = i; ++ } ++ } ++ ++ if (__builtin_expect (++GL(dl_tls_generation) == 0, 0)) ++ _dl_fatal_printf (N_("\ ++TLS generation counter wrapped! Please report this.")); ++ ++ /* We need a second pass for static tls data, because ++ _dl_update_slotinfo must not be run while calls to ++ _dl_add_to_slotinfo are still pending. */ ++ for (unsigned int i = first_static_tls; i < new->l_searchlist.r_nlist; ++i) ++ { ++ struct link_map *imap = new->l_searchlist.r_list[i]; ++ ++ if (imap->l_need_tls_init ++ && ! imap->l_init_called ++ && imap->l_tls_blocksize > 0) ++ { ++ /* For static TLS we have to allocate the memory here and ++ now, but we can delay updating the DTV. */ ++ imap->l_need_tls_init = 0; ++#ifdef SHARED ++ /* Update the slot information data for at least the ++ generation of the DSO we are allocating data for. */ ++ ++ /* FIXME: This can terminate the process on memory ++ allocation failure. It is not possible to raise ++ exceptions from this context; to fix this bug, ++ _dl_update_slotinfo would have to be split into two ++ operations, similar to resize_scopes and update_scopes ++ above. This is related to bug 16134. */ ++ _dl_update_slotinfo (imap->l_tls_modid); ++#endif ++ ++ GL(dl_init_static_tls) (imap); ++ assert (imap->l_need_tls_init == 0); ++ } ++ } ++} ++ + /* struct dl_init_args and call_dl_init are used to call _dl_init with + exception handling disabled. */ + struct dl_init_args +@@ -431,133 +641,40 @@ dl_open_worker (void *a) + relocation. */ + _dl_open_check (new); + +- /* If the file is not loaded now as a dependency, add the search +- list of the newly loaded object to the scope. */ +- bool any_tls = false; +- unsigned int first_static_tls = new->l_searchlist.r_nlist; +- for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i) +- { +- struct link_map *imap = new->l_searchlist.r_list[i]; +- int from_scope = 0; ++ /* This only performs the memory allocations. The actual update of ++ the scopes happens below, after failure is impossible. */ ++ resize_scopes (new); + +- /* If the initializer has been called already, the object has +- not been loaded here and now. */ +- if (imap->l_init_called && imap->l_type == lt_loaded) +- { +- struct r_scope_elem **runp = imap->l_scope; +- size_t cnt = 0; +- +- while (*runp != NULL) +- { +- if (*runp == &new->l_searchlist) +- break; +- ++cnt; +- ++runp; +- } +- +- if (*runp != NULL) +- /* Avoid duplicates. */ +- continue; +- +- if (__glibc_unlikely (cnt + 1 >= imap->l_scope_max)) +- { +- /* The 'r_scope' array is too small. Allocate a new one +- dynamically. */ +- size_t new_size; +- struct r_scope_elem **newp; +- +-#define SCOPE_ELEMS(imap) \ +- (sizeof (imap->l_scope_mem) / sizeof (imap->l_scope_mem[0])) ++ /* Increase the size of the GL (dl_tls_dtv_slotinfo_list) data ++ structure. */ ++ bool any_tls = resize_tls_slotinfo (new); + +- if (imap->l_scope != imap->l_scope_mem +- && imap->l_scope_max < SCOPE_ELEMS (imap)) +- { +- new_size = SCOPE_ELEMS (imap); +- newp = imap->l_scope_mem; +- } +- else +- { +- new_size = imap->l_scope_max * 2; +- newp = (struct r_scope_elem **) +- malloc (new_size * sizeof (struct r_scope_elem *)); +- if (newp == NULL) +- _dl_signal_error (ENOMEM, "dlopen", NULL, +- N_("cannot create scope list")); +- } +- +- memcpy (newp, imap->l_scope, cnt * sizeof (imap->l_scope[0])); +- struct r_scope_elem **old = imap->l_scope; +- +- imap->l_scope = newp; +- +- if (old != imap->l_scope_mem) +- _dl_scope_free (old); +- +- imap->l_scope_max = new_size; +- } +- +- /* First terminate the extended list. Otherwise a thread +- might use the new last element and then use the garbage +- at offset IDX+1. */ +- imap->l_scope[cnt + 1] = NULL; +- atomic_write_barrier (); +- imap->l_scope[cnt] = &new->l_searchlist; +- +- /* Print only new scope information. */ +- from_scope = cnt; +- } +- /* Only add TLS memory if this object is loaded now and +- therefore is not yet initialized. */ +- else if (! imap->l_init_called +- /* Only if the module defines thread local data. */ +- && __builtin_expect (imap->l_tls_blocksize > 0, 0)) +- { +- /* Now that we know the object is loaded successfully add +- modules containing TLS data to the slot info table. We +- might have to increase its size. */ +- _dl_add_to_slotinfo (imap); +- +- if (imap->l_need_tls_init +- && first_static_tls == new->l_searchlist.r_nlist) +- first_static_tls = i; +- +- /* We have to bump the generation counter. */ +- any_tls = true; +- } +- +- /* Print scope information. */ +- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES)) +- _dl_show_scope (imap, from_scope); +- } +- +- /* Bump the generation number if necessary. */ +- if (any_tls && __builtin_expect (++GL(dl_tls_generation) == 0, 0)) +- _dl_fatal_printf (N_("\ +-TLS generation counter wrapped! Please report this.")); +- +- /* We need a second pass for static tls data, because _dl_update_slotinfo +- must not be run while calls to _dl_add_to_slotinfo are still pending. */ +- for (unsigned int i = first_static_tls; i < new->l_searchlist.r_nlist; ++i) +- { +- struct link_map *imap = new->l_searchlist.r_list[i]; +- +- if (imap->l_need_tls_init +- && ! imap->l_init_called +- && imap->l_tls_blocksize > 0) +- { +- /* For static TLS we have to allocate the memory here and +- now, but we can delay updating the DTV. */ +- imap->l_need_tls_init = 0; +-#ifdef SHARED +- /* Update the slot information data for at least the +- generation of the DSO we are allocating data for. */ +- _dl_update_slotinfo (imap->l_tls_modid); +-#endif ++ /* Perform the necessary allocations for adding new global objects ++ to the global scope below. */ ++ if (mode & RTLD_GLOBAL) ++ add_to_global_resize (new); + +- GL(dl_init_static_tls) (imap); +- assert (imap->l_need_tls_init == 0); +- } +- } ++ /* Demarcation point: After this, no recoverable errors are allowed. ++ All memory allocations for new objects must have happened ++ before. */ ++ ++ /* Second stage after resize_scopes: Actually perform the scope ++ update. After this, dlsym and lazy binding can bind to new ++ objects. */ ++ update_scopes (new); ++ ++ /* FIXME: It is unclear whether the order here is correct. ++ Shouldn't new objects be made available for binding (and thus ++ execution) only after there TLS data has been set up fully? ++ Fixing bug 16134 will likely make this distinction less ++ important. */ ++ ++ /* Second stage after resize_tls_slotinfo: Update the slotinfo data ++ structures. */ ++ if (any_tls) ++ /* FIXME: This calls _dl_update_slotinfo, which aborts the process ++ on memory allocation failure. See bug 16134. */ ++ update_tls_slotinfo (new); + + /* Notify the debugger all new objects have been relocated. */ + if (relocation_in_progress) +diff --git a/elf/dl-tls.c b/elf/dl-tls.c +index c87caf13d6a97ba4..a2def280b7096960 100644 +--- a/elf/dl-tls.c ++++ b/elf/dl-tls.c +@@ -883,7 +883,7 @@ _dl_tls_get_addr_soft (struct link_map *l) + + + void +-_dl_add_to_slotinfo (struct link_map *l) ++_dl_add_to_slotinfo (struct link_map *l, bool do_add) + { + /* Now that we know the object is loaded successfully add + modules containing TLS data to the dtv info table. We +@@ -939,6 +939,9 @@ cannot create TLS data structures")); + } + + /* Add the information into the slotinfo data structure. */ +- listp->slotinfo[idx].map = l; +- listp->slotinfo[idx].gen = GL(dl_tls_generation) + 1; ++ if (do_add) ++ { ++ listp->slotinfo[idx].map = l; ++ listp->slotinfo[idx].gen = GL(dl_tls_generation) + 1; ++ } + } +diff --git a/elf/rtld.c b/elf/rtld.c +index 4ec26a79cbb0aa4f..0aa1a2a19f649e16 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -2167,7 +2167,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", + + /* Add object to slot information data if necessasy. */ + if (l->l_tls_blocksize != 0 && tls_init_tp_called) +- _dl_add_to_slotinfo (l); ++ _dl_add_to_slotinfo (l, true); + } + } + else +@@ -2215,7 +2215,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", + + /* Add object to slot information data if necessasy. */ + if (l->l_tls_blocksize != 0 && tls_init_tp_called) +- _dl_add_to_slotinfo (l); ++ _dl_add_to_slotinfo (l, true); + } + HP_TIMING_NOW (stop); + +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 57fbefea3cb841e9..c6b7e61badbfd513 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -1135,8 +1135,15 @@ extern void *_dl_open (const char *name, int mode, const void *caller, + old scope, OLD can't be freed until no thread is using it. */ + extern int _dl_scope_free (void *) attribute_hidden; + +-/* Add module to slot information data. */ +-extern void _dl_add_to_slotinfo (struct link_map *l) attribute_hidden; ++ ++/* Add module to slot information data. If DO_ADD is false, only the ++ required memory is allocated. Must be called with GL ++ (dl_load_lock) acquired. If the function has already been called ++ for the link map L with !do_add, then this function will not raise ++ an exception, otherwise it is possible that it encounters a memory ++ allocation failure. */ ++extern void _dl_add_to_slotinfo (struct link_map *l, bool do_add) ++ attribute_hidden; + + /* Update slot information data for at least the generation of the + module with the given index. */ diff --git a/SOURCES/glibc-rh1410154-8.patch b/SOURCES/glibc-rh1410154-8.patch new file mode 100644 index 0000000..c22f32a --- /dev/null +++ b/SOURCES/glibc-rh1410154-8.patch @@ -0,0 +1,619 @@ +commit f63b73814f74032c0e5d0a83300e3d864ef905e5 +Author: Florian Weimer +Date: Wed Nov 13 15:44:56 2019 +0100 + + Remove all loaded objects if dlopen fails, ignoring NODELETE [BZ #20839] + + This introduces a “pending NODELETE” state in the link map, which is + flipped to the persistent NODELETE state late in dlopen, via + activate_nodelete. During initial relocation, symbol binding + records pending NODELETE state only. dlclose ignores pending NODELETE + state. Taken together, this results that a partially completed dlopen + is rolled back completely because new NODELETE mappings are unloaded. + + Tested on x86_64-linux-gnu and i386-linux-gnu. + + Change-Id: Ib2a3d86af6f92d75baca65431d74783ee0dbc292 + +Conflicts: + elf/Makefile + (Usual conflicts due to test backport differences.) + +diff --git a/elf/Makefile b/elf/Makefile +index b752f6366400d221..bf7c41f38be42184 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -191,7 +191,8 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + tst-nodelete2 tst-audit11 tst-audit12 tst-dlsym-error tst-noload \ + tst-latepthread tst-tls-manydynamic tst-nodelete-dlclose \ + tst-debug1 tst-main1 tst-absolute-sym tst-absolute-zero tst-big-note \ +- tst-sonamemove-link tst-sonamemove-dlopen tst-initfinilazyfail ++ tst-sonamemove-link tst-sonamemove-dlopen tst-initfinilazyfail \ ++ tst-dlopenfail + # reldep9 + tests-internal += loadtest unload unload2 circleload1 \ + neededtest neededtest2 neededtest3 neededtest4 \ +@@ -282,7 +283,8 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + tst-absolute-zero-lib tst-big-note-lib \ + tst-sonamemove-linkmod1 \ + tst-sonamemove-runmod1 tst-sonamemove-runmod2 \ +- tst-initlazyfailmod tst-finilazyfailmod ++ tst-initlazyfailmod tst-finilazyfailmod \ ++ tst-dlopenfailmod1 tst-dlopenfaillinkmod tst-dlopenfailmod2 + + ifeq (yes,$(have-mtls-dialect-gnu2)) + tests += tst-gnu2-tls1 +@@ -1537,3 +1539,13 @@ LDFLAGS-tst-initlazyfailmod.so = \ + -Wl,-z,lazy -Wl,--unresolved-symbols=ignore-all + LDFLAGS-tst-finilazyfailmod.so = \ + -Wl,-z,lazy -Wl,--unresolved-symbols=ignore-all ++ ++$(objpfx)tst-dlopenfail: $(libdl) ++$(objpfx)tst-dlopenfail.out: \ ++ $(objpfx)tst-dlopenfailmod1.so $(objpfx)tst-dlopenfailmod2.so ++# Order matters here. tst-dlopenfaillinkmod.so's soname ensures ++# a run-time loader failure. ++$(objpfx)tst-dlopenfailmod1.so: \ ++ $(shared-thread-library) $(objpfx)tst-dlopenfaillinkmod.so ++LDFLAGS-tst-dlopenfaillinkmod.so = -Wl,-soname,tst-dlopenfail-missingmod.so ++$(objpfx)tst-dlopenfailmod2.so: $(shared-thread-library) +diff --git a/elf/dl-close.c b/elf/dl-close.c +index 88aeea25839a34e0..243a028c443173c1 100644 +--- a/elf/dl-close.c ++++ b/elf/dl-close.c +@@ -168,14 +168,6 @@ _dl_close_worker (struct link_map *map, bool force) + char done[nloaded]; + struct link_map *maps[nloaded]; + +- /* Clear DF_1_NODELETE to force object deletion. We don't need to touch +- l_tls_dtor_count because forced object deletion only happens when an +- error occurs during object load. Destructor registration for TLS +- non-POD objects should not have happened till then for this +- object. */ +- if (force) +- map->l_flags_1 &= ~DF_1_NODELETE; +- + /* Run over the list and assign indexes to the link maps and enter + them into the MAPS array. */ + int idx = 0; +@@ -205,7 +197,7 @@ _dl_close_worker (struct link_map *map, bool force) + /* Check whether this object is still used. */ + if (l->l_type == lt_loaded + && l->l_direct_opencount == 0 +- && (l->l_flags_1 & DF_1_NODELETE) == 0 ++ && l->l_nodelete != link_map_nodelete_active + /* See CONCURRENCY NOTES in cxa_thread_atexit_impl.c to know why + acquire is sufficient and correct. */ + && atomic_load_acquire (&l->l_tls_dtor_count) == 0 +@@ -288,7 +280,7 @@ _dl_close_worker (struct link_map *map, bool force) + if (!used[i]) + { + assert (imap->l_type == lt_loaded +- && (imap->l_flags_1 & DF_1_NODELETE) == 0); ++ && imap->l_nodelete != link_map_nodelete_active); + + /* Call its termination function. Do not do it for + half-cooked objects. Temporarily disable exception +@@ -828,7 +820,7 @@ _dl_close (void *_map) + before we took the lock. There is no way to detect this (see below) + so we proceed assuming this isn't the case. First see whether we + can remove the object at all. */ +- if (__glibc_unlikely (map->l_flags_1 & DF_1_NODELETE)) ++ if (__glibc_unlikely (map->l_nodelete == link_map_nodelete_active)) + { + /* Nope. Do nothing. */ + __rtld_lock_unlock_recursive (GL(dl_load_lock)); +diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c +index efbdb8deb3c0a9d4..c5e5857fb1fe2808 100644 +--- a/elf/dl-lookup.c ++++ b/elf/dl-lookup.c +@@ -192,9 +192,10 @@ enter_unique_sym (struct unique_sym *table, size_t size, + Return the matching symbol in RESULT. */ + static void + do_lookup_unique (const char *undef_name, uint_fast32_t new_hash, +- const struct link_map *map, struct sym_val *result, ++ struct link_map *map, struct sym_val *result, + int type_class, const ElfW(Sym) *sym, const char *strtab, +- const ElfW(Sym) *ref, const struct link_map *undef_map) ++ const ElfW(Sym) *ref, const struct link_map *undef_map, ++ int flags) + { + /* We have to determine whether we already found a symbol with this + name before. If not then we have to add it to the search table. +@@ -222,7 +223,7 @@ do_lookup_unique (const char *undef_name, uint_fast32_t new_hash, + copy from the copy addressed through the + relocation. */ + result->s = sym; +- result->m = (struct link_map *) map; ++ result->m = map; + } + else + { +@@ -311,9 +312,19 @@ do_lookup_unique (const char *undef_name, uint_fast32_t new_hash, + new_hash, strtab + sym->st_name, sym, map); + + if (map->l_type == lt_loaded) +- /* Make sure we don't unload this object by +- setting the appropriate flag. */ +- ((struct link_map *) map)->l_flags_1 |= DF_1_NODELETE; ++ { ++ /* Make sure we don't unload this object by ++ setting the appropriate flag. */ ++ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_BINDINGS) ++ && map->l_nodelete == link_map_nodelete_inactive) ++ _dl_debug_printf ("\ ++marking %s [%lu] as NODELETE due to unique symbol\n", ++ map->l_name, map->l_ns); ++ if (flags & DL_LOOKUP_FOR_RELOCATE) ++ map->l_nodelete = link_map_nodelete_pending; ++ else ++ map->l_nodelete = link_map_nodelete_active; ++ } + } + ++tab->n_elements; + +@@ -525,8 +536,9 @@ do_lookup_x (const char *undef_name, uint_fast32_t new_hash, + return 1; + + case STB_GNU_UNIQUE:; +- do_lookup_unique (undef_name, new_hash, map, result, type_class, +- sym, strtab, ref, undef_map); ++ do_lookup_unique (undef_name, new_hash, (struct link_map *) map, ++ result, type_class, sym, strtab, ref, ++ undef_map, flags); + return 1; + + default: +@@ -568,9 +580,13 @@ add_dependency (struct link_map *undef_map, struct link_map *map, int flags) + if (undef_map == map) + return 0; + +- /* Avoid references to objects which cannot be unloaded anyway. */ ++ /* Avoid references to objects which cannot be unloaded anyway. We ++ do not need to record dependencies if this object goes away ++ during dlopen failure, either. IFUNC resolvers with relocation ++ dependencies may pick an dependency which can be dlclose'd, but ++ such IFUNC resolvers are undefined anyway. */ + assert (map->l_type == lt_loaded); +- if ((map->l_flags_1 & DF_1_NODELETE) != 0) ++ if (map->l_nodelete != link_map_nodelete_inactive) + return 0; + + struct link_map_reldeps *l_reldeps +@@ -678,16 +694,33 @@ add_dependency (struct link_map *undef_map, struct link_map *map, int flags) + + /* Redo the NODELETE check, as when dl_load_lock wasn't held + yet this could have changed. */ +- if ((map->l_flags_1 & DF_1_NODELETE) != 0) ++ if (map->l_nodelete != link_map_nodelete_inactive) + goto out; + + /* If the object with the undefined reference cannot be removed ever + just make sure the same is true for the object which contains the + definition. */ + if (undef_map->l_type != lt_loaded +- || (undef_map->l_flags_1 & DF_1_NODELETE) != 0) ++ || (undef_map->l_nodelete != link_map_nodelete_inactive)) + { +- map->l_flags_1 |= DF_1_NODELETE; ++ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_BINDINGS) ++ && map->l_nodelete == link_map_nodelete_inactive) ++ { ++ if (undef_map->l_name[0] == '\0') ++ _dl_debug_printf ("\ ++marking %s [%lu] as NODELETE due to reference to main program\n", ++ map->l_name, map->l_ns); ++ else ++ _dl_debug_printf ("\ ++marking %s [%lu] as NODELETE due to reference to %s [%lu]\n", ++ map->l_name, map->l_ns, ++ undef_map->l_name, undef_map->l_ns); ++ } ++ ++ if (flags & DL_LOOKUP_FOR_RELOCATE) ++ map->l_nodelete = link_map_nodelete_pending; ++ else ++ map->l_nodelete = link_map_nodelete_active; + goto out; + } + +@@ -712,7 +745,18 @@ add_dependency (struct link_map *undef_map, struct link_map *map, int flags) + no fatal problem. We simply make sure the referenced object + cannot be unloaded. This is semantically the correct + behavior. */ +- map->l_flags_1 |= DF_1_NODELETE; ++ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_BINDINGS) ++ && map->l_nodelete == link_map_nodelete_inactive) ++ _dl_debug_printf ("\ ++marking %s [%lu] as NODELETE due to memory allocation failure\n", ++ map->l_name, map->l_ns); ++ if (flags & DL_LOOKUP_FOR_RELOCATE) ++ /* In case of non-lazy binding, we could actually ++ report the memory allocation error, but for now, we ++ use the conservative approximation as well. */ ++ map->l_nodelete = link_map_nodelete_pending; ++ else ++ map->l_nodelete = link_map_nodelete_active; + goto out; + } + else +diff --git a/elf/dl-open.c b/elf/dl-open.c +index b330cff7d349224a..79c6e4c8ed1c9dfa 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -424,6 +424,40 @@ TLS generation counter wrapped! Please report this.")); + } + } + ++/* Mark the objects as NODELETE if required. This is delayed until ++ after dlopen failure is not possible, so that _dl_close can clean ++ up objects if necessary. */ ++static void ++activate_nodelete (struct link_map *new, int mode) ++{ ++ if (mode & RTLD_NODELETE || new->l_nodelete == link_map_nodelete_pending) ++ { ++ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_FILES)) ++ _dl_debug_printf ("activating NODELETE for %s [%lu]\n", ++ new->l_name, new->l_ns); ++ new->l_nodelete = link_map_nodelete_active; ++ } ++ ++ for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i) ++ { ++ struct link_map *imap = new->l_searchlist.r_list[i]; ++ if (imap->l_nodelete == link_map_nodelete_pending) ++ { ++ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_FILES)) ++ _dl_debug_printf ("activating NODELETE for %s [%lu]\n", ++ imap->l_name, imap->l_ns); ++ ++ /* Only new objects should have set ++ link_map_nodelete_pending. Existing objects should not ++ have gained any new dependencies and therefore cannot ++ reach NODELETE status. */ ++ assert (!imap->l_init_called || imap->l_type != lt_loaded); ++ ++ imap->l_nodelete = link_map_nodelete_active; ++ } ++ } ++} ++ + /* struct dl_init_args and call_dl_init are used to call _dl_init with + exception handling disabled. */ + struct dl_init_args +@@ -493,12 +527,6 @@ dl_open_worker (void *a) + return; + } + +- /* Mark the object as not deletable if the RTLD_NODELETE flags was passed. +- Do this early so that we don't skip marking the object if it was +- already loaded. */ +- if (__glibc_unlikely (mode & RTLD_NODELETE)) +- new->l_flags_1 |= DF_1_NODELETE; +- + if (__glibc_unlikely (mode & __RTLD_SPROF)) + /* This happens only if we load a DSO for 'sprof'. */ + return; +@@ -514,19 +542,37 @@ dl_open_worker (void *a) + _dl_debug_printf ("opening file=%s [%lu]; direct_opencount=%u\n\n", + new->l_name, new->l_ns, new->l_direct_opencount); + +- /* If the user requested the object to be in the global namespace +- but it is not so far, add it now. */ ++ /* If the user requested the object to be in the global ++ namespace but it is not so far, prepare to add it now. This ++ can raise an exception to do a malloc failure. */ + if ((mode & RTLD_GLOBAL) && new->l_global == 0) ++ add_to_global_resize (new); ++ ++ /* Mark the object as not deletable if the RTLD_NODELETE flags ++ was passed. */ ++ if (__glibc_unlikely (mode & RTLD_NODELETE)) + { +- add_to_global_resize (new); +- add_to_global_update (new); ++ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_FILES) ++ && new->l_nodelete == link_map_nodelete_inactive) ++ _dl_debug_printf ("marking %s [%lu] as NODELETE\n", ++ new->l_name, new->l_ns); ++ new->l_nodelete = link_map_nodelete_active; + } + ++ /* Finalize the addition to the global scope. */ ++ if ((mode & RTLD_GLOBAL) && new->l_global == 0) ++ add_to_global_update (new); ++ + assert (_dl_debug_initialize (0, args->nsid)->r_state == RT_CONSISTENT); + + return; + } + ++ /* Schedule NODELETE marking for the directly loaded object if ++ requested. */ ++ if (__glibc_unlikely (mode & RTLD_NODELETE)) ++ new->l_nodelete = link_map_nodelete_pending; ++ + /* Load that object's dependencies. */ + _dl_map_object_deps (new, NULL, 0, 0, + mode & (__RTLD_DLOPEN | RTLD_DEEPBIND | __RTLD_AUDIT)); +@@ -598,6 +644,14 @@ dl_open_worker (void *a) + + int relocation_in_progress = 0; + ++ /* Perform relocation. This can trigger lazy binding in IFUNC ++ resolvers. For NODELETE mappings, these dependencies are not ++ recorded because the flag has not been applied to the newly ++ loaded objects. This means that upon dlopen failure, these ++ NODELETE objects can be unloaded despite existing references to ++ them. However, such relocation dependencies in IFUNC resolvers ++ are undefined anyway, so this is not a problem. */ ++ + for (unsigned int i = nmaps; i-- > 0; ) + { + l = maps[i]; +@@ -627,7 +681,7 @@ dl_open_worker (void *a) + _dl_start_profile (); + + /* Prevent unloading the object. */ +- GL(dl_profile_map)->l_flags_1 |= DF_1_NODELETE; ++ GL(dl_profile_map)->l_nodelete = link_map_nodelete_active; + } + } + else +@@ -658,6 +712,8 @@ dl_open_worker (void *a) + All memory allocations for new objects must have happened + before. */ + ++ activate_nodelete (new, mode); ++ + /* Second stage after resize_scopes: Actually perform the scope + update. After this, dlsym and lazy binding can bind to new + objects. */ +@@ -817,6 +873,10 @@ no more namespaces available for dlmopen()")); + GL(dl_tls_dtv_gaps) = true; + + _dl_close_worker (args.map, true); ++ ++ /* All link_map_nodelete_pending objects should have been ++ deleted at this point, which is why it is not necessary ++ to reset the flag here. */ + } + + assert (_dl_debug_initialize (0, args.nsid)->r_state == RT_CONSISTENT); +diff --git a/elf/get-dynamic-info.h b/elf/get-dynamic-info.h +index 4b1ea7c4078ee947..ea286abaea0128d1 100644 +--- a/elf/get-dynamic-info.h ++++ b/elf/get-dynamic-info.h +@@ -163,6 +163,8 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp) + if (info[VERSYMIDX (DT_FLAGS_1)] != NULL) + { + l->l_flags_1 = info[VERSYMIDX (DT_FLAGS_1)]->d_un.d_val; ++ if (l->l_flags_1 & DF_1_NODELETE) ++ l->l_nodelete = link_map_nodelete_pending; + + /* Only DT_1_SUPPORTED_MASK bits are supported, and we would like + to assert this, but we can't. Users have been setting +diff --git a/elf/tst-dlopenfail.c b/elf/tst-dlopenfail.c +new file mode 100644 +index 0000000000000000..ce3140c899562ca8 +--- /dev/null ++++ b/elf/tst-dlopenfail.c +@@ -0,0 +1,79 @@ ++/* Test dlopen rollback after failures involving NODELETE objects (bug 20839). ++ Copyright (C) 2019 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ /* This test uses libpthread as the canonical NODELETE module. If ++ libpthread is no longer NODELETE because it has been merged into ++ libc, the test needs to be updated. */ ++ TEST_VERIFY (dlsym (NULL, "pthread_create") == NULL); ++ ++ /* This is expected to fail because of the missing dependency. */ ++ puts ("info: attempting to load tst-dlopenfailmod1.so"); ++ TEST_VERIFY (dlopen ("tst-dlopenfailmod1.so", RTLD_LAZY) == NULL); ++ const char *message = dlerror (); ++ TEST_COMPARE_STRING (message, ++ "tst-dlopenfail-missingmod.so:" ++ " cannot open shared object file:" ++ " No such file or directory"); ++ ++ /* Do not probe for the presence of libpthread at this point because ++ that might trigger relocation if bug 20839 is present, obscuring ++ a subsequent crash. */ ++ ++ /* This is expected to succeed. */ ++ puts ("info: loading tst-dlopenfailmod2.so"); ++ void *handle = xdlopen ("tst-dlopenfailmod2.so", RTLD_NOW); ++ xdlclose (handle); ++ ++ /* libpthread should remain loaded. */ ++ TEST_VERIFY (dlopen (LIBPTHREAD_SO, RTLD_LAZY | RTLD_NOLOAD) != NULL); ++ TEST_VERIFY (dlsym (NULL, "pthread_create") == NULL); ++ ++ /* We can make libpthread global, and then the symbol should become ++ available. */ ++ TEST_VERIFY (dlopen (LIBPTHREAD_SO, RTLD_LAZY | RTLD_GLOBAL) != NULL); ++ TEST_VERIFY (dlsym (NULL, "pthread_create") != NULL); ++ ++ /* sem_open is sufficiently complex to depend on relocations. */ ++ void *(*sem_open_ptr) (const char *, int flag, ...) ++ = dlsym (NULL, "sem_open"); ++ if (sem_open_ptr == NULL) ++ /* Hurd does not implement sem_open. */ ++ puts ("warning: sem_open not found, further testing not possible"); ++ else ++ { ++ errno = 0; ++ TEST_VERIFY (sem_open_ptr ("/", 0) == NULL); ++ TEST_COMPARE (errno, EINVAL); ++ } ++ ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-dlopenfaillinkmod.c b/elf/tst-dlopenfaillinkmod.c +new file mode 100644 +index 0000000000000000..3b14b02bc9a12c0b +--- /dev/null ++++ b/elf/tst-dlopenfaillinkmod.c +@@ -0,0 +1,17 @@ ++/* Empty module with a soname which is not available at run time. ++ Copyright (C) 2019 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 ++ . */ +diff --git a/elf/tst-dlopenfailmod1.c b/elf/tst-dlopenfailmod1.c +new file mode 100644 +index 0000000000000000..6ef48829899a5a64 +--- /dev/null ++++ b/elf/tst-dlopenfailmod1.c +@@ -0,0 +1,36 @@ ++/* Module which depends on two modules: one NODELETE, one missing. ++ Copyright (C) 2019 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 ++ . */ ++ ++/* Note: Due to the missing second module, this object cannot be ++ loaded at run time. */ ++ ++#include ++#include ++#include ++ ++/* Force linking against libpthread. */ ++void *pthread_create_reference = pthread_create; ++ ++/* The constructor will never be executed because the module cannot be ++ loaded. */ ++static void __attribute__ ((constructor)) ++init (void) ++{ ++ puts ("tst-dlopenfailmod1 constructor executed"); ++ _exit (1); ++} +diff --git a/elf/tst-dlopenfailmod2.c b/elf/tst-dlopenfailmod2.c +new file mode 100644 +index 0000000000000000..7d600386c13b98bd +--- /dev/null ++++ b/elf/tst-dlopenfailmod2.c +@@ -0,0 +1,29 @@ ++/* Module which depends on on a NODELETE module, and can be loaded. ++ Copyright (C) 2019 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 ++ . */ ++ ++#include ++#include ++ ++/* Force linking against libpthread. */ ++void *pthread_create_reference = pthread_create; ++ ++static void __attribute__ ((constructor)) ++init (void) ++{ ++ puts ("info: tst-dlopenfailmod2.so constructor invoked"); ++} +diff --git a/include/link.h b/include/link.h +index 83b1c34b7b4db8f3..a277b77cad6b52b1 100644 +--- a/include/link.h ++++ b/include/link.h +@@ -79,6 +79,21 @@ struct r_search_path_struct + int malloced; + }; + ++/* Type used by the l_nodelete member. */ ++enum link_map_nodelete ++{ ++ /* This link map can be deallocated. */ ++ link_map_nodelete_inactive = 0, /* Zero-initialized in _dl_new_object. */ ++ ++ /* This link map cannot be deallocated. */ ++ link_map_nodelete_active, ++ ++ /* This link map cannot be deallocated after dlopen has succeded. ++ dlopen turns this into link_map_nodelete_active. dlclose treats ++ this intermediate state as link_map_nodelete_active. */ ++ link_map_nodelete_pending, ++}; ++ + + /* Structure describing a loaded shared object. The `l_next' and `l_prev' + members form a chain of all the shared objects loaded at startup. +@@ -203,6 +218,11 @@ struct link_map + freed, ie. not allocated with + the dummy malloc in ld.so. */ + ++ /* Actually of type enum link_map_nodelete. Separate byte due to ++ a read in add_dependency in elf/dl-lookup.c outside the loader ++ lock. Only valid for l_type == lt_loaded. */ ++ unsigned char l_nodelete; ++ + #include + + /* Collected information about own RPATH directories. */ diff --git a/SOURCES/glibc-rh1410154-9.patch b/SOURCES/glibc-rh1410154-9.patch new file mode 100644 index 0000000..ab5a3df --- /dev/null +++ b/SOURCES/glibc-rh1410154-9.patch @@ -0,0 +1,104 @@ +commit a2e8aa0d9ea648068d8be52dd7b15f1b6a008e23 +Author: Florian Weimer +Date: Thu Oct 31 19:30:19 2019 +0100 + + Block signals during the initial part of dlopen + + Lazy binding in a signal handler that interrupts a dlopen sees + intermediate dynamic linker state. This has likely been always + unsafe, but with the new pending NODELETE state, this is clearly + incorrect. Other threads are excluded via the loader lock, but the + current thread is not. Blocking signals until right before ELF + constructors run is the safe thing to do. + + Change-Id: Iad079080ebe7442c13313ba11dc2797953faef35 + +diff --git a/elf/dl-open.c b/elf/dl-open.c +index 79c6e4c8ed1c9dfa..25838b073ac1edaf 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -52,6 +53,10 @@ struct dl_open_args + /* Namespace ID. */ + Lmid_t nsid; + ++ /* Original signal mask. Used for unblocking signal handlers before ++ running ELF constructors. */ ++ sigset_t original_signal_mask; ++ + /* Original value of _ns_global_scope_pending_adds. Set by + dl_open_worker. Only valid if nsid is a real namespace + (non-negative). */ +@@ -524,12 +529,16 @@ dl_open_worker (void *a) + if (new == NULL) + { + assert (mode & RTLD_NOLOAD); ++ __libc_signal_restore_set (&args->original_signal_mask); + return; + } + + if (__glibc_unlikely (mode & __RTLD_SPROF)) +- /* This happens only if we load a DSO for 'sprof'. */ +- return; ++ { ++ /* This happens only if we load a DSO for 'sprof'. */ ++ __libc_signal_restore_set (&args->original_signal_mask); ++ return; ++ } + + /* This object is directly loaded. */ + ++new->l_direct_opencount; +@@ -565,6 +574,7 @@ dl_open_worker (void *a) + + assert (_dl_debug_initialize (0, args->nsid)->r_state == RT_CONSISTENT); + ++ __libc_signal_restore_set (&args->original_signal_mask); + return; + } + +@@ -745,6 +755,10 @@ dl_open_worker (void *a) + if (mode & RTLD_GLOBAL) + add_to_global_resize (new); + ++ /* Unblock signals. Data structures are now consistent, and ++ application code may run. */ ++ __libc_signal_restore_set (&args->original_signal_mask); ++ + /* Run the initializer functions of new objects. Temporarily + disable the exception handler, so that lazy binding failures are + fatal. */ +@@ -834,6 +848,10 @@ no more namespaces available for dlmopen()")); + args.argv = argv; + args.env = env; + ++ /* Recursive lazy binding during manipulation of the dynamic loader ++ structures may result in incorrect behavior. */ ++ __libc_signal_block_all (&args.original_signal_mask); ++ + struct dl_exception exception; + int errcode = _dl_catch_exception (&exception, dl_open_worker, &args); + +@@ -874,10 +892,16 @@ no more namespaces available for dlmopen()")); + + _dl_close_worker (args.map, true); + ++ /* Restore the signal mask. In the success case, this ++ happens inside dl_open_worker. */ ++ __libc_signal_restore_set (&args.original_signal_mask); ++ + /* All link_map_nodelete_pending objects should have been + deleted at this point, which is why it is not necessary + to reset the flag here. */ + } ++ else ++ __libc_signal_restore_set (&args.original_signal_mask); + + assert (_dl_debug_initialize (0, args.nsid)->r_state == RT_CONSISTENT); + diff --git a/SOURCES/glibc-rh1682954.patch b/SOURCES/glibc-rh1682954.patch new file mode 100644 index 0000000..4892f52 --- /dev/null +++ b/SOURCES/glibc-rh1682954.patch @@ -0,0 +1,545 @@ +From 0d3905b110000463775b3fb189213833acaebf81 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Mon, 1 Jul 2019 12:23:10 -0700 +Subject: Call _dl_open_check after relocation [BZ #24259] + +This is a workaround for [BZ #20839] which doesn't remove the NODELETE +object when _dl_open_check throws an exception. Move it after relocation +in dl_open_worker to avoid leaving the NODELETE object mapped without +relocation. + + [BZ #24259] + * elf/dl-open.c (dl_open_worker): Call _dl_open_check after + relocation. + * sysdeps/x86/Makefile (tests): Add tst-cet-legacy-5a, + tst-cet-legacy-5b, tst-cet-legacy-6a and tst-cet-legacy-6b. + (modules-names): Add tst-cet-legacy-mod-5a, tst-cet-legacy-mod-5b, + tst-cet-legacy-mod-5c, tst-cet-legacy-mod-6a, tst-cet-legacy-mod-6b + and tst-cet-legacy-mod-6c. + (CFLAGS-tst-cet-legacy-5a.c): New. + (CFLAGS-tst-cet-legacy-5b.c): Likewise. + (CFLAGS-tst-cet-legacy-mod-5a.c): Likewise. + (CFLAGS-tst-cet-legacy-mod-5b.c): Likewise. + (CFLAGS-tst-cet-legacy-mod-5c.c): Likewise. + (CFLAGS-tst-cet-legacy-6a.c): Likewise. + (CFLAGS-tst-cet-legacy-6b.c): Likewise. + (CFLAGS-tst-cet-legacy-mod-6a.c): Likewise. + (CFLAGS-tst-cet-legacy-mod-6b.c): Likewise. + (CFLAGS-tst-cet-legacy-mod-6c.c): Likewise. + ($(objpfx)tst-cet-legacy-5a): Likewise. + ($(objpfx)tst-cet-legacy-5a.out): Likewise. + ($(objpfx)tst-cet-legacy-mod-5a.so): Likewise. + ($(objpfx)tst-cet-legacy-mod-5b.so): Likewise. + ($(objpfx)tst-cet-legacy-5b): Likewise. + ($(objpfx)tst-cet-legacy-5b.out): Likewise. + (tst-cet-legacy-5b-ENV): Likewise. + ($(objpfx)tst-cet-legacy-6a): Likewise. + ($(objpfx)tst-cet-legacy-6a.out): Likewise. + ($(objpfx)tst-cet-legacy-mod-6a.so): Likewise. + ($(objpfx)tst-cet-legacy-mod-6b.so): Likewise. + ($(objpfx)tst-cet-legacy-6b): Likewise. + ($(objpfx)tst-cet-legacy-6b.out): Likewise. + (tst-cet-legacy-6b-ENV): Likewise. + * sysdeps/x86/tst-cet-legacy-5.c: New file. + * sysdeps/x86/tst-cet-legacy-5a.c: Likewise. + * sysdeps/x86/tst-cet-legacy-5b.c: Likewise. + * sysdeps/x86/tst-cet-legacy-6.c: Likewise. + * sysdeps/x86/tst-cet-legacy-6a.c: Likewise. + * sysdeps/x86/tst-cet-legacy-6b.c: Likewise. + * sysdeps/x86/tst-cet-legacy-mod-5.c: Likewise. + * sysdeps/x86/tst-cet-legacy-mod-5a.c: Likewise. + * sysdeps/x86/tst-cet-legacy-mod-5b.c: Likewise. + * sysdeps/x86/tst-cet-legacy-mod-5c.c: Likewise. + * sysdeps/x86/tst-cet-legacy-mod-6.c: Likewise. + * sysdeps/x86/tst-cet-legacy-mod-6a.c: Likewise. + * sysdeps/x86/tst-cet-legacy-mod-6b.c: Likewise. + * sysdeps/x86/tst-cet-legacy-mod-6c.c: Likewise. + +(cherry picked from commit d0093c5cefb7f7a4143f3bb03743633823229cc6) + +diff --git a/elf/dl-open.c b/elf/dl-open.c +index f6c8ef1043..518a6cad69 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -292,8 +292,6 @@ dl_open_worker (void *a) + _dl_debug_state (); + LIBC_PROBE (map_complete, 3, args->nsid, r, new); + +- _dl_open_check (new); +- + /* Print scope information. */ + if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES)) + _dl_show_scope (new, 0); +@@ -366,6 +364,12 @@ dl_open_worker (void *a) + _dl_relocate_object (l, l->l_scope, reloc_mode, 0); + } + ++ /* NB: Workaround for [BZ #20839] which doesn't remove the NODELETE ++ object when _dl_open_check throws an exception. Move it after ++ relocation to avoid leaving the NODELETE object mapped without ++ relocation. */ ++ _dl_open_check (new); ++ + /* If the file is not loaded now as a dependency, add the search + list of the newly loaded object to the scope. */ + bool any_tls = false; +diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile +index 337b0b63dc..43ad4a79ff 100644 +--- a/sysdeps/x86/Makefile ++++ b/sysdeps/x86/Makefile +@@ -19,12 +19,17 @@ ifeq ($(subdir),elf) + sysdep-dl-routines += dl-cet + + tests += tst-cet-legacy-1 tst-cet-legacy-2 tst-cet-legacy-2a \ +- tst-cet-legacy-3 tst-cet-legacy-4 ++ tst-cet-legacy-3 tst-cet-legacy-4 \ ++ tst-cet-legacy-5a tst-cet-legacy-6a + ifneq (no,$(have-tunables)) +-tests += tst-cet-legacy-4a tst-cet-legacy-4b tst-cet-legacy-4c ++tests += tst-cet-legacy-4a tst-cet-legacy-4b tst-cet-legacy-4c \ ++ tst-cet-legacy-5b tst-cet-legacy-6b + endif + modules-names += tst-cet-legacy-mod-1 tst-cet-legacy-mod-2 \ +- tst-cet-legacy-mod-4 ++ tst-cet-legacy-mod-4 tst-cet-legacy-mod-5a \ ++ tst-cet-legacy-mod-5b tst-cet-legacy-mod-5c \ ++ tst-cet-legacy-mod-6a tst-cet-legacy-mod-6b \ ++ tst-cet-legacy-mod-6c + + CFLAGS-tst-cet-legacy-2.c += -fcf-protection=branch + CFLAGS-tst-cet-legacy-2a.c += -fcf-protection +@@ -35,6 +40,16 @@ CFLAGS-tst-cet-legacy-4.c += -fcf-protection=branch + CFLAGS-tst-cet-legacy-4a.c += -fcf-protection + CFLAGS-tst-cet-legacy-4b.c += -fcf-protection + CFLAGS-tst-cet-legacy-mod-4.c += -fcf-protection=none ++CFLAGS-tst-cet-legacy-5a.c += -fcf-protection ++CFLAGS-tst-cet-legacy-5b.c += -fcf-protection ++CFLAGS-tst-cet-legacy-mod-5a.c += -fcf-protection=none ++CFLAGS-tst-cet-legacy-mod-5b.c += -fcf-protection ++CFLAGS-tst-cet-legacy-mod-5c.c += -fcf-protection ++CFLAGS-tst-cet-legacy-6a.c += -fcf-protection ++CFLAGS-tst-cet-legacy-6b.c += -fcf-protection ++CFLAGS-tst-cet-legacy-mod-6a.c += -fcf-protection=none ++CFLAGS-tst-cet-legacy-mod-6b.c += -fcf-protection ++CFLAGS-tst-cet-legacy-mod-6c.c += -fcf-protection + + $(objpfx)tst-cet-legacy-1: $(objpfx)tst-cet-legacy-mod-1.so \ + $(objpfx)tst-cet-legacy-mod-2.so +@@ -44,6 +59,17 @@ $(objpfx)tst-cet-legacy-2a: $(objpfx)tst-cet-legacy-mod-2.so $(libdl) + $(objpfx)tst-cet-legacy-2a.out: $(objpfx)tst-cet-legacy-mod-1.so + $(objpfx)tst-cet-legacy-4: $(libdl) + $(objpfx)tst-cet-legacy-4.out: $(objpfx)tst-cet-legacy-mod-4.so ++$(objpfx)tst-cet-legacy-5a: $(libdl) ++$(objpfx)tst-cet-legacy-5a.out: $(objpfx)tst-cet-legacy-mod-5a.so \ ++ $(objpfx)tst-cet-legacy-mod-5b.so ++$(objpfx)tst-cet-legacy-mod-5a.so: $(objpfx)tst-cet-legacy-mod-5c.so ++$(objpfx)tst-cet-legacy-mod-5b.so: $(objpfx)tst-cet-legacy-mod-5c.so ++$(objpfx)tst-cet-legacy-6a: $(libdl) ++$(objpfx)tst-cet-legacy-6a.out: $(objpfx)tst-cet-legacy-mod-6a.so \ ++ $(objpfx)tst-cet-legacy-mod-6b.so ++$(objpfx)tst-cet-legacy-mod-6a.so: $(objpfx)tst-cet-legacy-mod-6c.so ++$(objpfx)tst-cet-legacy-mod-6b.so: $(objpfx)tst-cet-legacy-mod-6c.so ++LDFLAGS-tst-cet-legacy-mod-6c.so = -Wl,--enable-new-dtags,-z,nodelete + ifneq (no,$(have-tunables)) + $(objpfx)tst-cet-legacy-4a: $(libdl) + $(objpfx)tst-cet-legacy-4a.out: $(objpfx)tst-cet-legacy-mod-4.so +@@ -54,6 +80,14 @@ tst-cet-legacy-4b-ENV = GLIBC_TUNABLES=glibc.tune.x86_shstk=on + $(objpfx)tst-cet-legacy-4c: $(libdl) + $(objpfx)tst-cet-legacy-4c.out: $(objpfx)tst-cet-legacy-mod-4.so + tst-cet-legacy-4c-ENV = GLIBC_TUNABLES=glibc.tune.x86_shstk=off ++$(objpfx)tst-cet-legacy-5b: $(libdl) ++$(objpfx)tst-cet-legacy-5b.out: $(objpfx)tst-cet-legacy-mod-5a.so \ ++ $(objpfx)tst-cet-legacy-mod-5b.so ++tst-cet-legacy-5b-ENV = GLIBC_TUNABLES=glibc.tune.x86_ibt=off:glibc.tune.x86_shstk=off ++$(objpfx)tst-cet-legacy-6b: $(libdl) ++$(objpfx)tst-cet-legacy-6b.out: $(objpfx)tst-cet-legacy-mod-6a.so \ ++ $(objpfx)tst-cet-legacy-mod-6b.so ++tst-cet-legacy-6b-ENV = GLIBC_TUNABLES=glibc.tune.x86_ibt=off:glibc.tune.x86_shstk=off + endif + endif + +diff --git a/sysdeps/x86/tst-cet-legacy-5.c b/sysdeps/x86/tst-cet-legacy-5.c +new file mode 100644 +index 0000000000..fbf640f664 +--- /dev/null ++++ b/sysdeps/x86/tst-cet-legacy-5.c +@@ -0,0 +1,76 @@ ++/* Check compatibility of CET-enabled executable with dlopened legacy ++ shared object. ++ Copyright (C) 2019 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++static void ++do_test_1 (const char *modname, bool fail) ++{ ++ int (*fp) (void); ++ void *h; ++ ++ h = dlopen (modname, RTLD_LAZY); ++ if (h == NULL) ++ { ++ if (fail) ++ { ++ const char *err = dlerror (); ++ if (strstr (err, "shadow stack isn't enabled") == NULL) ++ { ++ printf ("incorrect dlopen '%s' error: %s\n", modname, ++ dlerror ()); ++ exit (1); ++ } ++ ++ return; ++ } ++ ++ printf ("cannot open '%s': %s\n", modname, dlerror ()); ++ exit (1); ++ } ++ ++ fp = dlsym (h, "test"); ++ if (fp == NULL) ++ { ++ printf ("cannot get symbol 'test': %s\n", dlerror ()); ++ exit (1); ++ } ++ ++ if (fp () != 0) ++ { ++ puts ("test () != 0"); ++ exit (1); ++ } ++ ++ dlclose (h); ++} ++ ++static int ++do_test (void) ++{ ++ do_test_1 ("tst-cet-legacy-mod-5a.so", true); ++ do_test_1 ("tst-cet-legacy-mod-5b.so", false); ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/x86/tst-cet-legacy-5a.c b/sysdeps/x86/tst-cet-legacy-5a.c +new file mode 100644 +index 0000000000..fc5a609dff +--- /dev/null ++++ b/sysdeps/x86/tst-cet-legacy-5a.c +@@ -0,0 +1 @@ ++#include "tst-cet-legacy-5.c" +diff --git a/sysdeps/x86/tst-cet-legacy-5b.c b/sysdeps/x86/tst-cet-legacy-5b.c +new file mode 100644 +index 0000000000..fc5a609dff +--- /dev/null ++++ b/sysdeps/x86/tst-cet-legacy-5b.c +@@ -0,0 +1 @@ ++#include "tst-cet-legacy-5.c" +diff --git a/sysdeps/x86/tst-cet-legacy-6.c b/sysdeps/x86/tst-cet-legacy-6.c +new file mode 100644 +index 0000000000..9151225264 +--- /dev/null ++++ b/sysdeps/x86/tst-cet-legacy-6.c +@@ -0,0 +1,76 @@ ++/* Check compatibility of CET-enabled executable with dlopened legacy ++ shared object. ++ Copyright (C) 2019 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++static void ++do_test_1 (const char *modname, bool fail) ++{ ++ int (*fp) (void); ++ void *h; ++ ++ h = dlopen (modname, RTLD_LAZY); ++ if (h == NULL) ++ { ++ if (fail) ++ { ++ const char *err = dlerror (); ++ if (strstr (err, "shadow stack isn't enabled") == NULL) ++ { ++ printf ("incorrect dlopen '%s' error: %s\n", modname, ++ dlerror ()); ++ exit (1); ++ } ++ ++ return; ++ } ++ ++ printf ("cannot open '%s': %s\n", modname, dlerror ()); ++ exit (1); ++ } ++ ++ fp = dlsym (h, "test"); ++ if (fp == NULL) ++ { ++ printf ("cannot get symbol 'test': %s\n", dlerror ()); ++ exit (1); ++ } ++ ++ if (fp () != 0) ++ { ++ puts ("test () != 0"); ++ exit (1); ++ } ++ ++ dlclose (h); ++} ++ ++static int ++do_test (void) ++{ ++ do_test_1 ("tst-cet-legacy-mod-6a.so", true); ++ do_test_1 ("tst-cet-legacy-mod-6b.so", false); ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/x86/tst-cet-legacy-6a.c b/sysdeps/x86/tst-cet-legacy-6a.c +new file mode 100644 +index 0000000000..2d1546d36b +--- /dev/null ++++ b/sysdeps/x86/tst-cet-legacy-6a.c +@@ -0,0 +1 @@ ++#include "tst-cet-legacy-6.c" +diff --git a/sysdeps/x86/tst-cet-legacy-6b.c b/sysdeps/x86/tst-cet-legacy-6b.c +new file mode 100644 +index 0000000000..2d1546d36b +--- /dev/null ++++ b/sysdeps/x86/tst-cet-legacy-6b.c +@@ -0,0 +1 @@ ++#include "tst-cet-legacy-6.c" +diff --git a/sysdeps/x86/tst-cet-legacy-mod-5.c b/sysdeps/x86/tst-cet-legacy-mod-5.c +new file mode 100644 +index 0000000000..3c1071c2ef +--- /dev/null ++++ b/sysdeps/x86/tst-cet-legacy-mod-5.c +@@ -0,0 +1,31 @@ ++/* Check compatibility of CET-enabled executable with dlopened legacy ++ shared object. ++ Copyright (C) 2019 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 ++ . */ ++ ++#include ++#include ++#include ++ ++extern void foo (void); ++ ++int ++test (void) ++{ ++ foo (); ++ return 0; ++} +diff --git a/sysdeps/x86/tst-cet-legacy-mod-5a.c b/sysdeps/x86/tst-cet-legacy-mod-5a.c +new file mode 100644 +index 0000000000..daa43e4e8d +--- /dev/null ++++ b/sysdeps/x86/tst-cet-legacy-mod-5a.c +@@ -0,0 +1 @@ ++#include "tst-cet-legacy-mod-5.c" +diff --git a/sysdeps/x86/tst-cet-legacy-mod-5b.c b/sysdeps/x86/tst-cet-legacy-mod-5b.c +new file mode 100644 +index 0000000000..daa43e4e8d +--- /dev/null ++++ b/sysdeps/x86/tst-cet-legacy-mod-5b.c +@@ -0,0 +1 @@ ++#include "tst-cet-legacy-mod-5.c" +diff --git a/sysdeps/x86/tst-cet-legacy-mod-5c.c b/sysdeps/x86/tst-cet-legacy-mod-5c.c +new file mode 100644 +index 0000000000..e529a42ac0 +--- /dev/null ++++ b/sysdeps/x86/tst-cet-legacy-mod-5c.c +@@ -0,0 +1,36 @@ ++/* Check compatibility of CET-enabled executable with dlopened legacy ++ shared object. ++ Copyright (C) 2019 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 ++ . */ ++ ++#include ++ ++static int called = 0; ++ ++static void ++__attribute__ ((constructor)) ++init (void) ++{ ++ called = 1; ++} ++ ++void ++foo (void) ++{ ++ if (!called) ++ abort (); ++} +diff --git a/sysdeps/x86/tst-cet-legacy-mod-6.c b/sysdeps/x86/tst-cet-legacy-mod-6.c +new file mode 100644 +index 0000000000..3c1071c2ef +--- /dev/null ++++ b/sysdeps/x86/tst-cet-legacy-mod-6.c +@@ -0,0 +1,31 @@ ++/* Check compatibility of CET-enabled executable with dlopened legacy ++ shared object. ++ Copyright (C) 2019 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 ++ . */ ++ ++#include ++#include ++#include ++ ++extern void foo (void); ++ ++int ++test (void) ++{ ++ foo (); ++ return 0; ++} +diff --git a/sysdeps/x86/tst-cet-legacy-mod-6a.c b/sysdeps/x86/tst-cet-legacy-mod-6a.c +new file mode 100644 +index 0000000000..c89b8fe8ff +--- /dev/null ++++ b/sysdeps/x86/tst-cet-legacy-mod-6a.c +@@ -0,0 +1 @@ ++#include "tst-cet-legacy-mod-6.c" +diff --git a/sysdeps/x86/tst-cet-legacy-mod-6b.c b/sysdeps/x86/tst-cet-legacy-mod-6b.c +new file mode 100644 +index 0000000000..c89b8fe8ff +--- /dev/null ++++ b/sysdeps/x86/tst-cet-legacy-mod-6b.c +@@ -0,0 +1 @@ ++#include "tst-cet-legacy-mod-6.c" +diff --git a/sysdeps/x86/tst-cet-legacy-mod-6c.c b/sysdeps/x86/tst-cet-legacy-mod-6c.c +new file mode 100644 +index 0000000000..e529a42ac0 +--- /dev/null ++++ b/sysdeps/x86/tst-cet-legacy-mod-6c.c +@@ -0,0 +1,36 @@ ++/* Check compatibility of CET-enabled executable with dlopened legacy ++ shared object. ++ Copyright (C) 2019 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 ++ . */ ++ ++#include ++ ++static int called = 0; ++ ++static void ++__attribute__ ((constructor)) ++init (void) ++{ ++ called = 1; ++} ++ ++void ++foo (void) ++{ ++ if (!called) ++ abort (); ++} +diff --git a/sysdeps/x86/tst-cet-legacy-mod-6d.c b/sysdeps/x86/tst-cet-legacy-mod-6d.c +new file mode 100644 +index 0000000000..eb233a1d10 +--- /dev/null ++++ b/sysdeps/x86/tst-cet-legacy-mod-6d.c +@@ -0,0 +1 @@ ++#include "tst-cet-legacy-mod-6c.c" diff --git a/SOURCES/glibc-rh1717438.patch b/SOURCES/glibc-rh1717438.patch new file mode 100644 index 0000000..8bfaec8 --- /dev/null +++ b/SOURCES/glibc-rh1717438.patch @@ -0,0 +1,71 @@ +commit 11b451c8868d8a2b0edc5dfd44fc58d9ee538be0 +Author: Mark Wielaard +Date: Wed May 15 17:14:01 2019 +0200 + + dlfcn: Guard __dlerror_main_freeres with __libc_once_get (once) [BZ# 24476] + + dlerror.c (__dlerror_main_freeres) will try to free resources which only + have been initialized when init () has been called. That function is + called when resources are needed using __libc_once (once, init) where + once is a __libc_once_define (static, once) in the dlerror.c file. + Trying to free those resources if init () hasn't been called will + produce errors under valgrind memcheck. So guard the freeing of those + resources using __libc_once_get (once) and make sure we have a valid + key. Also add a similar guard to __dlerror (). + + * dlfcn/dlerror.c (__dlerror_main_freeres): Guard using + __libc_once_get (once) and static_bug == NULL. + (__dlerror): Check we have a valid key, set result to static_buf + otherwise. + + Reviewed-by: Carlos O'Donell + +diff --git a/dlfcn/dlerror.c b/dlfcn/dlerror.c +index 96bf92533335036b..06732460ea1512cd 100644 +--- a/dlfcn/dlerror.c ++++ b/dlfcn/dlerror.c +@@ -72,9 +72,16 @@ __dlerror (void) + __libc_once (once, init); + + /* Get error string. */ +- result = (struct dl_action_result *) __libc_getspecific (key); +- if (result == NULL) +- result = &last_result; ++ if (static_buf != NULL) ++ result = static_buf; ++ else ++ { ++ /* init () has been run and we don't use the static buffer. ++ So we have a valid key. */ ++ result = (struct dl_action_result *) __libc_getspecific (key); ++ if (result == NULL) ++ result = &last_result; ++ } + + /* Test whether we already returned the string. */ + if (result->returned != 0) +@@ -230,13 +237,19 @@ free_key_mem (void *mem) + void + __dlerror_main_freeres (void) + { +- void *mem; + /* Free the global memory if used. */ + check_free (&last_result); +- /* Free the TSD memory if used. */ +- mem = __libc_getspecific (key); +- if (mem != NULL) +- free_key_mem (mem); ++ ++ if (__libc_once_get (once) && static_buf == NULL) ++ { ++ /* init () has been run and we don't use the static buffer. ++ So we have a valid key. */ ++ void *mem; ++ /* Free the TSD memory if used. */ ++ mem = __libc_getspecific (key); ++ if (mem != NULL) ++ free_key_mem (mem); ++ } + } + + struct dlfcn_hook *_dlfcn_hook __attribute__((nocommon)); diff --git a/SOURCES/glibc-rh1722215.patch b/SOURCES/glibc-rh1722215.patch new file mode 100644 index 0000000..cbda401 --- /dev/null +++ b/SOURCES/glibc-rh1722215.patch @@ -0,0 +1,186 @@ +commit 21cc130b78a4db9113fb6695e2b951e697662440 +Author: Dmitry V. Levin +Date: Wed Feb 13 01:20:51 2019 +0000 + + libio: do not attempt to free wide buffers of legacy streams [BZ #24228] + + Commit a601b74d31ca086de38441d316a3dee24c866305 aka glibc-2.23~693 + ("In preparation for fixing BZ#16734, fix failure in misc/tst-error1-mem + when _G_HAVE_MMAP is turned off.") introduced a regression: + _IO_unbuffer_all now invokes _IO_wsetb to free wide buffers of all + files, including legacy standard files which are small statically + allocated objects that do not have wide buffers and the _mode member, + causing memory corruption. + + Another memory corruption in _IO_unbuffer_all happens when -1 + is assigned to the _mode member of legacy standard files that + do not have it. + + [BZ #24228] + * libio/genops.c (_IO_unbuffer_all) + [SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)]: Do not attempt to free wide + buffers and access _IO_FILE_complete members of legacy libio streams. + * libio/tst-bz24228.c: New file. + * libio/tst-bz24228.map: Likewise. + * libio/Makefile [build-shared] (tests): Add tst-bz24228. + [build-shared] (generated): Add tst-bz24228.mtrace and + tst-bz24228.check. + [run-built-tests && build-shared] (tests-special): Add + $(objpfx)tst-bz24228-mem.out. + (LDFLAGS-tst-bz24228, tst-bz24228-ENV): New variables. + ($(objpfx)tst-bz24228-mem.out): New rule. + +# Conflicts: +# libio/Makefile + +diff --git a/libio/Makefile b/libio/Makefile +index cbfaf3832a45fc22..314e03d5ce72be2d 100644 +--- a/libio/Makefile ++++ b/libio/Makefile +@@ -73,6 +73,9 @@ ifeq (yes,$(build-shared)) + # Add test-fopenloc only if shared library is enabled since it depends on + # shared localedata objects. + tests += tst-fopenloc ++# Add tst-bz24228 only if shared library is enabled since it can never meet its ++# objective with static linking because the relevant code just is not there. ++tests += tst-bz24228 + endif + test-srcs = test-freopen + +@@ -153,11 +156,14 @@ CFLAGS-oldtmpfile.c += -fexceptions + + CFLAGS-tst_putwc.c += -DOBJPFX=\"$(objpfx)\" + ++LDFLAGS-tst-bz24228 = -Wl,--version-script=tst-bz24228.map ++ + tst_wprintf2-ARGS = "Some Text" + + test-fmemopen-ENV = MALLOC_TRACE=$(objpfx)test-fmemopen.mtrace + tst-fopenloc-ENV = MALLOC_TRACE=$(objpfx)tst-fopenloc.mtrace + tst-bz22415-ENV = MALLOC_TRACE=$(objpfx)tst-bz22415.mtrace ++tst-bz24228-ENV = MALLOC_TRACE=$(objpfx)tst-bz24228.mtrace + + generated += test-fmemopen.mtrace test-fmemopen.check + generated += tst-fopenloc.mtrace tst-fopenloc.check +@@ -166,6 +172,7 @@ generated += tst-bz22415.mtrace tst-bz22415.check + aux := fileops genops stdfiles stdio strops + + ifeq ($(build-shared),yes) ++generated += tst-bz24228.mtrace tst-bz24228.check + aux += oldfileops oldstdfiles + endif + +@@ -180,7 +187,8 @@ tests-special += $(objpfx)test-freopen.out $(objpfx)test-fmemopen-mem.out \ + ifeq (yes,$(build-shared)) + # Run tst-fopenloc-cmp.out and tst-openloc-mem.out only if shared + # library is enabled since they depend on tst-fopenloc.out. +-tests-special += $(objpfx)tst-fopenloc-cmp.out $(objpfx)tst-fopenloc-mem.out ++tests-special += $(objpfx)tst-fopenloc-cmp.out $(objpfx)tst-fopenloc-mem.out \ ++ $(objpfx)tst-bz24228-mem.out + endif + endif + +@@ -232,3 +240,7 @@ $(objpfx)tst-fopenloc-mem.out: $(objpfx)tst-fopenloc.out + $(objpfx)tst-bz22415-mem.out: $(objpfx)tst-bz22415.out + $(common-objpfx)malloc/mtrace $(objpfx)tst-bz22415.mtrace > $@; \ + $(evaluate-test) ++ ++$(objpfx)tst-bz24228-mem.out: $(objpfx)tst-bz24228.out ++ $(common-objpfx)malloc/mtrace $(objpfx)tst-bz24228.mtrace > $@; \ ++ $(evaluate-test) +diff --git a/libio/genops.c b/libio/genops.c +index 2fec221b99729718..a8241dd26640bbcb 100644 +--- a/libio/genops.c ++++ b/libio/genops.c +@@ -789,9 +789,16 @@ _IO_unbuffer_all (void) + + for (fp = (FILE *) _IO_list_all; fp; fp = fp->_chain) + { ++ int legacy = 0; ++ ++#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1) ++ if (__glibc_unlikely (_IO_vtable_offset (fp) != 0)) ++ legacy = 1; ++#endif ++ + if (! (fp->_flags & _IO_UNBUFFERED) + /* Iff stream is un-orientated, it wasn't used. */ +- && fp->_mode != 0) ++ && (legacy || fp->_mode != 0)) + { + #ifdef _IO_MTSAFE_IO + int cnt; +@@ -805,7 +812,7 @@ _IO_unbuffer_all (void) + __sched_yield (); + #endif + +- if (! dealloc_buffers && !(fp->_flags & _IO_USER_BUF)) ++ if (! legacy && ! dealloc_buffers && !(fp->_flags & _IO_USER_BUF)) + { + fp->_flags |= _IO_USER_BUF; + +@@ -816,7 +823,7 @@ _IO_unbuffer_all (void) + + _IO_SETBUF (fp, NULL, 0); + +- if (fp->_mode > 0) ++ if (! legacy && fp->_mode > 0) + _IO_wsetb (fp, NULL, NULL, 0); + + #ifdef _IO_MTSAFE_IO +@@ -827,7 +834,8 @@ _IO_unbuffer_all (void) + + /* Make sure that never again the wide char functions can be + used. */ +- fp->_mode = -1; ++ if (! legacy) ++ fp->_mode = -1; + } + + #ifdef _IO_MTSAFE_IO +diff --git a/libio/tst-bz24228.c b/libio/tst-bz24228.c +new file mode 100644 +index 0000000000000000..6a74500d473ceeab +--- /dev/null ++++ b/libio/tst-bz24228.c +@@ -0,0 +1,29 @@ ++/* BZ #24228 check for memory corruption in legacy libio ++ Copyright (C) 2019 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 ++ . */ ++ ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ mtrace (); ++ return 0; ++} ++ ++#include +diff --git a/libio/tst-bz24228.map b/libio/tst-bz24228.map +new file mode 100644 +index 0000000000000000..4383e0817d7f5583 +--- /dev/null ++++ b/libio/tst-bz24228.map +@@ -0,0 +1,5 @@ ++# Hide the symbol from libc.so.6 to switch to the libio/oldfileops.c ++# implementation when it is available for the architecture. ++{ ++ local: _IO_stdin_used; ++}; diff --git a/SOURCES/glibc-rh1724975.patch b/SOURCES/glibc-rh1724975.patch new file mode 100644 index 0000000..7ea3267 --- /dev/null +++ b/SOURCES/glibc-rh1724975.patch @@ -0,0 +1,1013 @@ +commit 5a659ccc0ec217ab02a4c273a1f6d346a359560a +Author: Florian Weimer +Date: Fri Jun 28 09:39:21 2019 +0200 + + io: Remove copy_file_range emulation [BZ #24744] + + The kernel is evolving this interface (e.g., removal of the + restriction on cross-device copies), and keeping up with that + is difficult. Applications which need the function should + run kernels which support the system call instead of relying on + the imperfect glibc emulation. + + Reviewed-by: Adhemerval Zanella + +# Conflicts: +# io/copy_file_range-compat.c +# io/copy_file_range.c +# io/tst-copy_file_range-compat.c +# io/tst-copy_file_range.c +# sysdeps/unix/sysv/linux/arm/kernel-features.h +# sysdeps/unix/sysv/linux/microblaze/kernel-features.h +# sysdeps/unix/sysv/linux/sh/kernel-features.h + +diff --git a/io/Makefile b/io/Makefile +index 787a5c550ab64b17..62e71b4cbe879dbc 100644 +--- a/io/Makefile ++++ b/io/Makefile +@@ -75,11 +75,6 @@ tests := test-utime test-stat test-stat2 test-lfs tst-getcwd \ + tst-fts tst-fts-lfs tst-open-tmpfile \ + tst-copy_file_range tst-getcwd-abspath \ + +-# This test includes the compat implementation of copy_file_range, +-# which uses internal, unexported libc functions. +-tests-static += tst-copy_file_range-compat +-tests-internal += tst-copy_file_range-compat +- + # Likewise for statx, but we do not need static linking here. + tests-internal += tst-statx + +diff --git a/io/copy_file_range-compat.c b/io/copy_file_range-compat.c +deleted file mode 100644 +index 4ab22cad19146ca9..0000000000000000 +--- a/io/copy_file_range-compat.c ++++ /dev/null +@@ -1,160 +0,0 @@ +-/* Emulation of copy_file_range. +- Copyright (C) 2017-2018 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 +- . */ +- +-/* The following macros should be defined before including this +- file: +- +- COPY_FILE_RANGE_DECL Declaration specifiers for the function below. +- COPY_FILE_RANGE Name of the function to define. */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-COPY_FILE_RANGE_DECL +-ssize_t +-COPY_FILE_RANGE (int infd, __off64_t *pinoff, +- int outfd, __off64_t *poutoff, +- size_t length, unsigned int flags) +-{ +- if (flags != 0) +- { +- __set_errno (EINVAL); +- return -1; +- } +- +- { +- struct stat64 instat; +- struct stat64 outstat; +- if (fstat64 (infd, &instat) != 0 || fstat64 (outfd, &outstat) != 0) +- return -1; +- if (S_ISDIR (instat.st_mode) || S_ISDIR (outstat.st_mode)) +- { +- __set_errno (EISDIR); +- return -1; +- } +- if (!S_ISREG (instat.st_mode) || !S_ISREG (outstat.st_mode)) +- { +- /* We need a regular input file so that the we can seek +- backwards in case of a write failure. */ +- __set_errno (EINVAL); +- return -1; +- } +- if (instat.st_dev != outstat.st_dev) +- { +- /* Cross-device copies are not supported. */ +- __set_errno (EXDEV); +- return -1; +- } +- } +- +- /* The output descriptor must not have O_APPEND set. */ +- { +- int flags = __fcntl (outfd, F_GETFL); +- if (flags & O_APPEND) +- { +- __set_errno (EBADF); +- return -1; +- } +- } +- +- /* Avoid an overflow in the result. */ +- if (length > SSIZE_MAX) +- length = SSIZE_MAX; +- +- /* Main copying loop. The buffer size is arbitrary and is a +- trade-off between stack size consumption, cache usage, and +- amortization of system call overhead. */ +- size_t copied = 0; +- char buf[8192]; +- while (length > 0) +- { +- size_t to_read = length; +- if (to_read > sizeof (buf)) +- to_read = sizeof (buf); +- +- /* Fill the buffer. */ +- ssize_t read_count; +- if (pinoff == NULL) +- read_count = read (infd, buf, to_read); +- else +- read_count = __libc_pread64 (infd, buf, to_read, *pinoff); +- if (read_count == 0) +- /* End of file reached prematurely. */ +- return copied; +- if (read_count < 0) +- { +- if (copied > 0) +- /* Report the number of bytes copied so far. */ +- return copied; +- return -1; +- } +- if (pinoff != NULL) +- *pinoff += read_count; +- +- /* Write the buffer part which was read to the destination. */ +- char *end = buf + read_count; +- for (char *p = buf; p < end; ) +- { +- ssize_t write_count; +- if (poutoff == NULL) +- write_count = write (outfd, p, end - p); +- else +- write_count = __libc_pwrite64 (outfd, p, end - p, *poutoff); +- if (write_count < 0) +- { +- /* Adjust the input read position to match what we have +- written, so that the caller can pick up after the +- error. */ +- size_t written = p - buf; +- /* NB: This needs to be signed so that we can form the +- negative value below. */ +- ssize_t overread = read_count - written; +- if (pinoff == NULL) +- { +- if (overread > 0) +- { +- /* We are on an error recovery path, so we +- cannot deal with failure here. */ +- int save_errno = errno; +- (void) __libc_lseek64 (infd, -overread, SEEK_CUR); +- __set_errno (save_errno); +- } +- } +- else /* pinoff != NULL */ +- *pinoff -= overread; +- +- if (copied + written > 0) +- /* Report the number of bytes copied so far. */ +- return copied + written; +- return -1; +- } +- p += write_count; +- if (poutoff != NULL) +- *poutoff += write_count; +- } /* Write loop. */ +- +- copied += read_count; +- length -= read_count; +- } +- return copied; +-} +diff --git a/io/copy_file_range.c b/io/copy_file_range.c +index 98bff8bd2615b214..59fb979773b2b202 100644 +--- a/io/copy_file_range.c ++++ b/io/copy_file_range.c +@@ -1,5 +1,5 @@ +-/* Generic implementation of copy_file_range. +- Copyright (C) 2017-2018 Free Software Foundation, Inc. ++/* Stub implementation of copy_file_range. ++ Copyright (C) 2017-2019 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 +@@ -16,7 +16,15 @@ + License along with the GNU C Library; if not, see + . */ + +-#define COPY_FILE_RANGE_DECL +-#define COPY_FILE_RANGE copy_file_range ++#include ++#include + +-#include ++ssize_t ++copy_file_range (int infd, __off64_t *pinoff, ++ int outfd, __off64_t *poutoff, ++ size_t length, unsigned int flags) ++{ ++ __set_errno (ENOSYS); ++ return -1; ++} ++stub_warning (copy_file_range) +diff --git a/io/tst-copy_file_range-compat.c b/io/tst-copy_file_range-compat.c +deleted file mode 100644 +index 00c109a74d3c9d64..0000000000000000 +--- a/io/tst-copy_file_range-compat.c ++++ /dev/null +@@ -1,30 +0,0 @@ +-/* Test the fallback implementation of copy_file_range. +- Copyright (C) 2017-2018 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 +- . */ +- +-/* Get the declaration of the official copy_of_range function. */ +-#include +- +-/* Compile a local version of copy_file_range. */ +-#define COPY_FILE_RANGE_DECL static +-#define COPY_FILE_RANGE copy_file_range_compat +-#include +- +-/* Re-use the test, but run it against copy_file_range_compat defined +- above. */ +-#define copy_file_range copy_file_range_compat +-#include "tst-copy_file_range.c" +diff --git a/io/tst-copy_file_range.c b/io/tst-copy_file_range.c +index 3d531a19370911e5..4504020d2ee7d2ee 100644 +--- a/io/tst-copy_file_range.c ++++ b/io/tst-copy_file_range.c +@@ -20,22 +20,15 @@ + #include + #include + #include +-#include +-#include +-#include + #include + #include + #include + #include + #include +-#include + #include + #include + #include + #include +-#ifdef CLONE_NEWNS +-# include +-#endif + + /* Boolean flags which indicate whether to use pointers with explicit + output flags. */ +@@ -49,10 +42,6 @@ static int infd; + static char *outfile; + static int outfd; + +-/* Like the above, but on a different file system. xdevfile can be +- NULL if no suitable file system has been found. */ +-static char *xdevfile; +- + /* Input and output offsets. Set according to do_inoff and do_outoff + before the test. The offsets themselves are always set to + zero. */ +@@ -61,13 +50,10 @@ static off64_t *pinoff; + static off64_t outoff; + static off64_t *poutoff; + +-/* These are a collection of copy sizes used in tests. The selection +- takes into account that the fallback implementation uses an +- internal buffer of 8192 bytes. */ ++/* These are a collection of copy sizes used in tests. */ + enum { maximum_size = 99999 }; + static const int typical_sizes[] = +- { 0, 1, 2, 3, 1024, 2048, 4096, 8191, 8192, 8193, 16383, 16384, 16385, +- maximum_size }; ++ { 0, 1, 2, 3, 1024, 2048, 4096, 8191, 8192, 8193, maximum_size }; + + /* The random contents of this array can be used as a pattern to check + for correct write operations. */ +@@ -76,101 +62,6 @@ static unsigned char random_data[maximum_size]; + /* The size chosen by the test harness. */ + static int current_size; + +-/* Maximum writable file offset. Updated by find_maximum_offset +- below. */ +-static off64_t maximum_offset; +- +-/* Error code when crossing the offset. */ +-static int maximum_offset_errno; +- +-/* If true: Writes which cross the limit will fail. If false: Writes +- which cross the limit will result in a partial write. */ +-static bool maximum_offset_hard_limit; +- +-/* Fills maximum_offset etc. above. Truncates outfd as a side +- effect. */ +-static void +-find_maximum_offset (void) +-{ +- xftruncate (outfd, 0); +- if (maximum_offset != 0) +- return; +- +- uint64_t upper = -1; +- upper >>= 1; /* Maximum of off64_t. */ +- TEST_VERIFY ((off64_t) upper > 0); +- TEST_VERIFY ((off64_t) (upper + 1) < 0); +- if (lseek64 (outfd, upper, SEEK_SET) >= 0) +- { +- if (write (outfd, "", 1) == 1) +- FAIL_EXIT1 ("created a file larger than the off64_t range"); +- } +- +- uint64_t lower = 1024 * 1024; /* A reasonable minimum file size. */ +- /* Loop invariant: writing at lower succeeds, writing at upper fails. */ +- while (lower + 1 < upper) +- { +- uint64_t middle = (lower + upper) / 2; +- if (test_verbose > 0) +- printf ("info: %s: remaining test range %" PRIu64 " .. %" PRIu64 +- ", probe at %" PRIu64 "\n", __func__, lower, upper, middle); +- xftruncate (outfd, 0); +- if (lseek64 (outfd, middle, SEEK_SET) >= 0 +- && write (outfd, "", 1) == 1) +- lower = middle; +- else +- upper = middle; +- } +- TEST_VERIFY (lower + 1 == upper); +- maximum_offset = lower; +- printf ("info: maximum writable file offset: %" PRIu64 " (%" PRIx64 ")\n", +- lower, lower); +- +- /* Check that writing at the valid offset actually works. */ +- xftruncate (outfd, 0); +- xlseek (outfd, lower, SEEK_SET); +- TEST_COMPARE (write (outfd, "", 1), 1); +- +- /* Cross the boundary with a two-byte write. This can either result +- in a short write, or a failure. */ +- xlseek (outfd, lower, SEEK_SET); +- ssize_t ret = write (outfd, " ", 2); +- if (ret < 0) +- { +- maximum_offset_errno = errno; +- maximum_offset_hard_limit = true; +- } +- else +- maximum_offset_hard_limit = false; +- +- /* Check that writing at the next offset actually fails. This also +- obtains the expected errno value. */ +- xftruncate (outfd, 0); +- const char *action; +- if (lseek64 (outfd, lower + 1, SEEK_SET) != 0) +- { +- if (write (outfd, "", 1) != -1) +- FAIL_EXIT1 ("write to impossible offset %" PRIu64 " succeeded", +- lower + 1); +- action = "writing"; +- int errno_copy = errno; +- if (maximum_offset_hard_limit) +- TEST_COMPARE (errno_copy, maximum_offset_errno); +- else +- maximum_offset_errno = errno_copy; +- } +- else +- { +- action = "seeking"; +- maximum_offset_errno = errno; +- } +- printf ("info: %s out of range fails with %m (%d)\n", +- action, maximum_offset_errno); +- +- xftruncate (outfd, 0); +- xlseek (outfd, 0, SEEK_SET); +-} +- + /* Perform a copy of a file. */ + static void + simple_file_copy (void) +@@ -247,390 +138,6 @@ simple_file_copy (void) + free (bytes); + } + +-/* Test that reading from a pipe willfails. */ +-static void +-pipe_as_source (void) +-{ +- int pipefds[2]; +- xpipe (pipefds); +- +- for (int length = 0; length < 2; ++length) +- { +- if (test_verbose > 0) +- printf ("info: %s: length=%d\n", __func__, length); +- +- /* Make sure that there is something to copy in the pipe. */ +- xwrite (pipefds[1], "@", 1); +- +- TEST_COMPARE (copy_file_range (pipefds[0], pinoff, outfd, poutoff, +- length, 0), -1); +- /* Linux 4.10 and later return EINVAL. Older kernels return +- EXDEV. */ +- TEST_VERIFY (errno == EINVAL || errno == EXDEV); +- TEST_COMPARE (inoff, 0); +- TEST_COMPARE (outoff, 0); +- TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), 0); +- +- /* Make sure that nothing was read. */ +- char buf = 'A'; +- TEST_COMPARE (read (pipefds[0], &buf, 1), 1); +- TEST_COMPARE (buf, '@'); +- } +- +- xclose (pipefds[0]); +- xclose (pipefds[1]); +-} +- +-/* Test that writing to a pipe fails. */ +-static void +-pipe_as_destination (void) +-{ +- /* Make sure that there is something to read in the input file. */ +- xwrite (infd, "abc", 3); +- xlseek (infd, 0, SEEK_SET); +- +- int pipefds[2]; +- xpipe (pipefds); +- +- for (int length = 0; length < 2; ++length) +- { +- if (test_verbose > 0) +- printf ("info: %s: length=%d\n", __func__, length); +- +- TEST_COMPARE (copy_file_range (infd, pinoff, pipefds[1], poutoff, +- length, 0), -1); +- /* Linux 4.10 and later return EINVAL. Older kernels return +- EXDEV. */ +- TEST_VERIFY (errno == EINVAL || errno == EXDEV); +- TEST_COMPARE (inoff, 0); +- TEST_COMPARE (outoff, 0); +- TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0); +- +- /* Make sure that nothing was written. */ +- struct pollfd pollfd = { .fd = pipefds[0], .events = POLLIN, }; +- TEST_COMPARE (poll (&pollfd, 1, 0), 0); +- } +- +- xclose (pipefds[0]); +- xclose (pipefds[1]); +-} +- +-/* Test a write failure after (potentially) writing some bytes. +- Failure occurs near the start of the buffer. */ +-static void +-delayed_write_failure_beginning (void) +-{ +- /* We need to write something to provoke the error. */ +- if (current_size == 0) +- return; +- xwrite (infd, random_data, sizeof (random_data)); +- xlseek (infd, 0, SEEK_SET); +- +- /* Write failure near the start. The actual error code varies among +- file systems. */ +- find_maximum_offset (); +- off64_t where = maximum_offset; +- +- if (current_size == 1) +- ++where; +- outoff = where; +- if (do_outoff) +- xlseek (outfd, 1, SEEK_SET); +- else +- xlseek (outfd, where, SEEK_SET); +- if (maximum_offset_hard_limit || where > maximum_offset) +- { +- TEST_COMPARE (copy_file_range (infd, pinoff, outfd, poutoff, +- sizeof (random_data), 0), -1); +- TEST_COMPARE (errno, maximum_offset_errno); +- TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0); +- TEST_COMPARE (inoff, 0); +- if (do_outoff) +- TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), 1); +- else +- TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), where); +- TEST_COMPARE (outoff, where); +- struct stat64 st; +- xfstat (outfd, &st); +- TEST_COMPARE (st.st_size, 0); +- } +- else +- { +- /* The offset is not a hard limit. This means we write one +- byte. */ +- TEST_COMPARE (copy_file_range (infd, pinoff, outfd, poutoff, +- sizeof (random_data), 0), 1); +- if (do_inoff) +- { +- TEST_COMPARE (inoff, 1); +- TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0); +- } +- else +- { +- TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 1); +- TEST_COMPARE (inoff, 0); +- } +- if (do_outoff) +- { +- TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), 1); +- TEST_COMPARE (outoff, where + 1); +- } +- else +- { +- TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), where + 1); +- TEST_COMPARE (outoff, where); +- } +- struct stat64 st; +- xfstat (outfd, &st); +- TEST_COMPARE (st.st_size, where + 1); +- } +-} +- +-/* Test a write failure after (potentially) writing some bytes. +- Failure occurs near the end of the buffer. */ +-static void +-delayed_write_failure_end (void) +-{ +- if (current_size <= 1) +- /* This would be same as the first test because there is not +- enough data to write to make a difference. */ +- return; +- xwrite (infd, random_data, sizeof (random_data)); +- xlseek (infd, 0, SEEK_SET); +- +- find_maximum_offset (); +- off64_t where = maximum_offset - current_size + 1; +- if (current_size == sizeof (random_data)) +- /* Otherwise we do not reach the non-writable byte. */ +- ++where; +- outoff = where; +- if (do_outoff) +- xlseek (outfd, 1, SEEK_SET); +- else +- xlseek (outfd, where, SEEK_SET); +- ssize_t ret = copy_file_range (infd, pinoff, outfd, poutoff, +- sizeof (random_data), 0); +- if (ret < 0) +- { +- TEST_COMPARE (ret, -1); +- TEST_COMPARE (errno, maximum_offset_errno); +- struct stat64 st; +- xfstat (outfd, &st); +- TEST_COMPARE (st.st_size, 0); +- } +- else +- { +- /* The first copy succeeded. This happens in the emulation +- because the internal buffer of limited size does not +- necessarily cross the off64_t boundary on the first write +- operation. */ +- if (test_verbose > 0) +- printf ("info: copy_file_range (%zu) returned %zd\n", +- sizeof (random_data), ret); +- TEST_VERIFY (ret > 0); +- TEST_VERIFY (ret < maximum_size); +- struct stat64 st; +- xfstat (outfd, &st); +- TEST_COMPARE (st.st_size, where + ret); +- if (do_inoff) +- { +- TEST_COMPARE (inoff, ret); +- TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0); +- } +- else +- TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), ret); +- +- char *buffer = xmalloc (ret); +- TEST_COMPARE (pread64 (outfd, buffer, ret, where), ret); +- TEST_VERIFY (memcmp (buffer, random_data, ret) == 0); +- free (buffer); +- +- /* The second copy fails. */ +- TEST_COMPARE (copy_file_range (infd, pinoff, outfd, poutoff, +- sizeof (random_data), 0), -1); +- TEST_COMPARE (errno, maximum_offset_errno); +- } +-} +- +-/* Test a write failure across devices. */ +-static void +-cross_device_failure (void) +-{ +- if (xdevfile == NULL) +- /* Subtest not supported due to missing cross-device file. */ +- return; +- +- /* We need something to write. */ +- xwrite (infd, random_data, sizeof (random_data)); +- xlseek (infd, 0, SEEK_SET); +- +- int xdevfd = xopen (xdevfile, O_RDWR | O_LARGEFILE, 0); +- TEST_COMPARE (copy_file_range (infd, pinoff, xdevfd, poutoff, +- current_size, 0), -1); +- TEST_COMPARE (errno, EXDEV); +- TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0); +- struct stat64 st; +- xfstat (xdevfd, &st); +- TEST_COMPARE (st.st_size, 0); +- +- xclose (xdevfd); +-} +- +-/* Try to exercise ENOSPC behavior with a tempfs file system (so that +- we do not have to fill up a regular file system to get the error). +- This function runs in a subprocess, so that we do not change the +- mount namespace of the actual test process. */ +-static void +-enospc_failure_1 (void *closure) +-{ +-#ifdef CLONE_NEWNS +- support_become_root (); +- +- /* Make sure that we do not alter the file system mounts of the +- parents. */ +- if (! support_enter_mount_namespace ()) +- { +- printf ("warning: ENOSPC test skipped\n"); +- return; +- } +- +- char *mountpoint = closure; +- if (mount ("none", mountpoint, "tmpfs", MS_NODEV | MS_NOEXEC, +- "size=500k") != 0) +- { +- printf ("warning: could not mount tmpfs at %s: %m\n", mountpoint); +- return; +- } +- +- /* The source file must reside on the same file system. */ +- char *intmpfsfile = xasprintf ("%s/%s", mountpoint, "in"); +- int intmpfsfd = xopen (intmpfsfile, O_RDWR | O_CREAT | O_LARGEFILE, 0600); +- xwrite (intmpfsfd, random_data, sizeof (random_data)); +- xlseek (intmpfsfd, 1, SEEK_SET); +- inoff = 1; +- +- char *outtmpfsfile = xasprintf ("%s/%s", mountpoint, "out"); +- int outtmpfsfd = xopen (outtmpfsfile, O_RDWR | O_CREAT | O_LARGEFILE, 0600); +- +- /* Fill the file with data until ENOSPC is reached. */ +- while (true) +- { +- ssize_t ret = write (outtmpfsfd, random_data, sizeof (random_data)); +- if (ret < 0 && errno != ENOSPC) +- FAIL_EXIT1 ("write to %s: %m", outtmpfsfile); +- if (ret < sizeof (random_data)) +- break; +- } +- TEST_COMPARE (write (outtmpfsfd, "", 1), -1); +- TEST_COMPARE (errno, ENOSPC); +- off64_t maxsize = xlseek (outtmpfsfd, 0, SEEK_CUR); +- TEST_VERIFY_EXIT (maxsize > sizeof (random_data)); +- +- /* Constructed the expected file contents. */ +- char *expected = xmalloc (maxsize); +- TEST_COMPARE (pread64 (outtmpfsfd, expected, maxsize, 0), maxsize); +- /* Go back a little, so some bytes can be written. */ +- enum { offset = 20000 }; +- TEST_VERIFY_EXIT (offset < maxsize); +- TEST_VERIFY_EXIT (offset < sizeof (random_data)); +- memcpy (expected + maxsize - offset, random_data + 1, offset); +- +- if (do_outoff) +- { +- outoff = maxsize - offset; +- xlseek (outtmpfsfd, 2, SEEK_SET); +- } +- else +- xlseek (outtmpfsfd, -offset, SEEK_CUR); +- +- /* First call is expected to succeed because we made room for some +- bytes. */ +- TEST_COMPARE (copy_file_range (intmpfsfd, pinoff, outtmpfsfd, poutoff, +- maximum_size, 0), offset); +- if (do_inoff) +- { +- TEST_COMPARE (inoff, 1 + offset); +- TEST_COMPARE (xlseek (intmpfsfd, 0, SEEK_CUR), 1); +- } +- else +- TEST_COMPARE (xlseek (intmpfsfd, 0, SEEK_CUR), 1 + offset); +- if (do_outoff) +- { +- TEST_COMPARE (outoff, maxsize); +- TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_CUR), 2); +- } +- else +- TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_CUR), maxsize); +- struct stat64 st; +- xfstat (outtmpfsfd, &st); +- TEST_COMPARE (st.st_size, maxsize); +- char *actual = xmalloc (st.st_size); +- TEST_COMPARE (pread64 (outtmpfsfd, actual, st.st_size, 0), st.st_size); +- TEST_VERIFY (memcmp (expected, actual, maxsize) == 0); +- +- /* Second call should fail with ENOSPC. */ +- TEST_COMPARE (copy_file_range (intmpfsfd, pinoff, outtmpfsfd, poutoff, +- maximum_size, 0), -1); +- TEST_COMPARE (errno, ENOSPC); +- +- /* Offsets should be unchanged. */ +- if (do_inoff) +- { +- TEST_COMPARE (inoff, 1 + offset); +- TEST_COMPARE (xlseek (intmpfsfd, 0, SEEK_CUR), 1); +- } +- else +- TEST_COMPARE (xlseek (intmpfsfd, 0, SEEK_CUR), 1 + offset); +- if (do_outoff) +- { +- TEST_COMPARE (outoff, maxsize); +- TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_CUR), 2); +- } +- else +- TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_CUR), maxsize); +- TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_END), maxsize); +- TEST_COMPARE (pread64 (outtmpfsfd, actual, maxsize, 0), maxsize); +- TEST_VERIFY (memcmp (expected, actual, maxsize) == 0); +- +- free (actual); +- free (expected); +- +- xclose (intmpfsfd); +- xclose (outtmpfsfd); +- free (intmpfsfile); +- free (outtmpfsfile); +- +-#else /* !CLONE_NEWNS */ +- puts ("warning: ENOSPC test skipped (no mount namespaces)"); +-#endif +-} +- +-/* Call enospc_failure_1 in a subprocess. */ +-static void +-enospc_failure (void) +-{ +- char *mountpoint +- = support_create_temp_directory ("tst-copy_file_range-enospc-"); +- support_isolate_in_subprocess (enospc_failure_1, mountpoint); +- free (mountpoint); +-} +- +-/* The target file descriptor must have O_APPEND enabled. */ +-static void +-oappend_failure (void) +-{ +- /* Add data, to make sure we do not fail because there is +- insufficient input data. */ +- xwrite (infd, random_data, current_size); +- xlseek (infd, 0, SEEK_SET); +- +- xclose (outfd); +- outfd = xopen (outfile, O_RDWR | O_APPEND, 0); +- TEST_COMPARE (copy_file_range (infd, pinoff, outfd, poutoff, +- current_size, 0), -1); +- TEST_COMPARE (errno, EBADF); +-} +- + /* Test that a short input file results in a shortened copy. */ + static void + short_copy (void) +@@ -721,14 +228,6 @@ struct test_case + static struct test_case tests[] = + { + { "simple_file_copy", simple_file_copy, .sizes = true }, +- { "pipe_as_source", pipe_as_source, }, +- { "pipe_as_destination", pipe_as_destination, }, +- { "delayed_write_failure_beginning", delayed_write_failure_beginning, +- .sizes = true }, +- { "delayed_write_failure_end", delayed_write_failure_end, .sizes = true }, +- { "cross_device_failure", cross_device_failure, .sizes = true }, +- { "enospc_failure", enospc_failure, }, +- { "oappend_failure", oappend_failure, .sizes = true }, + { "short_copy", short_copy, .sizes = true }, + }; + +@@ -739,53 +238,18 @@ do_test (void) + *p = rand () >> 24; + + infd = create_temp_file ("tst-copy_file_range-in-", &infile); +- xclose (create_temp_file ("tst-copy_file_range-out-", &outfile)); +- +- /* Try to find a different directory from the default input/output +- file. */ ++ outfd = create_temp_file ("tst-copy_file_range-out-", &outfile); + { +- struct stat64 instat; +- xfstat (infd, &instat); +- static const char *const candidates[] = +- { NULL, "/var/tmp", "/dev/shm" }; +- for (const char *const *c = candidates; c < array_end (candidates); ++c) +- { +- const char *path = *c; +- char *to_free = NULL; +- if (path == NULL) +- { +- to_free = xreadlink ("/proc/self/exe"); +- path = dirname (to_free); +- } +- +- struct stat64 cstat; +- xstat (path, &cstat); +- if (cstat.st_dev == instat.st_dev) +- { +- free (to_free); +- continue; +- } +- +- printf ("info: using alternate temporary files directory: %s\n", path); +- xdevfile = xasprintf ("%s/tst-copy_file_range-xdev-XXXXXX", path); +- free (to_free); +- break; +- } +- if (xdevfile != NULL) ++ ssize_t ret = copy_file_range (infd, NULL, outfd, NULL, 0, 0); ++ if (ret != 0) + { +- int xdevfd = mkstemp (xdevfile); +- if (xdevfd < 0) +- FAIL_EXIT1 ("mkstemp (\"%s\"): %m", xdevfile); +- struct stat64 xdevst; +- xfstat (xdevfd, &xdevst); +- TEST_VERIFY (xdevst.st_dev != instat.st_dev); +- add_temp_file (xdevfile); +- xclose (xdevfd); ++ if (errno == ENOSYS) ++ FAIL_UNSUPPORTED ("copy_file_range is not support on this system"); ++ FAIL_EXIT1 ("copy_file_range probing call: %m"); + } +- else +- puts ("warning: no alternate directory on different file system found"); + } + xclose (infd); ++ xclose (outfd); + + for (do_inoff = 0; do_inoff < 2; ++do_inoff) + for (do_outoff = 0; do_outoff < 2; ++do_outoff) +@@ -827,7 +291,6 @@ do_test (void) + + free (infile); + free (outfile); +- free (xdevfile); + + return 0; + } +diff --git a/manual/llio.texi b/manual/llio.texi +index 2733b9cb7331df07..26f7d2cb3ea220d9 100644 +--- a/manual/llio.texi ++++ b/manual/llio.texi +@@ -1404,10 +1404,13 @@ failure occurs. The return value is zero if the end of the input file + is encountered immediately. + + If no bytes can be copied, to report an error, @code{copy_file_range} +-returns the value @math{-1} and sets @code{errno}. The following +-@code{errno} error conditions are specific to this function: ++returns the value @math{-1} and sets @code{errno}. The table below ++lists some of the error conditions for this function. + + @table @code ++@item ENOSYS ++The kernel does not implement the required functionality. ++ + @item EISDIR + At least one of the descriptors @var{inputfd} or @var{outputfd} refers + to a directory. +@@ -1437,9 +1440,6 @@ reading. + + The argument @var{outputfd} is not a valid file descriptor open for + writing, or @var{outputfd} has been opened with @code{O_APPEND}. +- +-@item EXDEV +-The input and output files reside on different file systems. + @end table + + In addition, @code{copy_file_range} can fail with the error codes +diff --git a/sysdeps/unix/sysv/linux/alpha/kernel-features.h b/sysdeps/unix/sysv/linux/alpha/kernel-features.h +index 402d2573d75794d5..26344cd610a1f8e7 100644 +--- a/sysdeps/unix/sysv/linux/alpha/kernel-features.h ++++ b/sysdeps/unix/sysv/linux/alpha/kernel-features.h +@@ -48,7 +48,6 @@ + /* Support for copy_file_range, statx was added in kernel 4.13. */ + #if __LINUX_KERNEL_VERSION < 0x040D00 + # undef __ASSUME_MLOCK2 +-# undef __ASSUME_COPY_FILE_RANGE + # undef __ASSUME_STATX + #endif + +diff --git a/sysdeps/unix/sysv/linux/copy_file_range.c b/sysdeps/unix/sysv/linux/copy_file_range.c +index 7b1a50f7529f2a84..b88b7c9e2ecd825f 100644 +--- a/sysdeps/unix/sysv/linux/copy_file_range.c ++++ b/sysdeps/unix/sysv/linux/copy_file_range.c +@@ -20,27 +20,16 @@ + #include + #include + +-/* Include the fallback implementation. */ +-#ifndef __ASSUME_COPY_FILE_RANGE +-#define COPY_FILE_RANGE_DECL static +-#define COPY_FILE_RANGE copy_file_range_compat +-#include +-#endif +- + ssize_t + copy_file_range (int infd, __off64_t *pinoff, + int outfd, __off64_t *poutoff, + size_t length, unsigned int flags) + { + #ifdef __NR_copy_file_range +- ssize_t ret = SYSCALL_CANCEL (copy_file_range, infd, pinoff, outfd, poutoff, +- length, flags); +-# ifndef __ASSUME_COPY_FILE_RANGE +- if (ret == -1 && errno == ENOSYS) +- ret = copy_file_range_compat (infd, pinoff, outfd, poutoff, length, flags); +-# endif +- return ret; +-#else /* !__NR_copy_file_range */ +- return copy_file_range_compat (infd, pinoff, outfd, poutoff, length, flags); ++ return SYSCALL_CANCEL (copy_file_range, infd, pinoff, outfd, poutoff, ++ length, flags); ++#else ++ __set_errno (ENOSYS); ++ return -1; + #endif + } +diff --git a/sysdeps/unix/sysv/linux/kernel-features.h b/sysdeps/unix/sysv/linux/kernel-features.h +index 5543d92d7e32e501..7a74835495250268 100644 +--- a/sysdeps/unix/sysv/linux/kernel-features.h ++++ b/sysdeps/unix/sysv/linux/kernel-features.h +@@ -111,10 +111,6 @@ + # define __ASSUME_MLOCK2 1 + #endif + +-#if __LINUX_KERNEL_VERSION >= 0x040500 +-# define __ASSUME_COPY_FILE_RANGE 1 +-#endif +- + /* Support for statx was added in kernel 4.11. */ + #if __LINUX_KERNEL_VERSION >= 0x040B00 + # define __ASSUME_STATX 1 +diff --git a/sysdeps/unix/sysv/linux/microblaze/kernel-features.h b/sysdeps/unix/sysv/linux/microblaze/kernel-features.h +index e8e2ac6a873126ac..1c49f099b7993f1d 100644 +--- a/sysdeps/unix/sysv/linux/microblaze/kernel-features.h ++++ b/sysdeps/unix/sysv/linux/microblaze/kernel-features.h +@@ -58,11 +58,6 @@ + # undef __ASSUME_EXECVEAT + #endif + +-/* Support for the copy_file_range syscall was added in 4.10. */ +-#if __LINUX_KERNEL_VERSION < 0x040A00 +-# undef __ASSUME_COPY_FILE_RANGE +-#endif +- + /* Support for statx was added in kernel 4.12. */ + #if __LINUX_KERNEL_VERSION < 0X040C00 + # undef __ASSUME_STATX diff --git a/SOURCES/glibc-rh1726638-1.patch b/SOURCES/glibc-rh1726638-1.patch new file mode 100644 index 0000000..96c2b21 --- /dev/null +++ b/SOURCES/glibc-rh1726638-1.patch @@ -0,0 +1,35 @@ +commit 55f82d328d2dd1c7c13c1992f4b9bf9c95b57551 +Author: Szabolcs Nagy +Date: Thu Apr 25 15:35:35 2019 +0100 + + aarch64: add STO_AARCH64_VARIANT_PCS and DT_AARCH64_VARIANT_PCS + + STO_AARCH64_VARIANT_PCS is a non-visibility st_other flag for marking + symbols that reference functions that may follow a variant PCS with + different register usage convention from the base PCS. + + DT_AARCH64_VARIANT_PCS is a dynamic tag that marks ELF modules that + have R_*_JUMP_SLOT relocations for symbols marked with + STO_AARCH64_VARIANT_PCS (i.e. have variant PCS calls via a PLT). + + * elf/elf.h (STO_AARCH64_VARIANT_PCS): Define. + (DT_AARCH64_VARIANT_PCS): Define. + +diff --git a/elf/elf.h b/elf/elf.h +index 7e2b072a7f75451c..74f7f479ce817040 100644 +--- a/elf/elf.h ++++ b/elf/elf.h +@@ -2847,6 +2847,13 @@ enum + #define R_AARCH64_TLSDESC 1031 /* TLS Descriptor. */ + #define R_AARCH64_IRELATIVE 1032 /* STT_GNU_IFUNC relocation. */ + ++/* AArch64 specific values for the Dyn d_tag field. */ ++#define DT_AARCH64_VARIANT_PCS (DT_LOPROC + 5) ++#define DT_AARCH64_NUM 6 ++ ++/* AArch64 specific values for the st_other field. */ ++#define STO_AARCH64_VARIANT_PCS 0x80 ++ + /* ARM relocs. */ + + #define R_ARM_NONE 0 /* No reloc */ diff --git a/SOURCES/glibc-rh1726638-2.patch b/SOURCES/glibc-rh1726638-2.patch new file mode 100644 index 0000000..f321c7a --- /dev/null +++ b/SOURCES/glibc-rh1726638-2.patch @@ -0,0 +1,138 @@ +commit 82bc69c012838a381c4167c156a06f4598f34227 +Author: Szabolcs Nagy +Date: Thu Apr 25 15:35:35 2019 +0100 + + aarch64: handle STO_AARCH64_VARIANT_PCS + + Avoid lazy binding of symbols that may follow a variant PCS with different + register usage convention from the base PCS. + + Currently the lazy binding entry code does not preserve all the registers + required for AdvSIMD and SVE vector calls. Saving and restoring all + registers unconditionally may break existing binaries, even if they never + use vector calls, because of the larger stack requirement for lazy + resolution, which can be significant on an SVE system. + + The solution is to mark all symbols in the symbol table that may follow + a variant PCS so the dynamic linker can handle them specially. In this + patch such symbols are always resolved at load time, not lazily. + + So currently LD_AUDIT for variant PCS symbols are not supported, for that + the _dl_runtime_profile entry needs to be changed e.g. to unconditionally + save/restore all registers (but pass down arg and retval registers to + pltentry/exit callbacks according to the base PCS). + + This patch also removes a __builtin_expect from the modified code because + the branch prediction hint did not seem useful. + + * sysdeps/aarch64/dl-dtprocnum.h: New file. + * sysdeps/aarch64/dl-machine.h (DT_AARCH64): Define. + (elf_machine_runtime_setup): Handle DT_AARCH64_VARIANT_PCS. + (elf_machine_lazy_rel): Check STO_AARCH64_VARIANT_PCS and bind such + symbols at load time. + * sysdeps/aarch64/linkmap.h (struct link_map_machine): Add variant_pcs. + +diff --git a/sysdeps/aarch64/dl-dtprocnum.h b/sysdeps/aarch64/dl-dtprocnum.h +new file mode 100644 +index 0000000000000000..4ac2adf23458e02d +--- /dev/null ++++ b/sysdeps/aarch64/dl-dtprocnum.h +@@ -0,0 +1,21 @@ ++/* Configuration of lookup functions. AArch64 version. ++ Copyright (C) 2019 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 ++ . */ ++ ++/* Number of extra dynamic section entries for this architecture. By ++ default there are none. */ ++#define DT_THISPROCNUM DT_AARCH64_NUM +diff --git a/sysdeps/aarch64/dl-machine.h b/sysdeps/aarch64/dl-machine.h +index 4935aa7c543876db..d4494852b32b8783 100644 +--- a/sysdeps/aarch64/dl-machine.h ++++ b/sysdeps/aarch64/dl-machine.h +@@ -27,6 +27,9 @@ + #include + #include + ++/* Translate a processor specific dynamic tag to the index in l_info array. */ ++#define DT_AARCH64(x) (DT_AARCH64_##x - DT_LOPROC + DT_NUM) ++ + /* Return nonzero iff ELF header is compatible with the running host. */ + static inline int __attribute__ ((unused)) + elf_machine_matches_host (const ElfW(Ehdr) *ehdr) +@@ -102,6 +105,10 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) + } + } + ++ /* Check if STO_AARCH64_VARIANT_PCS needs to be handled. */ ++ if (l->l_info[DT_AARCH64 (VARIANT_PCS)]) ++ l->l_mach.variant_pcs = 1; ++ + return lazy; + } + +@@ -388,10 +395,37 @@ elf_machine_lazy_rel (struct link_map *map, + /* Check for unexpected PLT reloc type. */ + if (__builtin_expect (r_type == AARCH64_R(JUMP_SLOT), 1)) + { +- if (__builtin_expect (map->l_mach.plt, 0) == 0) +- *reloc_addr += l_addr; +- else +- *reloc_addr = map->l_mach.plt; ++ if (map->l_mach.plt == 0) ++ { ++ /* Prelinking. */ ++ *reloc_addr += l_addr; ++ return; ++ } ++ ++ if (__glibc_unlikely (map->l_mach.variant_pcs)) ++ { ++ /* Check the symbol table for variant PCS symbols. */ ++ const Elf_Symndx symndx = ELFW (R_SYM) (reloc->r_info); ++ const ElfW (Sym) *symtab = ++ (const void *)D_PTR (map, l_info[DT_SYMTAB]); ++ const ElfW (Sym) *sym = &symtab[symndx]; ++ if (__glibc_unlikely (sym->st_other & STO_AARCH64_VARIANT_PCS)) ++ { ++ /* Avoid lazy resolution of variant PCS symbols. */ ++ const struct r_found_version *version = NULL; ++ if (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL) ++ { ++ const ElfW (Half) *vernum = ++ (const void *)D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]); ++ version = &map->l_versions[vernum[symndx] & 0x7fff]; ++ } ++ elf_machine_rela (map, reloc, sym, version, reloc_addr, ++ skip_ifunc); ++ return; ++ } ++ } ++ ++ *reloc_addr = map->l_mach.plt; + } + else if (__builtin_expect (r_type == AARCH64_R(TLSDESC), 1)) + { +diff --git a/sysdeps/aarch64/linkmap.h b/sysdeps/aarch64/linkmap.h +index 6852f343a1efd150..dd8597470c3d2174 100644 +--- a/sysdeps/aarch64/linkmap.h ++++ b/sysdeps/aarch64/linkmap.h +@@ -20,4 +20,5 @@ struct link_map_machine + { + ElfW(Addr) plt; /* Address of .plt */ + void *tlsdesc_table; /* Address of TLS descriptor hash table. */ ++ int variant_pcs; /* If set, PLT calls may follow a variant PCS. */ + }; diff --git a/SOURCES/glibc-rh1726638-3.patch b/SOURCES/glibc-rh1726638-3.patch new file mode 100644 index 0000000..6c37873 --- /dev/null +++ b/SOURCES/glibc-rh1726638-3.patch @@ -0,0 +1,49 @@ +commit 30ba0375464f34e4bf8129f3d3dc14d0c09add17 +Author: Szabolcs Nagy +Date: Tue Jul 9 12:11:39 2019 +0100 + + aarch64: simplify the DT_AARCH64_VARIANT_PCS handling code + + Remove unnecessary variant_pcs field: the dynamic tag can be checked + directly. + + * sysdeps/aarch64/dl-machine.h (elf_machine_runtime_setup): Remove the + DT_AARCH64_VARIANT_PCS check. + (elf_machine_lazy_rel): Use l_info[DT_AARCH64 (VARIANT_PCS)]. + * sysdeps/aarch64/linkmap.h (struct link_map_machine): Remove + variant_pcs. + +diff --git a/sysdeps/aarch64/dl-machine.h b/sysdeps/aarch64/dl-machine.h +index d4494852b32b8783..b39eae4acf4086ee 100644 +--- a/sysdeps/aarch64/dl-machine.h ++++ b/sysdeps/aarch64/dl-machine.h +@@ -105,10 +105,6 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) + } + } + +- /* Check if STO_AARCH64_VARIANT_PCS needs to be handled. */ +- if (l->l_info[DT_AARCH64 (VARIANT_PCS)]) +- l->l_mach.variant_pcs = 1; +- + return lazy; + } + +@@ -402,7 +398,7 @@ elf_machine_lazy_rel (struct link_map *map, + return; + } + +- if (__glibc_unlikely (map->l_mach.variant_pcs)) ++ if (__glibc_unlikely (map->l_info[DT_AARCH64 (VARIANT_PCS)] != NULL)) + { + /* Check the symbol table for variant PCS symbols. */ + const Elf_Symndx symndx = ELFW (R_SYM) (reloc->r_info); +diff --git a/sysdeps/aarch64/linkmap.h b/sysdeps/aarch64/linkmap.h +index dd8597470c3d2174..6852f343a1efd150 100644 +--- a/sysdeps/aarch64/linkmap.h ++++ b/sysdeps/aarch64/linkmap.h +@@ -20,5 +20,4 @@ struct link_map_machine + { + ElfW(Addr) plt; /* Address of .plt */ + void *tlsdesc_table; /* Address of TLS descriptor hash table. */ +- int variant_pcs; /* If set, PLT calls may follow a variant PCS. */ + }; diff --git a/SOURCES/glibc-rh1727152.patch b/SOURCES/glibc-rh1727152.patch new file mode 100644 index 0000000..8a5ed92 --- /dev/null +++ b/SOURCES/glibc-rh1727152.patch @@ -0,0 +1,22 @@ +commit 61595e3d36ded374f97961503e843a314b0203c2 +Author: Andreas Schwab +Date: Tue May 15 14:42:37 2018 +0200 + + nscd: avoid assertion failure during persistent db check + + nscd should not abort when it finds inconsistencies in the persistent db. + +diff --git a/nscd/connections.c b/nscd/connections.c +index 47fbb9923aa2aac7..98182007646a33d5 100644 +--- a/nscd/connections.c ++++ b/nscd/connections.c +@@ -304,7 +304,8 @@ static int + check_use (const char *data, nscd_ssize_t first_free, uint8_t *usemap, + enum usekey use, ref_t start, size_t len) + { +- assert (len >= 2); ++ if (len < 2) ++ return 0; + + if (start > first_free || start + len > first_free + || (start & BLOCK_ALIGN_M1)) diff --git a/SOURCES/glibc-rh1727241-1.patch b/SOURCES/glibc-rh1727241-1.patch new file mode 100644 index 0000000..5842b08 --- /dev/null +++ b/SOURCES/glibc-rh1727241-1.patch @@ -0,0 +1,221 @@ +commit 5e30b8ef0758763effa115634e0ed7d8938e4bc0 +Author: Florian Weimer +Date: Mon Jan 21 08:59:42 2019 +0100 + + resolv: Reformat inet_addr, inet_aton to GNU style + +diff --git a/resolv/inet_addr.c b/resolv/inet_addr.c +index 022f7ea0841b6bae..32f58b0e13598b32 100644 +--- a/resolv/inet_addr.c ++++ b/resolv/inet_addr.c +@@ -1,3 +1,21 @@ ++/* Legacy IPv4 text-to-address functions. ++ Copyright (C) 2019 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 ++ . */ ++ + /* + * Copyright (c) 1983, 1990, 1993 + * The Regents of the University of California. All rights reserved. +@@ -78,105 +96,97 @@ + #include + #include + +-/* +- * Ascii internet address interpretation routine. +- * The value returned is in network order. +- */ ++/* ASCII IPv4 Internet address interpretation routine. The value ++ returned is in network order. */ + in_addr_t +-__inet_addr(const char *cp) { +- struct in_addr val; ++__inet_addr (const char *cp) ++{ ++ struct in_addr val; + +- if (__inet_aton(cp, &val)) +- return (val.s_addr); +- return (INADDR_NONE); ++ if (__inet_aton (cp, &val)) ++ return val.s_addr; ++ return INADDR_NONE; + } + weak_alias (__inet_addr, inet_addr) + +-/* +- * Check whether "cp" is a valid ascii representation +- * of an Internet address and convert to a binary address. +- * Returns 1 if the address is valid, 0 if not. +- * This replaces inet_addr, the return value from which +- * cannot distinguish between failure and a local broadcast address. +- */ ++/* Check whether "cp" is a valid ASCII representation of an IPv4 ++ Internet address and convert it to a binary address. Returns 1 if ++ the address is valid, 0 if not. This replaces inet_addr, the ++ return value from which cannot distinguish between failure and a ++ local broadcast address. */ + int +-__inet_aton(const char *cp, struct in_addr *addr) ++__inet_aton (const char *cp, struct in_addr *addr) + { +- static const in_addr_t max[4] = { 0xffffffff, 0xffffff, 0xffff, 0xff }; +- in_addr_t val; +- char c; +- union iaddr { +- uint8_t bytes[4]; +- uint32_t word; +- } res; +- uint8_t *pp = res.bytes; +- int digit; +- +- int saved_errno = errno; +- __set_errno (0); +- +- res.word = 0; +- +- c = *cp; +- for (;;) { +- /* +- * Collect number up to ``.''. +- * Values are specified as for C: +- * 0x=hex, 0=octal, isdigit=decimal. +- */ +- if (!isdigit(c)) +- goto ret_0; +- { +- char *endp; +- unsigned long ul = strtoul (cp, (char **) &endp, 0); +- if (ul == ULONG_MAX && errno == ERANGE) +- goto ret_0; +- if (ul > 0xfffffffful) +- goto ret_0; +- val = ul; +- digit = cp != endp; +- cp = endp; +- } +- c = *cp; +- if (c == '.') { +- /* +- * Internet format: +- * a.b.c.d +- * a.b.c (with c treated as 16 bits) +- * a.b (with b treated as 24 bits) +- */ +- if (pp > res.bytes + 2 || val > 0xff) +- goto ret_0; +- *pp++ = val; +- c = *++cp; +- } else +- break; +- } +- /* +- * Check for trailing characters. +- */ +- if (c != '\0' && (!isascii(c) || !isspace(c))) +- goto ret_0; +- /* +- * Did we get a valid digit? +- */ +- if (!digit) +- goto ret_0; +- +- /* Check whether the last part is in its limits depending on +- the number of parts in total. */ +- if (val > max[pp - res.bytes]) ++ static const in_addr_t max[4] = { 0xffffffff, 0xffffff, 0xffff, 0xff }; ++ in_addr_t val; ++ char c; ++ union iaddr ++ { ++ uint8_t bytes[4]; ++ uint32_t word; ++ } res; ++ uint8_t *pp = res.bytes; ++ int digit; ++ ++ int saved_errno = errno; ++ __set_errno (0); ++ ++ res.word = 0; ++ ++ c = *cp; ++ for (;;) ++ { ++ /* Collect number up to ``.''. Values are specified as for C: ++ 0x=hex, 0=octal, isdigit=decimal. */ ++ if (!isdigit (c)) ++ goto ret_0; ++ { ++ char *endp; ++ unsigned long ul = strtoul (cp, &endp, 0); ++ if (ul == ULONG_MAX && errno == ERANGE) + goto ret_0; +- +- if (addr != NULL) +- addr->s_addr = res.word | htonl (val); +- +- __set_errno (saved_errno); +- return (1); +- +-ret_0: +- __set_errno (saved_errno); +- return (0); ++ if (ul > 0xfffffffful) ++ goto ret_0; ++ val = ul; ++ digit = cp != endp; ++ cp = endp; ++ } ++ c = *cp; ++ if (c == '.') ++ { ++ /* Internet format: ++ a.b.c.d ++ a.b.c (with c treated as 16 bits) ++ a.b (with b treated as 24 bits). */ ++ if (pp > res.bytes + 2 || val > 0xff) ++ goto ret_0; ++ *pp++ = val; ++ c = *++cp; ++ } ++ else ++ break; ++ } ++ /* Check for trailing characters. */ ++ if (c != '\0' && (!isascii (c) || !isspace (c))) ++ goto ret_0; ++ /* Did we get a valid digit? */ ++ if (!digit) ++ goto ret_0; ++ ++ /* Check whether the last part is in its limits depending on the ++ number of parts in total. */ ++ if (val > max[pp - res.bytes]) ++ goto ret_0; ++ ++ if (addr != NULL) ++ addr->s_addr = res.word | htonl (val); ++ ++ __set_errno (saved_errno); ++ return 1; ++ ++ ret_0: ++ __set_errno (saved_errno); ++ return 0; + } + weak_alias (__inet_aton, inet_aton) + libc_hidden_def (__inet_aton) diff --git a/SOURCES/glibc-rh1727241-2.patch b/SOURCES/glibc-rh1727241-2.patch new file mode 100644 index 0000000..7f9f417 --- /dev/null +++ b/SOURCES/glibc-rh1727241-2.patch @@ -0,0 +1,80 @@ +commit 6ca53a2453598804a2559a548a08424fca96434a +Author: Florian Weimer +Date: Mon Jan 21 09:26:41 2019 +0100 + + resolv: Do not send queries for non-host-names in nss_dns [BZ #24112] + + Before this commit, nss_dns would send a query which did not contain a + host name as the query name (such as invalid\032name.example.com) and + then reject the answer in getanswer_r and gaih_getanswer_slice, using + a check based on res_hnok. With this commit, no query is sent, and a + host-not-found error is returned to NSS without network interaction. + +diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c +index 5dc2829cd148a568..99c3b61e1cee4d42 100644 +--- a/resolv/nss_dns/dns-host.c ++++ b/resolv/nss_dns/dns-host.c +@@ -274,11 +274,26 @@ gethostbyname3_context (struct resolv_context *ctx, + return status; + } + ++/* Verify that the name looks like a host name. There is no point in ++ sending a query which will not produce a usable name in the ++ response. */ ++static enum nss_status ++check_name (const char *name, int *h_errnop) ++{ ++ if (res_hnok (name)) ++ return NSS_STATUS_SUCCESS; ++ *h_errnop = HOST_NOT_FOUND; ++ return NSS_STATUS_NOTFOUND; ++} ++ + enum nss_status + _nss_dns_gethostbyname2_r (const char *name, int af, struct hostent *result, + char *buffer, size_t buflen, int *errnop, + int *h_errnop) + { ++ enum nss_status status = check_name (name, h_errnop); ++ if (status != NSS_STATUS_SUCCESS) ++ return status; + return _nss_dns_gethostbyname3_r (name, af, result, buffer, buflen, errnop, + h_errnop, NULL, NULL); + } +@@ -289,6 +304,9 @@ _nss_dns_gethostbyname_r (const char *name, struct hostent *result, + char *buffer, size_t buflen, int *errnop, + int *h_errnop) + { ++ enum nss_status status = check_name (name, h_errnop); ++ if (status != NSS_STATUS_SUCCESS) ++ return status; + struct resolv_context *ctx = __resolv_context_get (); + if (ctx == NULL) + { +@@ -296,7 +314,7 @@ _nss_dns_gethostbyname_r (const char *name, struct hostent *result, + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_UNAVAIL; + } +- enum nss_status status = NSS_STATUS_NOTFOUND; ++ status = NSS_STATUS_NOTFOUND; + if (res_use_inet6 ()) + status = gethostbyname3_context (ctx, name, AF_INET6, result, buffer, + buflen, errnop, h_errnop, NULL, NULL); +@@ -313,6 +331,9 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, + char *buffer, size_t buflen, int *errnop, + int *herrnop, int32_t *ttlp) + { ++ enum nss_status status = check_name (name, herrnop); ++ if (status != NSS_STATUS_SUCCESS) ++ return status; + struct resolv_context *ctx = __resolv_context_get (); + if (ctx == NULL) + { +@@ -347,7 +368,6 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, + int ans2p_malloced = 0; + + int olderr = errno; +- enum nss_status status; + int n = __res_context_search (ctx, name, C_IN, T_QUERY_A_AND_AAAA, + host_buffer.buf->buf, 2048, &host_buffer.ptr, + &ans2p, &nans2p, &resplen2, &ans2p_malloced); diff --git a/SOURCES/glibc-rh1727241-3.patch b/SOURCES/glibc-rh1727241-3.patch new file mode 100644 index 0000000..f578ebd --- /dev/null +++ b/SOURCES/glibc-rh1727241-3.patch @@ -0,0 +1,698 @@ +commit 108bc4049f8ae82710aec26a92ffdb4b439c83fd +Author: Florian Weimer +Date: Mon Jan 21 21:26:03 2019 +0100 + + CVE-2016-10739: getaddrinfo: Fully parse IPv4 address strings [BZ #20018] + + The IPv4 address parser in the getaddrinfo function is changed so that + it does not ignore trailing whitespace and all characters after it. + For backwards compatibility, the getaddrinfo function still recognizes + legacy name syntax, such as 192.000.002.010 interpreted as 192.0.2.8 + (octal). + + This commit does not change the behavior of inet_addr and inet_aton. + gethostbyname already had additional sanity checks (but is switched + over to the new __inet_aton_exact function for completeness as well). + + To avoid sending the problematic query names over DNS, commit + 6ca53a2453598804a2559a548a08424fca96434a ("resolv: Do not send queries + for non-host-names in nss_dns [BZ #24112]") is needed. + +diff --git a/include/arpa/inet.h b/include/arpa/inet.h +index c3f28f2baaa2ed66..19aec74275069a45 100644 +--- a/include/arpa/inet.h ++++ b/include/arpa/inet.h +@@ -1,10 +1,10 @@ + #include + + #ifndef _ISOMAC +-extern int __inet_aton (const char *__cp, struct in_addr *__inp); +-libc_hidden_proto (__inet_aton) ++/* Variant of inet_aton which rejects trailing garbage. */ ++extern int __inet_aton_exact (const char *__cp, struct in_addr *__inp); ++libc_hidden_proto (__inet_aton_exact) + +-libc_hidden_proto (inet_aton) + libc_hidden_proto (inet_ntop) + libc_hidden_proto (inet_pton) + extern __typeof (inet_pton) __inet_pton; +diff --git a/nscd/gai.c b/nscd/gai.c +index 24bdfee1db3791e2..f57f396f574a6e52 100644 +--- a/nscd/gai.c ++++ b/nscd/gai.c +@@ -19,7 +19,6 @@ + + /* This file uses the getaddrinfo code but it compiles it without NSCD + support. We just need a few symbol renames. */ +-#define __inet_aton inet_aton + #define __ioctl ioctl + #define __getsockname getsockname + #define __socket socket +diff --git a/nscd/gethstbynm3_r.c b/nscd/gethstbynm3_r.c +index 7beb9dce9f4b350c..f792c4fcd042d13d 100644 +--- a/nscd/gethstbynm3_r.c ++++ b/nscd/gethstbynm3_r.c +@@ -38,8 +38,6 @@ + #define HAVE_LOOKUP_BUFFER 1 + #define HAVE_AF 1 + +-#define __inet_aton inet_aton +- + /* We are nscd, so we don't want to be talking to ourselves. */ + #undef USE_NSCD + +diff --git a/nss/digits_dots.c b/nss/digits_dots.c +index 39bff38865a1ac5b..5441bce16ea8b2e9 100644 +--- a/nss/digits_dots.c ++++ b/nss/digits_dots.c +@@ -29,7 +29,6 @@ + #include "nsswitch.h" + + #ifdef USE_NSCD +-# define inet_aton __inet_aton + # include + #endif + +@@ -160,7 +159,7 @@ __nss_hostname_digits_dots_context (struct resolv_context *ctx, + 255.255.255.255? The test below will succeed + spuriously... ??? */ + if (af == AF_INET) +- ok = __inet_aton (name, (struct in_addr *) host_addr); ++ ok = __inet_aton_exact (name, (struct in_addr *) host_addr); + else + { + assert (af == AF_INET6); +diff --git a/resolv/Makefile b/resolv/Makefile +index 56718654eeab85a3..72a0f196506ac489 100644 +--- a/resolv/Makefile ++++ b/resolv/Makefile +@@ -34,6 +34,9 @@ routines := herror inet_addr inet_ntop inet_pton nsap_addr res_init \ + tests = tst-aton tst-leaks tst-inet_ntop + xtests = tst-leaks2 + ++tests-internal += tst-inet_aton_exact ++ ++ + generate := mtrace-tst-leaks.out tst-leaks.mtrace tst-leaks2.mtrace + + extra-libs := libresolv libnss_dns +@@ -54,8 +57,10 @@ tests += \ + tst-resolv-binary \ + tst-resolv-edns \ + tst-resolv-network \ ++ tst-resolv-nondecimal \ + tst-resolv-res_init-multi \ + tst-resolv-search \ ++ tst-resolv-trailing \ + + # These tests need libdl. + ifeq (yes,$(build-shared)) +@@ -190,9 +195,11 @@ $(objpfx)tst-resolv-res_init-multi: $(objpfx)libresolv.so \ + $(shared-thread-library) + $(objpfx)tst-resolv-res_init-thread: $(libdl) $(objpfx)libresolv.so \ + $(shared-thread-library) ++$(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-trailing: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-threads: \ + $(libdl) $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-canonname: \ +diff --git a/resolv/Versions b/resolv/Versions +index b05778d9654aa0f2..9a82704af75f789b 100644 +--- a/resolv/Versions ++++ b/resolv/Versions +@@ -27,6 +27,7 @@ libc { + __h_errno; __resp; + + __res_iclose; ++ __inet_aton_exact; + __inet_pton_length; + __resolv_context_get; + __resolv_context_get_preinit; +diff --git a/resolv/inet_addr.c b/resolv/inet_addr.c +index 32f58b0e13598b32..41b6166a5bd5a44b 100644 +--- a/resolv/inet_addr.c ++++ b/resolv/inet_addr.c +@@ -96,26 +96,14 @@ + #include + #include + +-/* ASCII IPv4 Internet address interpretation routine. The value +- returned is in network order. */ +-in_addr_t +-__inet_addr (const char *cp) +-{ +- struct in_addr val; +- +- if (__inet_aton (cp, &val)) +- return val.s_addr; +- return INADDR_NONE; +-} +-weak_alias (__inet_addr, inet_addr) +- + /* Check whether "cp" is a valid ASCII representation of an IPv4 + Internet address and convert it to a binary address. Returns 1 if + the address is valid, 0 if not. This replaces inet_addr, the + return value from which cannot distinguish between failure and a +- local broadcast address. */ +-int +-__inet_aton (const char *cp, struct in_addr *addr) ++ local broadcast address. Write a pointer to the first ++ non-converted character to *endp. */ ++static int ++inet_aton_end (const char *cp, struct in_addr *addr, const char **endp) + { + static const in_addr_t max[4] = { 0xffffffff, 0xffffff, 0xffff, 0xff }; + in_addr_t val; +@@ -180,6 +168,7 @@ __inet_aton (const char *cp, struct in_addr *addr) + + if (addr != NULL) + addr->s_addr = res.word | htonl (val); ++ *endp = cp; + + __set_errno (saved_errno); + return 1; +@@ -188,6 +177,41 @@ __inet_aton (const char *cp, struct in_addr *addr) + __set_errno (saved_errno); + return 0; + } +-weak_alias (__inet_aton, inet_aton) +-libc_hidden_def (__inet_aton) +-libc_hidden_weak (inet_aton) ++ ++int ++__inet_aton_exact (const char *cp, struct in_addr *addr) ++{ ++ struct in_addr val; ++ const char *endp; ++ /* Check that inet_aton_end parsed the entire string. */ ++ if (inet_aton_end (cp, &val, &endp) != 0 && *endp == 0) ++ { ++ *addr = val; ++ return 1; ++ } ++ else ++ return 0; ++} ++libc_hidden_def (__inet_aton_exact) ++ ++/* inet_aton ignores trailing garbage. */ ++int ++__inet_aton_ignore_trailing (const char *cp, struct in_addr *addr) ++{ ++ const char *endp; ++ return inet_aton_end (cp, addr, &endp); ++} ++weak_alias (__inet_aton_ignore_trailing, inet_aton) ++ ++/* ASCII IPv4 Internet address interpretation routine. The value ++ returned is in network order. */ ++in_addr_t ++__inet_addr (const char *cp) ++{ ++ struct in_addr val; ++ const char *endp; ++ if (inet_aton_end (cp, &val, &endp)) ++ return val.s_addr; ++ return INADDR_NONE; ++} ++weak_alias (__inet_addr, inet_addr) +diff --git a/resolv/res_init.c b/resolv/res_init.c +index f5e52cbbb9377762..94743a252e39d64a 100644 +--- a/resolv/res_init.c ++++ b/resolv/res_init.c +@@ -399,8 +399,16 @@ res_vinit_1 (FILE *fp, struct resolv_conf_parser *parser) + cp = parser->buffer + sizeof ("nameserver") - 1; + while (*cp == ' ' || *cp == '\t') + cp++; ++ ++ /* Ignore trailing contents on the name server line. */ ++ { ++ char *el; ++ if ((el = strpbrk (cp, " \t\n")) != NULL) ++ *el = '\0'; ++ } ++ + struct sockaddr *sa; +- if ((*cp != '\0') && (*cp != '\n') && __inet_aton (cp, &a)) ++ if ((*cp != '\0') && (*cp != '\n') && __inet_aton_exact (cp, &a)) + { + sa = allocate_address_v4 (a, NAMESERVER_PORT); + if (sa == NULL) +@@ -410,9 +418,6 @@ res_vinit_1 (FILE *fp, struct resolv_conf_parser *parser) + { + struct in6_addr a6; + char *el; +- +- if ((el = strpbrk (cp, " \t\n")) != NULL) +- *el = '\0'; + if ((el = strchr (cp, SCOPE_DELIMITER)) != NULL) + *el = '\0'; + if ((*cp != '\0') && (__inet_pton (AF_INET6, cp, &a6) > 0)) +@@ -472,7 +477,7 @@ res_vinit_1 (FILE *fp, struct resolv_conf_parser *parser) + char separator = *cp; + *cp = 0; + struct resolv_sortlist_entry e; +- if (__inet_aton (net, &a)) ++ if (__inet_aton_exact (net, &a)) + { + e.addr = a; + if (is_sort_mask (separator)) +@@ -484,7 +489,7 @@ res_vinit_1 (FILE *fp, struct resolv_conf_parser *parser) + cp++; + separator = *cp; + *cp = 0; +- if (__inet_aton (net, &a)) ++ if (__inet_aton_exact (net, &a)) + e.mask = a.s_addr; + else + e.mask = net_mask (e.addr); +diff --git a/resolv/tst-aton.c b/resolv/tst-aton.c +index 08110a007af909ff..eb734d7758d6ed87 100644 +--- a/resolv/tst-aton.c ++++ b/resolv/tst-aton.c +@@ -1,11 +1,29 @@ ++/* Test legacy IPv4 text-to-address function inet_aton. ++ Copyright (C) 1998-2019 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 ++ . */ ++ ++#include + #include + #include + #include + #include + #include + +- +-static struct tests ++static const struct tests + { + const char *input; + int valid; +@@ -16,6 +34,7 @@ static struct tests + { "-1", 0, 0 }, + { "256", 1, 0x00000100 }, + { "256.", 0, 0 }, ++ { "255a", 0, 0 }, + { "256a", 0, 0 }, + { "0x100", 1, 0x00000100 }, + { "0200.0x123456", 1, 0x80123456 }, +@@ -40,7 +59,12 @@ static struct tests + { "1.2.256.4", 0, 0 }, + { "1.2.3.0x100", 0, 0 }, + { "323543357756889", 0, 0 }, +- { "10.1.2.3.4", 0, 0}, ++ { "10.1.2.3.4", 0, 0 }, ++ { "192.0.2.1", 1, 0xc0000201 }, ++ { "192.0.2.2\nX", 1, 0xc0000202 }, ++ { "192.0.2.3 Y", 1, 0xc0000203 }, ++ { "192.0.2.3Z", 0, 0 }, ++ { "192.000.002.010", 1, 0xc0000208 }, + }; + + +@@ -50,7 +74,7 @@ do_test (void) + int result = 0; + size_t cnt; + +- for (cnt = 0; cnt < sizeof (tests) / sizeof (tests[0]); ++cnt) ++ for (cnt = 0; cnt < array_length (tests); ++cnt) + { + struct in_addr addr; + +@@ -73,5 +97,4 @@ do_test (void) + return result; + } + +-#define TEST_FUNCTION do_test () +-#include "../test-skeleton.c" ++#include +diff --git a/resolv/tst-inet_aton_exact.c b/resolv/tst-inet_aton_exact.c +new file mode 100644 +index 0000000000000000..0fdfa3d6aa9aef91 +--- /dev/null ++++ b/resolv/tst-inet_aton_exact.c +@@ -0,0 +1,47 @@ ++/* Test internal legacy IPv4 text-to-address function __inet_aton_exact. ++ Copyright (C) 2019 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 ++ . */ ++ ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ struct in_addr addr = { }; ++ ++ TEST_COMPARE (__inet_aton_exact ("192.0.2.1", &addr), 1); ++ TEST_COMPARE (ntohl (addr.s_addr), 0xC0000201); ++ ++ TEST_COMPARE (__inet_aton_exact ("192.000.002.010", &addr), 1); ++ TEST_COMPARE (ntohl (addr.s_addr), 0xC0000208); ++ TEST_COMPARE (__inet_aton_exact ("0xC0000234", &addr), 1); ++ TEST_COMPARE (ntohl (addr.s_addr), 0xC0000234); ++ ++ /* Trailing content is not accepted. */ ++ TEST_COMPARE (__inet_aton_exact ("192.0.2.2X", &addr), 0); ++ TEST_COMPARE (__inet_aton_exact ("192.0.2.3 Y", &addr), 0); ++ TEST_COMPARE (__inet_aton_exact ("192.0.2.4\nZ", &addr), 0); ++ TEST_COMPARE (__inet_aton_exact ("192.0.2.5\tT", &addr), 0); ++ TEST_COMPARE (__inet_aton_exact ("192.0.2.6 Y", &addr), 0); ++ TEST_COMPARE (__inet_aton_exact ("192.0.2.7\n", &addr), 0); ++ TEST_COMPARE (__inet_aton_exact ("192.0.2.8\t", &addr), 0); ++ ++ return 0; ++} ++ ++#include +diff --git a/resolv/tst-resolv-nondecimal.c b/resolv/tst-resolv-nondecimal.c +new file mode 100644 +index 0000000000000000..a0df6f332ae8faf7 +--- /dev/null ++++ b/resolv/tst-resolv-nondecimal.c +@@ -0,0 +1,139 @@ ++/* Test name resolution behavior for octal, hexadecimal IPv4 addresses. ++ Copyright (C) 2019 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static void ++response (const struct resolv_response_context *ctx, ++ struct resolv_response_builder *b, ++ const char *qname, uint16_t qclass, uint16_t qtype) ++{ ++ /* The tests are not supposed send any DNS queries. */ ++ FAIL_EXIT1 ("unexpected DNS query for %s/%d/%d", qname, qclass, qtype); ++} ++ ++static void ++run_query_addrinfo (const char *query, const char *address) ++{ ++ char *quoted_query = support_quote_string (query); ++ ++ struct addrinfo *ai; ++ struct addrinfo hints = ++ { ++ .ai_socktype = SOCK_STREAM, ++ .ai_protocol = IPPROTO_TCP, ++ }; ++ ++ char *context = xasprintf ("getaddrinfo \"%s\" AF_INET", quoted_query); ++ char *expected = xasprintf ("address: STREAM/TCP %s 80\n", address); ++ hints.ai_family = AF_INET; ++ int ret = getaddrinfo (query, "80", &hints, &ai); ++ check_addrinfo (context, ai, ret, expected); ++ if (ret == 0) ++ freeaddrinfo (ai); ++ free (context); ++ ++ context = xasprintf ("getaddrinfo \"%s\" AF_UNSPEC", quoted_query); ++ hints.ai_family = AF_UNSPEC; ++ ret = getaddrinfo (query, "80", &hints, &ai); ++ check_addrinfo (context, ai, ret, expected); ++ if (ret == 0) ++ freeaddrinfo (ai); ++ free (expected); ++ free (context); ++ ++ context = xasprintf ("getaddrinfo \"%s\" AF_INET6", quoted_query); ++ expected = xasprintf ("flags: AI_V4MAPPED\n" ++ "address: STREAM/TCP ::ffff:%s 80\n", ++ address); ++ hints.ai_family = AF_INET6; ++ hints.ai_flags = AI_V4MAPPED; ++ ret = getaddrinfo (query, "80", &hints, &ai); ++ check_addrinfo (context, ai, ret, expected); ++ if (ret == 0) ++ freeaddrinfo (ai); ++ free (expected); ++ free (context); ++ ++ free (quoted_query); ++} ++ ++static void ++run_query (const char *query, const char *address) ++{ ++ char *quoted_query = support_quote_string (query); ++ char *context = xasprintf ("gethostbyname (\"%s\")", quoted_query); ++ char *expected = xasprintf ("name: %s\n" ++ "address: %s\n", query, address); ++ check_hostent (context, gethostbyname (query), expected); ++ free (context); ++ ++ context = xasprintf ("gethostbyname_r \"%s\"", quoted_query); ++ struct hostent storage; ++ char buf[4096]; ++ struct hostent *e = NULL; ++ TEST_COMPARE (gethostbyname_r (query, &storage, buf, sizeof (buf), ++ &e, &h_errno), 0); ++ check_hostent (context, e, expected); ++ free (context); ++ ++ context = xasprintf ("gethostbyname2 (\"%s\", AF_INET)", quoted_query); ++ check_hostent (context, gethostbyname2 (query, AF_INET), expected); ++ free (context); ++ ++ context = xasprintf ("gethostbyname2_r \"%s\" AF_INET", quoted_query); ++ e = NULL; ++ TEST_COMPARE (gethostbyname2_r (query, AF_INET, &storage, buf, sizeof (buf), ++ &e, &h_errno), 0); ++ check_hostent (context, e, expected); ++ free (context); ++ free (expected); ++ ++ free (quoted_query); ++ ++ /* The gethostbyname tests are always valid for getaddrinfo, but not ++ vice versa. */ ++ run_query_addrinfo (query, address); ++} ++ ++static int ++do_test (void) ++{ ++ struct resolv_test *aux = resolv_test_start ++ ((struct resolv_redirect_config) ++ { ++ .response_callback = response, ++ }); ++ ++ run_query ("192.000.002.010", "192.0.2.8"); ++ ++ /* Hexadecimal numbers are not accepted by gethostbyname. */ ++ run_query_addrinfo ("0xc0000210", "192.0.2.16"); ++ run_query_addrinfo ("192.0x234", "192.0.2.52"); ++ ++ resolv_test_end (aux); ++ ++ return 0; ++} ++ ++#include +diff --git a/resolv/tst-resolv-trailing.c b/resolv/tst-resolv-trailing.c +new file mode 100644 +index 0000000000000000..7504bdae572ed8d0 +--- /dev/null ++++ b/resolv/tst-resolv-trailing.c +@@ -0,0 +1,136 @@ ++/* Test name resolution behavior with trailing characters. ++ Copyright (C) 2019 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static void ++response (const struct resolv_response_context *ctx, ++ struct resolv_response_builder *b, ++ const char *qname, uint16_t qclass, uint16_t qtype) ++{ ++ /* The tests are not supposed send any DNS queries. */ ++ FAIL_EXIT1 ("unexpected DNS query for %s/%d/%d", qname, qclass, qtype); ++} ++ ++static int ++do_test (void) ++{ ++ struct resolv_test *aux = resolv_test_start ++ ((struct resolv_redirect_config) ++ { ++ .response_callback = response, ++ }); ++ ++ static const char *const queries[] = ++ { ++ "192.0.2.1 ", ++ "192.0.2.2\t", ++ "192.0.2.3\n", ++ "192.0.2.4 X", ++ "192.0.2.5\tY", ++ "192.0.2.6\nZ", ++ "192.0.2. ", ++ "192.0.2.\t", ++ "192.0.2.\n", ++ "192.0.2. X", ++ "192.0.2.\tY", ++ "192.0.2.\nZ", ++ "2001:db8::1 ", ++ "2001:db8::2\t", ++ "2001:db8::3\n", ++ "2001:db8::4 X", ++ "2001:db8::5\tY", ++ "2001:db8::6\nZ", ++ }; ++ for (size_t query_idx = 0; query_idx < array_length (queries); ++query_idx) ++ { ++ const char *query = queries[query_idx]; ++ struct hostent storage; ++ char buf[4096]; ++ struct hostent *e; ++ ++ h_errno = 0; ++ TEST_VERIFY (gethostbyname (query) == NULL); ++ TEST_COMPARE (h_errno, HOST_NOT_FOUND); ++ ++ h_errno = 0; ++ e = NULL; ++ TEST_COMPARE (gethostbyname_r (query, &storage, buf, sizeof (buf), ++ &e, &h_errno), 0); ++ TEST_VERIFY (e == NULL); ++ TEST_COMPARE (h_errno, HOST_NOT_FOUND); ++ ++ h_errno = 0; ++ TEST_VERIFY (gethostbyname2 (query, AF_INET) == NULL); ++ TEST_COMPARE (h_errno, HOST_NOT_FOUND); ++ ++ h_errno = 0; ++ e = NULL; ++ TEST_COMPARE (gethostbyname2_r (query, AF_INET, ++ &storage, buf, sizeof (buf), ++ &e, &h_errno), 0); ++ TEST_VERIFY (e == NULL); ++ TEST_COMPARE (h_errno, HOST_NOT_FOUND); ++ ++ h_errno = 0; ++ TEST_VERIFY (gethostbyname2 (query, AF_INET6) == NULL); ++ TEST_COMPARE (h_errno, HOST_NOT_FOUND); ++ ++ h_errno = 0; ++ e = NULL; ++ TEST_COMPARE (gethostbyname2_r (query, AF_INET6, ++ &storage, buf, sizeof (buf), ++ &e, &h_errno), 0); ++ TEST_VERIFY (e == NULL); ++ TEST_COMPARE (h_errno, HOST_NOT_FOUND); ++ ++ static const int gai_flags[] = ++ { ++ 0, ++ AI_ADDRCONFIG, ++ AI_NUMERICHOST, ++ AI_IDN, ++ AI_IDN | AI_NUMERICHOST, ++ AI_V4MAPPED, ++ AI_V4MAPPED | AI_NUMERICHOST, ++ }; ++ for (size_t gai_flags_idx; gai_flags_idx < array_length (gai_flags); ++ ++gai_flags_idx) ++ { ++ struct addrinfo hints = { .ai_flags = gai_flags[gai_flags_idx], }; ++ struct addrinfo *ai; ++ hints.ai_family = AF_INET; ++ TEST_COMPARE (getaddrinfo (query, "80", &hints, &ai), EAI_NONAME); ++ hints.ai_family = AF_INET6; ++ TEST_COMPARE (getaddrinfo (query, "80", &hints, &ai), EAI_NONAME); ++ hints.ai_family = AF_UNSPEC; ++ TEST_COMPARE (getaddrinfo (query, "80", &hints, &ai), EAI_NONAME); ++ } ++ }; ++ ++ resolv_test_end (aux); ++ ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index 00e0d94a8f5bb30d..6a5805c9e63a257c 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -488,7 +488,7 @@ gaih_inet (const char *name, const struct gaih_service *service, + malloc_name = true; + } + +- if (__inet_aton (name, (struct in_addr *) at->addr) != 0) ++ if (__inet_aton_exact (name, (struct in_addr *) at->addr) != 0) + { + if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET) + at->family = AF_INET; diff --git a/SOURCES/glibc-rh1735747-1.patch b/SOURCES/glibc-rh1735747-1.patch new file mode 100644 index 0000000..04c4136 --- /dev/null +++ b/SOURCES/glibc-rh1735747-1.patch @@ -0,0 +1,25 @@ +commit 6d750b18999b52ec74102c046cd27181f943bda8 +Author: Florian Weimer +Date: Thu Aug 1 14:06:24 2019 +0200 + + malloc: Remove unwanted leading whitespace in malloc_info [BZ #24867] + + It was introduced in commit 6c8dbf00f536d78b1937b5af6f57be47fd376344 + ("Reformat malloc to gnu style."). + + Reviewed-by: Carlos O'Donell + (cherry picked from commit b0f6679bcd738ea244a14acd879d974901e56c8e) + +diff --git a/malloc/malloc.c b/malloc/malloc.c +index e6a483d5cf7c4312..4fc7f175fe42d6c6 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -5518,7 +5518,7 @@ __malloc_info (int options, FILE *fp) + + for (size_t i = 0; i < nsizes; ++i) + if (sizes[i].count != 0 && i != NFASTBINS) +- fprintf (fp, " \ ++ fprintf (fp, "\ + \n", + sizes[i].from, sizes[i].to, sizes[i].total, sizes[i].count); + diff --git a/SOURCES/glibc-rh1735747-2.patch b/SOURCES/glibc-rh1735747-2.patch new file mode 100644 index 0000000..e2afd28 --- /dev/null +++ b/SOURCES/glibc-rh1735747-2.patch @@ -0,0 +1,35 @@ +commit 91d5989356325759503311df67e750b358ef4148 +Author: Niklas Hambüchen +Date: Thu Aug 8 22:02:27 2019 +0200 + + malloc: Fix missing accounting of top chunk in malloc_info [BZ #24026] + + Fixes ` incorrectly showing as 0 most + of the time. + + The rest value being wrong is significant because to compute the + actual amount of memory handed out via malloc, the user must subtract + it from . That result being wrong + makes investigating memory fragmentation issues like + close to + impossible. + + (cherry picked from commit b6d2c4475d5abc05dd009575b90556bdd3c78ad0) + +diff --git a/malloc/malloc.c b/malloc/malloc.c +index 4fc7f175fe42d6c6..fcf480acdaea1b86 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -5433,6 +5433,12 @@ __malloc_info (int options, FILE *fp) + + __libc_lock_lock (ar_ptr->mutex); + ++ /* Account for top chunk. The top-most available chunk is ++ treated specially and is never in any bin. See "initial_top" ++ comments. */ ++ avail = chunksize (ar_ptr->top); ++ nblocks = 1; /* Top always exists. */ ++ + for (size_t i = 0; i < NFASTBINS; ++i) + { + mchunkptr p = fastbin (ar_ptr, i); diff --git a/SOURCES/glibc-rh1746928.patch b/SOURCES/glibc-rh1746928.patch new file mode 100644 index 0000000..c21eb1d --- /dev/null +++ b/SOURCES/glibc-rh1746928.patch @@ -0,0 +1,117 @@ +commit 669ff911e2571f74a2668493e326ac9a505776bd +Author: Florian Weimer +Date: Fri Feb 8 12:46:19 2019 +0100 + + nptl: Avoid fork handler lock for async-signal-safe fork [BZ #24161] + + Commit 27761a1042daf01987e7d79636d0c41511c6df3c ("Refactor atfork + handlers") introduced a lock, atfork_lock, around fork handler list + accesses. It turns out that this lock occasionally results in + self-deadlocks in malloc/tst-mallocfork2: + + (gdb) bt + #0 __lll_lock_wait_private () + at ../sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:63 + #1 0x00007f160c6f927a in __run_fork_handlers (who=(unknown: 209394016), + who@entry=atfork_run_prepare) at register-atfork.c:116 + #2 0x00007f160c6b7897 in __libc_fork () at ../sysdeps/nptl/fork.c:58 + #3 0x00000000004027d6 in sigusr1_handler (signo=) + at tst-mallocfork2.c:80 + #4 sigusr1_handler (signo=) at tst-mallocfork2.c:64 + #5 + #6 0x00007f160c6f92e4 in __run_fork_handlers (who=who@entry=atfork_run_parent) + at register-atfork.c:136 + #7 0x00007f160c6b79a2 in __libc_fork () at ../sysdeps/nptl/fork.c:152 + #8 0x0000000000402567 in do_test () at tst-mallocfork2.c:156 + #9 0x0000000000402dd2 in support_test_main (argc=1, argv=0x7ffc81ef1ab0, + config=config@entry=0x7ffc81ef1970) at support_test_main.c:350 + #10 0x0000000000402362 in main (argc=, argv=) + at ../support/test-driver.c:168 + + If no locking happens in the single-threaded case (where fork is + expected to be async-signal-safe), this deadlock is avoided. + (pthread_atfork is not required to be async-signal-safe, so a fork + call from a signal handler interrupting pthread_atfork is not + a problem.) + +diff --git a/nptl/register-atfork.c b/nptl/register-atfork.c +index bc797b7..80a1bec 100644 +--- a/nptl/register-atfork.c ++++ b/nptl/register-atfork.c +@@ -107,13 +107,14 @@ __unregister_atfork (void *dso_handle) + } + + void +-__run_fork_handlers (enum __run_fork_handler_type who) ++__run_fork_handlers (enum __run_fork_handler_type who, _Bool do_locking) + { + struct fork_handler *runp; + + if (who == atfork_run_prepare) + { +- lll_lock (atfork_lock, LLL_PRIVATE); ++ if (do_locking) ++ lll_lock (atfork_lock, LLL_PRIVATE); + size_t sl = fork_handler_list_size (&fork_handlers); + for (size_t i = sl; i > 0; i--) + { +@@ -133,7 +134,8 @@ __run_fork_handlers (enum __run_fork_handler_type who) + else if (who == atfork_run_parent && runp->parent_handler) + runp->parent_handler (); + } +- lll_unlock (atfork_lock, LLL_PRIVATE); ++ if (do_locking) ++ lll_unlock (atfork_lock, LLL_PRIVATE); + } + } + +diff --git a/sysdeps/nptl/fork.c b/sysdeps/nptl/fork.c +index bd68f18..14b69a6 100644 +--- a/sysdeps/nptl/fork.c ++++ b/sysdeps/nptl/fork.c +@@ -55,7 +55,7 @@ __libc_fork (void) + but our current fork implementation is not. */ + bool multiple_threads = THREAD_GETMEM (THREAD_SELF, header.multiple_threads); + +- __run_fork_handlers (atfork_run_prepare); ++ __run_fork_handlers (atfork_run_prepare, multiple_threads); + + /* If we are not running multiple threads, we do not have to + preserve lock state. If fork runs from a signal handler, only +@@ -134,7 +134,7 @@ __libc_fork (void) + __rtld_lock_initialize (GL(dl_load_lock)); + + /* Run the handlers registered for the child. */ +- __run_fork_handlers (atfork_run_child); ++ __run_fork_handlers (atfork_run_child, multiple_threads); + } + else + { +@@ -149,7 +149,7 @@ __libc_fork (void) + } + + /* Run the handlers registered for the parent. */ +- __run_fork_handlers (atfork_run_parent); ++ __run_fork_handlers (atfork_run_parent, multiple_threads); + } + + return pid; +diff --git a/sysdeps/nptl/fork.h b/sysdeps/nptl/fork.h +index a1c3b26..99ed760 100644 +--- a/sysdeps/nptl/fork.h ++++ b/sysdeps/nptl/fork.h +@@ -52,9 +52,11 @@ enum __run_fork_handler_type + - atfork_run_child: run all the CHILD_HANDLER and unlocks the internal + lock. + - atfork_run_parent: run all the PARENT_HANDLER and unlocks the internal +- lock. */ +-extern void __run_fork_handlers (enum __run_fork_handler_type who) +- attribute_hidden; ++ lock. ++ ++ Perform locking only if DO_LOCKING. */ ++extern void __run_fork_handlers (enum __run_fork_handler_type who, ++ _Bool do_locking) attribute_hidden; + + /* C library side function to register new fork handlers. */ + extern int __register_atfork (void (*__prepare) (void), diff --git a/SOURCES/glibc-rh1746933-1.patch b/SOURCES/glibc-rh1746933-1.patch new file mode 100644 index 0000000..4697916 --- /dev/null +++ b/SOURCES/glibc-rh1746933-1.patch @@ -0,0 +1,60 @@ +commit 58d2672f64176fcb323859d3bd5240fb1cf8f25c +Author: Wilco Dijkstra +Date: Fri May 10 16:38:21 2019 +0100 + + Fix tcache count maximum (BZ #24531) + + The tcache counts[] array is a char, which has a very small range and thus + may overflow. When setting tcache_count tunable, there is no overflow check. + However the tunable must not be larger than the maximum value of the tcache + counts[] array, otherwise it can overflow when filling the tcache. + + [BZ #24531] + * malloc/malloc.c (MAX_TCACHE_COUNT): New define. + (do_set_tcache_count): Only update if count is small enough. + * manual/tunables.texi (glibc.malloc.tcache_count): Document max value. + + (cherry picked from commit 5ad533e8e65092be962e414e0417112c65d154fb) + +diff --git a/malloc/malloc.c b/malloc/malloc.c +index 723d393f529bdb4c..92239b3324584060 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -2919,6 +2919,8 @@ typedef struct tcache_perthread_struct + tcache_entry *entries[TCACHE_MAX_BINS]; + } tcache_perthread_struct; + ++#define MAX_TCACHE_COUNT 127 /* Maximum value of counts[] entries. */ ++ + static __thread bool tcache_shutting_down = false; + static __thread tcache_perthread_struct *tcache = NULL; + +@@ -5124,8 +5126,11 @@ static inline int + __always_inline + do_set_tcache_count (size_t value) + { +- LIBC_PROBE (memory_tunable_tcache_count, 2, value, mp_.tcache_count); +- mp_.tcache_count = value; ++ if (value <= MAX_TCACHE_COUNT) ++ { ++ LIBC_PROBE (memory_tunable_tcache_count, 2, value, mp_.tcache_count); ++ mp_.tcache_count = value; ++ } + return 1; + } + +diff --git a/manual/tunables.texi b/manual/tunables.texi +index bb4819bdf1de273e..9dccf2ee7f8eec17 100644 +--- a/manual/tunables.texi ++++ b/manual/tunables.texi +@@ -188,8 +188,8 @@ per-thread cache. The default (and maximum) value is 1032 bytes on + + @deftp Tunable glibc.malloc.tcache_count + The maximum number of chunks of each size to cache. The default is 7. +-There is no upper limit, other than available system memory. If set +-to zero, the per-thread cache is effectively disabled. ++The upper limit is 127. If set to zero, the per-thread cache is effectively ++disabled. + + The approximate maximum overhead of the per-thread cache is thus equal + to the number of bins times the chunk count in each bin times the size diff --git a/SOURCES/glibc-rh1746933-2.patch b/SOURCES/glibc-rh1746933-2.patch new file mode 100644 index 0000000..97fc261 --- /dev/null +++ b/SOURCES/glibc-rh1746933-2.patch @@ -0,0 +1,37 @@ +commit 3640758943c856268bc12a3307838c2a65d2f9ea +Author: Joseph Myers +Date: Mon Feb 4 23:46:58 2019 +0000 + + Fix assertion in malloc.c:tcache_get. + + One of the warnings that appears with -Wextra is "ordered comparison + of pointer with integer zero" in malloc.c:tcache_get, for the + assertion: + + assert (tcache->entries[tc_idx] > 0); + + Indeed, a "> 0" comparison does not make sense for + tcache->entries[tc_idx], which is a pointer. My guess is that + tcache->counts[tc_idx] is what's intended here, and this patch changes + the assertion accordingly. + + Tested for x86_64. + + * malloc/malloc.c (tcache_get): Compare tcache->counts[tc_idx] + with 0, not tcache->entries[tc_idx]. + + (cherry picked from commit 77dc0d8643aa99c92bf671352b0a8adde705896f) + +diff --git a/malloc/malloc.c b/malloc/malloc.c +index 92239b3324584060..998879aededf0d7c 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -2948,7 +2948,7 @@ tcache_get (size_t tc_idx) + { + tcache_entry *e = tcache->entries[tc_idx]; + assert (tc_idx < TCACHE_MAX_BINS); +- assert (tcache->entries[tc_idx] > 0); ++ assert (tcache->counts[tc_idx] > 0); + tcache->entries[tc_idx] = e->next; + --(tcache->counts[tc_idx]); + e->key = NULL; diff --git a/SOURCES/glibc-rh1746933-3.patch b/SOURCES/glibc-rh1746933-3.patch new file mode 100644 index 0000000..f4c1c95 --- /dev/null +++ b/SOURCES/glibc-rh1746933-3.patch @@ -0,0 +1,92 @@ +commit f88c59f4657ac2e0bab8f51f60022ecbe7f12e2e +Author: Wilco Dijkstra +Date: Fri May 17 18:16:20 2019 +0100 + + Small tcache improvements + + Change the tcache->counts[] entries to uint16_t - this removes + the limit set by char and allows a larger tcache. Remove a few + redundant asserts. + + bench-malloc-thread with 4 threads is ~15% faster on Cortex-A72. + + Reviewed-by: DJ Delorie + + * malloc/malloc.c (MAX_TCACHE_COUNT): Increase to UINT16_MAX. + (tcache_put): Remove redundant assert. + (tcache_get): Remove redundant asserts. + (__libc_malloc): Check tcache count is not zero. + * manual/tunables.texi (glibc.malloc.tcache_count): Update maximum. + + (cherry picked from commit 1f50f2ad854c84ead522bfc7331b46dbe6057d53) + +diff --git a/malloc/malloc.c b/malloc/malloc.c +index 998879aededf0d7c..e6a483d5cf7c4312 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -321,6 +321,10 @@ __malloc_assert (const char *assertion, const char *file, unsigned int line, + /* This is another arbitrary limit, which tunables can change. Each + tcache bin will hold at most this number of chunks. */ + # define TCACHE_FILL_COUNT 7 ++ ++/* Maximum chunks in tcache bins for tunables. This value must fit the range ++ of tcache->counts[] entries, else they may overflow. */ ++# define MAX_TCACHE_COUNT UINT16_MAX + #endif + + +@@ -2915,12 +2919,10 @@ typedef struct tcache_entry + time), this is for performance reasons. */ + typedef struct tcache_perthread_struct + { +- char counts[TCACHE_MAX_BINS]; ++ uint16_t counts[TCACHE_MAX_BINS]; + tcache_entry *entries[TCACHE_MAX_BINS]; + } tcache_perthread_struct; + +-#define MAX_TCACHE_COUNT 127 /* Maximum value of counts[] entries. */ +- + static __thread bool tcache_shutting_down = false; + static __thread tcache_perthread_struct *tcache = NULL; + +@@ -2930,7 +2932,6 @@ static __always_inline void + tcache_put (mchunkptr chunk, size_t tc_idx) + { + tcache_entry *e = (tcache_entry *) chunk2mem (chunk); +- assert (tc_idx < TCACHE_MAX_BINS); + + /* Mark this chunk as "in the tcache" so the test in _int_free will + detect a double free. */ +@@ -2947,8 +2948,6 @@ static __always_inline void * + tcache_get (size_t tc_idx) + { + tcache_entry *e = tcache->entries[tc_idx]; +- assert (tc_idx < TCACHE_MAX_BINS); +- assert (tcache->counts[tc_idx] > 0); + tcache->entries[tc_idx] = e->next; + --(tcache->counts[tc_idx]); + e->key = NULL; +@@ -3053,9 +3052,8 @@ __libc_malloc (size_t bytes) + + DIAG_PUSH_NEEDS_COMMENT; + if (tc_idx < mp_.tcache_bins +- /*&& tc_idx < TCACHE_MAX_BINS*/ /* to appease gcc */ + && tcache +- && tcache->entries[tc_idx] != NULL) ++ && tcache->counts[tc_idx] > 0) + { + return tcache_get (tc_idx); + } +diff --git a/manual/tunables.texi b/manual/tunables.texi +index 9dccf2ee7f8eec17..f6c49250e3889ddd 100644 +--- a/manual/tunables.texi ++++ b/manual/tunables.texi +@@ -188,7 +188,7 @@ per-thread cache. The default (and maximum) value is 1032 bytes on + + @deftp Tunable glibc.malloc.tcache_count + The maximum number of chunks of each size to cache. The default is 7. +-The upper limit is 127. If set to zero, the per-thread cache is effectively ++The upper limit is 65535. If set to zero, the per-thread cache is effectively + disabled. + + The approximate maximum overhead of the per-thread cache is thus equal diff --git a/SOURCES/glibc-rh1747453.patch b/SOURCES/glibc-rh1747453.patch new file mode 100644 index 0000000..d02b6b2 --- /dev/null +++ b/SOURCES/glibc-rh1747453.patch @@ -0,0 +1,156 @@ +commit 8692ebdb1259be60c545fa509d4852b26703777e +Author: David Newall +Date: Mon Feb 4 13:35:11 2019 +0100 + + elf: Implement --preload option for the dynamic linker + +diff --git a/elf/Makefile b/elf/Makefile +index 9cf5cd8dfd..db6a2a0c29 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -354,7 +354,8 @@ endif + + ifeq (yes,$(build-shared)) + ifeq ($(run-built-tests),yes) +-tests-special += $(objpfx)tst-pathopt.out $(objpfx)tst-rtld-load-self.out ++tests-special += $(objpfx)tst-pathopt.out $(objpfx)tst-rtld-load-self.out \ ++ $(objpfx)tst-rtld-preload.out + endif + tests-special += $(objpfx)check-textrel.out $(objpfx)check-execstack.out \ + $(objpfx)check-localplt.out $(objpfx)check-initfini.out +@@ -883,6 +884,15 @@ $(objpfx)tst-rtld-load-self.out: tst-rtld-load-self.sh $(objpfx)ld.so + $(SHELL) $^ '$(test-wrapper)' '$(test-wrapper-env)' > $@; \ + $(evaluate-test) + ++tst-rtld-preload-OBJS = $(subst $(empty) ,:,$(strip $(preloadtest-preloads:=.so))) ++$(objpfx)tst-rtld-preload.out: tst-rtld-preload.sh $(objpfx)ld.so \ ++ $(objpfx)preloadtest \ ++ $(preloadtest-preloads:%=$(objpfx)%.so) ++ $(SHELL) $< $(objpfx)ld.so $(objpfx)preloadtest \ ++ '$(test-wrapper)' '$(test-wrapper-env)' '$(run_program_env)' \ ++ '$(rpath-link)' '$(tst-rtld-preload-OBJS)' > $@; \ ++ $(evaluate-test) ++ + $(objpfx)initfirst: $(libdl) + $(objpfx)initfirst.out: $(objpfx)firstobj.so + +diff --git a/elf/rtld.c b/elf/rtld.c +index 5d97f41b7b..5a90e78ed6 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -826,15 +826,18 @@ static const char *library_path attribute_relro; + static const char *preloadlist attribute_relro; + /* Nonzero if information about versions has to be printed. */ + static int version_info attribute_relro; ++/* The preload list passed as a command argument. */ ++static const char *preloadarg attribute_relro; + + /* The LD_PRELOAD environment variable gives list of libraries + separated by white space or colons that are loaded before the + executable's dependencies and prepended to the global scope list. + (If the binary is running setuid all elements containing a '/' are + ignored since it is insecure.) Return the number of preloads +- performed. */ ++ performed. Ditto for --preload command argument. */ + unsigned int +-handle_ld_preload (const char *preloadlist, struct link_map *main_map) ++handle_preload_list (const char *preloadlist, struct link_map *main_map, ++ const char *where) + { + unsigned int npreloads = 0; + const char *p = preloadlist; +@@ -858,7 +861,7 @@ handle_ld_preload (const char *preloadlist, struct link_map *main_map) + ++p; + + if (dso_name_valid_for_suid (fname)) +- npreloads += do_preload (fname, main_map, "LD_PRELOAD"); ++ npreloads += do_preload (fname, main_map, where); + } + return npreloads; + } +@@ -974,6 +977,13 @@ dl_main (const ElfW(Phdr) *phdr, + { + process_dl_audit (_dl_argv[2]); + ++ _dl_skip_args += 2; ++ _dl_argc -= 2; ++ _dl_argv += 2; ++ } ++ else if (! strcmp (_dl_argv[1], "--preload") && _dl_argc > 2) ++ { ++ preloadarg = _dl_argv[2]; + _dl_skip_args += 2; + _dl_argc -= 2; + _dl_argv += 2; +@@ -1006,7 +1016,8 @@ of this helper program; chances are you did not intend to run this program.\n\ + variable LD_LIBRARY_PATH\n\ + --inhibit-rpath LIST ignore RUNPATH and RPATH information in object names\n\ + in LIST\n\ +- --audit LIST use objects named in LIST as auditors\n"); ++ --audit LIST use objects named in LIST as auditors\n\ ++ --preload LIST preload objects named in LIST\n"); + + ++_dl_skip_args; + --_dl_argc; +@@ -1620,7 +1631,16 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", + if (__glibc_unlikely (preloadlist != NULL)) + { + HP_TIMING_NOW (start); +- npreloads += handle_ld_preload (preloadlist, main_map); ++ npreloads += handle_preload_list (preloadlist, main_map, "LD_PRELOAD"); ++ HP_TIMING_NOW (stop); ++ HP_TIMING_DIFF (diff, start, stop); ++ HP_TIMING_ACCUM_NT (load_time, diff); ++ } ++ ++ if (__glibc_unlikely (preloadarg != NULL)) ++ { ++ HP_TIMING_NOW (start); ++ npreloads += handle_preload_list (preloadarg, main_map, "--preload"); + HP_TIMING_NOW (stop); + HP_TIMING_DIFF (diff, start, stop); + HP_TIMING_ACCUM_NT (load_time, diff); +diff --git a/elf/tst-rtld-preload.sh b/elf/tst-rtld-preload.sh +new file mode 100755 +index 0000000000..f0c0ca11ba +--- /dev/null ++++ b/elf/tst-rtld-preload.sh +@@ -0,0 +1,38 @@ ++#!/bin/sh ++# Test --preload argument ld.so. ++# Copyright (C) 2019 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 ++# . ++ ++set -e ++ ++rtld=$1 ++test_program=$2 ++test_wrapper=$3 ++test_wrapper_env=$4 ++run_program_env=$5 ++library_path=$6 ++preload=$7 ++ ++echo "# [${test_wrapper}] [$rtld] [--library-path] [$library_path]" \ ++ "[--preload] [$preload] [$test_program]" ++${test_wrapper_env} \ ++${run_program_env} \ ++${test_wrapper} $rtld --library-path "$library_path" \ ++ --preload "$preload" $test_program 2>&1 && rc=0 || rc=$? ++echo "# exit status $rc" ++ ++exit $rc diff --git a/SOURCES/glibc-rh1747502-1.patch b/SOURCES/glibc-rh1747502-1.patch new file mode 100644 index 0000000..b57f046 --- /dev/null +++ b/SOURCES/glibc-rh1747502-1.patch @@ -0,0 +1,168 @@ +commit 561b0bec4448f0302cb4915bf67c919bde4a1c57 +Author: DJ Delorie +Date: Fri Jul 6 01:10:41 2018 -0400 + + Add test-in-container infrastructure. + + * Makefile (testroot.pristine): New rules to initialize the + test-in-container "testroot". + * Makerules (all-testsuite): Add tests-container. + * Rules (tests-expected): Add tests-container. + (binaries-all-tests): Likewise. + (tests-container): New, run these tests in the testroot container. + * support/links-dso-program-c.c: New. + * support/links-dso-program.cc: New. + * support/test-container.c: New. + * support/shell-container.c: New. + * support/echo-container.c: New. + * support/true-container.c: New. + * support/xmkdirp.c: New. + * support/xsymlink.c: New. + * support/support_paths.c: New. + * support/support.h: Add support paths prototypes. + * support/xunistd.h: Add xmkdirp () and xsymlink (). + + * nss/tst-nss-test3.c: Convert to test-in-container. + * nss/tst-nss-test3.root/: New. + +(note: support/ already present, not needed; sample test not included) + +diff --git a/Makefile b/Makefile +index d3f25a5..3df55e6 100644 +--- a/Makefile ++++ b/Makefile +@@ -340,6 +340,62 @@ define summarize-tests + @! egrep -q -v '^(X?PASS|XFAIL|UNSUPPORTED):' $(objpfx)$1 + endef + ++# The intention here is to do ONE install of our build into the ++# testroot.pristine/ directory, then rsync (internal to ++# support/test-container) that to testroot.root/ at the start of each ++# test. That way we can promise each test a "clean" install, without ++# having to do the install for each test. ++# ++# In addition, we have to copy some files (which we build) into this ++# root in addition to what glibc installs. For example, many tests ++# require additional programs including /bin/sh, /bin/true, and ++# /bin/echo, all of which we build below to limit library dependencies ++# to just those things in glibc and language support libraries which ++# we also copy into the into the rootfs. To determine what language ++# support libraries we need we build a "test" program in either C or ++# (if available) C++ just so we can copy in any shared objects ++# (which we do not build) that GCC-compiled programs depend on. ++ ++ ++ifeq (,$(CXX)) ++LINKS_DSO_PROGRAM = links-dso-program-c ++else ++LINKS_DSO_PROGRAM = links-dso-program ++endif ++ ++$(tests-container) $(addsuffix /tests,$(subdirs)) : \ ++ $(objpfx)testroot.pristine/install.stamp ++$(objpfx)testroot.pristine/install.stamp : ++ test -d $(objpfx)testroot.pristine || \ ++ mkdir $(objpfx)testroot.pristine ++ # We need a working /bin/sh for some of the tests. ++ test -d $(objpfx)testroot.pristine/bin || \ ++ mkdir $(objpfx)testroot.pristine/bin ++ cp $(objpfx)support/shell-container $(objpfx)testroot.pristine/bin/sh ++ cp $(objpfx)support/echo-container $(objpfx)testroot.pristine/bin/echo ++ cp $(objpfx)support/true-container $(objpfx)testroot.pristine/bin/true ++ # Copy these DSOs first so we can overwrite them with our own. ++ for dso in `$(test-wrapper-env) LD_TRACE_LOADED_OBJECTS=1 \ ++ $(objpfx)elf/$(rtld-installed-name) \ ++ $(objpfx)testroot.pristine/bin/sh \ ++ | grep / | sed 's/^[^/]*//' | sed 's/ .*//'` ;\ ++ do \ ++ test -d `dirname $(objpfx)testroot.pristine$$dso` || \ ++ mkdir -p `dirname $(objpfx)testroot.pristine$$dso` ;\ ++ $(test-wrapper) cp $$dso $(objpfx)testroot.pristine$$dso ;\ ++ done ++ for dso in `$(test-wrapper-env) LD_TRACE_LOADED_OBJECTS=1 \ ++ $(objpfx)elf/$(rtld-installed-name) \ ++ $(objpfx)support/$(LINKS_DSO_PROGRAM) \ ++ | grep / | sed 's/^[^/]*//' | sed 's/ .*//'` ;\ ++ do \ ++ test -d `dirname $(objpfx)testroot.pristine$$dso` || \ ++ mkdir -p `dirname $(objpfx)testroot.pristine$$dso` ;\ ++ $(test-wrapper) cp $$dso $(objpfx)testroot.pristine$$dso ;\ ++ done ++ $(MAKE) install DESTDIR=$(objpfx)testroot.pristine ++ touch $(objpfx)testroot.pristine/install.stamp ++ + tests-special-notdir = $(patsubst $(objpfx)%, %, $(tests-special)) + tests: $(tests-special) + $(..)scripts/merge-test-results.sh -s $(objpfx) "" \ +diff --git a/Makerules b/Makerules +index a10a0b4..5d6434c 100644 +--- a/Makerules ++++ b/Makerules +@@ -1369,7 +1369,8 @@ xcheck: xtests + # The only difference between MODULE_NAME=testsuite and MODULE_NAME=nonlib is + # that almost all internal declarations from config.h, libc-symbols.h, and + # include/*.h are not available to 'testsuite' code, but are to 'nonlib' code. +-all-testsuite := $(strip $(tests) $(xtests) $(test-srcs) $(test-extras)) ++all-testsuite := $(strip $(tests) $(xtests) $(test-srcs) $(test-extras) \ ++ $(tests-container)) + ifneq (,$(all-testsuite)) + cpp-srcs-left = $(all-testsuite) + lib := testsuite +diff --git a/Rules b/Rules +index 706c8a7..5abb727 100644 +--- a/Rules ++++ b/Rules +@@ -130,12 +130,14 @@ others: $(py-const) + + ifeq ($(run-built-tests),no) + tests: $(addprefix $(objpfx),$(filter-out $(tests-unsupported), \ +- $(tests) $(tests-internal)) \ ++ $(tests) $(tests-internal) \ ++ $(tests-container)) \ + $(test-srcs)) $(tests-special) \ + $(tests-printers-programs) + xtests: tests $(xtests-special) + else + tests: $(tests:%=$(objpfx)%.out) $(tests-internal:%=$(objpfx)%.out) \ ++ $(tests-container:%=$(objpfx)%.out) \ + $(tests-special) $(tests-printers-out) + xtests: tests $(xtests:%=$(objpfx)%.out) $(xtests-special) + endif +@@ -145,7 +147,8 @@ xtests-special-notdir = $(patsubst $(objpfx)%, %, $(xtests-special)) + ifeq ($(run-built-tests),no) + tests-expected = + else +-tests-expected = $(tests) $(tests-internal) $(tests-printers) ++tests-expected = $(tests) $(tests-internal) $(tests-printers) \ ++ $(tests-container) + endif + tests: + $(..)scripts/merge-test-results.sh -s $(objpfx) $(subdir) \ +@@ -158,7 +161,8 @@ xtests: + + ifeq ($(build-programs),yes) + binaries-all-notests = $(others) $(sysdep-others) +-binaries-all-tests = $(tests) $(tests-internal) $(xtests) $(test-srcs) ++binaries-all-tests = $(tests) $(tests-internal) $(xtests) $(test-srcs) \ ++ $(tests-container) + binaries-all = $(binaries-all-notests) $(binaries-all-tests) + binaries-static-notests = $(others-static) + binaries-static-tests = $(tests-static) $(xtests-static) +@@ -248,6 +252,17 @@ $(objpfx)%.out: /dev/null $(objpfx)% # Make it 2nd arg for canned sequence. + $(make-test-out) > $@; \ + $(evaluate-test) + ++ ++# Any tests that require an isolated container (filesystem, network ++# and pid namespaces) in which to run, should be added to ++# tests-container. ++$(tests-container:%=$(objpfx)%.out): $(objpfx)%.out : $(if $(wildcard $(objpfx)%.files),$(objpfx)%.files,/dev/null) $(objpfx)% ++ $(test-wrapper-env) $(run-program-env) $(run-via-rtld-prefix) \ ++ $(common-objpfx)support/test-container env $(run-program-env) $($*-ENV) \ ++ $(host-test-program-cmd) $($*-ARGS) > $@; \ ++ $(evaluate-test) ++ ++ + # tests-unsupported lists tests that we will not try to build at all in + # this configuration. Note this runs every time because it does not + # actually create its target. The dependency on Makefile is meant to diff --git a/SOURCES/glibc-rh1747502-2.patch b/SOURCES/glibc-rh1747502-2.patch new file mode 100644 index 0000000..17a53e1 --- /dev/null +++ b/SOURCES/glibc-rh1747502-2.patch @@ -0,0 +1,48 @@ +commit bd598da9f454bc1091b4ebe0303b07e6f96ca130 +Author: Joseph Myers +Date: Tue Dec 4 16:52:39 2018 +0000 + + Stop test-in-container trying to run other-OS binaries. + + I noticed that, now that build-many-glibcs.py no longer copies glibc + sources, I was getting core dumps in my glibc source directories. The + cause appears to be, from the i686-gnu build: + + for dso in ` env LD_TRACE_LOADED_OBJECTS=1 \ + /scratch/jmyers/glibc-bot/build/glibcs/i686-gnu/glibc/elf/ld.so.1 \ + /scratch/jmyers/glibc-bot/build/glibcs/i686-gnu/glibc/testroot.pristine/bin/sh \ + [...] + Segmentation fault (core dumped) + + In this case, the x86 architecture means the binary executes, but + dumps core rather than actually working. + + Anything involving running the newly built glibc should only be done + ifeq ($(run-built-tests),yes). This patch conditions the relevant + part of the testroot setup accordingly. + + Tested for x86_64, and with build-many-glibcs.py for i686-gnu. + + * Makefile ($(objpfx)testroot.pristine/install.stamp): Do not run + dynamic linker unless [$(run-built-tests) = yes]. + +diff --git a/Makefile b/Makefile +index b4703e4..fd73d9b 100644 +--- a/Makefile ++++ b/Makefile +@@ -374,6 +374,7 @@ $(objpfx)testroot.pristine/install.stamp : + cp $(objpfx)support/shell-container $(objpfx)testroot.pristine/bin/sh + cp $(objpfx)support/echo-container $(objpfx)testroot.pristine/bin/echo + cp $(objpfx)support/true-container $(objpfx)testroot.pristine/bin/true ++ifeq ($(run-built-tests),yes) + # Copy these DSOs first so we can overwrite them with our own. + for dso in `$(test-wrapper-env) LD_TRACE_LOADED_OBJECTS=1 \ + $(objpfx)elf/$(rtld-installed-name) \ +@@ -393,6 +394,7 @@ $(objpfx)testroot.pristine/install.stamp : + mkdir -p `dirname $(objpfx)testroot.pristine$$dso` ;\ + $(test-wrapper) cp $$dso $(objpfx)testroot.pristine$$dso ;\ + done ++endif + $(MAKE) install DESTDIR=$(objpfx)testroot.pristine + touch $(objpfx)testroot.pristine/install.stamp + diff --git a/SOURCES/glibc-rh1747502-3.patch b/SOURCES/glibc-rh1747502-3.patch new file mode 100644 index 0000000..f0c5027 --- /dev/null +++ b/SOURCES/glibc-rh1747502-3.patch @@ -0,0 +1,40 @@ +commit 95da14dac04b494149290d85bc5306226e30839e +Author: Tulio Magno Quites Machado Filho +Date: Mon Jul 22 16:30:45 2019 -0300 + + test-container: Avoid copying unintended system libraries + + Some DSOs are distributed in hardware capability directories, e.g. + /usr/lib64/power7/libc.so.6 + Whenever the processor is able to use one of these hardware-enabled + DSOs, testroot.pristine ends up with copies of glibc-provided libraries + from the system because it can't overwrite or remove them. + + This patch avoids the unintended copies by executing ld.so with the same + arguments passed to each glibc test. + + * Makefile (testroot.pristine/install.stamp): Execute ld.so with + the same arguments used in all tests. + +diff --git a/Makefile b/Makefile +index dc5de7a..a4ed747 100644 +--- a/Makefile ++++ b/Makefile +@@ -383,7 +383,7 @@ $(objpfx)testroot.pristine/install.stamp : + ifeq ($(run-built-tests),yes) + # Copy these DSOs first so we can overwrite them with our own. + for dso in `$(test-wrapper-env) LD_TRACE_LOADED_OBJECTS=1 \ +- $(objpfx)elf/$(rtld-installed-name) \ ++ $(rtld-prefix) \ + $(objpfx)testroot.pristine/bin/sh \ + | grep / | sed 's/^[^/]*//' | sed 's/ .*//'` ;\ + do \ +@@ -392,7 +392,7 @@ ifeq ($(run-built-tests),yes) + $(test-wrapper) cp $$dso $(objpfx)testroot.pristine$$dso ;\ + done + for dso in `$(test-wrapper-env) LD_TRACE_LOADED_OBJECTS=1 \ +- $(objpfx)elf/$(rtld-installed-name) \ ++ $(rtld-prefix) \ + $(objpfx)support/$(LINKS_DSO_PROGRAM) \ + | grep / | sed 's/^[^/]*//' | sed 's/ .*//'` ;\ + do \ diff --git a/SOURCES/glibc-rh1747502-4.patch b/SOURCES/glibc-rh1747502-4.patch new file mode 100644 index 0000000..2e25309 --- /dev/null +++ b/SOURCES/glibc-rh1747502-4.patch @@ -0,0 +1,31 @@ +commit 35e038c1d2ccb3a75395662f9c4f28d85a61444f +Author: Tulio Magno Quites Machado Filho +Date: Mon Jul 22 17:34:13 2019 -0300 + + test-container: Install with $(all-subdirs) [BZ #24794] + + Whenever a sub-make is created, it inherits the variable subdirs from its + parent. This is also true when make check is called with a restricted + list of subdirs. In this scenario, make install is executed "partially" + and testroot.pristine ends up with an incomplete installation. + + [BZ #24794] + * Makefile (testroot.pristine/install.stamp): Pass + subdirs='$(all-subdirs)' to make install. + + Reviewed-by: DJ Delorie + +diff --git a/Makefile b/Makefile +index a4ed747..9fbf705 100644 +--- a/Makefile ++++ b/Makefile +@@ -401,7 +401,8 @@ ifeq ($(run-built-tests),yes) + $(test-wrapper) cp $$dso $(objpfx)testroot.pristine$$dso ;\ + done + endif +- $(MAKE) install DESTDIR=$(objpfx)testroot.pristine ++ $(MAKE) install DESTDIR=$(objpfx)testroot.pristine \ ++ subdirs='$(all-subdirs)' + touch $(objpfx)testroot.pristine/install.stamp + + tests-special-notdir = $(patsubst $(objpfx)%, %, $(tests-special)) diff --git a/SOURCES/glibc-rh1747502-5.patch b/SOURCES/glibc-rh1747502-5.patch new file mode 100644 index 0000000..30dd75e --- /dev/null +++ b/SOURCES/glibc-rh1747502-5.patch @@ -0,0 +1,56 @@ +commit 7db1fe38de21831d53ceab9ae83493d8d1aec601 +Author: Joseph Myers +Date: Tue Oct 22 20:24:10 2019 +0000 + + Fix testroot.pristine creation copying dynamic linker. + + This patch addresses an issue reported in + where the + creation of testroot.pristine, on encountering + LD_TRACE_LOADED_OBJECTS=1 of the form + + libc.so.6 => /scratch/jmyers/glibc/mbs/obj/glibc-8-0-mips64-linux-gnu-x86_64-linux-gnu/default/libc.so.6 (0x772dd000) + /lib32/ld.so.1 => /scratch/jmyers/glibc/mbs/obj/glibc-8-0-mips64-linux-gnu-x86_64-linux-gnu/default/elf/ld.so.1 (0x7747b000) + + tries to copy /lib32/ld.so.1 (which does not exist) into the testroot + instead of copying the path on the RHS of "=>", which does exist, + because the Makefile logic assumes that the path on such a line with + '/' should be copied, when if there are such paths on both the LHS and + the RHS of "=>", only the one on the RHS necessarily exists and so + only that should be copied. The patch follows the approach suggested + by DJ in , + with the suggestion from Andreas in + of a + single sed command in place of pipeline of grep and three sed + commands. + + Tested for x86_64, with and without --enable-hardcoded-path-in-tests; + a previous version with multiple sed commands, implementing the same + logic, also tested for MIPS, with and without + --enable-hardcoded-path-in-tests, to confirm it fixes the original + problem. + + Co-authored-by: DJ Delorie + +diff --git a/Makefile b/Makefile +index d7e4be9..0711b97 100644 +--- a/Makefile ++++ b/Makefile +@@ -564,7 +564,7 @@ ifeq ($(run-built-tests),yes) + for dso in `$(test-wrapper-env) LD_TRACE_LOADED_OBJECTS=1 \ + $(rtld-prefix) \ + $(objpfx)testroot.pristine/bin/sh \ +- | grep / | sed 's/^[^/]*//' | sed 's/ .*//'` ;\ ++ | sed -n '/\//{s@.*=> /@/@;s/^[^/]*//;s/ .*//p;}'` ;\ + do \ + test -d `dirname $(objpfx)testroot.pristine$$dso` || \ + mkdir -p `dirname $(objpfx)testroot.pristine$$dso` ;\ +@@ -573,7 +573,7 @@ ifeq ($(run-built-tests),yes) + for dso in `$(test-wrapper-env) LD_TRACE_LOADED_OBJECTS=1 \ + $(rtld-prefix) \ + $(objpfx)support/$(LINKS_DSO_PROGRAM) \ +- | grep / | sed 's/^[^/]*//' | sed 's/ .*//'` ;\ ++ | sed -n '/\//{s@.*=> /@/@;s/^[^/]*//;s/ .*//p;}'` ;\ + do \ + test -d `dirname $(objpfx)testroot.pristine$$dso` || \ + mkdir -p `dirname $(objpfx)testroot.pristine$$dso` ;\ diff --git a/SOURCES/glibc-rh1747502-6.patch b/SOURCES/glibc-rh1747502-6.patch new file mode 100644 index 0000000..c84940c --- /dev/null +++ b/SOURCES/glibc-rh1747502-6.patch @@ -0,0 +1,56 @@ +commit c7ac9caaae6f8d02d4e0c7618d4991324a084c66 +Author: Adhemerval Zanella +Date: Mon May 13 13:57:37 2019 -0300 + + support: Export bindir path on support_path + + Checked on x86_64-linux-gnu. + + * support/Makefile (CFLAGS-support_paths.c): Add -DBINDIR_PATH. + * support/support.h (support_bindir_prefix): New variable. + * support/support_paths.c [BINDIR_PATH] (support_bindir_prefix): + + Reviewed-by: DJ Delorie + +diff --git a/support/Makefile b/support/Makefile +index 64044f6..fe416cd 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -179,7 +179,8 @@ CFLAGS-support_paths.c = \ + -DOBJDIR_PATH=\"`cd $(objpfx)/..; pwd`\" \ + -DOBJDIR_ELF_LDSO_PATH=\"`cd $(objpfx)/..; pwd`/elf/$(rtld-installed-name)\" \ + -DINSTDIR_PATH=\"$(prefix)\" \ +- -DLIBDIR_PATH=\"$(libdir)\" ++ -DLIBDIR_PATH=\"$(libdir)\" \ ++ -DBINDIR_PATH=\"$(bindir)\" + + ifeq (,$(CXX)) + LINKS_DSO_PROGRAM = links-dso-program-c +diff --git a/support/support.h b/support/support.h +index 97fef2c..b162491 100644 +--- a/support/support.h ++++ b/support/support.h +@@ -105,6 +105,8 @@ extern const char support_objdir_elf_ldso[]; + extern const char support_install_prefix[]; + /* Corresponds to the install's lib/ or lib64/ directory. */ + extern const char support_libdir_prefix[]; ++/* Corresponds to the install's bin/ directory. */ ++extern const char support_bindir_prefix[]; + + extern ssize_t support_copy_file_range (int, off64_t *, int, off64_t *, + size_t, unsigned int); +diff --git a/support/support_paths.c b/support/support_paths.c +index 937e6e1..75634aa 100644 +--- a/support/support_paths.c ++++ b/support/support_paths.c +@@ -57,3 +57,10 @@ const char support_libdir_prefix[] = LIBDIR_PATH; + #else + # error please -DLIBDIR_PATH=something in the Makefile + #endif ++ ++#ifdef BINDIR_PATH ++/* Corresponds to the install's bin/ directory. */ ++const char support_bindir_prefix[] = BINDIR_PATH; ++#else ++# error please -DBINDIR_PATH=something in the Makefile ++#endif diff --git a/SOURCES/glibc-rh1747502-7.patch b/SOURCES/glibc-rh1747502-7.patch new file mode 100644 index 0000000..fa6a63d --- /dev/null +++ b/SOURCES/glibc-rh1747502-7.patch @@ -0,0 +1,46 @@ +From 354e4c1adddb1da19c1043e3e5db61ee2148d912 Mon Sep 17 00:00:00 2001 +From: Tulio Magno Quites Machado Filho +Date: Wed, 24 Jul 2019 19:49:00 -0300 +Subject: test-container: Install with $(sorted-subdirs) [BZ #24794] + +Commit 35e038c1d2ccb3a75395662f9c4f28d85a61444f started to use an +incomplete list of subdirs based on $(all-subdirs) causing +testroot.pristine to miss files from nss. + +Tested if the list of files in testroot.pristine remains the same. + + [BZ #24794] + * Makeconfig (all-subdirs): Improved source comments. + * Makefile (testroot.pristine/install.stamp): Pass + subdirs='$(sorted-subdirs)' to make install. + +diff --git a/Makeconfig b/Makeconfig +index 0e386fbc19..fd36c58c04 100644 +--- a/Makeconfig ++++ b/Makeconfig +@@ -1267,9 +1267,9 @@ else + libsupport = $(common-objpfx)support/libsupport.a + endif + +-# These are the subdirectories containing the library source. The order +-# is more or less arbitrary. The sorting step will take care of the +-# dependencies. ++# This is a partial list of subdirectories containing the library source. ++# The order is more or less arbitrary. The sorting step will take care of the ++# dependencies and generate sorted-subdirs dynamically. + all-subdirs = csu assert ctype locale intl catgets math setjmp signal \ + stdlib stdio-common libio malloc string wcsmbs time dirent \ + grp pwd posix io termios resource misc socket sysvipc gmon \ +diff --git a/Makefile b/Makefile +index 9fbf705200..ac1125853b 100644 +--- a/Makefile ++++ b/Makefile +@@ -402,7 +402,7 @@ ifeq ($(run-built-tests),yes) + done + endif + $(MAKE) install DESTDIR=$(objpfx)testroot.pristine \ +- subdirs='$(all-subdirs)' ++ subdirs='$(sorted-subdirs)' + touch $(objpfx)testroot.pristine/install.stamp + + tests-special-notdir = $(patsubst $(objpfx)%, %, $(tests-special)) diff --git a/SOURCES/glibc-rh1747502-8.patch b/SOURCES/glibc-rh1747502-8.patch new file mode 100644 index 0000000..16f6bf7 --- /dev/null +++ b/SOURCES/glibc-rh1747502-8.patch @@ -0,0 +1,50 @@ +commit d50f09181eca10a91fd9035bb90711b265770dc9 +Author: Alexandra Hájková +Date: Mon May 13 19:31:53 2019 +0200 + + support: Add support_install_rootsbindir + + Reviewed by: Adhemerval Zanella + +diff --git a/support/Makefile b/support/Makefile +index fe416cd..18d39f5 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -180,7 +180,8 @@ CFLAGS-support_paths.c = \ + -DOBJDIR_ELF_LDSO_PATH=\"`cd $(objpfx)/..; pwd`/elf/$(rtld-installed-name)\" \ + -DINSTDIR_PATH=\"$(prefix)\" \ + -DLIBDIR_PATH=\"$(libdir)\" \ +- -DBINDIR_PATH=\"$(bindir)\" ++ -DBINDIR_PATH=\"$(bindir)\" \ ++ -DROOTSBINDIR_PATH=\"$(rootsbindir)\" + + ifeq (,$(CXX)) + LINKS_DSO_PROGRAM = links-dso-program-c +diff --git a/support/support.h b/support/support.h +index b162491..13076b7 100644 +--- a/support/support.h ++++ b/support/support.h +@@ -107,6 +107,8 @@ extern const char support_install_prefix[]; + extern const char support_libdir_prefix[]; + /* Corresponds to the install's bin/ directory. */ + extern const char support_bindir_prefix[]; ++/* Corresponds to the install's sbin/ directory. */ ++extern const char support_install_rootsbindir[]; + + extern ssize_t support_copy_file_range (int, off64_t *, int, off64_t *, + size_t, unsigned int); +diff --git a/support/support_paths.c b/support/support_paths.c +index 75634aa..1fe3283 100644 +--- a/support/support_paths.c ++++ b/support/support_paths.c +@@ -64,3 +64,10 @@ const char support_bindir_prefix[] = BINDIR_PATH; + #else + # error please -DBINDIR_PATH=something in the Makefile + #endif ++ ++#ifdef ROOTSBINDIR_PATH ++/* Corresponds to the install's sbin/ directory. */ ++const char support_install_rootsbindir[] = ROOTSBINDIR_PATH; ++#else ++# error please -DROOTSBINDIR_PATH=something in the Makefile ++#endif diff --git a/SOURCES/glibc-rh1747502-9.patch b/SOURCES/glibc-rh1747502-9.patch new file mode 100644 index 0000000..8bf528d --- /dev/null +++ b/SOURCES/glibc-rh1747502-9.patch @@ -0,0 +1,86 @@ +From 304c61a24f909168c16793ccf7c686237e53d003 Mon Sep 17 00:00:00 2001 +From: DJ Delorie +Date: Wed, 5 Dec 2018 12:39:47 -0500 +Subject: test-container: move postclean outside of namespace changes + +During postclean.req testing it was found that the fork in the +parent process (after the unshare syscall) would fail with ENOMEM +(see recursive_remove() in test-container.c). While failing with +ENOMEM is certainly unexpected, it is simply easier to refactor +the design and have the parent remain outside of the namespace. +This change moves the postclean.req processing to a distinct +process (the parent) that then forks the test process (which will +have to fork once more to complete uid/gid transitions). When the +test process exists the cleanup process will ensure all files are +deleted when a post clean is requested. + +Signed-off-by: DJ Delorie +Reviewed-by: Carlos O'Donell + +[BZ #23948] +* support/test-container.c: Move postclean step to before we +change namespaces. + +diff --git a/support/test-container.c b/support/test-container.c +index df450adfdb..1d1aebeaf3 100644 +--- a/support/test-container.c ++++ b/support/test-container.c +@@ -921,6 +921,43 @@ main (int argc, char **argv) + } + } + ++ if (do_postclean) ++ { ++ pid_t pc_pid = fork (); ++ ++ if (pc_pid < 0) ++ { ++ FAIL_EXIT1 ("Can't fork for post-clean"); ++ } ++ else if (pc_pid > 0) ++ { ++ /* Parent. */ ++ int status; ++ waitpid (pc_pid, &status, 0); ++ ++ /* Child has exited, we can post-clean the test root. */ ++ printf("running post-clean rsync\n"); ++ rsync (pristine_root_path, new_root_path, 1); ++ ++ if (WIFEXITED (status)) ++ exit (WEXITSTATUS (status)); ++ ++ if (WIFSIGNALED (status)) ++ { ++ printf ("%%SIGNALLED%%\n"); ++ exit (77); ++ } ++ ++ printf ("%%EXITERROR%%\n"); ++ exit (78); ++ } ++ ++ /* Child continues. */ ++ } ++ ++ /* This is the last point in the program where we're still in the ++ "normal" namespace. */ ++ + #ifdef CLONE_NEWNS + /* The unshare here gives us our own spaces and capabilities. */ + if (unshare (CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWNS) < 0) +@@ -974,14 +1011,6 @@ main (int argc, char **argv) + int status; + waitpid (child, &status, 0); + +- /* There's a bit of magic here, since the buildroot is mounted +- in our space, the paths are still valid, and since the mounts +- aren't recursive, it sees *only* the built root, not anything +- we would normally se if we rsync'd to "/" like mounted /dev +- files. */ +- if (do_postclean) +- rsync (pristine_root_path, new_root_path, 1); +- + if (WIFEXITED (status)) + exit (WEXITSTATUS (status)); + diff --git a/SOURCES/glibc-rh1747502.patch b/SOURCES/glibc-rh1747502.patch new file mode 100644 index 0000000..e28de98 --- /dev/null +++ b/SOURCES/glibc-rh1747502.patch @@ -0,0 +1,268 @@ +commit 99135114ba23c3110b7e4e650fabdc5e639746b7 +Author: DJ Delorie +Date: Fri Jun 28 18:30:00 2019 -0500 + + nss_db: fix endent wrt NULL mappings [BZ #24695] [BZ #24696] + + nss_db allows for getpwent et al to be called without a set*ent, + but it only works once. After the last get*ent a set*ent is + required to restart, because the end*ent did not properly reset + the module. Resetting it to NULL allows for a proper restart. + + If the database doesn't exist, however, end*ent erroniously called + munmap which set errno. + + The test case runs "makedb" inside the testroot, so needs selinux + DSOs installed. + +diff -rupN a/nss/Makefile b/nss/Makefile +--- a/nss/Makefile 2019-11-04 15:14:16.721221038 -0500 ++++ b/nss/Makefile 2019-11-04 15:15:46.447544678 -0500 +@@ -60,6 +60,10 @@ tests = test-netdb test-digits-dots ts + tst-nss-test5 + xtests = bug-erange + ++tests-container = \ ++ tst-nss-db-endpwent \ ++ tst-nss-db-endgrent ++ + # Tests which need libdl + ifeq (yes,$(build-shared)) + tests += tst-nss-files-hosts-erange +diff -rupN a/nss/nss_db/db-open.c b/nss/nss_db/db-open.c +--- a/nss/nss_db/db-open.c 2018-08-01 01:10:47.000000000 -0400 ++++ b/nss/nss_db/db-open.c 2019-11-04 15:15:10.520213846 -0500 +@@ -63,5 +63,9 @@ internal_setent (const char *file, struc + void + internal_endent (struct nss_db_map *mapping) + { +- munmap (mapping->header, mapping->len); ++ if (mapping->header != NULL) ++ { ++ munmap (mapping->header, mapping->len); ++ mapping->header = NULL; ++ } + } +diff -rupN a/nss/tst-nss-db-endgrent.c b/nss/tst-nss-db-endgrent.c +--- a/nss/tst-nss-db-endgrent.c 1969-12-31 19:00:00.000000000 -0500 ++++ b/nss/tst-nss-db-endgrent.c 2019-11-04 15:15:10.526214069 -0500 +@@ -0,0 +1,54 @@ ++/* Test for endgrent changing errno for BZ #24696 ++ Copyright (C) 2019 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++/* The following test verifies that if the db NSS Service is initialized ++ with no database (getgrent), that a subsequent closure (endgrent) does ++ not set errno. In the case of the db service it is not an error to close ++ the service and so it should not set errno. */ ++ ++static int ++do_test (void) ++{ ++ /* Just make sure it's not there, although usually it won't be. */ ++ unlink ("/var/db/group.db"); ++ ++ /* This, in conjunction with the testroot's nsswitch.conf, causes ++ the nss_db module to be "connected" and initialized - but the ++ testroot has no group.db, so no mapping will be created. */ ++ getgrent (); ++ ++ errno = 0; ++ ++ /* Before the fix, this would call munmap (NULL) and set errno. */ ++ endgrent (); ++ ++ if (errno != 0) ++ FAIL_EXIT1 ("endgrent set errno to %d\n", errno); ++ ++ return 0; ++} ++#include +diff -rupN a/nss/tst-nss-db-endgrent.root/etc/nsswitch.conf b/nss/tst-nss-db-endgrent.root/etc/nsswitch.conf +--- a/nss/tst-nss-db-endgrent.root/etc/nsswitch.conf 1969-12-31 19:00:00.000000000 -0500 ++++ b/nss/tst-nss-db-endgrent.root/etc/nsswitch.conf 2019-11-04 15:15:10.539214550 -0500 +@@ -0,0 +1 @@ ++group : db files +diff -rupN a/nss/tst-nss-db-endpwent.c b/nss/tst-nss-db-endpwent.c +--- a/nss/tst-nss-db-endpwent.c 1969-12-31 19:00:00.000000000 -0500 ++++ b/nss/tst-nss-db-endpwent.c 2019-11-04 15:15:10.545214772 -0500 +@@ -0,0 +1,66 @@ ++/* Test for endpwent->getpwent crash for BZ #24695 ++ Copyright (C) 2019 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++/* It is entirely allowed to start with a getpwent call without ++ resetting the state of the service via a call to setpwent. ++ You can also call getpwent more times than you have entries in ++ the service, and it should not fail. This test iteratates the ++ database once, gets to the end, and then attempts a second ++ iteration to look for crashes. */ ++ ++static void ++try_it (void) ++{ ++ struct passwd *pw; ++ ++ /* setpwent is intentionally omitted here. The first call to ++ getpwent detects that it's first and initializes. The second ++ time try_it is called, this "first call" was not detected before ++ the fix, and getpwent would crash. */ ++ ++ while ((pw = getpwent ()) != NULL) ++ ; ++ ++ /* We only care if this segfaults or not. */ ++ endpwent (); ++} ++ ++static int ++do_test (void) ++{ ++ char *cmd; ++ ++ cmd = xasprintf ("%s/makedb -o /var/db/passwd.db /var/db/passwd.in", ++ support_bindir_prefix); ++ system (cmd); ++ free (cmd); ++ ++ try_it (); ++ try_it (); ++ ++ return 0; ++} ++#include +diff -rupN a/nss/tst-nss-db-endpwent.root/etc/nsswitch.conf b/nss/tst-nss-db-endpwent.root/etc/nsswitch.conf +--- a/nss/tst-nss-db-endpwent.root/etc/nsswitch.conf 1969-12-31 19:00:00.000000000 -0500 ++++ b/nss/tst-nss-db-endpwent.root/etc/nsswitch.conf 2019-11-04 15:15:10.556215180 -0500 +@@ -0,0 +1 @@ ++passwd: db +diff -rupN a/nss/tst-nss-db-endpwent.root/var/db/passwd.in b/nss/tst-nss-db-endpwent.root/var/db/passwd.in +--- a/nss/tst-nss-db-endpwent.root/var/db/passwd.in 1969-12-31 19:00:00.000000000 -0500 ++++ b/nss/tst-nss-db-endpwent.root/var/db/passwd.in 2019-11-04 15:15:10.567215588 -0500 +@@ -0,0 +1,4 @@ ++.root root:x:0:0:root:/root:/bin/bash ++=0 root:x:0:0:root:/root:/bin/bash ++.bin bin:x:1:1:bin:/bin:/sbin/nologin ++=1 bin:x:1:1:bin:/bin:/sbin/nologin +diff -rupN a/support/Makefile b/support/Makefile +--- a/support/Makefile 2019-11-04 15:14:20.416357911 -0500 ++++ b/support/Makefile 2019-11-04 15:15:10.574215847 -0500 +@@ -180,6 +180,11 @@ LINKS_DSO_PROGRAM = links-dso-program + LDLIBS-links-dso-program = -lstdc++ -lgcc -lgcc_s $(libunwind) + endif + ++ifeq (yes,$(have-selinux)) ++LDLIBS-$(LINKS_DSO_PROGRAM) += -lselinux ++endif ++ ++ + LDLIBS-test-container = $(libsupport) + + others += test-container +diff -rupN a/support/links-dso-program-c.c b/support/links-dso-program-c.c +--- a/support/links-dso-program-c.c 2019-11-04 15:14:17.073234077 -0500 ++++ b/support/links-dso-program-c.c 2019-11-04 15:15:10.580216069 -0500 +@@ -1,9 +1,26 @@ + #include + ++/* makedb needs selinux dso's. */ ++#ifdef HAVE_SELINUX ++# include ++#endif ++ ++/* The purpose of this file is to indicate to the build system which ++ shared objects need to be copied into the testroot, such as gcc or ++ selinux support libraries. This program is never executed, only ++ scanned for dependencies on shared objects, so the code below may ++ seem weird - it's written to survive gcc optimization and force ++ such dependencies. ++*/ ++ + int + main (int argc, char **argv) + { + /* Complexity to keep gcc from optimizing this away. */ + printf ("This is a test %s.\n", argc > 1 ? argv[1] : "null"); ++#ifdef HAVE_SELINUX ++ /* This exists to force libselinux.so to be required. */ ++ printf ("selinux %d\n", is_selinux_enabled ()); ++#endif + return 0; + } +diff -rupN a/support/links-dso-program.cc b/support/links-dso-program.cc +--- a/support/links-dso-program.cc 2019-11-04 15:14:17.079234300 -0500 ++++ b/support/links-dso-program.cc 2019-11-04 15:15:10.587216328 -0500 +@@ -1,11 +1,28 @@ + #include + ++/* makedb needs selinux dso's. */ ++#ifdef HAVE_SELINUX ++# include ++#endif ++ + using namespace std; + ++/* The purpose of this file is to indicate to the build system which ++ shared objects need to be copied into the testroot, such as gcc or ++ selinux support libraries. This program is never executed, only ++ scanned for dependencies on shared objects, so the code below may ++ seem weird - it's written to survive gcc optimization and force ++ such dependencies. ++*/ ++ + int + main (int argc, char **argv) + { + /* Complexity to keep gcc from optimizing this away. */ + cout << (argc > 1 ? argv[1] : "null"); ++#ifdef HAVE_SELINUX ++ /* This exists to force libselinux.so to be required. */ ++ cout << "selinux " << is_selinux_enabled (); ++#endif + return 0; + } diff --git a/SOURCES/glibc-rh1747505-1.patch b/SOURCES/glibc-rh1747505-1.patch new file mode 100644 index 0000000..7569dff --- /dev/null +++ b/SOURCES/glibc-rh1747505-1.patch @@ -0,0 +1,196 @@ +commit 4b7c74179c8928d971d370e1137d202f891a4cf5 +Author: Carlos O'Donell +Date: Wed Mar 20 12:40:18 2019 -0400 + + nss: Make nsswitch.conf more distribution friendly. + + The current default nsswitch.conf file provided by glibc is not very + distribution friendly. The file contains some minimal directives that no + real distribution uses. This update aims to provide a rich set of + comments which are useful for all distributions, and a broader set of + service defines which should work for all distributions. + + Tested defaults on x86_64 and they work. The nsswitch.conf file more + closely matches what we have in Fedora now, and I'll adjust Fedora to + use this version with minor changes to enable Fedora-specific service + providers. + + v2 + - Add missing databases to manual. + - Add link to manual from default nsswitch.conf. + - Sort nsswitch.conf according to most used database first. + + v3 + - Only mention implemented services in 'NSS Basics.' + - Mention 'automount' in 'Services in the NSS configuration.' + - Sort services in alphabetical order. + + v4 + - Project name is 'Samba'. + + v5 + - Fix typo in manual/nss.texi. + + v6 + - Fix another typo in manual/nss.texi. Ran spell checker this time. + +diff --git a/manual/nss.texi b/manual/nss.texi +index 164ae33246..821469a78a 100644 +--- a/manual/nss.texi ++++ b/manual/nss.texi +@@ -56,13 +56,17 @@ functions to access the databases. + @noindent + The databases available in the NSS are + ++@cindex aliases + @cindex ethers + @cindex group ++@cindex gshadow + @cindex hosts ++@cindex initgroups + @cindex netgroup + @cindex networks +-@cindex protocols + @cindex passwd ++@cindex protocols ++@cindex publickey + @cindex rpc + @cindex services + @cindex shadow +@@ -75,16 +79,22 @@ Ethernet numbers, + @comment @pxref{Ethernet Numbers}. + @item group + Groups of users, @pxref{Group Database}. ++@item gshadow ++Group passphrase hashes and related information. + @item hosts + Host names and numbers, @pxref{Host Names}. ++@item initgroups ++Supplementary group access list. + @item netgroup + Network wide list of host and users, @pxref{Netgroup Database}. + @item networks + Network names and numbers, @pxref{Networks Database}. +-@item protocols +-Network protocols, @pxref{Protocols Database}. + @item passwd + User identities, @pxref{User Database}. ++@item protocols ++Network protocols, @pxref{Protocols Database}. ++@item publickey ++Public keys for Secure RPC. + @item rpc + Remote procedure call names and numbers. + @comment @pxref{RPC Database}. +@@ -96,8 +106,8 @@ User passphrase hashes and related information. + @end table + + @noindent +-There will be some more added later (@code{automount}, @code{bootparams}, +-@code{netmasks}, and @code{publickey}). ++@c We currently don't implement automount, netmasks, or bootparams. ++More databases may be added later. + + @node NSS Configuration File, NSS Module Internals, NSS Basics, Name Service Switch + @section The NSS Configuration File +@@ -159,6 +169,10 @@ these files since they should be placed in a directory where they are + found automatically. Only the names of all available services are + important. + ++Lastly, some system software may make use of the NSS configuration file ++to store their own configuration for similar purposes. Examples of this ++include the @code{automount} service which is used by @code{autofs}. ++ + @node Actions in the NSS configuration, Notes on NSS Configuration File, Services in the NSS configuration, NSS Configuration File + @subsection Actions in the NSS configuration + +diff --git a/nss/nsswitch.conf b/nss/nsswitch.conf +index 39ca88bf51..f553588114 100644 +--- a/nss/nsswitch.conf ++++ b/nss/nsswitch.conf +@@ -1,20 +1,69 @@ ++# + # /etc/nsswitch.conf + # +-# Example configuration of GNU Name Service Switch functionality. ++# An example Name Service Switch config file. This file should be ++# sorted with the most-used services at the beginning. + # ++# Valid databases are: aliases, ethers, group, gshadow, hosts, ++# initgroups, netgroup, networks, passwd, protocols, publickey, ++# rpc, services, and shadow. ++# ++# Valid service provider entries include (in alphabetical order): ++# ++# compat Use /etc files plus *_compat pseudo-db ++# db Use the pre-processed /var/db files ++# dns Use DNS (Domain Name Service) ++# files Use the local files in /etc ++# hesiod Use Hesiod (DNS) for user lookups ++# nis Use NIS (NIS version 2), also called YP ++# nisplus Use NIS+ (NIS version 3) ++# ++# See `info libc 'NSS Basics'` for more information. ++# ++# Commonly used alternative service providers (may need installation): ++# ++# ldap Use LDAP directory server ++# myhostname Use systemd host names ++# mymachines Use systemd machine names ++# mdns*, mdns*_minimal Use Avahi mDNS/DNS-SD ++# resolve Use systemd resolved resolver ++# sss Use System Security Services Daemon (sssd) ++# systemd Use systemd for dynamic user option ++# winbind Use Samba winbind support ++# wins Use Samba wins support ++# wrapper Use wrapper module for testing ++# ++# Notes: ++# ++# 'sssd' performs its own 'files'-based caching, so it should generally ++# come before 'files'. ++# ++# WARNING: Running nscd with a secondary caching service like sssd may ++# lead to unexpected behaviour, especially with how long ++# entries are cached. ++# ++# Installation instructions: ++# ++# To use 'db', install the appropriate package(s) (provide 'makedb' and ++# libnss_db.so.*), and place the 'db' in front of 'files' for entries ++# you want to be looked up first in the databases, like this: ++# ++# passwd: db files ++# shadow: db files ++# group: db files + +-passwd: db files +-group: db files +-initgroups: db [SUCCESS=continue] files +-shadow: db files +-gshadow: files +- +-hosts: files dns +-networks: files dns +- +-protocols: db files +-services: db files +-ethers: db files +-rpc: db files +- +-netgroup: db files ++# In alphabetical order. Re-order as required to optimize peformance. ++aliases: files ++ethers: files ++group: files ++gshadow: files ++hosts: files dns ++initgroups: files ++netgroup: files ++networks: files dns ++passwd: files ++protocols: files ++publickey: files ++rpc: files ++shadow: files ++services: files diff --git a/SOURCES/glibc-rh1747505-2.patch b/SOURCES/glibc-rh1747505-2.patch new file mode 100644 index 0000000..085c2c3 --- /dev/null +++ b/SOURCES/glibc-rh1747505-2.patch @@ -0,0 +1,38 @@ +commit d34d4c80226b3f5a1b51a8e5b005a52fba07d7ba +Author: Carlos O'Donell +Date: Wed Mar 20 22:11:32 2019 -0400 + + nscd: Improve nscd.conf comments. + + This change adds a warning to nscd.conf about running multiple caching + services together and that it may lead to unexpected behaviours. Also we + add a note that enabling the 'shared' option will cause cache hit rates + to be misreported (a side effect of the implementation). + + v2 + - Rewrite comment to avoid implementation details. + +diff --git a/nscd/nscd.conf b/nscd/nscd.conf +index 39b875912d..487ffe461d 100644 +--- a/nscd/nscd.conf ++++ b/nscd/nscd.conf +@@ -3,6 +3,9 @@ + # + # An example Name Service Cache config file. This file is needed by nscd. + # ++# WARNING: Running nscd with a secondary caching service like sssd may lead to ++# unexpected behaviour, especially with how long entries are cached. ++# + # Legal entries are: + # + # logfile +@@ -23,6 +26,9 @@ + # check-files + # persistent + # shared ++# NOTE: Setting 'shared' to a value of 'yes' will accelerate the lookup, ++# but those lookups will not be counted as cache hits ++# i.e. 'nscd -g' may show '0%'. + # max-db-size + # auto-propagate + # diff --git a/SOURCES/glibc-rh1747505-3.patch b/SOURCES/glibc-rh1747505-3.patch new file mode 100644 index 0000000..01e4959 --- /dev/null +++ b/SOURCES/glibc-rh1747505-3.patch @@ -0,0 +1,40 @@ +diff -Nrup a/nss/nsswitch.conf b/nss/nsswitch.conf +--- a/nss/nsswitch.conf 2019-10-25 12:14:09.255834866 -0400 ++++ b/nss/nsswitch.conf 2019-10-25 12:50:08.425769248 -0400 +@@ -1,7 +1,7 @@ + # + # /etc/nsswitch.conf + # +-# An example Name Service Switch config file. This file should be ++# Name Service Switch config file. This file should be + # sorted with the most-used services at the beginning. + # + # Valid databases are: aliases, ethers, group, gshadow, hosts, +@@ -52,18 +52,20 @@ + # shadow: db files + # group: db files + +-# In alphabetical order. Re-order as required to optimize peformance. ++# In order of likelihood of use to accelerate lookup. ++passwd: sss files ++shadow: files sss ++group: sss files ++hosts: files dns myhostname ++services: files sss ++netgroup: sss ++automount: files sss ++ + aliases: files + ethers: files +-group: files + gshadow: files +-hosts: files dns + initgroups: files +-netgroup: files + networks: files dns +-passwd: files + protocols: files + publickey: files + rpc: files +-shadow: files +-services: files diff --git a/SOURCES/glibc-rh1747505-4.patch b/SOURCES/glibc-rh1747505-4.patch new file mode 100644 index 0000000..c0a9b7f --- /dev/null +++ b/SOURCES/glibc-rh1747505-4.patch @@ -0,0 +1,27 @@ +commit eed1f6fcdb0526498223ebfe95f91ef5dec2172a +Author: Carlos O'Donell +Date: Tue Oct 29 11:58:03 2019 -0400 + + Comment out initgroups from example nsswitch.conf (Bug 25146) + + In commit 4b7c74179c8928d971d370e1137d202f891a4cf5 the nsswitch.conf + file was harmonized with downstream distributions, but this change + included adding "initgroups: files". We should not add initgroups by + default, we can have it, but it should be commented out to allow it + to inherit the settings for group. The problem is principally that + downstream authconfig won't update initgroups and it will get out of + sync with the setting for group. + +diff -Nrup a/nss/nsswitch.conf b/nss/nsswitch.conf +--- a/nss/nsswitch.conf 2019-10-29 14:13:15.883199544 -0400 ++++ b/nss/nsswitch.conf 2019-10-29 14:15:44.860978858 -0400 +@@ -64,7 +64,8 @@ automount: files sss + aliases: files + ethers: files + gshadow: files +-initgroups: files ++# Allow initgroups to default to the setting for group. ++# initgroups: files + networks: files dns + protocols: files + publickey: files diff --git a/SOURCES/glibc-rh1749439-1.patch b/SOURCES/glibc-rh1749439-1.patch new file mode 100644 index 0000000..18b7195 --- /dev/null +++ b/SOURCES/glibc-rh1749439-1.patch @@ -0,0 +1,512 @@ +commit 1a7fe2ebe52b3c8bf465d1756e69452d05c1c103 +Author: Florian Weimer +Date: Mon Aug 5 15:54:10 2019 +0200 + + login: Remove utmp backend jump tables [BZ #23518] + + There is just one file-based implementation, so this dispatch + mechanism is unnecessary. Instead of the vtable pointer + __libc_utmp_jump_table, use a non-negative file_fd as the indicator + that the backend is initialized. + +diff --git a/login/getutent_r.c b/login/getutent_r.c +index 6a244ba6e0b86da7..44239ecb81bacea4 100644 +--- a/login/getutent_r.c ++++ b/login/getutent_r.c +@@ -23,115 +23,16 @@ + + #include "utmp-private.h" + +- +-/* Functions defined here. */ +-static int setutent_unknown (void); +-static int getutent_r_unknown (struct utmp *buffer, struct utmp **result); +-static int getutid_r_unknown (const struct utmp *line, struct utmp *buffer, +- struct utmp **result); +-static int getutline_r_unknown (const struct utmp *id, struct utmp *buffer, +- struct utmp **result); +-static struct utmp *pututline_unknown (const struct utmp *data); +-static void endutent_unknown (void); +- +-/* Initial Jump table. */ +-const struct utfuncs __libc_utmp_unknown_functions = +-{ +- setutent_unknown, +- getutent_r_unknown, +- getutid_r_unknown, +- getutline_r_unknown, +- pututline_unknown, +- endutent_unknown, +- NULL +-}; +- +-/* Currently selected backend. */ +-const struct utfuncs *__libc_utmp_jump_table = &__libc_utmp_unknown_functions; +- + /* We need to protect the opening of the file. */ + __libc_lock_define_initialized (, __libc_utmp_lock attribute_hidden) + + +-static int +-setutent_unknown (void) +-{ +- int result; +- +- result = (*__libc_utmp_file_functions.setutent) (); +- if (result) +- __libc_utmp_jump_table = &__libc_utmp_file_functions; +- +- return result; +-} +- +- +-static int +-getutent_r_unknown (struct utmp *buffer, struct utmp **result) +-{ +- /* The backend was not yet initialized. */ +- if (setutent_unknown ()) +- return (*__libc_utmp_jump_table->getutent_r) (buffer, result); +- +- /* Not available. */ +- *result = NULL; +- return -1; +-} +- +- +-static int +-getutid_r_unknown (const struct utmp *id, struct utmp *buffer, +- struct utmp **result) +-{ +- /* The backend was not yet initialized. */ +- if (setutent_unknown ()) +- return (*__libc_utmp_jump_table->getutid_r) (id, buffer, result); +- +- /* Not available. */ +- *result = NULL; +- return -1; +-} +- +- +-static int +-getutline_r_unknown (const struct utmp *line, struct utmp *buffer, +- struct utmp **result) +-{ +- /* The backend was not yet initialized. */ +- if (setutent_unknown ()) +- return (*__libc_utmp_jump_table->getutline_r) (line, buffer, result); +- +- /* Not available. */ +- *result = NULL; +- return -1; +-} +- +- +-static struct utmp * +-pututline_unknown (const struct utmp *data) +-{ +- /* The backend was not yet initialized. */ +- if (setutent_unknown ()) +- return (*__libc_utmp_jump_table->pututline) (data); +- +- /* Not available. */ +- return NULL; +-} +- +- +-static void +-endutent_unknown (void) +-{ +- /* Nothing to do. */ +-} +- +- + void + __setutent (void) + { + __libc_lock_lock (__libc_utmp_lock); + +- (*__libc_utmp_jump_table->setutent) (); ++ __libc_setutent (); + + __libc_lock_unlock (__libc_utmp_lock); + } +@@ -145,7 +46,7 @@ __getutent_r (struct utmp *buffer, struct utmp **result) + + __libc_lock_lock (__libc_utmp_lock); + +- retval = (*__libc_utmp_jump_table->getutent_r) (buffer, result); ++ retval = __libc_getutent_r (buffer, result); + + __libc_lock_unlock (__libc_utmp_lock); + +@@ -162,7 +63,7 @@ __pututline (const struct utmp *data) + + __libc_lock_lock (__libc_utmp_lock); + +- buffer = (*__libc_utmp_jump_table->pututline) (data); ++ buffer = __libc_pututline (data); + + __libc_lock_unlock (__libc_utmp_lock); + +@@ -177,8 +78,7 @@ __endutent (void) + { + __libc_lock_lock (__libc_utmp_lock); + +- (*__libc_utmp_jump_table->endutent) (); +- __libc_utmp_jump_table = &__libc_utmp_unknown_functions; ++ __libc_endutent (); + + __libc_lock_unlock (__libc_utmp_lock); + } +diff --git a/login/getutid_r.c b/login/getutid_r.c +index b7d3dbac75774b0a..8cb6b16d735e8265 100644 +--- a/login/getutid_r.c ++++ b/login/getutid_r.c +@@ -49,7 +49,7 @@ __getutid_r (const struct utmp *id, struct utmp *buffer, struct utmp **result) + + __libc_lock_lock (__libc_utmp_lock); + +- retval = (*__libc_utmp_jump_table->getutid_r) (id, buffer, result); ++ retval = __libc_getutid_r (id, buffer, result); + + __libc_lock_unlock (__libc_utmp_lock); + +diff --git a/login/getutline_r.c b/login/getutline_r.c +index 6996887f76b28816..5607c19ed2e1ca66 100644 +--- a/login/getutline_r.c ++++ b/login/getutline_r.c +@@ -36,7 +36,7 @@ __getutline_r (const struct utmp *line, struct utmp *buffer, + + __libc_lock_lock (__libc_utmp_lock); + +- retval = (*__libc_utmp_jump_table->getutline_r) (line, buffer, result); ++ retval = __libc_getutline_r (line, buffer, result); + + __libc_lock_unlock (__libc_utmp_lock); + +diff --git a/login/updwtmp.c b/login/updwtmp.c +index 56fb41916a776c0a..7ae96224ca789b6d 100644 +--- a/login/updwtmp.c ++++ b/login/updwtmp.c +@@ -29,7 +29,7 @@ __updwtmp (const char *wtmp_file, const struct utmp *utmp) + { + const char *file_name = TRANSFORM_UTMP_FILE_NAME (wtmp_file); + +- (*__libc_utmp_file_functions.updwtmp) (file_name, utmp); ++ __libc_updwtmp (file_name, utmp); + } + libc_hidden_def (__updwtmp) + weak_alias (__updwtmp, updwtmp) +diff --git a/login/utmp-private.h b/login/utmp-private.h +index bd8773984cfc56de..5c2048ee52dc3cee 100644 +--- a/login/utmp-private.h ++++ b/login/utmp-private.h +@@ -24,24 +24,17 @@ + #include + #include + +-/* The structure describing the functions in a backend. */ +-struct utfuncs +-{ +- int (*setutent) (void); +- int (*getutent_r) (struct utmp *, struct utmp **); +- int (*getutid_r) (const struct utmp *, struct utmp *, struct utmp **); +- int (*getutline_r) (const struct utmp *, struct utmp *, struct utmp **); +- struct utmp *(*pututline) (const struct utmp *); +- void (*endutent) (void); +- int (*updwtmp) (const char *, const struct utmp *); +-}; +- +-/* The tables from the services. */ +-extern const struct utfuncs __libc_utmp_file_functions attribute_hidden; +-extern const struct utfuncs __libc_utmp_unknown_functions attribute_hidden; +- +-/* Currently selected backend. */ +-extern const struct utfuncs *__libc_utmp_jump_table attribute_hidden; ++/* These functions check for initialization, but not perform any ++ locking. */ ++int __libc_setutent (void) attribute_hidden; ++int __libc_getutent_r (struct utmp *, struct utmp **) attribute_hidden; ++int __libc_getutid_r (const struct utmp *, struct utmp *, struct utmp **) ++ attribute_hidden; ++int __libc_getutline_r (const struct utmp *, struct utmp *, struct utmp **) ++ attribute_hidden; ++struct utmp *__libc_pututline (const struct utmp *) attribute_hidden; ++void __libc_endutent (void) attribute_hidden; ++int __libc_updwtmp (const char *, const struct utmp *) attribute_hidden; + + /* Current file name. */ + extern const char *__libc_utmp_file_name attribute_hidden; +diff --git a/login/utmp_file.c b/login/utmp_file.c +index 040a5057116bb69d..069e6d0452e333ad 100644 +--- a/login/utmp_file.c ++++ b/login/utmp_file.c +@@ -105,37 +105,12 @@ static void timeout_handler (int signum) {}; + alarm (old_timeout); \ + } while (0) + +- +-/* Functions defined here. */ +-static int setutent_file (void); +-static int getutent_r_file (struct utmp *buffer, struct utmp **result); +-static int getutid_r_file (const struct utmp *key, struct utmp *buffer, +- struct utmp **result); +-static int getutline_r_file (const struct utmp *key, struct utmp *buffer, +- struct utmp **result); +-static struct utmp *pututline_file (const struct utmp *data); +-static void endutent_file (void); +-static int updwtmp_file (const char *file, const struct utmp *utmp); +- +-/* Jump table for file functions. */ +-const struct utfuncs __libc_utmp_file_functions = +-{ +- setutent_file, +- getutent_r_file, +- getutid_r_file, +- getutline_r_file, +- pututline_file, +- endutent_file, +- updwtmp_file +-}; +- +- + #ifndef TRANSFORM_UTMP_FILE_NAME + # define TRANSFORM_UTMP_FILE_NAME(file_name) (file_name) + #endif + +-static int +-setutent_file (void) ++int ++__libc_setutent (void) + { + if (file_fd < 0) + { +@@ -166,15 +141,19 @@ setutent_file (void) + return 1; + } + ++/* Preform initialization if necessary. */ ++static bool ++maybe_setutent (void) ++{ ++ return file_fd >= 0 || __libc_setutent (); ++} + +-static int +-getutent_r_file (struct utmp *buffer, struct utmp **result) ++int ++__libc_getutent_r (struct utmp *buffer, struct utmp **result) + { + ssize_t nbytes; + +- assert (file_fd >= 0); +- +- if (file_offset == -1l) ++ if (!maybe_setutent () || file_offset == -1l) + { + /* Not available. */ + *result = NULL; +@@ -279,13 +258,11 @@ unlock_return: + + /* For implementing this function we don't use the getutent_r function + because we can avoid the reposition on every new entry this way. */ +-static int +-getutid_r_file (const struct utmp *id, struct utmp *buffer, +- struct utmp **result) ++int ++__libc_getutid_r (const struct utmp *id, struct utmp *buffer, ++ struct utmp **result) + { +- assert (file_fd >= 0); +- +- if (file_offset == -1l) ++ if (!maybe_setutent () || file_offset == -1l) + { + *result = NULL; + return -1; +@@ -309,13 +286,11 @@ getutid_r_file (const struct utmp *id, struct utmp *buffer, + + /* For implementing this function we don't use the getutent_r function + because we can avoid the reposition on every new entry this way. */ +-static int +-getutline_r_file (const struct utmp *line, struct utmp *buffer, +- struct utmp **result) ++int ++__libc_getutline_r (const struct utmp *line, struct utmp *buffer, ++ struct utmp **result) + { +- assert (file_fd >= 0); +- +- if (file_offset == -1l) ++ if (!maybe_setutent () || file_offset == -1l) + { + *result = NULL; + return -1; +@@ -361,15 +336,16 @@ unlock_return: + } + + +-static struct utmp * +-pututline_file (const struct utmp *data) ++struct utmp * ++__libc_pututline (const struct utmp *data) + { ++ if (!maybe_setutent ()) ++ return NULL; ++ + struct utmp buffer; + struct utmp *pbuf; + int found; + +- assert (file_fd >= 0); +- + if (! file_writable) + { + /* We must make the file descriptor writable before going on. */ +@@ -467,18 +443,19 @@ pututline_file (const struct utmp *data) + } + + +-static void +-endutent_file (void) ++void ++__libc_endutent (void) + { +- assert (file_fd >= 0); +- +- __close_nocancel_nostatus (file_fd); +- file_fd = -1; ++ if (file_fd >= 0) ++ { ++ __close_nocancel_nostatus (file_fd); ++ file_fd = -1; ++ } + } + + +-static int +-updwtmp_file (const char *file, const struct utmp *utmp) ++int ++__libc_updwtmp (const char *file, const struct utmp *utmp) + { + int result = -1; + off64_t offset; +diff --git a/login/utmpname.c b/login/utmpname.c +index 21cb890a1a2fdc92..73b19c33ceab4dd7 100644 +--- a/login/utmpname.c ++++ b/login/utmpname.c +@@ -42,8 +42,7 @@ __utmpname (const char *file) + __libc_lock_lock (__libc_utmp_lock); + + /* Close the old file. */ +- (*__libc_utmp_jump_table->endutent) (); +- __libc_utmp_jump_table = &__libc_utmp_unknown_functions; ++ __libc_endutent (); + + if (strcmp (file, __libc_utmp_file_name) != 0) + { +diff --git a/manual/users.texi b/manual/users.texi +index 4ed79ba26fc8e9d0..a006bb58acfd0568 100644 +--- a/manual/users.texi ++++ b/manual/users.texi +@@ -894,9 +894,9 @@ The @code{getlogin} function is declared in @file{unistd.h}, while + @c ttyname_r dup @ascuheap @acsmem @acsfd + @c strncpy dup ok + @c libc_lock_lock dup @asulock @aculock +-@c *libc_utmp_jump_table->setutent dup @mtasurace:utent @acsfd +-@c *libc_utmp_jump_table->getutline_r dup @mtasurace:utent @mtascusig:ALRM @mtascutimer +-@c *libc_utmp_jump_table->endutent dup @mtasurace:utent @asulock @aculock ++@c __libc_setutent dup @mtasurace:utent @acsfd ++@c __libc_getutline_r dup @mtasurace:utent @mtascusig:ALRM @mtascutimer ++@c __libc_endutent dup @mtasurace:utent @asulock @aculock + @c libc_lock_unlock dup ok + @c strlen dup ok + @c memcpy dup ok +@@ -1111,7 +1111,7 @@ compatibility only, @file{utmp.h} defines @code{ut_time} as an alias for + + @c setutent @mtasurace:utent @asulock @aculock @acsfd + @c libc_lock_lock dup @asulock @aculock +-@c *libc_utmp_jump_table->setutent @mtasurace:utent @acsfd ++@c __libc_setutent @mtasurace:utent @acsfd + @c setutent_unknown @mtasurace:utent @acsfd + @c *libc_utmp_file_functions.setutent = setutent_file @mtasurace:utent @acsfd + @c open_not_cancel_2 dup @acsfd +@@ -1152,7 +1152,7 @@ A null pointer is returned in case no further entry is available. + @safety{@prelim{}@mtunsafe{@mtasurace{:utent}}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{}}} + @c endutent @mtasurace:utent @asulock @aculock @acsfd + @c libc_lock_lock dup @asulock @aculock +-@c *libc_utmp_jump_table->endutent @mtasurace:utent @acsfd ++@c __libc_endutent @mtasurace:utent @acsfd + @c endutent_unknown ok + @c endutent_file @mtasurace:utent @acsfd + @c close_not_cancel_no_status dup @acsfd +@@ -1230,7 +1230,7 @@ over again. + @safety{@prelim{}@mtunsafe{@mtasurace{:utent} @mtascusig{:ALRM} @mtascutimer{}}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{}}} + @c pututline @mtasurace:utent @mtascusig:ALRM @mtascutimer @asulock @aculock @acsfd + @c libc_lock_lock dup @asulock @aculock +-@c *libc_utmp_jump_table->pututline @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd ++@c __libc_pututline @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd + @c pututline_unknown @mtasurace:utent @acsfd + @c setutent_unknown dup @mtasurace:utent @acsfd + @c pututline_file @mtascusig:ALRM @mtascutimer @acsfd +@@ -1282,7 +1282,7 @@ user-provided buffer. + @safety{@prelim{}@mtunsafe{@mtasurace{:utent} @mtascusig{:ALRM} @mtascutimer{}}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{}}} + @c getutent_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @asulock @aculock @acsfd + @c libc_lock_lock dup @asulock @aculock +-@c *libc_utmp_jump_table->getutent_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd ++@c __libc_getutent_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd + @c getutent_r_unknown @mtasurace:utent @acsfd + @c setutent_unknown dup @mtasurace:utent @acsfd + @c getutent_r_file @mtasurace:utent @mtascusig:ALRM @mtascutimer +@@ -1319,7 +1319,7 @@ This function is a GNU extension. + @safety{@prelim{}@mtunsafe{@mtasurace{:utent} @mtascusig{:ALRM} @mtascutimer{}}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{}}} + @c getutid_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @asulock @aculock @acsfd + @c libc_lock_lock dup @asulock @aculock +-@c *libc_utmp_jump_table->getutid_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd ++@c __libc_getutid_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd + @c getutid_r_unknown @mtasurace:utent @acsfd + @c setutent_unknown dup @mtasurace:utent @acsfd + @c getutid_r_file @mtascusig:ALRM @mtascutimer +@@ -1349,7 +1349,7 @@ This function is a GNU extension. + @safety{@prelim{}@mtunsafe{@mtasurace{:utent} @mtascusig{:ALRM} @mtascutimer{}}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{}}} + @c getutline_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @asulock @aculock @acsfd + @c libc_lock_lock dup @asulock @aculock +-@c *libc_utmp_jump_table->getutline_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd ++@c __libc_getutline_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd + @c getutline_r_unknown @mtasurace:utent @acsfd + @c setutent_unknown dup @mtasurace:utent @acsfd + @c getutline_r_file @mtasurace:utent @mtascusig:ALRM @mtascutimer +@@ -1393,7 +1393,7 @@ be used. + @safety{@prelim{}@mtunsafe{@mtasurace{:utent}}@asunsafe{@asulock{} @ascuheap{}}@acunsafe{@aculock{} @acsmem{}}} + @c utmpname @mtasurace:utent @asulock @ascuheap @aculock @acsmem + @c libc_lock_lock dup @asulock @aculock +-@c *libc_utmp_jump_table->endutent dup @mtasurace:utent ++@c __libc_endutent dup @mtasurace:utent + @c strcmp dup ok + @c free dup @ascuheap @acsmem + @c strdup dup @ascuheap @acsmem +diff --git a/sysdeps/unix/getlogin_r.c b/sysdeps/unix/getlogin_r.c +index 444df7e4d3210cf6..180c0bbca13d0f87 100644 +--- a/sysdeps/unix/getlogin_r.c ++++ b/sysdeps/unix/getlogin_r.c +@@ -64,8 +64,8 @@ __getlogin_r (char *name, size_t name_len) + held so that our search is thread-safe. */ + + __libc_lock_lock (__libc_utmp_lock); +- (*__libc_utmp_jump_table->setutent) (); +- result = (*__libc_utmp_jump_table->getutline_r) (&line, &buffer, &ut); ++ __libc_setutent (); ++ result = __libc_getutline_r (&line, &buffer, &ut); + if (result < 0) + { + if (errno == ESRCH) +@@ -74,8 +74,7 @@ __getlogin_r (char *name, size_t name_len) + else + result = errno; + } +- (*__libc_utmp_jump_table->endutent) (); +- __libc_utmp_jump_table = &__libc_utmp_unknown_functions; ++ __libc_endutent (); + __libc_lock_unlock (__libc_utmp_lock); + + if (result == 0) diff --git a/SOURCES/glibc-rh1749439-10.patch b/SOURCES/glibc-rh1749439-10.patch new file mode 100644 index 0000000..92741c7 --- /dev/null +++ b/SOURCES/glibc-rh1749439-10.patch @@ -0,0 +1,389 @@ +commit be6b16d975683e6cca57852cd4cfe715b2a9d8b1 +Author: Florian Weimer +Date: Thu Nov 7 18:15:18 2019 +0100 + + login: Acquire write lock early in pututline [BZ #24882] + + It has been reported that due to lack of fairness in POSIX file + locking, the current reader-to-writer lock upgrade can result in + lack of forward progress. Acquiring the write lock directly + hopefully avoids this issue if there are only writers. + + This also fixes bug 24882 due to the cache revalidation in + __libc_pututline. + + Reviewed-by: Carlos O'Donell + Change-Id: I57e31ae30719e609a53505a0924dda101d46372e + +diff --git a/login/Makefile b/login/Makefile +index 82132c83fd799357..030cf489b2e037d4 100644 +--- a/login/Makefile ++++ b/login/Makefile +@@ -44,7 +44,7 @@ subdir-dirs = programs + vpath %.c programs + + tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname tst-getlogin tst-updwtmpx \ +- tst-pututxline-lockfail ++ tst-pututxline-lockfail tst-pututxline-cache + + # Build the -lutil library with these extra functions. + extra-libs := libutil +@@ -74,3 +74,4 @@ $(inst_libexecdir)/pt_chown: $(objpfx)pt_chown $(+force) + -$(INSTALL_PROGRAM) -m 4755 -o root $< $@ + + $(objpfx)tst-pututxline-lockfail: $(shared-thread-library) ++$(objpfx)tst-pututxline-cache: $(shared-thread-library) +diff --git a/login/tst-pututxline-cache.c b/login/tst-pututxline-cache.c +new file mode 100644 +index 0000000000000000..3f30dd1776711769 +--- /dev/null ++++ b/login/tst-pututxline-cache.c +@@ -0,0 +1,193 @@ ++/* Test case for cache invalidation after concurrent write (bug 24882). ++ Copyright (C) 2019 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; see the file COPYING.LIB. If ++ not, see . */ ++ ++/* This test writes an entry to the utmpx file, reads it (so that it ++ is cached) in process1, and overwrites the same entry in process2 ++ with something that does not match the search criteria. At this ++ point, the cache of the first process is stale, and when process1 ++ attempts to write a new record which would have gone to the same ++ place (as indicated by the cache), it needs to realize that it has ++ to pick a different slot because the old slot is now used for ++ something else. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Set to the path of the utmp file. */ ++static char *utmp_file; ++ ++/* Used to synchronize the subprocesses. The barrier itself is ++ allocated in shared memory. */ ++static pthread_barrier_t *barrier; ++ ++/* setutxent with error checking. */ ++static void ++xsetutxent (void) ++{ ++ errno = 0; ++ setutxent (); ++ TEST_COMPARE (errno, 0); ++} ++ ++/* getutxent with error checking. */ ++static struct utmpx * ++xgetutxent (void) ++{ ++ errno = 0; ++ struct utmpx *result = getutxent (); ++ if (result == NULL) ++ FAIL_EXIT1 ("getutxent: %m"); ++ return result; ++} ++ ++static void ++put_entry (const char *id, pid_t pid, const char *user, const char *line) ++{ ++ struct utmpx ut = ++ { ++ .ut_type = LOGIN_PROCESS, ++ .ut_pid = pid, ++ .ut_host = "localhost", ++ }; ++ strcpy (ut.ut_id, id); ++ strncpy (ut.ut_user, user, sizeof (ut.ut_user)); ++ strncpy (ut.ut_line, line, sizeof (ut.ut_line)); ++ TEST_VERIFY (pututxline (&ut) != NULL); ++} ++ ++/* Use two cooperating subprocesses to avoid issues related to ++ unlock-on-close semantics of POSIX advisory locks. */ ++ ++static __attribute__ ((noreturn)) void ++process1 (void) ++{ ++ TEST_COMPARE (utmpname (utmp_file), 0); ++ ++ /* Create an entry. */ ++ xsetutxent (); ++ put_entry ("1", 101, "root", "process1"); ++ ++ /* Retrieve the entry. This will fill the internal cache. */ ++ { ++ errno = 0; ++ setutxent (); ++ TEST_COMPARE (errno, 0); ++ struct utmpx ut = ++ { ++ .ut_type = LOGIN_PROCESS, ++ .ut_line = "process1", ++ }; ++ struct utmpx *result = getutxline (&ut); ++ if (result == NULL) ++ FAIL_EXIT1 ("getutxline (\"process1\"): %m"); ++ TEST_COMPARE (result->ut_pid, 101); ++ } ++ ++ /* Signal the other process to overwrite the entry. */ ++ xpthread_barrier_wait (barrier); ++ ++ /* Wait for the other process to complete the write operation. */ ++ xpthread_barrier_wait (barrier); ++ ++ /* Add another entry. Note: This time, there is no setutxent call. */ ++ put_entry ("1", 103, "root", "process1"); ++ ++ _exit (0); ++} ++ ++static void ++process2 (void *closure) ++{ ++ /* Wait for the first process to write its entry. */ ++ xpthread_barrier_wait (barrier); ++ ++ /* Truncate the file. The glibc interface does not support ++ re-purposing records, but an external expiration mechanism may ++ trigger this. */ ++ TEST_COMPARE (truncate64 (utmp_file, 0), 0); ++ ++ /* Write the replacement entry. */ ++ TEST_COMPARE (utmpname (utmp_file), 0); ++ xsetutxent (); ++ put_entry ("2", 102, "user", "process2"); ++ ++ /* Signal the other process that the entry has been replaced. */ ++ xpthread_barrier_wait (barrier); ++} ++ ++static int ++do_test (void) ++{ ++ xclose (create_temp_file ("tst-tumpx-cache-write-", &utmp_file)); ++ { ++ pthread_barrierattr_t attr; ++ xpthread_barrierattr_init (&attr); ++ xpthread_barrierattr_setpshared (&attr, PTHREAD_SCOPE_PROCESS); ++ barrier = support_shared_allocate (sizeof (*barrier)); ++ xpthread_barrier_init (barrier, &attr, 2); ++ } ++ ++ /* Run both subprocesses in parallel. */ ++ { ++ pid_t pid1 = xfork (); ++ if (pid1 == 0) ++ process1 (); ++ support_isolate_in_subprocess (process2, NULL); ++ int status; ++ xwaitpid (pid1, &status, 0); ++ TEST_COMPARE (status, 0); ++ } ++ ++ /* Check that the utmpx database contains the expected records. */ ++ { ++ TEST_COMPARE (utmpname (utmp_file), 0); ++ xsetutxent (); ++ ++ struct utmpx *ut = xgetutxent (); ++ TEST_COMPARE_STRING (ut->ut_id, "2"); ++ TEST_COMPARE (ut->ut_pid, 102); ++ TEST_COMPARE_STRING (ut->ut_user, "user"); ++ TEST_COMPARE_STRING (ut->ut_line, "process2"); ++ ++ ut = xgetutxent (); ++ TEST_COMPARE_STRING (ut->ut_id, "1"); ++ TEST_COMPARE (ut->ut_pid, 103); ++ TEST_COMPARE_STRING (ut->ut_user, "root"); ++ TEST_COMPARE_STRING (ut->ut_line, "process1"); ++ ++ if (getutxent () != NULL) ++ FAIL_EXIT1 ("additional utmpx entry"); ++ } ++ ++ xpthread_barrier_destroy (barrier); ++ support_shared_free (barrier); ++ free (utmp_file); ++ ++ return 0; ++} ++ ++#include +diff --git a/login/utmp_file.c b/login/utmp_file.c +index 9ad80364682bae92..6bba120db9cc574e 100644 +--- a/login/utmp_file.c ++++ b/login/utmp_file.c +@@ -186,19 +186,11 @@ __libc_getutent_r (struct utmp *buffer, struct utmp **result) + + + /* Search for *ID, updating last_entry and file_offset. Return 0 on +- success and -1 on failure. If the locking operation failed, write +- true to *LOCK_FAILED. */ ++ success and -1 on failure. Does not perform locking; for that see ++ internal_getut_r below. */ + static int +-internal_getut_r (const struct utmp *id, bool *lock_failed) ++internal_getut_nolock (const struct utmp *id) + { +- int result = -1; +- +- if (try_file_lock (file_fd, F_RDLCK)) +- { +- *lock_failed = true; +- return -1; +- } +- + if (id->ut_type == RUN_LVL || id->ut_type == BOOT_TIME + || id->ut_type == OLD_TIME || id->ut_type == NEW_TIME) + { +@@ -213,7 +205,7 @@ internal_getut_r (const struct utmp *id, bool *lock_failed) + { + __set_errno (ESRCH); + file_offset = -1l; +- goto unlock_return; ++ return -1; + } + file_offset += sizeof (struct utmp); + +@@ -234,7 +226,7 @@ internal_getut_r (const struct utmp *id, bool *lock_failed) + { + __set_errno (ESRCH); + file_offset = -1l; +- goto unlock_return; ++ return -1; + } + file_offset += sizeof (struct utmp); + +@@ -243,15 +235,26 @@ internal_getut_r (const struct utmp *id, bool *lock_failed) + } + } + +- result = 0; ++ return 0; ++} + +-unlock_return: +- file_unlock (file_fd); ++/* Search for *ID, updating last_entry and file_offset. Return 0 on ++ success and -1 on failure. If the locking operation failed, write ++ true to *LOCK_FAILED. */ ++static int ++internal_getut_r (const struct utmp *id, bool *lock_failed) ++{ ++ if (try_file_lock (file_fd, F_RDLCK)) ++ { ++ *lock_failed = true; ++ return -1; ++ } + ++ int result = internal_getut_nolock (id); ++ file_unlock (file_fd); + return result; + } + +- + /* For implementing this function we don't use the getutent_r function + because we can avoid the reposition on every new entry this way. */ + int +@@ -279,7 +282,6 @@ __libc_getutid_r (const struct utmp *id, struct utmp *buffer, + return 0; + } + +- + /* For implementing this function we don't use the getutent_r function + because we can avoid the reposition on every new entry this way. */ + int +@@ -336,7 +338,6 @@ __libc_pututline (const struct utmp *data) + return NULL; + + struct utmp *pbuf; +- int found; + + if (! file_writable) + { +@@ -358,7 +359,12 @@ __libc_pututline (const struct utmp *data) + file_writable = true; + } + ++ /* Exclude other writers before validating the cache. */ ++ if (try_file_lock (file_fd, F_WRLCK)) ++ return NULL; ++ + /* Find the correct place to insert the data. */ ++ bool found = false; + if (file_offset > 0 + && ((last_entry.ut_type == data->ut_type + && (last_entry.ut_type == RUN_LVL +@@ -366,23 +372,30 @@ __libc_pututline (const struct utmp *data) + || last_entry.ut_type == OLD_TIME + || last_entry.ut_type == NEW_TIME)) + || __utmp_equal (&last_entry, data))) +- found = 1; +- else + { +- bool lock_failed = false; +- found = internal_getut_r (data, &lock_failed); +- +- if (__builtin_expect (lock_failed, false)) ++ if (__lseek64 (file_fd, file_offset, SEEK_SET) < 0) + { +- __set_errno (EAGAIN); ++ file_unlock (file_fd); + return NULL; + } ++ if (__read_nocancel (file_fd, &last_entry, sizeof (last_entry)) ++ != sizeof (last_entry)) ++ { ++ if (__lseek64 (file_fd, file_offset, SEEK_SET) < 0) ++ { ++ file_unlock (file_fd); ++ return NULL; ++ } ++ found = false; ++ } ++ else ++ found = __utmp_equal (&last_entry, data); + } + +- if (try_file_lock (file_fd, F_WRLCK)) +- return NULL; ++ if (!found) ++ found = internal_getut_nolock (data) >= 0; + +- if (found < 0) ++ if (!found) + { + /* We append the next entry. */ + file_offset = __lseek64 (file_fd, 0, SEEK_END); +@@ -411,7 +424,7 @@ __libc_pututline (const struct utmp *data) + { + /* If we appended a new record this is only partially written. + Remove it. */ +- if (found < 0) ++ if (!found) + (void) __ftruncate64 (file_fd, file_offset); + pbuf = NULL; + } diff --git a/SOURCES/glibc-rh1749439-11.patch b/SOURCES/glibc-rh1749439-11.patch new file mode 100644 index 0000000..d1289d6 --- /dev/null +++ b/SOURCES/glibc-rh1749439-11.patch @@ -0,0 +1,138 @@ +commit 76a7c103eb9060f9e3ba01d073ae4621a17d8b46 +Author: Florian Weimer +Date: Tue Nov 12 12:02:57 2019 +0100 + + login: Introduce matches_last_entry to utmp processing + + This simplifies internal_getut_nolock and fixes a regression, + introduced in commit be6b16d975683e6cca57852cd4cfe715b2a9d8b1 + ("login: Acquire write lock early in pututline [BZ #24882]") + in pututxline because __utmp_equal can only compare process-related + utmp entries. + + Fixes: be6b16d975683e6cca57852cd4cfe715b2a9d8b1 + Change-Id: Ib8a85002f7f87ee41590846d16d7e52bdb82f5a5 + +diff --git a/login/utmp_file.c b/login/utmp_file.c +index 6bba120db9cc574e..e653d14967c4fb7a 100644 +--- a/login/utmp_file.c ++++ b/login/utmp_file.c +@@ -43,6 +43,25 @@ static off64_t file_offset; + /* Cache for the last read entry. */ + static struct utmp last_entry; + ++/* Returns true if *ENTRY matches last_entry, based on ++ data->ut_type. */ ++static bool ++matches_last_entry (const struct utmp *data) ++{ ++ if (file_offset <= 0) ++ /* Nothing has been read. last_entry is stale and cannot match. */ ++ return false; ++ ++ if (data->ut_type == RUN_LVL ++ || data->ut_type == BOOT_TIME ++ || data->ut_type == OLD_TIME ++ || data->ut_type == NEW_TIME) ++ /* For some entry types, only a type match is required. */ ++ return data->ut_type == last_entry.ut_type; ++ else ++ /* For the process-related entries, a full match is needed. */ ++ return __utmp_equal (&last_entry, data); ++} + + /* Locking timeout. */ + #ifndef TIMEOUT +@@ -133,9 +152,6 @@ __libc_setutent (void) + __lseek64 (file_fd, 0, SEEK_SET); + file_offset = 0; + +- /* Make sure the entry won't match. */ +- last_entry.ut_type = -1; +- + return 1; + } + +@@ -191,48 +207,20 @@ __libc_getutent_r (struct utmp *buffer, struct utmp **result) + static int + internal_getut_nolock (const struct utmp *id) + { +- if (id->ut_type == RUN_LVL || id->ut_type == BOOT_TIME +- || id->ut_type == OLD_TIME || id->ut_type == NEW_TIME) ++ while (1) + { +- /* Search for next entry with type RUN_LVL, BOOT_TIME, +- OLD_TIME, or NEW_TIME. */ +- +- while (1) ++ /* Read the next entry. */ ++ if (__read_nocancel (file_fd, &last_entry, sizeof (struct utmp)) ++ != sizeof (struct utmp)) + { +- /* Read the next entry. */ +- if (__read_nocancel (file_fd, &last_entry, sizeof (struct utmp)) +- != sizeof (struct utmp)) +- { +- __set_errno (ESRCH); +- file_offset = -1l; +- return -1; +- } +- file_offset += sizeof (struct utmp); +- +- if (id->ut_type == last_entry.ut_type) +- break; ++ __set_errno (ESRCH); ++ file_offset = -1l; ++ return -1; + } +- } +- else +- { +- /* Search for the next entry with the specified ID and with type +- INIT_PROCESS, LOGIN_PROCESS, USER_PROCESS, or DEAD_PROCESS. */ +- +- while (1) +- { +- /* Read the next entry. */ +- if (__read_nocancel (file_fd, &last_entry, sizeof (struct utmp)) +- != sizeof (struct utmp)) +- { +- __set_errno (ESRCH); +- file_offset = -1l; +- return -1; +- } +- file_offset += sizeof (struct utmp); ++ file_offset += sizeof (struct utmp); + +- if (__utmp_equal (&last_entry, id)) +- break; +- } ++ if (matches_last_entry (id)) ++ break; + } + + return 0; +@@ -365,13 +353,7 @@ __libc_pututline (const struct utmp *data) + + /* Find the correct place to insert the data. */ + bool found = false; +- if (file_offset > 0 +- && ((last_entry.ut_type == data->ut_type +- && (last_entry.ut_type == RUN_LVL +- || last_entry.ut_type == BOOT_TIME +- || last_entry.ut_type == OLD_TIME +- || last_entry.ut_type == NEW_TIME)) +- || __utmp_equal (&last_entry, data))) ++ if (matches_last_entry (data)) + { + if (__lseek64 (file_fd, file_offset, SEEK_SET) < 0) + { +@@ -389,7 +371,7 @@ __libc_pututline (const struct utmp *data) + found = false; + } + else +- found = __utmp_equal (&last_entry, data); ++ found = matches_last_entry (data); + } + + if (!found) diff --git a/SOURCES/glibc-rh1749439-12.patch b/SOURCES/glibc-rh1749439-12.patch new file mode 100644 index 0000000..0308708 --- /dev/null +++ b/SOURCES/glibc-rh1749439-12.patch @@ -0,0 +1,114 @@ +commit fed33b0fb03d1942a6713286176d42869c0f1580 +Author: Leandro Pereira +Date: Wed Oct 2 12:42:28 2019 -0400 + + Add nocancel version of pread64() + + This is in preparation for changes in the dynamic linker so that + pread() is used instead of lseek()+read(). + + Reviewed-by: Carlos O'Donell + +Conflicts: + sysdeps/unix/sysv/linux/Makefile + (Textual conflict in routines list.) + +diff --git a/sysdeps/generic/not-cancel.h b/sysdeps/generic/not-cancel.h +index d9f8a75dbda85ed5..260e6e4081f5fe16 100644 +--- a/sysdeps/generic/not-cancel.h ++++ b/sysdeps/generic/not-cancel.h +@@ -41,6 +41,8 @@ + (void) __close (fd) + #define __read_nocancel(fd, buf, n) \ + __read (fd, buf, n) ++#define __pread64_nocancel(fd, buf, count, offset) \ ++ __pread64 (fd, buf, count, offset) + #define __write_nocancel(fd, buf, n) \ + __write (fd, buf, n) + #define __writev_nocancel_nostatus(fd, iov, n) \ +diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile +index 773aaea0e980bdd6..fb4ccd63ddec7eca 100644 +--- a/sysdeps/unix/sysv/linux/Makefile ++++ b/sysdeps/unix/sysv/linux/Makefile +@@ -174,7 +174,8 @@ sysdep_routines += xstatconv internal_statvfs internal_statvfs64 \ + close_nocancel fcntl_nocancel nanosleep_nocancel \ + open_nocancel open64_nocancel \ + openat_nocancel openat64_nocancel \ +- pause_nocancel read_nocancel waitpid_nocancel write_nocancel ++ pause_nocancel read_nocancel pread64_nocancel \ ++ waitpid_nocancel write_nocancel + + sysdep_headers += bits/fcntl-linux.h + +diff --git a/sysdeps/unix/sysv/linux/Versions b/sysdeps/unix/sysv/linux/Versions +index 336c13b57dba727a..95759bead1b0b3ca 100644 +--- a/sysdeps/unix/sysv/linux/Versions ++++ b/sysdeps/unix/sysv/linux/Versions +@@ -176,6 +176,7 @@ libc { + __syscall_rt_sigqueueinfo; + __open_nocancel; + __read_nocancel; ++ __pread64_nocancel; + __close_nocancel; + __sigtimedwait; + # functions used by nscd +diff --git a/sysdeps/unix/sysv/linux/not-cancel.h b/sysdeps/unix/sysv/linux/not-cancel.h +index 09de92dee9437d98..e58db475682a8c6a 100644 +--- a/sysdeps/unix/sysv/linux/not-cancel.h ++++ b/sysdeps/unix/sysv/linux/not-cancel.h +@@ -43,6 +43,9 @@ __typeof (openat64) __openat64_nocancel; + /* Non cancellable read syscall. */ + __typeof (__read) __read_nocancel; + ++/* Non cancellable pread syscall (LFS version). */ ++__typeof (__pread64) __pread64_nocancel; ++ + /* Uncancelable write. */ + __typeof (__write) __write_nocancel; + +@@ -84,6 +87,7 @@ hidden_proto (__open64_nocancel) + hidden_proto (__openat_nocancel) + hidden_proto (__openat64_nocancel) + hidden_proto (__read_nocancel) ++hidden_proto (__pread64_nocancel) + hidden_proto (__write_nocancel) + hidden_proto (__close_nocancel) + hidden_proto (__waitpid_nocancel) +diff --git a/sysdeps/unix/sysv/linux/pread64_nocancel.c b/sysdeps/unix/sysv/linux/pread64_nocancel.c +new file mode 100644 +index 0000000000000000..dab61260e5db43b5 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/pread64_nocancel.c +@@ -0,0 +1,32 @@ ++/* Linux pread64() syscall implementation -- non-cancellable. ++ Copyright (C) 2019 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 ++ . */ ++ ++#include ++#include ++#include ++ ++#ifndef __NR_pread64 ++# define __NR_pread64 __NR_pread ++#endif ++ ++ssize_t ++__pread64_nocancel (int fd, void *buf, size_t count, off64_t offset) ++{ ++ return INLINE_SYSCALL_CALL (pread64, fd, buf, count, SYSCALL_LL64_PRW (offset)); ++} ++hidden_def (__pread64_nocancel) diff --git a/SOURCES/glibc-rh1749439-13.patch b/SOURCES/glibc-rh1749439-13.patch new file mode 100644 index 0000000..333f1f6 --- /dev/null +++ b/SOURCES/glibc-rh1749439-13.patch @@ -0,0 +1,307 @@ +commit d4625a19fe64f664119a541b317fb83de01bb273 +Author: Florian Weimer +Date: Tue Nov 12 12:25:49 2019 +0100 + + login: Use pread64 in utmp implementation + + This reduces the possible error scenarios considerably because + no longer can file seek fail, leaving the file descriptor in an + inconsistent state and out of sync with the cache. + + As a result, it is possible to avoid setting file_offset to -1 + to make an error persistent. Instead, subsequent calls will retry + the operation and report any errors returned by the kernel. + + This change also avoids reading the file from the start if pututline + is called multiple times, to work around lock acquisition failures + due to timeouts. + + Change-Id: If21ea0c162c38830a89331ea93cddec14c0974de + +diff --git a/login/utmp_file.c b/login/utmp_file.c +index e653d14967c4fb7a..c828a28ac54c150e 100644 +--- a/login/utmp_file.c ++++ b/login/utmp_file.c +@@ -162,12 +162,35 @@ maybe_setutent (void) + return file_fd >= 0 || __libc_setutent (); + } + ++/* Reads the entry at file_offset, storing it in last_entry and ++ updating file_offset on success. Returns -1 for a read error, 0 ++ for EOF, and 1 for a successful read. last_entry and file_offset ++ are only updated on a successful and complete read. */ ++static ssize_t ++read_last_entry (void) ++{ ++ struct utmp buffer; ++ ssize_t nbytes = __pread64_nocancel (file_fd, &buffer, sizeof (buffer), ++ file_offset); ++ if (nbytes < 0) ++ return -1; ++ else if (nbytes != sizeof (buffer)) ++ /* Assume EOF. */ ++ return 0; ++ else ++ { ++ last_entry = buffer; ++ file_offset += sizeof (buffer); ++ return 1; ++ } ++} ++ + int + __libc_getutent_r (struct utmp *buffer, struct utmp **result) + { +- ssize_t nbytes; ++ int saved_errno = errno; + +- if (!maybe_setutent () || file_offset == -1l) ++ if (!maybe_setutent ()) + { + /* Not available. */ + *result = NULL; +@@ -175,25 +198,22 @@ __libc_getutent_r (struct utmp *buffer, struct utmp **result) + } + + if (try_file_lock (file_fd, F_RDLCK)) +- nbytes = 0; +- else +- { +- /* Read the next entry. */ +- nbytes = __read_nocancel (file_fd, &last_entry, sizeof (struct utmp)); +- file_unlock (file_fd); +- } ++ return -1; + +- if (nbytes != sizeof (struct utmp)) ++ ssize_t nbytes = read_last_entry (); ++ file_unlock (file_fd); ++ ++ if (nbytes <= 0) /* Read error or EOF. */ + { +- if (nbytes != 0) +- file_offset = -1l; ++ if (nbytes == 0) ++ /* errno should be unchanged to indicate success. A premature ++ EOF is treated like an EOF (missing complete record at the ++ end). */ ++ __set_errno (saved_errno); + *result = NULL; + return -1; + } + +- /* Update position pointer. */ +- file_offset += sizeof (struct utmp); +- + memcpy (buffer, &last_entry, sizeof (struct utmp)); + *result = buffer; + +@@ -209,15 +229,15 @@ internal_getut_nolock (const struct utmp *id) + { + while (1) + { +- /* Read the next entry. */ +- if (__read_nocancel (file_fd, &last_entry, sizeof (struct utmp)) +- != sizeof (struct utmp)) ++ ssize_t nbytes = read_last_entry (); ++ if (nbytes < 0) ++ return -1; ++ if (nbytes == 0) + { ++ /* End of file reached. */ + __set_errno (ESRCH); +- file_offset = -1l; + return -1; + } +- file_offset += sizeof (struct utmp); + + if (matches_last_entry (id)) + break; +@@ -249,7 +269,7 @@ int + __libc_getutid_r (const struct utmp *id, struct utmp *buffer, + struct utmp **result) + { +- if (!maybe_setutent () || file_offset == -1l) ++ if (!maybe_setutent ()) + { + *result = NULL; + return -1; +@@ -276,7 +296,7 @@ int + __libc_getutline_r (const struct utmp *line, struct utmp *buffer, + struct utmp **result) + { +- if (!maybe_setutent () || file_offset == -1l) ++ if (!maybe_setutent ()) + { + *result = NULL; + return -1; +@@ -290,16 +310,21 @@ __libc_getutline_r (const struct utmp *line, struct utmp *buffer, + + while (1) + { +- /* Read the next entry. */ +- if (__read_nocancel (file_fd, &last_entry, sizeof (struct utmp)) +- != sizeof (struct utmp)) ++ ssize_t nbytes = read_last_entry (); ++ if (nbytes < 0) + { ++ file_unlock (file_fd); ++ *result = NULL; ++ return -1; ++ } ++ if (nbytes == 0) ++ { ++ /* End of file reached. */ ++ file_unlock (file_fd); + __set_errno (ESRCH); +- file_offset = -1l; + *result = NULL; +- goto unlock_return; ++ return -1; + } +- file_offset += sizeof (struct utmp); + + /* Stop if we found a user or login entry. */ + if ((last_entry.ut_type == USER_PROCESS +@@ -309,20 +334,18 @@ __libc_getutline_r (const struct utmp *line, struct utmp *buffer, + break; + } + ++ file_unlock (file_fd); + memcpy (buffer, &last_entry, sizeof (struct utmp)); + *result = buffer; + +-unlock_return: +- file_unlock (file_fd); +- +- return ((*result == NULL) ? -1 : 0); ++ return 0; + } + + + struct utmp * + __libc_pututline (const struct utmp *data) + { +- if (!maybe_setutent () || file_offset == -1l) ++ if (!maybe_setutent ()) + return NULL; + + struct utmp *pbuf; +@@ -337,8 +360,7 @@ __libc_pututline (const struct utmp *data) + if (new_fd == -1) + return NULL; + +- if (__lseek64 (new_fd, __lseek64 (file_fd, 0, SEEK_CUR), SEEK_SET) == -1 +- || __dup2 (new_fd, file_fd) < 0) ++ if (__dup2 (new_fd, file_fd) < 0) + { + __close_nocancel_nostatus (new_fd); + return NULL; +@@ -355,69 +377,70 @@ __libc_pututline (const struct utmp *data) + bool found = false; + if (matches_last_entry (data)) + { +- if (__lseek64 (file_fd, file_offset, SEEK_SET) < 0) ++ /* Read back the entry under the write lock. */ ++ file_offset -= sizeof (last_entry); ++ ssize_t nbytes = read_last_entry (); ++ if (nbytes < 0) + { + file_unlock (file_fd); + return NULL; + } +- if (__read_nocancel (file_fd, &last_entry, sizeof (last_entry)) +- != sizeof (last_entry)) +- { +- if (__lseek64 (file_fd, file_offset, SEEK_SET) < 0) +- { +- file_unlock (file_fd); +- return NULL; +- } +- found = false; +- } ++ ++ if (nbytes == 0) ++ /* End of file reached. */ ++ found = false; + else + found = matches_last_entry (data); + } + + if (!found) ++ /* Search forward for the entry. */ + found = internal_getut_nolock (data) >= 0; + ++ off64_t write_offset; + if (!found) + { + /* We append the next entry. */ +- file_offset = __lseek64 (file_fd, 0, SEEK_END); +- if (file_offset % sizeof (struct utmp) != 0) +- { +- file_offset -= file_offset % sizeof (struct utmp); +- __ftruncate64 (file_fd, file_offset); +- +- if (__lseek64 (file_fd, 0, SEEK_END) < 0) +- { +- pbuf = NULL; +- goto unlock_return; +- } +- } ++ write_offset = __lseek64 (file_fd, 0, SEEK_END); ++ ++ /* Round down to the next multiple of the entry size. This ++ ensures any partially-written record is overwritten by the ++ new record. */ ++ write_offset = (write_offset / sizeof (struct utmp) ++ * sizeof (struct utmp)); + } + else ++ /* Overwrite last_entry. */ ++ write_offset = file_offset - sizeof (struct utmp); ++ ++ /* Write the new data. */ ++ ssize_t nbytes; ++ if (__lseek64 (file_fd, write_offset, SEEK_SET) < 0 ++ || (nbytes = __write_nocancel (file_fd, data, sizeof (struct utmp))) < 0) + { +- /* We replace the just read entry. */ +- file_offset -= sizeof (struct utmp); +- __lseek64 (file_fd, file_offset, SEEK_SET); ++ /* There is no need to recover the file position because all ++ reads use pread64, and any future write is preceded by ++ another seek. */ ++ file_unlock (file_fd); ++ return NULL; + } + +- /* Write the new data. */ +- if (__write_nocancel (file_fd, data, sizeof (struct utmp)) +- != sizeof (struct utmp)) ++ if (nbytes != sizeof (struct utmp)) + { + /* If we appended a new record this is only partially written. + Remove it. */ + if (!found) +- (void) __ftruncate64 (file_fd, file_offset); +- pbuf = NULL; +- } +- else +- { +- file_offset += sizeof (struct utmp); +- pbuf = (struct utmp *) data; ++ (void) __ftruncate64 (file_fd, write_offset); ++ file_unlock (file_fd); ++ /* Assume that the write failure was due to missing disk ++ space. */ ++ __set_errno (ENOSPC); ++ return NULL; + } + +- unlock_return: + file_unlock (file_fd); ++ file_offset = write_offset + sizeof (struct utmp); ++ pbuf = (struct utmp *) data; + + return pbuf; + } diff --git a/SOURCES/glibc-rh1749439-2.patch b/SOURCES/glibc-rh1749439-2.patch new file mode 100644 index 0000000..f00334c --- /dev/null +++ b/SOURCES/glibc-rh1749439-2.patch @@ -0,0 +1,676 @@ +commit a33b817f13170b5c24263b92e7e09880fe797d7e +Author: Florian Weimer +Date: Tue Aug 13 12:09:32 2019 +0200 + + login: Assume that _HAVE_UT_* constants are true + + Make the GNU version of bits/utmp.h the generic version because + all remaining ports use it (with a sysdeps override for + Linux s390/s390x). + +Conflicts: + bits/utmp.h + sysdeps/gnu/bits/utmp.h + (Upstream copyright year change.) + +diff --git a/bits/utmp.h b/bits/utmp.h +index 6e8695fbf072e5f1..3c02dd4f3fe4e99b 100644 +--- a/bits/utmp.h ++++ b/bits/utmp.h +@@ -1,5 +1,5 @@ +-/* The `struct utmp' type, describing entries in the utmp file. Generic/BSDish +- Copyright (C) 1993-2018 Free Software Foundation, Inc. ++/* The `struct utmp' type, describing entries in the utmp file. ++ Copyright (C) 1993-2019 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 +@@ -21,29 +21,106 @@ + #endif + + #include +-#include ++#include ++#include ++#include + + +-#define UT_NAMESIZE 8 +-#define UT_LINESIZE 8 +-#define UT_HOSTSIZE 16 ++#define UT_LINESIZE 32 ++#define UT_NAMESIZE 32 ++#define UT_HOSTSIZE 256 + + ++/* The structure describing an entry in the database of ++ previous logins. */ + struct lastlog + { +- time_t ll_time; ++#if __WORDSIZE_TIME64_COMPAT32 ++ int32_t ll_time; ++#else ++ __time_t ll_time; ++#endif + char ll_line[UT_LINESIZE]; + char ll_host[UT_HOSTSIZE]; + }; + +-struct utmp ++ ++/* The structure describing the status of a terminated process. This ++ type is used in `struct utmp' below. */ ++struct exit_status + { +- char ut_line[UT_LINESIZE]; +- char ut_user[UT_NAMESIZE]; +-#define ut_name ut_user +- char ut_host[UT_HOSTSIZE]; +- long int ut_time; ++ short int e_termination; /* Process termination status. */ ++ short int e_exit; /* Process exit status. */ + }; + + +-#define _HAVE_UT_HOST 1 /* We have the ut_host field. */ ++/* The structure describing an entry in the user accounting database. */ ++struct utmp ++{ ++ short int ut_type; /* Type of login. */ ++ pid_t ut_pid; /* Process ID of login process. */ ++ char ut_line[UT_LINESIZE] ++ __attribute_nonstring__; /* Devicename. */ ++ char ut_id[4]; /* Inittab ID. */ ++ char ut_user[UT_NAMESIZE] ++ __attribute_nonstring__; /* Username. */ ++ char ut_host[UT_HOSTSIZE] ++ __attribute_nonstring__; /* Hostname for remote login. */ ++ struct exit_status ut_exit; /* Exit status of a process marked ++ as DEAD_PROCESS. */ ++/* The ut_session and ut_tv fields must be the same size when compiled ++ 32- and 64-bit. This allows data files and shared memory to be ++ shared between 32- and 64-bit applications. */ ++#if __WORDSIZE_TIME64_COMPAT32 ++ int32_t ut_session; /* Session ID, used for windowing. */ ++ struct ++ { ++ int32_t tv_sec; /* Seconds. */ ++ int32_t tv_usec; /* Microseconds. */ ++ } ut_tv; /* Time entry was made. */ ++#else ++ long int ut_session; /* Session ID, used for windowing. */ ++ struct timeval ut_tv; /* Time entry was made. */ ++#endif ++ ++ int32_t ut_addr_v6[4]; /* Internet address of remote host. */ ++ char __glibc_reserved[20]; /* Reserved for future use. */ ++}; ++ ++/* Backwards compatibility hacks. */ ++#define ut_name ut_user ++#ifndef _NO_UT_TIME ++/* We have a problem here: `ut_time' is also used otherwise. Define ++ _NO_UT_TIME if the compiler complains. */ ++# define ut_time ut_tv.tv_sec ++#endif ++#define ut_xtime ut_tv.tv_sec ++#define ut_addr ut_addr_v6[0] ++ ++ ++/* Values for the `ut_type' field of a `struct utmp'. */ ++#define EMPTY 0 /* No valid user accounting information. */ ++ ++#define RUN_LVL 1 /* The system's runlevel. */ ++#define BOOT_TIME 2 /* Time of system boot. */ ++#define NEW_TIME 3 /* Time after system clock changed. */ ++#define OLD_TIME 4 /* Time when system clock changed. */ ++ ++#define INIT_PROCESS 5 /* Process spawned by the init process. */ ++#define LOGIN_PROCESS 6 /* Session leader of a logged in user. */ ++#define USER_PROCESS 7 /* Normal process. */ ++#define DEAD_PROCESS 8 /* Terminated process. */ ++ ++#define ACCOUNTING 9 ++ ++/* Old Linux name for the EMPTY type. */ ++#define UT_UNKNOWN EMPTY ++ ++ ++/* Tell the user that we have a modern system with UT_HOST, UT_PID, ++ UT_TYPE, UT_ID and UT_TV fields. */ ++#define _HAVE_UT_TYPE 1 ++#define _HAVE_UT_PID 1 ++#define _HAVE_UT_ID 1 ++#define _HAVE_UT_TV 1 ++#define _HAVE_UT_HOST 1 +diff --git a/login/getutid_r.c b/login/getutid_r.c +index 8cb6b16d735e8265..11b288e99be6ee50 100644 +--- a/login/getutid_r.c ++++ b/login/getutid_r.c +@@ -32,7 +32,6 @@ __libc_lock_define (extern, __libc_utmp_lock attribute_hidden) + int + __getutid_r (const struct utmp *id, struct utmp *buffer, struct utmp **result) + { +-#if (_HAVE_UT_ID - 0) && (_HAVE_UT_TYPE - 0) + int retval; + + /* Test whether ID has any of the legal types. */ +@@ -54,10 +53,6 @@ __getutid_r (const struct utmp *id, struct utmp *buffer, struct utmp **result) + __libc_lock_unlock (__libc_utmp_lock); + + return retval; +-#else /* !_HAVE_UT_ID && !_HAVE_UT_TYPE */ +- __set_errno (ENOSYS); +- return -1; +-#endif + } + libc_hidden_def (__getutid_r) + weak_alias (__getutid_r, getutid_r) +diff --git a/login/getutmp.c b/login/getutmp.c +index 481150d5ef5a0bf0..32468ecae699fbf7 100644 +--- a/login/getutmp.c ++++ b/login/getutmp.c +@@ -23,23 +23,11 @@ + void + getutmp (const struct utmpx *utmpx, struct utmp *utmp) + { +-#if _HAVE_UT_TYPE - 0 + utmp->ut_type = utmpx->ut_type; +-#endif +-#if _HAVE_UT_PID - 0 + utmp->ut_pid = utmpx->ut_pid; +-#endif + memcpy (utmp->ut_line, utmpx->ut_line, sizeof (utmp->ut_line)); + memcpy (utmp->ut_user, utmpx->ut_user, sizeof (utmp->ut_user)); +-#if _HAVE_UT_ID - 0 + memcpy (utmp->ut_id, utmpx->ut_id, sizeof (utmp->ut_id)); +-#endif +-#if _HAVE_UT_HOST - 0 + memcpy (utmp->ut_host, utmpx->ut_host, sizeof (utmp->ut_host)); +-#endif +-#if _HAVE_UT_TV - 0 + utmp->ut_tv = utmpx->ut_tv; +-#else +- utmp->ut_time = utmpx->ut_time; +-#endif + } +diff --git a/login/getutmpx.c b/login/getutmpx.c +index 34145fe8db71faf0..92a182698e2be438 100644 +--- a/login/getutmpx.c ++++ b/login/getutmpx.c +@@ -24,24 +24,11 @@ void + getutmpx (const struct utmp *utmp, struct utmpx *utmpx) + { + memset (utmpx, 0, sizeof (struct utmpx)); +- +-#if _HAVE_UT_TYPE - 0 + utmpx->ut_type = utmp->ut_type; +-#endif +-#if _HAVE_UT_PID - 0 + utmpx->ut_pid = utmp->ut_pid; +-#endif + memcpy (utmpx->ut_line, utmp->ut_line, sizeof (utmp->ut_line)); + memcpy (utmpx->ut_user, utmp->ut_user, sizeof (utmp->ut_user)); +-#if _HAVE_UT_ID - 0 + memcpy (utmpx->ut_id, utmp->ut_id, sizeof (utmp->ut_id)); +-#endif +-#if _HAVE_UT_HOST - 0 + memcpy (utmpx->ut_host, utmp->ut_host, sizeof (utmp->ut_host)); +-#endif +-#if _HAVE_UT_TV - 0 + utmpx->ut_tv = utmp->ut_tv; +-#else +- utmpx->ut_time = utmp->ut_time; +-#endif + } +diff --git a/login/login.c b/login/login.c +index 5d48cd487f237ca0..1729fc070fcc1e4b 100644 +--- a/login/login.c ++++ b/login/login.c +@@ -91,12 +91,8 @@ login (const struct utmp *ut) + struct utmp copy = *ut; + + /* Fill in those fields we supply. */ +-#if _HAVE_UT_TYPE - 0 + copy.ut_type = USER_PROCESS; +-#endif +-#if _HAVE_UT_PID - 0 + copy.ut_pid = getpid (); +-#endif + + /* Seek tty. */ + found_tty = tty_name (STDIN_FILENO, &tty, sizeof (_tty)); +diff --git a/login/logout.c b/login/logout.c +index d49bc4ecac9a8379..4d76ecf1b40d306a 100644 +--- a/login/logout.c ++++ b/login/logout.c +@@ -36,9 +36,7 @@ logout (const char *line) + setutent (); + + /* Fill in search information. */ +-#if _HAVE_UT_TYPE - 0 + tmp.ut_type = USER_PROCESS; +-#endif + strncpy (tmp.ut_line, line, sizeof tmp.ut_line); + + /* Read the record. */ +@@ -46,20 +44,12 @@ logout (const char *line) + { + /* Clear information about who & from where. */ + memset (ut->ut_name, '\0', sizeof ut->ut_name); +-#if _HAVE_UT_HOST - 0 + memset (ut->ut_host, '\0', sizeof ut->ut_host); +-#endif +-#if _HAVE_UT_TV - 0 + struct timeval tv; + __gettimeofday (&tv, NULL); + ut->ut_tv.tv_sec = tv.tv_sec; + ut->ut_tv.tv_usec = tv.tv_usec; +-#else +- ut->ut_time = time (NULL); +-#endif +-#if _HAVE_UT_TYPE - 0 + ut->ut_type = DEAD_PROCESS; +-#endif + + if (pututline (ut) != NULL) + result = 1; +diff --git a/login/logwtmp.c b/login/logwtmp.c +index a19da4ab5ef7a624..e0b52b23e3603b7c 100644 +--- a/login/logwtmp.c ++++ b/login/logwtmp.c +@@ -30,26 +30,16 @@ logwtmp (const char *line, const char *name, const char *host) + + /* Set information in new entry. */ + memset (&ut, 0, sizeof (ut)); +-#if _HAVE_UT_PID - 0 + ut.ut_pid = getpid (); +-#endif +-#if _HAVE_UT_TYPE - 0 + ut.ut_type = name[0] ? USER_PROCESS : DEAD_PROCESS; +-#endif + strncpy (ut.ut_line, line, sizeof ut.ut_line); + strncpy (ut.ut_name, name, sizeof ut.ut_name); +-#if _HAVE_UT_HOST - 0 + strncpy (ut.ut_host, host, sizeof ut.ut_host); +-#endif + +-#if _HAVE_UT_TV - 0 + struct timeval tv; + __gettimeofday (&tv, NULL); + ut.ut_tv.tv_sec = tv.tv_sec; + ut.ut_tv.tv_usec = tv.tv_usec; +-#else +- ut.ut_time = time (NULL); +-#endif + + updwtmp (_PATH_WTMP, &ut); + } +diff --git a/login/programs/utmpdump.c b/login/programs/utmpdump.c +index dccdb669f5fb9c74..1763e55af2f03d8d 100644 +--- a/login/programs/utmpdump.c ++++ b/login/programs/utmpdump.c +@@ -37,47 +37,11 @@ print_entry (struct utmp *up) + temp_tv.tv_sec = up->ut_tv.tv_sec; + temp_tv.tv_usec = up->ut_tv.tv_usec; + +- (printf) ( +- /* The format string. */ +-#if _HAVE_UT_TYPE +- "[%d] " +-#endif +-#if _HAVE_UT_PID +- "[%05d] " +-#endif +-#if _HAVE_UT_ID +- "[%-4.4s] " +-#endif +- "[%-8.8s] [%-12.12s]" +-#if _HAVE_UT_HOST +- " [%-16.16s]" +-#endif +- " [%-15.15s]" +-#if _HAVE_UT_TV +- " [%ld]" +-#endif +- "\n" +- /* The arguments. */ +-#if _HAVE_UT_TYPE +- , up->ut_type +-#endif +-#if _HAVE_UT_PID +- , up->ut_pid +-#endif +-#if _HAVE_UT_ID +- , up->ut_id +-#endif +- , up->ut_user, up->ut_line +-#if _HAVE_UT_HOST +- , up->ut_host +-#endif +-#if _HAVE_UT_TV +- , 4 + ctime (&temp_tv.tv_sec) +- , (long int) temp_tv.tv_usec +-#else +- , 4 + ctime (&up->ut_time) +-#endif +- ); ++ printf ("[%d] [%05d] [%-4.4s] [%-8.8s] [%-12.12s] [%-16.16s] [%-15.15s]" ++ " [%ld]\n", ++ up->ut_type, up->ut_pid, up->ut_id, up->ut_user, up->ut_line, ++ up->ut_host, 4 + ctime (&temp_tv.tv_sec), ++ (long int) temp_tv.tv_usec); + } + + int +diff --git a/login/tst-utmp.c b/login/tst-utmp.c +index 8cc7aafa89c0ea8c..49b0cbda2a719643 100644 +--- a/login/tst-utmp.c ++++ b/login/tst-utmp.c +@@ -39,8 +39,6 @@ + #endif + + +-#if defined UTMPX || _HAVE_UT_TYPE +- + /* Prototype for our test function. */ + static int do_test (int argc, char *argv[]); + +@@ -75,11 +73,7 @@ do_prepare (int argc, char *argv[]) + + struct utmp entry[] = + { +-#if defined UTMPX || _HAVE_UT_TV + #define UT(a) .ut_tv = { .tv_sec = (a)} +-#else +-#define UT(a) .ut_time = (a) +-#endif + + { .ut_type = BOOT_TIME, .ut_pid = 1, UT(1000) }, + { .ut_type = RUN_LVL, .ut_pid = 1, UT(2000) }, +@@ -167,11 +161,7 @@ simulate_login (const char *line, const char *user) + entry[n].ut_pid = (entry_pid += 27); + entry[n].ut_type = USER_PROCESS; + strncpy (entry[n].ut_user, user, sizeof (entry[n].ut_user)); +-#if defined UTMPX || _HAVE_UT_TV - 0 + entry[n].ut_tv.tv_sec = (entry_time += 1000); +-#else +- entry[n].ut_time = (entry_time += 1000); +-#endif + setutent (); + + if (pututline (&entry[n]) == NULL) +@@ -201,11 +191,7 @@ simulate_logout (const char *line) + { + entry[n].ut_type = DEAD_PROCESS; + strncpy (entry[n].ut_user, "", sizeof (entry[n].ut_user)); +-#if defined UTMPX || _HAVE_UT_TV - 0 + entry[n].ut_tv.tv_sec = (entry_time += 1000); +-#else +- entry[n].ut_time = (entry_time += 1000); +-#endif + setutent (); + + if (pututline (&entry[n]) == NULL) +@@ -390,14 +376,3 @@ do_test (int argc, char *argv[]) + + return result; + } +- +-#else +- +-/* No field 'ut_type' in struct utmp. */ +-int +-main (void) +-{ +- return 0; +-} +- +-#endif +diff --git a/login/utmp_file.c b/login/utmp_file.c +index 069e6d0452e333ad..da1baa6948d0eb39 100644 +--- a/login/utmp_file.c ++++ b/login/utmp_file.c +@@ -129,14 +129,7 @@ __libc_setutent (void) + file_offset = 0; + + /* Make sure the entry won't match. */ +-#if _HAVE_UT_TYPE - 0 + last_entry.ut_type = -1; +-#else +- last_entry.ut_line[0] = '\177'; +-# if _HAVE_UT_ID - 0 +- last_entry.ut_id[0] = '\0'; +-# endif +-#endif + + return 1; + } +@@ -201,7 +194,6 @@ internal_getut_r (const struct utmp *id, struct utmp *buffer, + LOCKING_FAILED (); + } + +-#if _HAVE_UT_TYPE - 0 + if (id->ut_type == RUN_LVL || id->ut_type == BOOT_TIME + || id->ut_type == OLD_TIME || id->ut_type == NEW_TIME) + { +@@ -225,7 +217,6 @@ internal_getut_r (const struct utmp *id, struct utmp *buffer, + } + } + else +-#endif /* _HAVE_UT_TYPE */ + { + /* Search for the next entry with the specified ID and with type + INIT_PROCESS, LOGIN_PROCESS, USER_PROCESS, or DEAD_PROCESS. */ +@@ -316,13 +307,10 @@ __libc_getutline_r (const struct utmp *line, struct utmp *buffer, + file_offset += sizeof (struct utmp); + + /* Stop if we found a user or login entry. */ +- if ( +-#if _HAVE_UT_TYPE - 0 +- (last_entry.ut_type == USER_PROCESS ++ if ((last_entry.ut_type == USER_PROCESS + || last_entry.ut_type == LOGIN_PROCESS) +- && +-#endif +- !strncmp (line->ut_line, last_entry.ut_line, sizeof line->ut_line)) ++ && (strncmp (line->ut_line, last_entry.ut_line, sizeof line->ut_line) ++ == 0)) + break; + } + +@@ -368,16 +356,12 @@ __libc_pututline (const struct utmp *data) + + /* Find the correct place to insert the data. */ + if (file_offset > 0 +- && ( +-#if _HAVE_UT_TYPE - 0 +- (last_entry.ut_type == data->ut_type ++ && ((last_entry.ut_type == data->ut_type + && (last_entry.ut_type == RUN_LVL + || last_entry.ut_type == BOOT_TIME + || last_entry.ut_type == OLD_TIME + || last_entry.ut_type == NEW_TIME)) +- || +-#endif +- __utmp_equal (&last_entry, data))) ++ || __utmp_equal (&last_entry, data))) + found = 1; + else + { +diff --git a/sysdeps/generic/utmp-equal.h b/sysdeps/generic/utmp-equal.h +index 8b5c2e2cd2c4cf95..39993af192ab66ce 100644 +--- a/sysdeps/generic/utmp-equal.h ++++ b/sysdeps/generic/utmp-equal.h +@@ -27,26 +27,16 @@ + static int + __utmp_equal (const struct utmp *entry, const struct utmp *match) + { +- return +- ( +-#if _HAVE_UT_TYPE - 0 +- (entry->ut_type == INIT_PROCESS +- || entry->ut_type == LOGIN_PROCESS +- || entry->ut_type == USER_PROCESS +- || entry->ut_type == DEAD_PROCESS) +- && +- (match->ut_type == INIT_PROCESS +- || match->ut_type == LOGIN_PROCESS +- || match->ut_type == USER_PROCESS +- || match->ut_type == DEAD_PROCESS) +- && +-#endif +-#if _HAVE_UT_ID - 0 +- (entry->ut_id[0] && match->ut_id[0] +- ? strncmp (entry->ut_id, match->ut_id, sizeof match->ut_id) == 0 +- : strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line) == 0) +-#else +- strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line) == 0 +-#endif +- ); ++ return (entry->ut_type == INIT_PROCESS ++ || entry->ut_type == LOGIN_PROCESS ++ || entry->ut_type == USER_PROCESS ++ || entry->ut_type == DEAD_PROCESS) ++ && (match->ut_type == INIT_PROCESS ++ || match->ut_type == LOGIN_PROCESS ++ || match->ut_type == USER_PROCESS ++ || match->ut_type == DEAD_PROCESS) ++ && (entry->ut_id[0] && match->ut_id[0] ++ ? strncmp (entry->ut_id, match->ut_id, sizeof match->ut_id) == 0 ++ : (strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line) ++ == 0)); + } +diff --git a/sysdeps/gnu/bits/utmp.h b/sysdeps/gnu/bits/utmp.h +deleted file mode 100644 +index 47a6082eacc56b4d..0000000000000000 +--- a/sysdeps/gnu/bits/utmp.h ++++ /dev/null +@@ -1,126 +0,0 @@ +-/* The `struct utmp' type, describing entries in the utmp file. GNU version. +- Copyright (C) 1993-2018 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 +- . */ +- +-#ifndef _UTMP_H +-# error "Never include directly; use instead." +-#endif +- +-#include +-#include +-#include +-#include +- +- +-#define UT_LINESIZE 32 +-#define UT_NAMESIZE 32 +-#define UT_HOSTSIZE 256 +- +- +-/* The structure describing an entry in the database of +- previous logins. */ +-struct lastlog +- { +-#if __WORDSIZE_TIME64_COMPAT32 +- int32_t ll_time; +-#else +- __time_t ll_time; +-#endif +- char ll_line[UT_LINESIZE]; +- char ll_host[UT_HOSTSIZE]; +- }; +- +- +-/* The structure describing the status of a terminated process. This +- type is used in `struct utmp' below. */ +-struct exit_status +- { +- short int e_termination; /* Process termination status. */ +- short int e_exit; /* Process exit status. */ +- }; +- +- +-/* The structure describing an entry in the user accounting database. */ +-struct utmp +-{ +- short int ut_type; /* Type of login. */ +- pid_t ut_pid; /* Process ID of login process. */ +- char ut_line[UT_LINESIZE] +- __attribute_nonstring__; /* Devicename. */ +- char ut_id[4]; /* Inittab ID. */ +- char ut_user[UT_NAMESIZE] +- __attribute_nonstring__; /* Username. */ +- char ut_host[UT_HOSTSIZE] +- __attribute_nonstring__; /* Hostname for remote login. */ +- struct exit_status ut_exit; /* Exit status of a process marked +- as DEAD_PROCESS. */ +-/* The ut_session and ut_tv fields must be the same size when compiled +- 32- and 64-bit. This allows data files and shared memory to be +- shared between 32- and 64-bit applications. */ +-#if __WORDSIZE_TIME64_COMPAT32 +- int32_t ut_session; /* Session ID, used for windowing. */ +- struct +- { +- int32_t tv_sec; /* Seconds. */ +- int32_t tv_usec; /* Microseconds. */ +- } ut_tv; /* Time entry was made. */ +-#else +- long int ut_session; /* Session ID, used for windowing. */ +- struct timeval ut_tv; /* Time entry was made. */ +-#endif +- +- int32_t ut_addr_v6[4]; /* Internet address of remote host. */ +- char __glibc_reserved[20]; /* Reserved for future use. */ +-}; +- +-/* Backwards compatibility hacks. */ +-#define ut_name ut_user +-#ifndef _NO_UT_TIME +-/* We have a problem here: `ut_time' is also used otherwise. Define +- _NO_UT_TIME if the compiler complains. */ +-# define ut_time ut_tv.tv_sec +-#endif +-#define ut_xtime ut_tv.tv_sec +-#define ut_addr ut_addr_v6[0] +- +- +-/* Values for the `ut_type' field of a `struct utmp'. */ +-#define EMPTY 0 /* No valid user accounting information. */ +- +-#define RUN_LVL 1 /* The system's runlevel. */ +-#define BOOT_TIME 2 /* Time of system boot. */ +-#define NEW_TIME 3 /* Time after system clock changed. */ +-#define OLD_TIME 4 /* Time when system clock changed. */ +- +-#define INIT_PROCESS 5 /* Process spawned by the init process. */ +-#define LOGIN_PROCESS 6 /* Session leader of a logged in user. */ +-#define USER_PROCESS 7 /* Normal process. */ +-#define DEAD_PROCESS 8 /* Terminated process. */ +- +-#define ACCOUNTING 9 +- +-/* Old Linux name for the EMPTY type. */ +-#define UT_UNKNOWN EMPTY +- +- +-/* Tell the user that we have a modern system with UT_HOST, UT_PID, +- UT_TYPE, UT_ID and UT_TV fields. */ +-#define _HAVE_UT_TYPE 1 +-#define _HAVE_UT_PID 1 +-#define _HAVE_UT_ID 1 +-#define _HAVE_UT_TV 1 +-#define _HAVE_UT_HOST 1 diff --git a/SOURCES/glibc-rh1749439-3.patch b/SOURCES/glibc-rh1749439-3.patch new file mode 100644 index 0000000..7a18d19 --- /dev/null +++ b/SOURCES/glibc-rh1749439-3.patch @@ -0,0 +1,260 @@ +commit 5a3afa9738f3dbbaf8c0a35665318c1af782111b +Author: Florian Weimer +Date: Tue Aug 13 15:53:19 2019 +0200 + + login: Replace macro-based control flow with function calls in utmp + +diff --git a/login/utmp_file.c b/login/utmp_file.c +index da1baa6948d0eb39..812de8fd3d099ce9 100644 +--- a/login/utmp_file.c ++++ b/login/utmp_file.c +@@ -52,58 +52,71 @@ static struct utmp last_entry; + /* Do-nothing handler for locking timeout. */ + static void timeout_handler (int signum) {}; + +-/* LOCK_FILE(fd, type) failure_statement +- attempts to get a lock on the utmp file referenced by FD. If it fails, +- the failure_statement is executed, otherwise it is skipped. +- LOCKING_FAILED() +- jumps into the UNLOCK_FILE macro and ensures cleanup of LOCK_FILE. +- UNLOCK_FILE(fd) +- unlocks the utmp file referenced by FD and performs the cleanup of +- LOCK_FILE. +- */ +-#define LOCK_FILE(fd, type) \ +-{ \ +- struct flock fl; \ +- struct sigaction action, old_action; \ +- unsigned int old_timeout; \ +- \ +- /* Cancel any existing alarm. */ \ +- old_timeout = alarm (0); \ +- \ +- /* Establish signal handler. */ \ +- action.sa_handler = timeout_handler; \ +- __sigemptyset (&action.sa_mask); \ +- action.sa_flags = 0; \ +- __sigaction (SIGALRM, &action, &old_action); \ +- \ +- alarm (TIMEOUT); \ +- \ +- /* Try to get the lock. */ \ +- memset (&fl, '\0', sizeof (struct flock)); \ +- fl.l_type = (type); \ +- fl.l_whence = SEEK_SET; \ +- if (__fcntl64_nocancel ((fd), F_SETLKW, &fl) < 0) +- +-#define LOCKING_FAILED() \ +- goto unalarm_return +- +-#define UNLOCK_FILE(fd) \ +- /* Unlock the file. */ \ +- fl.l_type = F_UNLCK; \ +- __fcntl64_nocancel ((fd), F_SETLKW, &fl); \ +- \ +- unalarm_return: \ +- /* Reset the signal handler and alarm. We must reset the alarm \ +- before resetting the handler so our alarm does not generate a \ +- spurious SIGALRM seen by the user. However, we cannot just set \ +- the user's old alarm before restoring the handler, because then \ +- it's possible our handler could catch the user alarm's SIGARLM \ +- and then the user would never see the signal he expected. */ \ +- alarm (0); \ +- __sigaction (SIGALRM, &old_action, NULL); \ +- if (old_timeout != 0) \ +- alarm (old_timeout); \ +-} while (0) ++ ++/* try_file_lock (LOCKING, FD, TYPE) returns true if the locking ++ operation failed and recovery needs to be performed. ++ (file_lock_restore (LOCKING) still needs to be called.) ++ ++ file_unlock (FD) removes the lock (which must have been ++ acquired). ++ ++ file_lock_restore (LOCKING) is needed to clean up in both ++ cases. */ ++ ++struct file_locking ++{ ++ struct sigaction old_action; ++ unsigned int old_timeout; ++}; ++ ++static bool ++try_file_lock (struct file_locking *locking, int fd, int type) ++{ ++ /* Cancel any existing alarm. */ ++ locking->old_timeout = alarm (0); ++ ++ /* Establish signal handler. */ ++ struct sigaction action; ++ action.sa_handler = timeout_handler; ++ __sigemptyset (&action.sa_mask); ++ action.sa_flags = 0; ++ __sigaction (SIGALRM, &action, &locking->old_action); ++ ++ alarm (TIMEOUT); ++ ++ /* Try to get the lock. */ ++ struct flock fl = ++ { ++ .l_type = type, ++ fl.l_whence = SEEK_SET, ++ }; ++ return __fcntl64_nocancel (fd, F_SETLKW, &fl) < 0; ++} ++ ++static void ++file_unlock (int fd) ++{ ++ struct flock fl = ++ { ++ .l_type = F_UNLCK, ++ }; ++ __fcntl64_nocancel (fd, F_SETLKW, &fl); ++} ++ ++static void ++file_lock_restore (struct file_locking *locking) ++{ ++ /* Reset the signal handler and alarm. We must reset the alarm ++ before resetting the handler so our alarm does not generate a ++ spurious SIGALRM seen by the user. However, we cannot just set ++ the user's old alarm before restoring the handler, because then ++ it's possible our handler could catch the user alarm's SIGARLM ++ and then the user would never see the signal he expected. */ ++ alarm (0); ++ __sigaction (SIGALRM, &locking->old_action, NULL); ++ if (locking->old_timeout != 0) ++ alarm (locking->old_timeout); ++} + + #ifndef TRANSFORM_UTMP_FILE_NAME + # define TRANSFORM_UTMP_FILE_NAME(file_name) (file_name) +@@ -153,16 +166,16 @@ __libc_getutent_r (struct utmp *buffer, struct utmp **result) + return -1; + } + +- LOCK_FILE (file_fd, F_RDLCK) ++ struct file_locking fl; ++ if (try_file_lock (&fl, file_fd, F_RDLCK)) ++ nbytes = 0; ++ else + { +- nbytes = 0; +- LOCKING_FAILED (); ++ /* Read the next entry. */ ++ nbytes = __read_nocancel (file_fd, &last_entry, sizeof (struct utmp)); ++ file_unlock (file_fd); + } +- +- /* Read the next entry. */ +- nbytes = __read_nocancel (file_fd, &last_entry, sizeof (struct utmp)); +- +- UNLOCK_FILE (file_fd); ++ file_lock_restore (&fl); + + if (nbytes != sizeof (struct utmp)) + { +@@ -188,10 +201,12 @@ internal_getut_r (const struct utmp *id, struct utmp *buffer, + { + int result = -1; + +- LOCK_FILE (file_fd, F_RDLCK) ++ struct file_locking fl; ++ if (try_file_lock (&fl, file_fd, F_RDLCK)) + { + *lock_failed = true; +- LOCKING_FAILED (); ++ file_lock_restore (&fl); ++ return -1; + } + + if (id->ut_type == RUN_LVL || id->ut_type == BOOT_TIME +@@ -241,7 +256,8 @@ internal_getut_r (const struct utmp *id, struct utmp *buffer, + result = 0; + + unlock_return: +- UNLOCK_FILE (file_fd); ++ file_unlock (file_fd); ++ file_lock_restore (&fl); + + return result; + } +@@ -287,10 +303,12 @@ __libc_getutline_r (const struct utmp *line, struct utmp *buffer, + return -1; + } + +- LOCK_FILE (file_fd, F_RDLCK) ++ struct file_locking fl; ++ if (try_file_lock (&fl, file_fd, F_RDLCK)) + { + *result = NULL; +- LOCKING_FAILED (); ++ file_lock_restore (&fl); ++ return -1; + } + + while (1) +@@ -318,7 +336,8 @@ __libc_getutline_r (const struct utmp *line, struct utmp *buffer, + *result = buffer; + + unlock_return: +- UNLOCK_FILE (file_fd); ++ file_unlock (file_fd); ++ file_lock_restore (&fl); + + return ((*result == NULL) ? -1 : 0); + } +@@ -375,10 +394,11 @@ __libc_pututline (const struct utmp *data) + } + } + +- LOCK_FILE (file_fd, F_WRLCK) ++ struct file_locking fl; ++ if (try_file_lock (&fl, file_fd, F_WRLCK)) + { +- pbuf = NULL; +- LOCKING_FAILED (); ++ file_lock_restore (&fl); ++ return NULL; + } + + if (found < 0) +@@ -421,7 +441,8 @@ __libc_pututline (const struct utmp *data) + } + + unlock_return: +- UNLOCK_FILE (file_fd); ++ file_unlock (file_fd); ++ file_lock_restore (&fl); + + return pbuf; + } +@@ -450,8 +471,13 @@ __libc_updwtmp (const char *file, const struct utmp *utmp) + if (fd < 0) + return -1; + +- LOCK_FILE (fd, F_WRLCK) +- LOCKING_FAILED (); ++ struct file_locking fl; ++ if (try_file_lock (&fl, fd, F_WRLCK)) ++ { ++ file_lock_restore (&fl); ++ __close_nocancel_nostatus (fd); ++ return -1; ++ } + + /* Remember original size of log file. */ + offset = __lseek64 (fd, 0, SEEK_END); +@@ -477,7 +503,8 @@ __libc_updwtmp (const char *file, const struct utmp *utmp) + result = 0; + + unlock_return: +- UNLOCK_FILE (fd); ++ file_unlock (file_fd); ++ file_lock_restore (&fl); + + /* Close WTMP file. */ + __close_nocancel_nostatus (fd); diff --git a/SOURCES/glibc-rh1749439-4.patch b/SOURCES/glibc-rh1749439-4.patch new file mode 100644 index 0000000..b2c7972 --- /dev/null +++ b/SOURCES/glibc-rh1749439-4.patch @@ -0,0 +1,155 @@ +commit 341da5b4b6253de9a7581a066f33f89cacb44dec +Author: Florian Weimer +Date: Thu Aug 15 10:30:23 2019 +0200 + + login: Fix updwtmp, updwtmx unlocking + + Commit 5a3afa9738f3dbbaf8c0a35665318c1af782111b (login: Replace + macro-based control flow with function calls in utmp) introduced + a regression because after it, __libc_updwtmp attempts to unlock + the wrong file descriptor. + +diff --git a/login/Makefile b/login/Makefile +index 8b31991be835fa8e..81986ab6bd8560ea 100644 +--- a/login/Makefile ++++ b/login/Makefile +@@ -43,7 +43,7 @@ endif + subdir-dirs = programs + vpath %.c programs + +-tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname tst-getlogin ++tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname tst-getlogin tst-updwtmpx + + # Build the -lutil library with these extra functions. + extra-libs := libutil +diff --git a/login/tst-updwtmpx.c b/login/tst-updwtmpx.c +new file mode 100644 +index 0000000000000000..0a4a27daeb0440fd +--- /dev/null ++++ b/login/tst-updwtmpx.c +@@ -0,0 +1,112 @@ ++/* Basic test coverage for updwtmpx. ++ Copyright (C) 2019 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; see the file COPYING.LIB. If ++ not, see . */ ++ ++/* This program runs a series of tests. Each one calls updwtmpx ++ twice, to write two records, optionally with misalignment in the ++ file, and reads back the results. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ /* Two entries filled with an arbitrary bit pattern. */ ++ struct utmpx entries[2]; ++ unsigned char pad; ++ { ++ unsigned char *p = (unsigned char *) &entries[0]; ++ for (size_t i = 0; i < sizeof (entries); ++i) ++ { ++ p[i] = i; ++ } ++ /* Make sure that the first and second entry and the padding are ++ different. */ ++ p[sizeof (struct utmpx)] = p[0] + 1; ++ pad = p[0] + 2; ++ } ++ ++ char *path; ++ int fd = create_temp_file ("tst-updwtmpx-", &path); ++ ++ /* Used to check that updwtmpx does not leave an open file ++ descriptor around. */ ++ struct support_descriptors *descriptors = support_descriptors_list (); ++ ++ /* updwtmpx is expected to remove misalignment. Optionally insert ++ one byte of misalignment at the start and in the middle (after ++ the first entry). */ ++ for (int misaligned_start = 0; misaligned_start < 2; ++misaligned_start) ++ for (int misaligned_middle = 0; misaligned_middle < 2; ++misaligned_middle) ++ { ++ if (test_verbose > 0) ++ printf ("info: misaligned_start=%d misaligned_middle=%d\n", ++ misaligned_start, misaligned_middle); ++ ++ xftruncate (fd, 0); ++ TEST_COMPARE (pwrite64 (fd, &pad, misaligned_start, 0), ++ misaligned_start); ++ ++ /* Write first entry and check it. */ ++ errno = 0; ++ updwtmpx (path, &entries[0]); ++ TEST_COMPARE (errno, 0); ++ support_descriptors_check (descriptors); ++ TEST_COMPARE (xlseek (fd, 0, SEEK_END), sizeof (struct utmpx)); ++ struct utmpx buffer; ++ TEST_COMPARE (pread64 (fd, &buffer, sizeof (buffer), 0), ++ sizeof (buffer)); ++ TEST_COMPARE_BLOB (&entries[0], sizeof (entries[0]), ++ &buffer, sizeof (buffer)); ++ ++ /* Middle mis-alignmet. */ ++ TEST_COMPARE (pwrite64 (fd, &pad, misaligned_middle, ++ sizeof (struct utmpx)), misaligned_middle); ++ ++ /* Write second entry and check both entries. */ ++ errno = 0; ++ updwtmpx (path, &entries[1]); ++ TEST_COMPARE (errno, 0); ++ support_descriptors_check (descriptors); ++ TEST_COMPARE (xlseek (fd, 0, SEEK_END), 2 * sizeof (struct utmpx)); ++ TEST_COMPARE (pread64 (fd, &buffer, sizeof (buffer), 0), ++ sizeof (buffer)); ++ TEST_COMPARE_BLOB (&entries[0], sizeof (entries[0]), ++ &buffer, sizeof (buffer)); ++ TEST_COMPARE (pread64 (fd, &buffer, sizeof (buffer), sizeof (buffer)), ++ sizeof (buffer)); ++ TEST_COMPARE_BLOB (&entries[1], sizeof (entries[1]), ++ &buffer, sizeof (buffer)); ++ } ++ ++ support_descriptors_free (descriptors); ++ free (path); ++ xclose (fd); ++ ++ return 0; ++} ++ ++#include +diff --git a/login/utmp_file.c b/login/utmp_file.c +index 812de8fd3d099ce9..54f424fd6165bae7 100644 +--- a/login/utmp_file.c ++++ b/login/utmp_file.c +@@ -503,7 +503,7 @@ __libc_updwtmp (const char *file, const struct utmp *utmp) + result = 0; + + unlock_return: +- file_unlock (file_fd); ++ file_unlock (fd); + file_lock_restore (&fl); + + /* Close WTMP file. */ diff --git a/SOURCES/glibc-rh1749439-5.patch b/SOURCES/glibc-rh1749439-5.patch new file mode 100644 index 0000000..b9cfe31 --- /dev/null +++ b/SOURCES/glibc-rh1749439-5.patch @@ -0,0 +1,33 @@ +commit 0d5b2917530ccaf8ad312dfbb7bce69d569c23ad +Author: Florian Weimer +Date: Thu Aug 15 16:09:20 2019 +0200 + + login: Use struct flock64 in utmp [BZ #24880] + + Commit 06ab719d30b01da401150068054d3b8ea93dd12f ("Fix Linux fcntl OFD + locks for non-LFS architectures (BZ#20251)") introduced the use of + fcntl64 into the utmp implementation. However, the lock file + structure was not updated to struct flock64 at that point. + +diff --git a/login/utmp_file.c b/login/utmp_file.c +index 54f424fd6165bae7..8b6fee96b623fa90 100644 +--- a/login/utmp_file.c ++++ b/login/utmp_file.c +@@ -85,7 +85,7 @@ try_file_lock (struct file_locking *locking, int fd, int type) + alarm (TIMEOUT); + + /* Try to get the lock. */ +- struct flock fl = ++ struct flock64 fl = + { + .l_type = type, + fl.l_whence = SEEK_SET, +@@ -96,7 +96,7 @@ try_file_lock (struct file_locking *locking, int fd, int type) + static void + file_unlock (int fd) + { +- struct flock fl = ++ struct flock64 fl = + { + .l_type = F_UNLCK, + }; diff --git a/SOURCES/glibc-rh1749439-6.patch b/SOURCES/glibc-rh1749439-6.patch new file mode 100644 index 0000000..3a8ad22 --- /dev/null +++ b/SOURCES/glibc-rh1749439-6.patch @@ -0,0 +1,204 @@ +commit 628598be7e1bfaa04f34df71ef6678f2c5103dfd +Author: Florian Weimer +Date: Thu Aug 15 16:09:05 2019 +0200 + + login: Disarm timer after utmp lock acquisition [BZ #24879] + + If the file processing takes a long time for some reason, SIGALRM can + arrive while the file is still being processed. At that point, file + access will fail with EINTR. Disarming the timer after lock + acquisition avoids that. (If there was a previous alarm, it is the + responsibility of the caller to deal with the EINTR error.) + +diff --git a/login/utmp_file.c b/login/utmp_file.c +index 8b6fee96b623fa90..a736d3d25e005920 100644 +--- a/login/utmp_file.c ++++ b/login/utmp_file.c +@@ -55,32 +55,23 @@ static void timeout_handler (int signum) {}; + + /* try_file_lock (LOCKING, FD, TYPE) returns true if the locking + operation failed and recovery needs to be performed. +- (file_lock_restore (LOCKING) still needs to be called.) + + file_unlock (FD) removes the lock (which must have been +- acquired). +- +- file_lock_restore (LOCKING) is needed to clean up in both +- cases. */ +- +-struct file_locking +-{ +- struct sigaction old_action; +- unsigned int old_timeout; +-}; ++ successfully acquired). */ + + static bool +-try_file_lock (struct file_locking *locking, int fd, int type) ++try_file_lock (int fd, int type) + { + /* Cancel any existing alarm. */ +- locking->old_timeout = alarm (0); ++ int old_timeout = alarm (0); + + /* Establish signal handler. */ ++ struct sigaction old_action; + struct sigaction action; + action.sa_handler = timeout_handler; + __sigemptyset (&action.sa_mask); + action.sa_flags = 0; +- __sigaction (SIGALRM, &action, &locking->old_action); ++ __sigaction (SIGALRM, &action, &old_action); + + alarm (TIMEOUT); + +@@ -90,7 +81,23 @@ try_file_lock (struct file_locking *locking, int fd, int type) + .l_type = type, + fl.l_whence = SEEK_SET, + }; +- return __fcntl64_nocancel (fd, F_SETLKW, &fl) < 0; ++ ++ bool status = __fcntl64_nocancel (fd, F_SETLKW, &fl) < 0; ++ int saved_errno = errno; ++ ++ /* Reset the signal handler and alarm. We must reset the alarm ++ before resetting the handler so our alarm does not generate a ++ spurious SIGALRM seen by the user. However, we cannot just set ++ the user's old alarm before restoring the handler, because then ++ it's possible our handler could catch the user alarm's SIGARLM and ++ then the user would never see the signal he expected. */ ++ alarm (0); ++ __sigaction (SIGALRM, &old_action, NULL); ++ if (old_timeout != 0) ++ alarm (old_timeout); ++ ++ __set_errno (saved_errno); ++ return status; + } + + static void +@@ -103,21 +110,6 @@ file_unlock (int fd) + __fcntl64_nocancel (fd, F_SETLKW, &fl); + } + +-static void +-file_lock_restore (struct file_locking *locking) +-{ +- /* Reset the signal handler and alarm. We must reset the alarm +- before resetting the handler so our alarm does not generate a +- spurious SIGALRM seen by the user. However, we cannot just set +- the user's old alarm before restoring the handler, because then +- it's possible our handler could catch the user alarm's SIGARLM +- and then the user would never see the signal he expected. */ +- alarm (0); +- __sigaction (SIGALRM, &locking->old_action, NULL); +- if (locking->old_timeout != 0) +- alarm (locking->old_timeout); +-} +- + #ifndef TRANSFORM_UTMP_FILE_NAME + # define TRANSFORM_UTMP_FILE_NAME(file_name) (file_name) + #endif +@@ -166,8 +158,7 @@ __libc_getutent_r (struct utmp *buffer, struct utmp **result) + return -1; + } + +- struct file_locking fl; +- if (try_file_lock (&fl, file_fd, F_RDLCK)) ++ if (try_file_lock (file_fd, F_RDLCK)) + nbytes = 0; + else + { +@@ -175,7 +166,6 @@ __libc_getutent_r (struct utmp *buffer, struct utmp **result) + nbytes = __read_nocancel (file_fd, &last_entry, sizeof (struct utmp)); + file_unlock (file_fd); + } +- file_lock_restore (&fl); + + if (nbytes != sizeof (struct utmp)) + { +@@ -201,11 +191,9 @@ internal_getut_r (const struct utmp *id, struct utmp *buffer, + { + int result = -1; + +- struct file_locking fl; +- if (try_file_lock (&fl, file_fd, F_RDLCK)) ++ if (try_file_lock (file_fd, F_RDLCK)) + { + *lock_failed = true; +- file_lock_restore (&fl); + return -1; + } + +@@ -257,7 +245,6 @@ internal_getut_r (const struct utmp *id, struct utmp *buffer, + + unlock_return: + file_unlock (file_fd); +- file_lock_restore (&fl); + + return result; + } +@@ -303,11 +290,9 @@ __libc_getutline_r (const struct utmp *line, struct utmp *buffer, + return -1; + } + +- struct file_locking fl; +- if (try_file_lock (&fl, file_fd, F_RDLCK)) ++ if (try_file_lock (file_fd, F_RDLCK)) + { + *result = NULL; +- file_lock_restore (&fl); + return -1; + } + +@@ -337,7 +322,6 @@ __libc_getutline_r (const struct utmp *line, struct utmp *buffer, + + unlock_return: + file_unlock (file_fd); +- file_lock_restore (&fl); + + return ((*result == NULL) ? -1 : 0); + } +@@ -394,12 +378,8 @@ __libc_pututline (const struct utmp *data) + } + } + +- struct file_locking fl; +- if (try_file_lock (&fl, file_fd, F_WRLCK)) +- { +- file_lock_restore (&fl); +- return NULL; +- } ++ if (try_file_lock (file_fd, F_WRLCK)) ++ return NULL; + + if (found < 0) + { +@@ -442,7 +422,6 @@ __libc_pututline (const struct utmp *data) + + unlock_return: + file_unlock (file_fd); +- file_lock_restore (&fl); + + return pbuf; + } +@@ -471,10 +450,8 @@ __libc_updwtmp (const char *file, const struct utmp *utmp) + if (fd < 0) + return -1; + +- struct file_locking fl; +- if (try_file_lock (&fl, fd, F_WRLCK)) ++ if (try_file_lock (fd, F_WRLCK)) + { +- file_lock_restore (&fl); + __close_nocancel_nostatus (fd); + return -1; + } +@@ -504,7 +481,6 @@ __libc_updwtmp (const char *file, const struct utmp *utmp) + + unlock_return: + file_unlock (fd); +- file_lock_restore (&fl); + + /* Close WTMP file. */ + __close_nocancel_nostatus (fd); diff --git a/SOURCES/glibc-rh1749439-7.patch b/SOURCES/glibc-rh1749439-7.patch new file mode 100644 index 0000000..370dab2 --- /dev/null +++ b/SOURCES/glibc-rh1749439-7.patch @@ -0,0 +1,309 @@ +commit 61d3db428176d9d0822e4e680305fe34285edff2 +Author: Florian Weimer +Date: Wed Aug 28 11:59:45 2019 +0200 + + login: pututxline could fail to overwrite existing entries [BZ #24902] + + The internal_getut_r function updates the file_offset variable and + therefore must always update last_entry as well. + + Previously, if pututxline could not upgrade the read lock to a + write lock, internal_getut_r would update file_offset only, + without updating last_entry, and a subsequent call would not + overwrite the existing utmpx entry at file_offset, instead + creating a new entry. This has been observed to cause unbounded + file growth in high-load situations. + + This commit removes the buffer argument to internal_getut_r and + updates the last_entry variable directly, along with file_offset. + + Initially reported and fixed by Ondřej Lysoněk. + + Reviewed-by: Gabriel F. T. Gomes + +diff --git a/login/Makefile b/login/Makefile +index 81986ab6bd8560ea..82132c83fd799357 100644 +--- a/login/Makefile ++++ b/login/Makefile +@@ -43,7 +43,8 @@ endif + subdir-dirs = programs + vpath %.c programs + +-tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname tst-getlogin tst-updwtmpx ++tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname tst-getlogin tst-updwtmpx \ ++ tst-pututxline-lockfail + + # Build the -lutil library with these extra functions. + extra-libs := libutil +@@ -71,3 +72,5 @@ endif + $(inst_libexecdir)/pt_chown: $(objpfx)pt_chown $(+force) + $(make-target-directory) + -$(INSTALL_PROGRAM) -m 4755 -o root $< $@ ++ ++$(objpfx)tst-pututxline-lockfail: $(shared-thread-library) +diff --git a/login/tst-pututxline-lockfail.c b/login/tst-pututxline-lockfail.c +new file mode 100644 +index 0000000000000000..47c25dc0658d3c60 +--- /dev/null ++++ b/login/tst-pututxline-lockfail.c +@@ -0,0 +1,176 @@ ++/* Test the lock upgrade path in tst-pututxline. ++ Copyright (C) 2019 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; see the file COPYING.LIB. If ++ not, see . */ ++ ++/* pututxline upgrades the read lock on the file to a write lock. ++ This test verifies that if the lock upgrade fails, the utmp ++ subsystem remains in a consistent state, so that pututxline can be ++ called again. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Path to the temporary utmp file. */ ++static char *path; ++ ++/* Used to synchronize the subprocesses. The barrier itself is ++ allocated in shared memory. */ ++static pthread_barrier_t *barrier; ++ ++/* Use pututxline to write an entry for PID. */ ++static struct utmpx * ++write_entry (pid_t pid) ++{ ++ struct utmpx ut = ++ { ++ .ut_type = LOGIN_PROCESS, ++ .ut_id = "1", ++ .ut_user = "root", ++ .ut_pid = pid, ++ .ut_line = "entry", ++ .ut_host = "localhost", ++ }; ++ return pututxline (&ut); ++} ++ ++/* Create the initial entry in a subprocess, so that the utmp ++ subsystem in the original process is not disturbed. */ ++static void ++subprocess_create_entry (void *closure) ++{ ++ TEST_COMPARE (utmpname (path), 0); ++ TEST_VERIFY (write_entry (101) != NULL); ++} ++ ++/* Acquire an advisory read lock on PATH. */ ++__attribute__ ((noreturn)) static void ++subprocess_lock_file (void) ++{ ++ int fd = xopen (path, O_RDONLY, 0); ++ ++ struct flock64 fl = ++ { ++ .l_type = F_RDLCK, ++ fl.l_whence = SEEK_SET, ++ }; ++ TEST_COMPARE (fcntl64 (fd, F_SETLKW, &fl), 0); ++ ++ /* Signal to the main process that the lock has been acquired. */ ++ xpthread_barrier_wait (barrier); ++ ++ /* Wait for the unlock request from the main process. */ ++ xpthread_barrier_wait (barrier); ++ ++ /* Implicitly unlock the file. */ ++ xclose (fd); ++ ++ /* Overwrite the existing entry. */ ++ TEST_COMPARE (utmpname (path), 0); ++ errno = 0; ++ setutxent (); ++ TEST_COMPARE (errno, 0); ++ TEST_VERIFY (write_entry (102) != NULL); ++ errno = 0; ++ endutxent (); ++ TEST_COMPARE (errno, 0); ++ ++ _exit (0); ++} ++ ++static int ++do_test (void) ++{ ++ xclose (create_temp_file ("tst-pututxline-lockfail-", &path)); ++ ++ { ++ pthread_barrierattr_t attr; ++ xpthread_barrierattr_init (&attr); ++ xpthread_barrierattr_setpshared (&attr, PTHREAD_SCOPE_PROCESS); ++ barrier = support_shared_allocate (sizeof (*barrier)); ++ xpthread_barrier_init (barrier, &attr, 2); ++ xpthread_barrierattr_destroy (&attr); ++ } ++ ++ /* Write the initial entry. */ ++ support_isolate_in_subprocess (subprocess_create_entry, NULL); ++ ++ pid_t locker_pid = xfork (); ++ if (locker_pid == 0) ++ subprocess_lock_file (); ++ ++ /* Wait for the file locking to complete. */ ++ xpthread_barrier_wait (barrier); ++ ++ /* Try to add another entry. This attempt will fail, with EINTR or ++ EAGAIN. */ ++ TEST_COMPARE (utmpname (path), 0); ++ TEST_VERIFY (write_entry (102) == NULL); ++ if (errno != EINTR) ++ TEST_COMPARE (errno, EAGAIN); ++ ++ /* Signal the subprocess to overwrite the entry. */ ++ xpthread_barrier_wait (barrier); ++ ++ /* Wait for write and unlock to complete. */ ++ { ++ int status; ++ xwaitpid (locker_pid, &status, 0); ++ TEST_COMPARE (status, 0); ++ } ++ ++ /* The file is no longer locked, so this operation will succeed. */ ++ TEST_VERIFY (write_entry (103) != NULL); ++ errno = 0; ++ endutxent (); ++ TEST_COMPARE (errno, 0); ++ ++ /* Check that there is just one entry with the expected contents. ++ If pututxline becomes desynchronized internally, the entry is not ++ overwritten (bug 24902). */ ++ errno = 0; ++ setutxent (); ++ TEST_COMPARE (errno, 0); ++ struct utmpx *ut = getutxent (); ++ TEST_VERIFY_EXIT (ut != NULL); ++ TEST_COMPARE (ut->ut_type, LOGIN_PROCESS); ++ TEST_COMPARE_STRING (ut->ut_id, "1"); ++ TEST_COMPARE_STRING (ut->ut_user, "root"); ++ TEST_COMPARE (ut->ut_pid, 103); ++ TEST_COMPARE_STRING (ut->ut_line, "entry"); ++ TEST_COMPARE_STRING (ut->ut_host, "localhost"); ++ TEST_VERIFY (getutxent () == NULL); ++ errno = 0; ++ endutxent (); ++ TEST_COMPARE (errno, 0); ++ ++ xpthread_barrier_destroy (barrier); ++ support_shared_free (barrier); ++ free (path); ++ return 0; ++} ++ ++#include +diff --git a/login/utmp_file.c b/login/utmp_file.c +index a736d3d25e005920..cbc53d06de280af9 100644 +--- a/login/utmp_file.c ++++ b/login/utmp_file.c +@@ -185,9 +185,11 @@ __libc_getutent_r (struct utmp *buffer, struct utmp **result) + } + + ++/* Search for *ID, updating last_entry and file_offset. Return 0 on ++ success and -1 on failure. If the locking operation failed, write ++ true to *LOCK_FAILED. */ + static int +-internal_getut_r (const struct utmp *id, struct utmp *buffer, +- bool *lock_failed) ++internal_getut_r (const struct utmp *id, bool *lock_failed) + { + int result = -1; + +@@ -206,7 +208,7 @@ internal_getut_r (const struct utmp *id, struct utmp *buffer, + while (1) + { + /* Read the next entry. */ +- if (__read_nocancel (file_fd, buffer, sizeof (struct utmp)) ++ if (__read_nocancel (file_fd, &last_entry, sizeof (struct utmp)) + != sizeof (struct utmp)) + { + __set_errno (ESRCH); +@@ -215,7 +217,7 @@ internal_getut_r (const struct utmp *id, struct utmp *buffer, + } + file_offset += sizeof (struct utmp); + +- if (id->ut_type == buffer->ut_type) ++ if (id->ut_type == last_entry.ut_type) + break; + } + } +@@ -227,7 +229,7 @@ internal_getut_r (const struct utmp *id, struct utmp *buffer, + while (1) + { + /* Read the next entry. */ +- if (__read_nocancel (file_fd, buffer, sizeof (struct utmp)) ++ if (__read_nocancel (file_fd, &last_entry, sizeof (struct utmp)) + != sizeof (struct utmp)) + { + __set_errno (ESRCH); +@@ -236,7 +238,7 @@ internal_getut_r (const struct utmp *id, struct utmp *buffer, + } + file_offset += sizeof (struct utmp); + +- if (__utmp_equal (buffer, id)) ++ if (__utmp_equal (&last_entry, id)) + break; + } + } +@@ -265,7 +267,7 @@ __libc_getutid_r (const struct utmp *id, struct utmp *buffer, + /* We don't have to distinguish whether we can lock the file or + whether there is no entry. */ + bool lock_failed = false; +- if (internal_getut_r (id, &last_entry, &lock_failed) < 0) ++ if (internal_getut_r (id, &lock_failed) < 0) + { + *result = NULL; + return -1; +@@ -330,10 +332,9 @@ unlock_return: + struct utmp * + __libc_pututline (const struct utmp *data) + { +- if (!maybe_setutent ()) ++ if (!maybe_setutent () || file_offset == -1l) + return NULL; + +- struct utmp buffer; + struct utmp *pbuf; + int found; + +@@ -369,7 +370,7 @@ __libc_pututline (const struct utmp *data) + else + { + bool lock_failed = false; +- found = internal_getut_r (data, &buffer, &lock_failed); ++ found = internal_getut_r (data, &lock_failed); + + if (__builtin_expect (lock_failed, false)) + { diff --git a/SOURCES/glibc-rh1749439-8.patch b/SOURCES/glibc-rh1749439-8.patch new file mode 100644 index 0000000..3fc23cf --- /dev/null +++ b/SOURCES/glibc-rh1749439-8.patch @@ -0,0 +1,86 @@ +commit c2adefbafcdd2519ff43eca6891c77cd7b29ab62 +Author: Florian Weimer +Date: Thu Aug 15 16:09:43 2019 +0200 + + login: Add nonstring attributes to struct utmp, struct utmpx [BZ #24899] + + Commit 7532837d7b03b3ca5b9a63d77a5bd81dd23f3d9c ("The + -Wstringop-truncation option new in GCC 8 detects common misuses") + added __attribute_nonstring__ to bits/utmp.h, but it did not update + the parallel bits/utmpx.h header. In struct utmp, the nonstring + attribute for ut_id was missing. + +diff --git a/bits/utmp.h b/bits/utmp.h +index 3c02dd4f3fe4e99b..854b342164b785e0 100644 +--- a/bits/utmp.h ++++ b/bits/utmp.h +@@ -61,7 +61,8 @@ struct utmp + pid_t ut_pid; /* Process ID of login process. */ + char ut_line[UT_LINESIZE] + __attribute_nonstring__; /* Devicename. */ +- char ut_id[4]; /* Inittab ID. */ ++ char ut_id[4] ++ __attribute_nonstring__; /* Inittab ID. */ + char ut_user[UT_NAMESIZE] + __attribute_nonstring__; /* Username. */ + char ut_host[UT_HOSTSIZE] +diff --git a/sysdeps/gnu/bits/utmpx.h b/sysdeps/gnu/bits/utmpx.h +index 2a77efc607ae2ac0..71c743ebfcd41194 100644 +--- a/sysdeps/gnu/bits/utmpx.h ++++ b/sysdeps/gnu/bits/utmpx.h +@@ -56,10 +56,14 @@ struct utmpx + { + short int ut_type; /* Type of login. */ + __pid_t ut_pid; /* Process ID of login process. */ +- char ut_line[__UT_LINESIZE]; /* Devicename. */ +- char ut_id[4]; /* Inittab ID. */ +- char ut_user[__UT_NAMESIZE]; /* Username. */ +- char ut_host[__UT_HOSTSIZE]; /* Hostname for remote login. */ ++ char ut_line[__UT_LINESIZE] ++ __attribute_nonstring__; /* Devicename. */ ++ char ut_id[4] ++ __attribute_nonstring__; /* Inittab ID. */ ++ char ut_user[__UT_NAMESIZE] ++ __attribute_nonstring__; /* Username. */ ++ char ut_host[__UT_HOSTSIZE] ++ __attribute_nonstring__; /* Hostname for remote login. */ + struct __exit_status ut_exit; /* Exit status of a process marked + as DEAD_PROCESS. */ + +diff --git a/sysdeps/unix/sysv/linux/s390/bits/utmp.h b/sysdeps/unix/sysv/linux/s390/bits/utmp.h +index b3fa362f478ae6fe..82e8d17e2e8cc031 100644 +--- a/sysdeps/unix/sysv/linux/s390/bits/utmp.h ++++ b/sysdeps/unix/sysv/linux/s390/bits/utmp.h +@@ -61,7 +61,8 @@ struct utmp + pid_t ut_pid; /* Process ID of login process. */ + char ut_line[UT_LINESIZE] + __attribute_nonstring__; /* Devicename. */ +- char ut_id[4]; /* Inittab ID. */ ++ char ut_id[4] ++ __attribute_nonstring__; /* Inittab ID. */ + char ut_user[UT_NAMESIZE] + __attribute_nonstring__; /* Username. */ + char ut_host[UT_HOSTSIZE] +diff --git a/sysdeps/unix/sysv/linux/s390/bits/utmpx.h b/sysdeps/unix/sysv/linux/s390/bits/utmpx.h +index 3d3036c3b91e6f57..3818ed3aa4df1e65 100644 +--- a/sysdeps/unix/sysv/linux/s390/bits/utmpx.h ++++ b/sysdeps/unix/sysv/linux/s390/bits/utmpx.h +@@ -56,10 +56,14 @@ struct utmpx + { + short int ut_type; /* Type of login. */ + __pid_t ut_pid; /* Process ID of login process. */ +- char ut_line[__UT_LINESIZE]; /* Devicename. */ +- char ut_id[4]; /* Inittab ID. */ +- char ut_user[__UT_NAMESIZE]; /* Username. */ +- char ut_host[__UT_HOSTSIZE]; /* Hostname for remote login. */ ++ char ut_line[__UT_LINESIZE] ++ __attribute_nonstring__; /* Devicename. */ ++ char ut_id[4] ++ __attribute_nonstring__; /* Inittab ID. */ ++ char ut_user[__UT_NAMESIZE] ++ __attribute_nonstring__; /* Username. */ ++ char ut_host[__UT_HOSTSIZE] ++ __attribute_nonstring__; /* Hostname for remote login. */ + struct __exit_status ut_exit; /* Exit status of a process marked + as DEAD_PROCESS. */ + diff --git a/SOURCES/glibc-rh1749439-9.patch b/SOURCES/glibc-rh1749439-9.patch new file mode 100644 index 0000000..0a8470b --- /dev/null +++ b/SOURCES/glibc-rh1749439-9.patch @@ -0,0 +1,26 @@ +commit b0a83ae71b2588bd2a9e6b40f95191602940e01e +Author: Florian Weimer +Date: Thu Nov 7 09:53:41 2019 +0100 + + login: Remove double-assignment of fl.l_whence in try_file_lock + + Since l_whence is the second member of struct flock, it is written + twice. The double-assignment is technically undefined behavior due to + the lack of a sequence point. + + Reviewed-by: Carlos O'Donell + Change-Id: I2baf9e70690e723c61051b25ccbd510aec15976c + +diff --git a/login/utmp_file.c b/login/utmp_file.c +index cbc53d06de280af9..9ad80364682bae92 100644 +--- a/login/utmp_file.c ++++ b/login/utmp_file.c +@@ -79,7 +79,7 @@ try_file_lock (int fd, int type) + struct flock64 fl = + { + .l_type = type, +- fl.l_whence = SEEK_SET, ++ .l_whence = SEEK_SET, + }; + + bool status = __fcntl64_nocancel (fd, F_SETLKW, &fl) < 0; diff --git a/SOURCES/glibc-rh1764214.patch b/SOURCES/glibc-rh1764214.patch new file mode 100644 index 0000000..fb7703c --- /dev/null +++ b/SOURCES/glibc-rh1764214.patch @@ -0,0 +1,305 @@ +commit bc79db3fd487daea36e7c130f943cfb9826a41b4 +Author: Stefan Liebler +Date: Wed Feb 6 09:06:34 2019 +0100 + + Fix alignment of TLS variables for tls variant TLS_TCB_AT_TP [BZ #23403] + + The alignment of TLS variables is wrong if accessed from within a thread + for architectures with tls variant TLS_TCB_AT_TP. + For the main thread the static tls data is properly aligned. + For other threads the alignment depends on the alignment of the thread + pointer as the static tls data is located relative to this pointer. + + This patch adds this alignment for TLS_TCB_AT_TP variants in the same way + as it is already done for TLS_DTV_AT_TP. The thread pointer is also already + properly aligned if the user provides its own stack for the new thread. + + This patch extends the testcase nptl/tst-tls1.c in order to check the + alignment of the tls variables and it adds a pthread_create invocation + with a user provided stack. + The test itself is migrated from test-skeleton.c to test-driver.c + and the missing support functions xpthread_attr_setstack and xposix_memalign + are added. + + ChangeLog: + + [BZ #23403] + * nptl/allocatestack.c (allocate_stack): Align pointer pd for + TLS_TCB_AT_TP tls variant. + * nptl/tst-tls1.c: Migrate to support/test-driver.c. + Add alignment checks. + * support/Makefile (libsupport-routines): Add xposix_memalign and + xpthread_setstack. + * support/support.h: Add xposix_memalign. + * support/xthread.h: Add xpthread_attr_setstack. + * support/xposix_memalign.c: New File. + * support/xpthread_attr_setstack.c: Likewise. + +diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c +index 670cb8ffe6..590350647b 100644 +--- a/nptl/allocatestack.c ++++ b/nptl/allocatestack.c +@@ -572,7 +572,9 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp, + + /* Place the thread descriptor at the end of the stack. */ + #if TLS_TCB_AT_TP +- pd = (struct pthread *) ((char *) mem + size) - 1; ++ pd = (struct pthread *) ((((uintptr_t) mem + size) ++ - TLS_TCB_SIZE) ++ & ~__static_tls_align_m1); + #elif TLS_DTV_AT_TP + pd = (struct pthread *) ((((uintptr_t) mem + size + - __static_tls_size) +diff --git a/nptl/tst-tls1.c b/nptl/tst-tls1.c +index 00489e23e9..1a915224a7 100644 +--- a/nptl/tst-tls1.c ++++ b/nptl/tst-tls1.c +@@ -19,12 +19,16 @@ + #include + #include + #include +- ++#include ++#include ++#include ++#include ++#include + + struct test_s + { +- int a; +- int b; ++ __attribute__ ((aligned(0x20))) int a; ++ __attribute__ ((aligned(0x200))) int b; + }; + + #define INIT_A 1 +@@ -36,15 +40,34 @@ __thread struct test_s s __attribute__ ((tls_model ("initial-exec"))) = + .b = INIT_B + }; + ++/* Use noinline in combination with not static to ensure that the ++ alignment check is really done. Otherwise it was optimized out! */ ++__attribute__ ((noinline)) void ++check_alignment (const char *thr_name, const char *ptr_name, ++ int *ptr, int alignment) ++{ ++ uintptr_t offset_aligment = ((uintptr_t) ptr) & (alignment - 1); ++ if (offset_aligment) ++ { ++ FAIL_EXIT1 ("%s (%p) is not 0x%x-byte aligned in %s thread\n", ++ ptr_name, ptr, alignment, thr_name); ++ } ++} ++ ++static void ++check_s (const char *thr_name) ++{ ++ if (s.a != INIT_A || s.b != INIT_B) ++ FAIL_EXIT1 ("initial value of s in %s thread wrong\n", thr_name); ++ ++ check_alignment (thr_name, "s.a", &s.a, 0x20); ++ check_alignment (thr_name, "s.b", &s.b, 0x200); ++} + + static void * + tf (void *arg) + { +- if (s.a != INIT_A || s.b != INIT_B) +- { +- puts ("initial value of s in child thread wrong"); +- exit (1); +- } ++ check_s ("child"); + + ++s.a; + +@@ -55,25 +78,14 @@ tf (void *arg) + int + do_test (void) + { +- if (s.a != INIT_A || s.b != INIT_B) +- { +- puts ("initial value of s in main thread wrong"); +- exit (1); +- } ++ check_s ("main"); + + pthread_attr_t a; + +- if (pthread_attr_init (&a) != 0) +- { +- puts ("attr_init failed"); +- exit (1); +- } ++ xpthread_attr_init (&a); + +- if (pthread_attr_setstacksize (&a, 1 * 1024 * 1024) != 0) +- { +- puts ("attr_setstacksize failed"); +- return 1; +- } ++#define STACK_SIZE (1 * 1024 * 1024) ++ xpthread_attr_setstacksize (&a, STACK_SIZE); + + #define N 10 + int i; +@@ -83,29 +95,25 @@ do_test (void) + pthread_t th[M]; + int j; + for (j = 0; j < M; ++j, ++s.a) +- if (pthread_create (&th[j], &a, tf, NULL) != 0) +- { +- puts ("pthread_create failed"); +- exit (1); +- } ++ th[j] = xpthread_create (&a, tf, NULL); + + for (j = 0; j < M; ++j) +- if (pthread_join (th[j], NULL) != 0) +- { +- puts ("pthread_join failed"); +- exit (1); +- } ++ xpthread_join (th[j]); + } + +- if (pthread_attr_destroy (&a) != 0) +- { +- puts ("attr_destroy failed"); +- exit (1); +- } ++ /* Also check the alignment of the tls variables if a misaligned stack is ++ specified. */ ++ pthread_t th; ++ void *thr_stack = NULL; ++ thr_stack = xposix_memalign (0x200, STACK_SIZE + 1); ++ xpthread_attr_setstack (&a, thr_stack + 1, STACK_SIZE); ++ th = xpthread_create (&a, tf, NULL); ++ xpthread_join (th); ++ free (thr_stack); ++ ++ xpthread_attr_destroy (&a); + + return 0; + } + +- +-#define TEST_FUNCTION do_test () +-#include "../test-skeleton.c" ++#include +diff --git a/support/Makefile b/support/Makefile +index c15b93647c..9ff0ec3fff 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -99,10 +99,12 @@ libsupport-routines = \ + xopen \ + xpipe \ + xpoll \ ++ xposix_memalign \ + xpthread_attr_destroy \ + xpthread_attr_init \ + xpthread_attr_setdetachstate \ + xpthread_attr_setguardsize \ ++ xpthread_attr_setstack \ + xpthread_attr_setstacksize \ + xpthread_barrier_destroy \ + xpthread_barrier_init \ +diff --git a/support/support.h b/support/support.h +index 119495e5a9..97fef2cd23 100644 +--- a/support/support.h ++++ b/support/support.h +@@ -86,6 +86,7 @@ int support_descriptor_supports_holes (int fd); + void *xmalloc (size_t) __attribute__ ((malloc)); + void *xcalloc (size_t n, size_t s) __attribute__ ((malloc)); + void *xrealloc (void *p, size_t n); ++void *xposix_memalign (size_t alignment, size_t n); + char *xasprintf (const char *format, ...) + __attribute__ ((format (printf, 1, 2), malloc)); + char *xstrdup (const char *); +diff --git a/support/xposix_memalign.c b/support/xposix_memalign.c +new file mode 100644 +index 0000000000..5501a0846a +--- /dev/null ++++ b/support/xposix_memalign.c +@@ -0,0 +1,35 @@ ++/* Error-checking wrapper for posix_memalign. ++ Copyright (C) 2019 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 ++ . */ ++ ++#include ++#include ++#include ++ ++void * ++xposix_memalign (size_t alignment, size_t n) ++{ ++ void *p = NULL; ++ ++ int ret = posix_memalign (&p, alignment, n); ++ if (ret) ++ { ++ errno = ret; ++ oom_error ("posix_memalign", n); ++ } ++ return p; ++} +diff --git a/support/xpthread_attr_setstack.c b/support/xpthread_attr_setstack.c +new file mode 100644 +index 0000000000..c3772e240b +--- /dev/null ++++ b/support/xpthread_attr_setstack.c +@@ -0,0 +1,26 @@ ++/* pthread_attr_setstack with error checking. ++ Copyright (C) 2019 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 ++ . */ ++ ++#include ++ ++void ++xpthread_attr_setstack (pthread_attr_t *attr, void *stackaddr, size_t stacksize) ++{ ++ xpthread_check_return ("pthread_attr_setstack", ++ pthread_attr_setstack (attr, stackaddr, stacksize)); ++} +diff --git a/support/xthread.h b/support/xthread.h +index 9fe1f68b3b..5204f78ed2 100644 +--- a/support/xthread.h ++++ b/support/xthread.h +@@ -68,6 +68,8 @@ void xpthread_attr_destroy (pthread_attr_t *attr); + void xpthread_attr_init (pthread_attr_t *attr); + void xpthread_attr_setdetachstate (pthread_attr_t *attr, + int detachstate); ++void xpthread_attr_setstack (pthread_attr_t *attr, void *stackaddr, ++ size_t stacksize); + void xpthread_attr_setstacksize (pthread_attr_t *attr, + size_t stacksize); + void xpthread_attr_setguardsize (pthread_attr_t *attr, diff --git a/SOURCES/glibc-rh1764218-1.patch b/SOURCES/glibc-rh1764218-1.patch new file mode 100644 index 0000000..583f7a7 --- /dev/null +++ b/SOURCES/glibc-rh1764218-1.patch @@ -0,0 +1,192 @@ +commit cb89ba9c72f66327f5d66034681eb1d46eedf96f +Author: DJ Delorie +Date: Thu Aug 8 19:09:43 2019 -0400 + + Add glibc.malloc.mxfast tunable + + * elf/dl-tunables.list: Add glibc.malloc.mxfast. + * manual/tunables.texi: Document it. + * malloc/malloc.c (do_set_mxfast): New. + (__libc_mallopt): Call it. + * malloc/arena.c: Add mxfast tunable. + * malloc/tst-mxfast.c: New. + * malloc/Makefile: Add it. + + Reviewed-by: Carlos O'Donell + (cherry picked from commit c48d92b430c480de06762f80c104922239416826) + +diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list +index 1f8ecb8437a0460f..1ff6fcb6f24f93a8 100644 +--- a/elf/dl-tunables.list ++++ b/elf/dl-tunables.list +@@ -85,6 +85,11 @@ glibc { + tcache_unsorted_limit { + type: SIZE_T + } ++ mxfast { ++ type: SIZE_T ++ minval: 0 ++ security_level: SXID_IGNORE ++ } + } + tune { + hwcap_mask { +diff --git a/malloc/Makefile b/malloc/Makefile +index 228a1279a5960d8c..bf9a53cb7c5ebacb 100644 +--- a/malloc/Makefile ++++ b/malloc/Makefile +@@ -39,6 +39,7 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \ + tst-malloc-too-large \ + tst-malloc-stats-cancellation \ + tst-tcfree1 tst-tcfree2 tst-tcfree3 \ ++ tst-mxfast \ + + tests-static := \ + tst-interpose-static-nothread \ +@@ -196,6 +197,8 @@ tst-malloc-usable-static-ENV = $(tst-malloc-usable-ENV) + tst-malloc-usable-tunables-ENV = GLIBC_TUNABLES=glibc.malloc.check=3 + tst-malloc-usable-static-tunables-ENV = $(tst-malloc-usable-tunables-ENV) + ++tst-mxfast-ENV = GLIBC_TUNABLES=glibc.malloc.tcache_count=0:glibc.malloc.mxfast=0 ++ + ifeq ($(experimental-malloc),yes) + CPPFLAGS-malloc.c += -DUSE_TCACHE=1 + else +diff --git a/malloc/arena.c b/malloc/arena.c +index ff8fd5d2a7e51ac8..f5c7ad4570ad6186 100644 +--- a/malloc/arena.c ++++ b/malloc/arena.c +@@ -237,6 +237,7 @@ TUNABLE_CALLBACK_FNDECL (set_tcache_max, size_t) + TUNABLE_CALLBACK_FNDECL (set_tcache_count, size_t) + TUNABLE_CALLBACK_FNDECL (set_tcache_unsorted_limit, size_t) + #endif ++TUNABLE_CALLBACK_FNDECL (set_mxfast, size_t) + #else + /* Initialization routine. */ + #include +@@ -324,6 +325,7 @@ ptmalloc_init (void) + TUNABLE_GET (tcache_unsorted_limit, size_t, + TUNABLE_CALLBACK (set_tcache_unsorted_limit)); + # endif ++ TUNABLE_GET (mxfast, size_t, TUNABLE_CALLBACK (set_mxfast)); + #else + const char *s = NULL; + if (__glibc_likely (_environ != NULL)) +diff --git a/malloc/malloc.c b/malloc/malloc.c +index fcf480acdaea1b86..9756ed0a0d28c5f6 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -5142,6 +5142,19 @@ do_set_tcache_unsorted_limit (size_t value) + } + #endif + ++static inline int ++__always_inline ++do_set_mxfast (size_t value) ++{ ++ if (value >= 0 && value <= MAX_FAST_SIZE) ++ { ++ LIBC_PROBE (memory_mallopt_mxfast, 2, value, get_max_fast ()); ++ set_max_fast (value); ++ return 1; ++ } ++ return 0; ++} ++ + int + __libc_mallopt (int param_number, int value) + { +@@ -5161,13 +5174,7 @@ __libc_mallopt (int param_number, int value) + switch (param_number) + { + case M_MXFAST: +- if (value >= 0 && value <= MAX_FAST_SIZE) +- { +- LIBC_PROBE (memory_mallopt_mxfast, 2, value, get_max_fast ()); +- set_max_fast (value); +- } +- else +- res = 0; ++ do_set_mxfast (value); + break; + + case M_TRIM_THRESHOLD: +diff --git a/malloc/tst-mxfast.c b/malloc/tst-mxfast.c +new file mode 100644 +index 0000000000000000..7a371d2f9d2f0005 +--- /dev/null ++++ b/malloc/tst-mxfast.c +@@ -0,0 +1,50 @@ ++/* Test that glibc.malloc.mxfast tunable works. ++ Copyright (C) 2018, 2019 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 ++ . */ ++ ++/* This test verifies that setting the glibc.malloc.mxfast tunable to ++ zero results in free'd blocks being returned to the small bins, not ++ the fast bins. */ ++ ++#include ++#include ++ ++int ++do_test(void) ++{ ++ struct mallinfo m; ++ char * volatile p1; ++ char * volatile p2; ++ ++ /* Arbitrary value; must be in default fastbin range. */ ++ p1 = malloc (3); ++ /* Something large so that p1 isn't a "top block" */ ++ p2 = malloc (512); ++ free (p1); ++ ++ m = mallinfo(); ++ ++ /* This will fail if there are any blocks in the fastbins. */ ++ assert (m.smblks == 0); ++ ++ /* To keep gcc happy. */ ++ free (p2); ++ ++ return 0; ++} ++ ++#include +diff --git a/manual/tunables.texi b/manual/tunables.texi +index f6c49250e3889ddd..3dc6f9a44592c030 100644 +--- a/manual/tunables.texi ++++ b/manual/tunables.texi +@@ -213,6 +213,18 @@ pre-fill the per-thread cache with. The default, or when set to zero, + is no limit. + @end deftp + ++@deftp Tunable glibc.malloc.mxfast ++One of the optimizations malloc uses is to maintain a series of ``fast ++bins'' that hold chunks up to a specific size. The default and ++maximum size which may be held this way is 80 bytes on 32-bit systems ++or 160 bytes on 64-bit systems. Applications which value size over ++speed may choose to reduce the size of requests which are serviced ++from fast bins with this tunable. Note that the value specified ++includes malloc's internal overhead, which is normally the size of one ++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 ++ + @node Elision Tunables + @section Elision Tunables + @cindex elision tunables diff --git a/SOURCES/glibc-rh1764218-2.patch b/SOURCES/glibc-rh1764218-2.patch new file mode 100644 index 0000000..8408975 --- /dev/null +++ b/SOURCES/glibc-rh1764218-2.patch @@ -0,0 +1,72 @@ +commit 5dab5eafb3dc2f72aaab911084d127d1af45a08c +Author: Florian Weimer +Date: Thu Aug 15 11:37:18 2019 +0200 + + malloc: Various cleanups for malloc/tst-mxfast + + (cherry picked from commit f9769a239784772453d595bc2f4bed8739810e06) + +diff --git a/malloc/Makefile b/malloc/Makefile +index bf9a53cb7c5ebacb..19c2a846ed8ce049 100644 +--- a/malloc/Makefile ++++ b/malloc/Makefile +@@ -39,7 +39,6 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \ + tst-malloc-too-large \ + tst-malloc-stats-cancellation \ + tst-tcfree1 tst-tcfree2 tst-tcfree3 \ +- tst-mxfast \ + + tests-static := \ + tst-interpose-static-nothread \ +@@ -55,7 +54,7 @@ tests-internal += \ + tst-dynarray-at-fail \ + + ifneq (no,$(have-tunables)) +-tests += tst-malloc-usable-tunables ++tests += tst-malloc-usable-tunables tst-mxfast + tests-static += tst-malloc-usable-static-tunables + endif + +diff --git a/malloc/tst-mxfast.c b/malloc/tst-mxfast.c +index 7a371d2f9d2f0005..7a7750bc71024bfb 100644 +--- a/malloc/tst-mxfast.c ++++ b/malloc/tst-mxfast.c +@@ -1,5 +1,5 @@ + /* Test that glibc.malloc.mxfast tunable works. +- Copyright (C) 2018, 2019 Free Software Foundation, Inc. ++ Copyright (C) 2019 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 +@@ -21,14 +21,14 @@ + the fast bins. */ + + #include +-#include ++#include + + int +-do_test(void) ++do_test (void) + { + struct mallinfo m; +- char * volatile p1; +- char * volatile p2; ++ char *volatile p1; ++ char *volatile p2; + + /* Arbitrary value; must be in default fastbin range. */ + p1 = malloc (3); +@@ -36,10 +36,10 @@ do_test(void) + p2 = malloc (512); + free (p1); + +- m = mallinfo(); ++ m = mallinfo (); + + /* This will fail if there are any blocks in the fastbins. */ +- assert (m.smblks == 0); ++ TEST_COMPARE (m.smblks, 0); + + /* To keep gcc happy. */ + free (p2); diff --git a/SOURCES/glibc-rh1764218-3.patch b/SOURCES/glibc-rh1764218-3.patch new file mode 100644 index 0000000..ba35b8e --- /dev/null +++ b/SOURCES/glibc-rh1764218-3.patch @@ -0,0 +1,31 @@ +commit f144981490bd2ab13189d85902ca74beecb307e4 +Author: DJ Delorie +Date: Wed Oct 30 18:03:14 2019 -0400 + + Base max_fast on alignment, not width, of bins (Bug 24903) + + set_max_fast sets the "impossibly small" value based on, + eventually, MALLOC_ALIGNMENT. The comparisons for the smallest + chunk used is, eventually, MIN_CHUNK_SIZE. Note that i386 + is the only platform where these are the same, so a smallest + chunk *would* be put in a no-fastbins fastbin. + + This change calculates the "impossibly small" value + based on MIN_CHUNK_SIZE instead, so that we can know it will + always be impossibly small. + + (cherry picked from commit ff12e0fb91b9072800f031cb21fb2651ee7b6251) + +diff --git a/malloc/malloc.c b/malloc/malloc.c +index 9756ed0a0d28c5f6..90825b2aaed53761 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -1635,7 +1635,7 @@ static INTERNAL_SIZE_T global_max_fast; + + #define set_max_fast(s) \ + global_max_fast = (((s) == 0) \ +- ? SMALLBIN_WIDTH : ((s + SIZE_SZ) & ~MALLOC_ALIGN_MASK)) ++ ? MIN_CHUNK_SIZE / 2 : ((s + SIZE_SZ) & ~MALLOC_ALIGN_MASK)) + + static inline INTERNAL_SIZE_T + get_max_fast (void) diff --git a/SOURCES/glibc-rh1764223.patch b/SOURCES/glibc-rh1764223.patch new file mode 100644 index 0000000..372efaf --- /dev/null +++ b/SOURCES/glibc-rh1764223.patch @@ -0,0 +1,142 @@ +commit 2c75b545de6fe3c44138799c68217a94bc669a88 +Author: Florian Weimer +Date: Tue Jun 18 16:42:10 2019 +0200 + + elf: Refuse to dlopen PIE objects [BZ #24323] + + Another executable has already been mapped, so the dynamic linker + cannot perform relocations correctly for the second executable. + +diff --git a/elf/Makefile b/elf/Makefile +index 08e2f99..27a2fa8 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -310,7 +310,7 @@ test-xfail-tst-protected1b = yes + endif + ifeq (yesyes,$(have-fpie)$(build-shared)) + modules-names += tst-piemod1 +-tests += tst-pie1 tst-pie2 ++tests += tst-pie1 tst-pie2 tst-dlopen-pie + tests-pie += tst-pie1 tst-pie2 + ifeq (yes,$(have-protected-data)) + tests += vismain +@@ -1084,6 +1084,8 @@ CFLAGS-tst-pie2.c += $(pie-ccflag) + + $(objpfx)tst-piemod1.so: $(libsupport) + $(objpfx)tst-pie1: $(objpfx)tst-piemod1.so ++$(objpfx)tst-dlopen-pie: $(libdl) ++$(objpfx)tst-dlopen-pie.out: $(objpfx)tst-pie1 + + ifeq (yes,$(build-shared)) + # NB: Please keep cet-built-dso in sysdeps/x86/Makefile in sync with +diff --git a/elf/dl-load.c b/elf/dl-load.c +index 2bbef81..5abeb86 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -1158,6 +1158,10 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, + goto call_lose; + } + ++ /* dlopen of an executable is not valid because it is not possible ++ to perform proper relocations, handle static TLS, or run the ++ ELF constructors. For PIE, the check needs the dynamic ++ section, so there is another check below. */ + if (__glibc_unlikely (type != ET_DYN) + && __glibc_unlikely ((mode & __RTLD_OPENEXEC) == 0)) + { +@@ -1194,9 +1198,11 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, + elf_get_dynamic_info (l, NULL); + + /* Make sure we are not dlopen'ing an object that has the +- DF_1_NOOPEN flag set. */ +- if (__glibc_unlikely (l->l_flags_1 & DF_1_NOOPEN) +- && (mode & __RTLD_DLOPEN)) ++ DF_1_NOOPEN flag set, or a PIE object. */ ++ if ((__glibc_unlikely (l->l_flags_1 & DF_1_NOOPEN) ++ && (mode & __RTLD_DLOPEN)) ++ || (__glibc_unlikely (l->l_flags_1 & DF_1_PIE) ++ && __glibc_unlikely ((mode & __RTLD_OPENEXEC) == 0))) + { + /* We are not supposed to load this object. Free all resources. */ + _dl_unmap_segments (l); +@@ -1207,7 +1213,11 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, + if (l->l_phdr_allocated) + free ((void *) l->l_phdr); + +- errstring = N_("shared object cannot be dlopen()ed"); ++ if (l->l_flags_1 & DF_1_PIE) ++ errstring ++ = N_("cannot dynamically load position-independent executable"); ++ else ++ errstring = N_("shared object cannot be dlopen()ed"); + goto call_lose; + } + +diff --git a/elf/tst-dlopen-pie.c b/elf/tst-dlopen-pie.c +new file mode 100644 +index 0000000..6a41c73 +--- /dev/null ++++ b/elf/tst-dlopen-pie.c +@@ -0,0 +1,49 @@ ++/* dlopen test for PIE objects. ++ Copyright (C) 2019 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 ++ . */ ++ ++/* This test attempts to open the (otherwise unrelated) PIE test ++ program elf/tst-pie1 and expects the attempt to fail. */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++static void ++test_mode (int mode) ++{ ++ char *pie_path = xasprintf ("%s/elf/tst-pie1", support_objdir_root); ++ if (dlopen (pie_path, mode) != NULL) ++ FAIL_EXIT1 ("dlopen succeeded unexpectedly (%d)", mode); ++ const char *message = dlerror (); ++ const char *expected ++ = "cannot dynamically load position-independent executable"; ++ if (strstr (message, expected) == NULL) ++ FAIL_EXIT1 ("unexpected error message (mode %d): %s", mode, message); ++} ++ ++static int ++do_test (void) ++{ ++ test_mode (RTLD_LAZY); ++ test_mode (RTLD_NOW); ++ return 0; ++} ++ ++#include +diff --git a/include/elf.h b/include/elf.h +index ab76aaf..14ed67f 100644 +--- a/include/elf.h ++++ b/include/elf.h +@@ -23,7 +23,7 @@ + # endif + # define DT_1_SUPPORTED_MASK \ + (DF_1_NOW | DF_1_NODELETE | DF_1_INITFIRST | DF_1_NOOPEN \ +- | DF_1_ORIGIN | DF_1_NODEFLIB) ++ | DF_1_ORIGIN | DF_1_NODEFLIB | DF_1_PIE) + + #endif /* !_ISOMAC */ + #endif /* elf.h */ diff --git a/SOURCES/glibc-rh1764226-1.patch b/SOURCES/glibc-rh1764226-1.patch new file mode 100644 index 0000000..44035fe --- /dev/null +++ b/SOURCES/glibc-rh1764226-1.patch @@ -0,0 +1,82 @@ +commit 6c29942cbf059aca47fd4bbd852ea42c9d46b71f +Author: Stefan Liebler +Date: Mon Feb 18 16:12:01 2019 +0100 + + misc/tst-clone3: Fix waiting for exited thread. + + From time to time the test misc/tst-clone3 fails with a timeout. + Then futex_wait is blocking. Usually ctid should be set to zero + due to CLONE_CHILD_CLEARTID and the futex should be waken up. + But the fail occures if the thread has already exited before + ctid is set to the return value of clone(). Then futex_wait() will + block as there will be nobody who wakes the futex up again. + + This patch initializes ctid to a known value before calling clone + and the kernel is the only one who updates the value to zero after clone. + If futex_wait is called then it is either waked up due to the exited thread + or the futex syscall fails as *ctid_ptr is already zero instead of the + specified value 1. + + ChangeLog: + + * sysdeps/unix/sysv/linux/tst-clone3.c (do_test): + Initialize ctid with a known value and remove update of ctid + after clone. + (wait_tid): Adjust arguments and call futex_wait with ctid_val + as assumed current value of ctid_ptr. + +diff --git a/sysdeps/unix/sysv/linux/tst-clone3.c b/sysdeps/unix/sysv/linux/tst-clone3.c +index 784ce18f5343ec72..9f1ed6355e7acffd 100644 +--- a/sysdeps/unix/sysv/linux/tst-clone3.c ++++ b/sysdeps/unix/sysv/linux/tst-clone3.c +@@ -27,6 +27,7 @@ + + #include /* For _STACK_GROWS_{UP,DOWN}. */ + #include ++#include + + /* Test if clone call with CLONE_THREAD does not call exit_group. The 'f' + function returns '1', which will be used by clone thread to call the +@@ -42,11 +43,14 @@ f (void *a) + + /* Futex wait for TID argument, similar to pthread_join internal + implementation. */ +-#define wait_tid(tid) \ +- do { \ +- __typeof (tid) __tid; \ +- while ((__tid = (tid)) != 0) \ +- futex_wait (&(tid), __tid); \ ++#define wait_tid(ctid_ptr, ctid_val) \ ++ do { \ ++ __typeof (*(ctid_ptr)) __tid; \ ++ /* We need acquire MO here so that we synchronize with the \ ++ kernel's store to 0 when the clone terminates. */ \ ++ while ((__tid = atomic_load_explicit (ctid_ptr, \ ++ memory_order_acquire)) != 0) \ ++ futex_wait (ctid_ptr, ctid_val); \ + } while (0) + + static inline int +@@ -64,7 +68,11 @@ do_test (void) + clone_flags |= CLONE_VM | CLONE_SIGHAND; + /* We will used ctid to call on futex to wait for thread exit. */ + clone_flags |= CLONE_CHILD_CLEARTID; +- pid_t ctid, tid; ++ /* Initialize with a known value. ctid is set to zero by the kernel after the ++ cloned thread has exited. */ ++#define CTID_INIT_VAL 1 ++ pid_t ctid = CTID_INIT_VAL; ++ pid_t tid; + + #ifdef __ia64__ + extern int __clone2 (int (*__fn) (void *__arg), void *__child_stack_base, +@@ -86,8 +94,7 @@ do_test (void) + if (tid == -1) + FAIL_EXIT1 ("clone failed: %m"); + +- ctid = tid; +- wait_tid (ctid); ++ wait_tid (&ctid, CTID_INIT_VAL); + + return 2; + } diff --git a/SOURCES/glibc-rh1764226-2.patch b/SOURCES/glibc-rh1764226-2.patch new file mode 100644 index 0000000..69902cc --- /dev/null +++ b/SOURCES/glibc-rh1764226-2.patch @@ -0,0 +1,159 @@ +commit 481c30cb9573a280649fbf27251e6a0f4af1b2b1 +Author: Alexandra Hájková +Date: Thu May 9 13:51:40 2019 +0200 + + elf: Add tst-ldconfig-bad-aux-cache test [BZ #18093] + + This test corrupts /var/cache/ldconfig/aux-cache and executes ldconfig + to check it will not segfault using the corrupted aux_cache. The test + uses the test-in-container framework. Verified no regressions on + x86_64. + +diff --git a/elf/Makefile b/elf/Makefile +index 139d072e136284e1..8e907e69eb35e089 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -156,6 +156,9 @@ tests-static-internal := tst-tls1-static tst-tls2-static \ + CRT-tst-tls1-static-non-pie := $(csu-objpfx)crt1.o + tst-tls1-static-non-pie-no-pie = yes + ++tests-container = \ ++ tst-ldconfig-bad-aux-cache ++ + tests := tst-tls9 tst-leaks1 \ + tst-array1 tst-array2 tst-array3 tst-array4 tst-array5 \ + tst-auxv +diff --git a/elf/tst-ldconfig-bad-aux-cache.c b/elf/tst-ldconfig-bad-aux-cache.c +new file mode 100644 +index 0000000000000000..68ce90a95648f6ab +--- /dev/null ++++ b/elf/tst-ldconfig-bad-aux-cache.c +@@ -0,0 +1,117 @@ ++/* Test ldconfig does not segfault when aux-cache is corrupted (Bug 18093). ++ Copyright (C) 2019 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; see the file COPYING.LIB. If ++ not, see . */ ++ ++/* This test does the following: ++ Run ldconfig to create the caches. ++ Corrupt the caches. ++ Run ldconfig again. ++ At each step we verify that ldconfig does not crash. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++ ++static int ++display_info (const char *fpath, const struct stat *sb, ++ int tflag, struct FTW *ftwbuf) ++{ ++ printf ("info: %-3s %2d %7jd %-40s %d %s\n", ++ (tflag == FTW_D) ? "d" : (tflag == FTW_DNR) ? "dnr" : ++ (tflag == FTW_DP) ? "dp" : (tflag == FTW_F) ? "f" : ++ (tflag == FTW_NS) ? "ns" : (tflag == FTW_SL) ? "sl" : ++ (tflag == FTW_SLN) ? "sln" : "???", ++ ftwbuf->level, (intmax_t) sb->st_size, ++ fpath, ftwbuf->base, fpath + ftwbuf->base); ++ /* To tell nftw to continue. */ ++ return 0; ++} ++ ++/* Run ldconfig with a corrupt aux-cache, in particular we test for size ++ truncation that might happen if a previous ldconfig run failed or if ++ there were storage or power issues while we were writing the file. ++ We want ldconfig not to crash, and it should be able to do so by ++ computing the expected size of the file (bug 18093). */ ++static int ++do_test (void) ++{ ++ char *prog = xasprintf ("%s/ldconfig", support_install_rootsbindir); ++ char *const args[] = { prog, NULL }; ++ const char *path = "/var/cache/ldconfig/aux-cache"; ++ struct stat64 fs; ++ long int size, new_size, i; ++ int status; ++ pid_t pid; ++ ++ /* Create the needed directories. */ ++ xmkdirp ("/var/cache/ldconfig", 0777); ++ ++ pid = xfork (); ++ /* Run ldconfig fist to generate the aux-cache. */ ++ if (pid == 0) ++ { ++ execv (args[0], args); ++ _exit (1); ++ } ++ else ++ { ++ xwaitpid (pid, &status, 0); ++ TEST_COMPARE(status, 0); ++ xstat (path, &fs); ++ ++ size = fs.st_size; ++ /* Run 3 tests, each truncating aux-cache shorter and shorter. */ ++ for (i = 3; i > 0; i--) ++ { ++ new_size = size * i / 4; ++ if (truncate (path, new_size)) ++ FAIL_EXIT1 ("truncation failed: %m"); ++ if (nftw (path, display_info, 1000, 0) == -1) ++ FAIL_EXIT1 ("nftw failed."); ++ ++ pid = xfork (); ++ /* Verify that ldconfig can run with a truncated ++ aux-cache and doesn't crash. */ ++ if (pid == 0) ++ { ++ execv (args[0], args); ++ _exit (1); ++ } ++ else ++ { ++ xwaitpid (pid, &status, 0); ++ TEST_COMPARE(status, 0); ++ } ++ } ++ } ++ ++ free (prog); ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-ldconfig-bad-aux-cache.root/etc/ld.so.conf b/elf/tst-ldconfig-bad-aux-cache.root/etc/ld.so.conf +new file mode 100644 +index 0000000000000000..e1e74dbda2bf3dfa +--- /dev/null ++++ b/elf/tst-ldconfig-bad-aux-cache.root/etc/ld.so.conf +@@ -0,0 +1,2 @@ ++# This file was created to suppress a warning from ldconfig: ++# /sbin/ldconfig: Warning: ignoring configuration file that cannot be opened: /etc/ld.so.conf: No such file or directory +diff --git a/elf/tst-ldconfig-bad-aux-cache.root/postclean.req b/elf/tst-ldconfig-bad-aux-cache.root/postclean.req +new file mode 100644 +index 0000000000000000..e69de29bb2d1d643 diff --git a/SOURCES/glibc-rh1764226-3.patch b/SOURCES/glibc-rh1764226-3.patch new file mode 100644 index 0000000..cda312f --- /dev/null +++ b/SOURCES/glibc-rh1764226-3.patch @@ -0,0 +1,112 @@ +commit a6c1ce778e5c05a2e6925883b410157ef47654fd +Author: Alexandra Hájková +Date: Mon Aug 5 13:18:57 2019 +0200 + + elf: tst-ldconfig-bad-aux-cache: use support_capture_subprocess + +diff --git a/elf/tst-ldconfig-bad-aux-cache.c b/elf/tst-ldconfig-bad-aux-cache.c +index 68ce90a95648f6ab..6e22ff815eaaa817 100644 +--- a/elf/tst-ldconfig-bad-aux-cache.c ++++ b/elf/tst-ldconfig-bad-aux-cache.c +@@ -31,6 +31,7 @@ + #include + #include + ++#include + #include + #include + #include +@@ -52,6 +53,15 @@ display_info (const char *fpath, const struct stat *sb, + return 0; + } + ++static void ++execv_wrapper (void *args) ++{ ++ char **argv = args; ++ ++ execv (argv[0], argv); ++ FAIL_EXIT1 ("execv: %m"); ++} ++ + /* Run ldconfig with a corrupt aux-cache, in particular we test for size + truncation that might happen if a previous ldconfig run failed or if + there were storage or power issues while we were writing the file. +@@ -61,53 +71,38 @@ static int + do_test (void) + { + char *prog = xasprintf ("%s/ldconfig", support_install_rootsbindir); +- char *const args[] = { prog, NULL }; ++ char *args[] = { prog, NULL }; + const char *path = "/var/cache/ldconfig/aux-cache"; + struct stat64 fs; + long int size, new_size, i; +- int status; +- pid_t pid; + + /* Create the needed directories. */ + xmkdirp ("/var/cache/ldconfig", 0777); + +- pid = xfork (); +- /* Run ldconfig fist to generate the aux-cache. */ +- if (pid == 0) +- { +- execv (args[0], args); +- _exit (1); +- } +- else ++ /* Run ldconfig first to generate the aux-cache. */ ++ struct support_capture_subprocess result; ++ result = support_capture_subprocess (execv_wrapper, args); ++ support_capture_subprocess_check (&result, "execv", 0, sc_allow_none); ++ support_capture_subprocess_free (&result); ++ ++ xstat (path, &fs); ++ ++ size = fs.st_size; ++ /* Run 3 tests, each truncating aux-cache shorter and shorter. */ ++ for (i = 3; i > 0; i--) + { +- xwaitpid (pid, &status, 0); +- TEST_COMPARE(status, 0); +- xstat (path, &fs); +- +- size = fs.st_size; +- /* Run 3 tests, each truncating aux-cache shorter and shorter. */ +- for (i = 3; i > 0; i--) +- { +- new_size = size * i / 4; +- if (truncate (path, new_size)) +- FAIL_EXIT1 ("truncation failed: %m"); +- if (nftw (path, display_info, 1000, 0) == -1) +- FAIL_EXIT1 ("nftw failed."); +- +- pid = xfork (); +- /* Verify that ldconfig can run with a truncated +- aux-cache and doesn't crash. */ +- if (pid == 0) +- { +- execv (args[0], args); +- _exit (1); +- } +- else +- { +- xwaitpid (pid, &status, 0); +- TEST_COMPARE(status, 0); +- } +- } ++ new_size = size * i / 4; ++ if (truncate (path, new_size)) ++ FAIL_EXIT1 ("truncation failed: %m"); ++ if (nftw (path, display_info, 1000, 0) == -1) ++ FAIL_EXIT1 ("nftw failed."); ++ ++ /* Verify that ldconfig can run with a truncated ++ aux-cache and doesn't crash. */ ++ struct support_capture_subprocess result; ++ result = support_capture_subprocess (execv_wrapper, args); ++ support_capture_subprocess_check (&result, "execv", 0, sc_allow_none); ++ support_capture_subprocess_free (&result); + } + + free (prog); diff --git a/SOURCES/glibc-rh1764231-1.patch b/SOURCES/glibc-rh1764231-1.patch new file mode 100644 index 0000000..f879427 --- /dev/null +++ b/SOURCES/glibc-rh1764231-1.patch @@ -0,0 +1,49 @@ +commit 17432d7150bdab3bce2ea66c70ad6c920f54077a +Author: Florian Weimer +Date: Fri Jun 28 10:15:30 2019 +0200 + + support: Add xdlvsym function + +diff --git a/support/xdlfcn.c b/support/xdlfcn.c +index f34bb059c00f27f7..b4a6b85649d181c8 100644 +--- a/support/xdlfcn.c ++++ b/support/xdlfcn.c +@@ -48,6 +48,26 @@ xdlsym (void *handle, const char *symbol) + return sym; + } + ++void * ++xdlvsym (void *handle, const char *symbol, const char *version) ++{ ++ /* Clear any pending errors. */ ++ dlerror (); ++ ++ void *sym = dlvsym (handle, symbol, version); ++ ++ if (sym == NULL) ++ { ++ const char *error = dlerror (); ++ if (error != NULL) ++ FAIL_EXIT1 ("error: dlvsym: %s\n", error); ++ /* If there was no error, we found a NULL symbol. Return the ++ NULL value in this case. */ ++ } ++ ++ return sym; ++} ++ + void + xdlclose (void *handle) + { +diff --git a/support/xdlfcn.h b/support/xdlfcn.h +index 5ab7494e70924f52..ab1cbb3cb9bb1cc7 100644 +--- a/support/xdlfcn.h ++++ b/support/xdlfcn.h +@@ -26,6 +26,7 @@ __BEGIN_DECLS + /* Each of these terminates process on failure with relevant error message. */ + void *xdlopen (const char *filename, int flags); + void *xdlsym (void *handle, const char *symbol); ++void *xdlvsym (void *handle, const char *symbol, const char *version); + void xdlclose (void *handle); + + diff --git a/SOURCES/glibc-rh1764231-2.patch b/SOURCES/glibc-rh1764231-2.patch new file mode 100644 index 0000000..aaff767 --- /dev/null +++ b/SOURCES/glibc-rh1764231-2.patch @@ -0,0 +1,342 @@ +commit f0b2132b35248c1f4a80f62a2c38cddcc802aa8c +Author: Florian Weimer +Date: Fri Jun 28 10:12:50 2019 +0200 + + ld.so: Support moving versioned symbols between sonames [BZ #24741] + + This change should be fully backwards-compatible because the old + code aborted the load if a soname mismatch was encountered + (instead of searching further for a matching symbol). This means + that no different symbols are found. + + The soname check was explicitly disabled for the skip_map != NULL + case. However, this only happens with dl(v)sym and RTLD_NEXT, + and those lookups do not come with a verneed entry that could be used + for the check. + + The error check was already explicitly disabled for the skip_map != + NULL case, that is, when dl(v)sym was called with RTLD_NEXT. But + _dl_vsym always sets filename in the struct r_found_version argument + to NULL, so the check was not active anyway. This means that + symbol lookup results for the skip_map != NULL case do not change, + either. + +Conflicts: + elf/Makefile + (usual missing backports) + +diff --git a/elf/Makefile b/elf/Makefile +index 29aa3a96738e4176..73f9e25ea5efd63a 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -187,7 +187,8 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + tst-tlsalign tst-tlsalign-extern tst-nodelete-opened \ + tst-nodelete2 tst-audit11 tst-audit12 tst-dlsym-error tst-noload \ + tst-latepthread tst-tls-manydynamic tst-nodelete-dlclose \ +- tst-debug1 tst-main1 tst-absolute-sym tst-absolute-zero tst-big-note ++ tst-debug1 tst-main1 tst-absolute-sym tst-absolute-zero tst-big-note \ ++ tst-sonamemove-link tst-sonamemove-dlopen + # reldep9 + tests-internal += loadtest unload unload2 circleload1 \ + neededtest neededtest2 neededtest3 neededtest4 \ +@@ -275,7 +276,9 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + tst-latepthreadmod $(tst-tls-many-dynamic-modules) \ + tst-nodelete-dlclose-dso tst-nodelete-dlclose-plugin \ + tst-main1mod tst-libc_dlvsym-dso tst-absolute-sym-lib \ +- tst-absolute-zero-lib tst-big-note-lib ++ tst-absolute-zero-lib tst-big-note-lib \ ++ tst-sonamemove-linkmod1 \ ++ tst-sonamemove-runmod1 tst-sonamemove-runmod2 + + ifeq (yes,$(have-mtls-dialect-gnu2)) + tests += tst-gnu2-tls1 +@@ -1374,6 +1377,28 @@ tst-audit12-ENV = LD_AUDIT=$(objpfx)tst-auditmod12.so + $(objpfx)tst-audit12mod1.so: $(objpfx)tst-audit12mod2.so + LDFLAGS-tst-audit12mod2.so = -Wl,--version-script=tst-audit12mod2.map + ++# tst-sonamemove links against an older implementation of the library. ++LDFLAGS-tst-sonamemove-linkmod1.so = \ ++ -Wl,--version-script=tst-sonamemove-linkmod1.map \ ++ -Wl,-soname,tst-sonamemove-runmod1.so ++LDFLAGS-tst-sonamemove-runmod1.so = -Wl,--no-as-needed \ ++ -Wl,--version-script=tst-sonamemove-runmod1.map \ ++ -Wl,-soname,tst-sonamemove-runmod1.so ++LDFLAGS-tst-sonamemove-runmod2.so = \ ++ -Wl,--version-script=tst-sonamemove-runmod2.map \ ++ -Wl,-soname,tst-sonamemove-runmod2.so ++$(objpfx)tst-sonamemove-runmod1.so: $(objpfx)tst-sonamemove-runmod2.so ++# Link against the link module, but depend on the run-time modules ++# for execution. ++$(objpfx)tst-sonamemove-link: $(objpfx)tst-sonamemove-linkmod1.so ++$(objpfx)tst-sonamemove-link.out: \ ++ $(objpfx)tst-sonamemove-runmod1.so \ ++ $(objpfx)tst-sonamemove-runmod2.so ++$(objpfx)tst-sonamemove-dlopen: $(libdl) ++$(objpfx)tst-sonamemove-dlopen.out: \ ++ $(objpfx)tst-sonamemove-runmod1.so \ ++ $(objpfx)tst-sonamemove-runmod2.so ++ + # Override -z defs, so that we can reference an undefined symbol. + # Force lazy binding for the same reason. + LDFLAGS-tst-latepthreadmod.so = \ +diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c +index 68ecc6179f608547..1d046caf017b582b 100644 +--- a/elf/dl-lookup.c ++++ b/elf/dl-lookup.c +@@ -536,11 +536,7 @@ do_lookup_x (const char *undef_name, uint_fast32_t new_hash, + } + + skip: +- /* If this current map is the one mentioned in the verneed entry +- and we have not found a weak entry, it is a bug. */ +- if (symidx == STN_UNDEF && version != NULL && version->filename != NULL +- && __glibc_unlikely (_dl_name_match_p (version->filename, map))) +- return -1; ++ ; + } + while (++i < n); + +@@ -810,34 +806,10 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map, + + /* Search the relevant loaded objects for a definition. */ + for (size_t start = i; *scope != NULL; start = 0, ++scope) +- { +- int res = do_lookup_x (undef_name, new_hash, &old_hash, *ref, +- ¤t_value, *scope, start, version, flags, +- skip_map, type_class, undef_map); +- if (res > 0) +- break; +- +- if (__glibc_unlikely (res < 0) && skip_map == NULL) +- { +- /* Oh, oh. The file named in the relocation entry does not +- contain the needed symbol. This code is never reached +- for unversioned lookups. */ +- assert (version != NULL); +- const char *reference_name = undef_map ? undef_map->l_name : ""; +- struct dl_exception exception; +- /* XXX We cannot translate the message. */ +- _dl_exception_create_format +- (&exception, DSO_FILENAME (reference_name), +- "symbol %s version %s not defined in file %s" +- " with link time reference%s", +- undef_name, version->name, version->filename, +- res == -2 ? " (no version symbols)" : ""); +- _dl_signal_cexception (0, &exception, N_("relocation error")); +- _dl_exception_free (&exception); +- *ref = NULL; +- return 0; +- } +- } ++ if (do_lookup_x (undef_name, new_hash, &old_hash, *ref, ++ ¤t_value, *scope, start, version, flags, ++ skip_map, type_class, undef_map) != 0) ++ break; + + if (__glibc_unlikely (current_value.s == NULL)) + { +diff --git a/elf/tst-sonamemove-dlopen.c b/elf/tst-sonamemove-dlopen.c +new file mode 100644 +index 0000000000000000..c496705044cdd53c +--- /dev/null ++++ b/elf/tst-sonamemove-dlopen.c +@@ -0,0 +1,35 @@ ++/* Check that a moved versioned symbol can be found using dlsym, dlvsym. ++ Copyright (C) 2019 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 ++ . */ ++ ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ /* tst-sonamemove-runmod1.so does not define moved_function, but it ++ depends on tst-sonamemove-runmod2.so, which does. */ ++ void *handle = xdlopen ("tst-sonamemove-runmod1.so", RTLD_NOW); ++ TEST_VERIFY (xdlsym (handle, "moved_function") != NULL); ++ TEST_VERIFY (xdlvsym (handle, "moved_function", "SONAME_MOVE") != NULL); ++ ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-sonamemove-link.c b/elf/tst-sonamemove-link.c +new file mode 100644 +index 0000000000000000..4bc3bf32f88f97a9 +--- /dev/null ++++ b/elf/tst-sonamemove-link.c +@@ -0,0 +1,41 @@ ++/* Check that a versioned symbol can move from one library to another. ++ Copyright (C) 2019 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 ++ . */ ++ ++/* At link time, moved_function is bound to the symbol version ++ SONAME_MOVE in tst-sonamemove-runmod1.so, using the ++ tst-sonamemove-linkmod1.so stub object. ++ ++ At run time, the process loads the real tst-sonamemove-runmod1.so, ++ which depends on tst-sonamemove-runmod2.so. ++ tst-sonamemove-runmod1.so does not define moved_function, but ++ tst-sonamemove-runmod2.so does. ++ ++ The net effect is that the versioned symbol ++ moved_function@SONAME_MOVE moved from the soname ++ tst-sonamemove-linkmod1.so at link time to the soname ++ tst-sonamemove-linkmod2.so at run time. */ ++void moved_function (void); ++ ++static int ++do_test (void) ++{ ++ moved_function (); ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-sonamemove-linkmod1.c b/elf/tst-sonamemove-linkmod1.c +new file mode 100644 +index 0000000000000000..b8a354e5e394f566 +--- /dev/null ++++ b/elf/tst-sonamemove-linkmod1.c +@@ -0,0 +1,25 @@ ++/* Link interface for (lack of) soname matching in versioned symbol refs. ++ Copyright (C) 2019 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 ++ . */ ++ ++/* This function moved from tst-sonamemove-runmod1.so. This module is ++ intended for linking only, to simulate an old application which was ++ linked against an older version of the library. */ ++void ++moved_function (void) ++{ ++} +diff --git a/elf/tst-sonamemove-linkmod1.map b/elf/tst-sonamemove-linkmod1.map +new file mode 100644 +index 0000000000000000..8fe5904018972009 +--- /dev/null ++++ b/elf/tst-sonamemove-linkmod1.map +@@ -0,0 +1,3 @@ ++SONAME_MOVE { ++ global: moved_function; ++}; +diff --git a/elf/tst-sonamemove-runmod1.c b/elf/tst-sonamemove-runmod1.c +new file mode 100644 +index 0000000000000000..5c409e22898bc836 +--- /dev/null ++++ b/elf/tst-sonamemove-runmod1.c +@@ -0,0 +1,23 @@ ++/* Run-time module whose moved_function moved to a library dependency. ++ Copyright (C) 2019 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 ++ . */ ++ ++/* Dummy function to add the required symbol version. */ ++void ++other_function (void) ++{ ++} +diff --git a/elf/tst-sonamemove-runmod1.map b/elf/tst-sonamemove-runmod1.map +new file mode 100644 +index 0000000000000000..2ea81c6e6ffae2be +--- /dev/null ++++ b/elf/tst-sonamemove-runmod1.map +@@ -0,0 +1,3 @@ ++SONAME_MOVE { ++ global: other_function; ++}; +diff --git a/elf/tst-sonamemove-runmod2.c b/elf/tst-sonamemove-runmod2.c +new file mode 100644 +index 0000000000000000..b5e482eff57d7d83 +--- /dev/null ++++ b/elf/tst-sonamemove-runmod2.c +@@ -0,0 +1,24 @@ ++/* Run-time module with the actual implementation of moved_function. ++ Copyright (C) 2019 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 ++ . */ ++ ++/* In the test scenario, this function was originally in ++ tst-sonamemove-runmod1.so. */ ++void ++moved_function (void) ++{ ++} +diff --git a/elf/tst-sonamemove-runmod2.map b/elf/tst-sonamemove-runmod2.map +new file mode 100644 +index 0000000000000000..8fe5904018972009 +--- /dev/null ++++ b/elf/tst-sonamemove-runmod2.map +@@ -0,0 +1,3 @@ ++SONAME_MOVE { ++ global: moved_function; ++}; diff --git a/SOURCES/glibc-rh1764234-1.patch b/SOURCES/glibc-rh1764234-1.patch new file mode 100644 index 0000000..0bbcf35 --- /dev/null +++ b/SOURCES/glibc-rh1764234-1.patch @@ -0,0 +1,40 @@ +commit 47ad5e1a2a3ab8eeda491454cbef3b1c5239dc02 +Author: Joseph Myers +Date: Tue Jan 1 02:01:02 2019 +0000 + + Update syscall-names.list for Linux 4.20. + + This patch updates sysdeps/unix/sysv/linux/syscall-names.list for + Linux 4.20. Although there are no new syscalls, the + riscv_flush_icache syscall has moved to asm/unistd.h (previously in + asm/syscalls.h) and so now needs to be added to the list. + + Tested with build-many-glibcs.py. + + * sysdeps/unix/sysv/linux/syscall-names.list: Update kernel + version to 4.20. + (riscv_flush_icache): New syscall. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index 698069a52d..b650dc07cc 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -22,8 +22,8 @@ + # names are only used if the installed kernel headers also provide + # them. + +-# The list of system calls is current as of Linux 4.19. +-kernel 4.19 ++# The list of system calls is current as of Linux 4.20. ++kernel 4.20 + + FAST_atomic_update + FAST_cmpxchg +@@ -431,6 +431,7 @@ renameat + renameat2 + request_key + restart_syscall ++riscv_flush_icache + rmdir + rseq + rt_sigaction diff --git a/SOURCES/glibc-rh1764234-2.patch b/SOURCES/glibc-rh1764234-2.patch new file mode 100644 index 0000000..d8d5245 --- /dev/null +++ b/SOURCES/glibc-rh1764234-2.patch @@ -0,0 +1,43 @@ +commit 477e739b324349df854209117047779ac3142130 +Author: Joseph Myers +Date: Fri Mar 15 18:18:40 2019 +0000 + + Update syscall-names.list for Linux 5.0. + + This patch updates sysdeps/unix/sysv/linux/syscall-names.list for + Linux 5.0. Based on testing with build-many-glibcs.py, the only new + entry needed is for old_getpagesize (a newly added __NR_* name for an + old syscall on ia64). (Because 5.0 changes how syscall tables are + handled in the kernel, checking diffs wasn't a useful way of looking + for new syscalls in 5.0 as most of the syscall tables were moved to + the new representation without actually adding any syscalls to them.) + + Tested with build-many-glibcs.py. + + * sysdeps/unix/sysv/linux/syscall-names.list: Update kernel + version to 5.0. + (old_getpagesize): New syscall. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index b650dc07cc..0227e52a5f 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -22,8 +22,8 @@ + # names are only used if the installed kernel headers also provide + # them. + +-# The list of system calls is current as of Linux 4.20. +-kernel 4.20 ++# The list of system calls is current as of Linux 5.0. ++kernel 5.0 + + FAST_atomic_update + FAST_cmpxchg +@@ -261,6 +261,7 @@ nfsservctl + ni_syscall + nice + old_adjtimex ++old_getpagesize + oldfstat + oldlstat + oldolduname diff --git a/SOURCES/glibc-rh1764234-3.patch b/SOURCES/glibc-rh1764234-3.patch new file mode 100644 index 0000000..a336060 --- /dev/null +++ b/SOURCES/glibc-rh1764234-3.patch @@ -0,0 +1,181 @@ +commit 7621676f7a5130c030f7fff1cab72dbf2993b837 +Author: Joseph Myers +Date: Tue May 7 23:57:26 2019 +0000 + + Update syscall-names.list for Linux 5.1. + + This patch updates syscall-names.list for Linux 5.1 (which has many + new syscalls, mainly but not entirely ones for 64-bit time). + + Tested with build-many-glibcs.py (before the revert of the move to + Linux 5.1 there; verified there were no tst-syscall-list failures). + + * sysdeps/unix/sysv/linux/syscall-names.list: Update kernel + version to 5.1. + (clock_adjtime64) New syscall. + (clock_getres_time64) Likewise. + (clock_gettime64) Likewise. + (clock_nanosleep_time64) Likewise. + (clock_settime64) Likewise. + (futex_time64) Likewise. + (io_pgetevents_time64) Likewise. + (io_uring_enter) Likewise. + (io_uring_register) Likewise. + (io_uring_setup) Likewise. + (mq_timedreceive_time64) Likewise. + (mq_timedsend_time64) Likewise. + (pidfd_send_signal) Likewise. + (ppoll_time64) Likewise. + (pselect6_time64) Likewise. + (recvmmsg_time64) Likewise. + (rt_sigtimedwait_time64) Likewise. + (sched_rr_get_interval_time64) Likewise. + (semtimedop_time64) Likewise. + (timer_gettime64) Likewise. + (timer_settime64) Likewise. + (timerfd_gettime64) Likewise. + (timerfd_settime64) Likewise. + (utimensat_time64) Likewise. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index 0227e52a5f..2d0354b8b3 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -22,8 +22,8 @@ + # names are only used if the installed kernel headers also provide + # them. + +-# The list of system calls is current as of Linux 5.0. +-kernel 5.0 ++# The list of system calls is current as of Linux 5.1. ++kernel 5.1 + + FAST_atomic_update + FAST_cmpxchg +@@ -63,10 +63,15 @@ chown + chown32 + chroot + clock_adjtime ++clock_adjtime64 + clock_getres ++clock_getres_time64 + clock_gettime ++clock_gettime64 + clock_nanosleep ++clock_nanosleep_time64 + clock_settime ++clock_settime64 + clone + clone2 + close +@@ -128,6 +133,7 @@ ftime + ftruncate + ftruncate64 + futex ++futex_time64 + futimesat + get_kernel_syms + get_mempolicy +@@ -187,8 +193,12 @@ io_cancel + io_destroy + io_getevents + io_pgetevents ++io_pgetevents_time64 + io_setup + io_submit ++io_uring_enter ++io_uring_register ++io_uring_setup + ioctl + ioperm + iopl +@@ -242,7 +252,9 @@ mq_getsetattr + mq_notify + mq_open + mq_timedreceive ++mq_timedreceive_time64 + mq_timedsend ++mq_timedsend_time64 + mq_unlink + mremap + msgctl +@@ -389,6 +401,7 @@ perf_event_open + perfctr + perfmonctl + personality ++pidfd_send_signal + pipe + pipe2 + pivot_root +@@ -397,6 +410,7 @@ pkey_free + pkey_mprotect + poll + ppoll ++ppoll_time64 + prctl + pread64 + preadv +@@ -407,6 +421,7 @@ process_vm_writev + prof + profil + pselect6 ++pselect6_time64 + ptrace + putpmsg + pwrite64 +@@ -424,6 +439,7 @@ reboot + recv + recvfrom + recvmmsg ++recvmmsg_time64 + recvmsg + remap_file_pages + removexattr +@@ -442,6 +458,7 @@ rt_sigqueueinfo + rt_sigreturn + rt_sigsuspend + rt_sigtimedwait ++rt_sigtimedwait_time64 + rt_tgsigqueueinfo + rtas + s390_guarded_storage +@@ -457,6 +474,7 @@ sched_getattr + sched_getparam + sched_getscheduler + sched_rr_get_interval ++sched_rr_get_interval_time64 + sched_set_affinity + sched_setaffinity + sched_setattr +@@ -470,6 +488,7 @@ semctl + semget + semop + semtimedop ++semtimedop_time64 + send + sendfile + sendfile64 +@@ -567,11 +586,15 @@ timer_create + timer_delete + timer_getoverrun + timer_gettime ++timer_gettime64 + timer_settime ++timer_settime64 + timerfd + timerfd_create + timerfd_gettime ++timerfd_gettime64 + timerfd_settime ++timerfd_settime64 + times + tkill + truncate +@@ -591,6 +614,7 @@ userfaultfd + ustat + utime + utimensat ++utimensat_time64 + utimes + utrap_install + vfork diff --git a/SOURCES/glibc-rh1764234-4.patch b/SOURCES/glibc-rh1764234-4.patch new file mode 100644 index 0000000..5488fe1 --- /dev/null +++ b/SOURCES/glibc-rh1764234-4.patch @@ -0,0 +1,58 @@ +commit 0bb8f8c791862a4ff38a584af23bbb5bf3f90acd +Author: Florian Weimer +Date: Fri May 31 13:52:16 2019 +0200 + + Linux: Add oddly-named arm syscalls to syscall-names.list + + on arm defines the following macros: + + #define __ARM_NR_breakpoint (__ARM_NR_BASE+1) + #define __ARM_NR_cacheflush (__ARM_NR_BASE+2) + #define __ARM_NR_usr26 (__ARM_NR_BASE+3) + #define __ARM_NR_usr32 (__ARM_NR_BASE+4) + #define __ARM_NR_set_tls (__ARM_NR_BASE+5) + #define __ARM_NR_get_tls (__ARM_NR_BASE+6) + + These do not follow the regular __NR_* naming convention and + have so far been ignored by the syscall-names.list consistency + checks. This commit adds these names to the file, preparing + for the availability of these names in the regular __NR_* + namespace. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index 2d0354b8b3..ae8adabb70 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -52,6 +52,7 @@ bdflush + bind + bpf + break ++breakpoint + brk + cachectl + cacheflush +@@ -139,6 +140,7 @@ get_kernel_syms + get_mempolicy + get_robust_list + get_thread_area ++get_tls + getcpu + getcwd + getdents +@@ -499,6 +501,7 @@ set_mempolicy + set_robust_list + set_thread_area + set_tid_address ++set_tls + setdomainname + setfsgid + setfsgid32 +@@ -611,6 +614,8 @@ unlinkat + unshare + uselib + userfaultfd ++usr26 ++usr32 + ustat + utime + utimensat diff --git a/SOURCES/glibc-rh1764234-5.patch b/SOURCES/glibc-rh1764234-5.patch new file mode 100644 index 0000000..53988c6 --- /dev/null +++ b/SOURCES/glibc-rh1764234-5.patch @@ -0,0 +1,30 @@ +commit a63b96fbddbf97feaa068a9efed3b5623a1a1e78 +Author: Vincent Chen +Date: Wed Jun 26 17:30:11 2019 +0800 + + Linux: Add nds32 specific syscalls to syscall-names.list + + The nds32 creates two specific syscalls, udftrap and fp_udfiex_crtl, in + kernel v5.0 and v5.2, respectively. Add these two syscalls to + syscall-names.list. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index ae8adabb70..95aa3ec7a5 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -121,6 +121,7 @@ finit_module + flistxattr + flock + fork ++fp_udfiex_crtl + free_hugepages + fremovexattr + fsetxattr +@@ -603,6 +604,7 @@ tkill + truncate + truncate64 + tuxcall ++udftrap + ugetrlimit + ulimit + umask diff --git a/SOURCES/glibc-rh1764234-6.patch b/SOURCES/glibc-rh1764234-6.patch new file mode 100644 index 0000000..5f29118 --- /dev/null +++ b/SOURCES/glibc-rh1764234-6.patch @@ -0,0 +1,52 @@ +commit 1f7097d09ce628878107ed30341cfc1eb3649a81 +Author: Florian Weimer +Date: Fri Jul 19 08:53:04 2019 +0200 + + Linux: Update syscall-names.list to Linux 5.2 + + This adds the system call names fsconfig, fsmount, fsopen, fspick, + move_mount, open_tree. + + Tested with build-many-glibcs.py. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index 95aa3ec7a5..21bf37c627 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -23,7 +23,7 @@ + # them. + + # The list of system calls is current as of Linux 5.1. +-kernel 5.1 ++kernel 5.2 + + FAST_atomic_update + FAST_cmpxchg +@@ -124,7 +124,11 @@ fork + fp_udfiex_crtl + free_hugepages + fremovexattr ++fsconfig + fsetxattr ++fsmount ++fsopen ++fspick + fstat + fstat64 + fstatat64 +@@ -248,6 +252,7 @@ mmap + mmap2 + modify_ldt + mount ++move_mount + move_pages + mprotect + mpx +@@ -285,6 +290,7 @@ oldumount + olduname + open + open_by_handle_at ++open_tree + openat + osf_adjtime + osf_afs_syscall diff --git a/SOURCES/glibc-rh1764234-7.patch b/SOURCES/glibc-rh1764234-7.patch new file mode 100644 index 0000000..9322a53 --- /dev/null +++ b/SOURCES/glibc-rh1764234-7.patch @@ -0,0 +1,24 @@ +commit 9c37bde5a2067e5b4dc878bac0291d6b207b8add +Author: Joseph Myers +Date: Fri Aug 2 15:08:02 2019 +0000 + + Update kernel version in comment in syscall-names.list. + + This patch updates the Linux kernel version in a comment in + syscall-names.list to agree with the following "kernel" line. + + * sysdeps/unix/sysv/linux/syscall-names.list: Update comment. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index 21bf37c627..9dcdd293d3 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -22,7 +22,7 @@ + # names are only used if the installed kernel headers also provide + # them. + +-# The list of system calls is current as of Linux 5.1. ++# The list of system calls is current as of Linux 5.2. + kernel 5.2 + + FAST_atomic_update diff --git a/SOURCES/glibc-rh1764234-8.patch b/SOURCES/glibc-rh1764234-8.patch new file mode 100644 index 0000000..1728729 --- /dev/null +++ b/SOURCES/glibc-rh1764234-8.patch @@ -0,0 +1,47 @@ +commit 0f02b6cfc44af73d4d4363c46b3cbb18b8ff9171 +Author: Joseph Myers +Date: Wed Sep 18 22:57:46 2019 +0000 + + Update syscall-names.list for Linux 5.3. + + This patch updates syscall-names.list for Linux 5.3, adding two new + syscalls. + + Tested with build-many-glibcs.py. + + * sysdeps/unix/sysv/linux/syscall-names.list: Update kernel + version to 5.3. + (clone3): New syscall. + (pidfd_open): Likewise. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index e2382d3414..b55ffbc2a0 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -22,8 +22,8 @@ + # names are only used if the installed kernel headers also provide + # them. + +-# The list of system calls is current as of Linux 5.2. +-kernel 5.2 ++# The list of system calls is current as of Linux 5.3. ++kernel 5.3 + + FAST_atomic_update + FAST_cmpxchg +@@ -75,6 +75,7 @@ clock_settime + clock_settime64 + clone + clone2 ++clone3 + close + cmpxchg_badaddr + connect +@@ -410,6 +411,7 @@ perf_event_open + perfctr + perfmonctl + personality ++pidfd_open + pidfd_send_signal + pipe + pipe2 diff --git a/SOURCES/glibc-rh1764235.patch b/SOURCES/glibc-rh1764235.patch new file mode 100644 index 0000000..1b783b9 --- /dev/null +++ b/SOURCES/glibc-rh1764235.patch @@ -0,0 +1,165 @@ +commit e621246ec6393ea08ae50310f9d5e72500f8c9bc +Author: Carlos O'Donell +Date: Mon Apr 8 17:35:05 2019 -0400 + + malloc: Set and reset all hooks for tracing (Bug 16573) + + If an error occurs during the tracing operation, particularly during a + call to lock_and_info() which calls _dl_addr, we may end up calling back + into the malloc-subsystem and relock the loader lock and deadlock. For + all intents and purposes the call to _dl_addr can call any of the malloc + family API functions and so we should disable all tracing before calling + such loader functions. This is similar to the strategy that the new + malloc tracer takes when calling the real malloc, namely that all + tracing ceases at the boundary to the real function and any faults at + that point are the purvue of the library (though the new tracer does + this on a per-thread basis in an MT-safe fashion). Since the new tracer + and the hook deprecation are not yet complete we must fix these issues + where we can. + + Tested on x86_64 with no regressions. + + Co-authored-by: Kwok Cheung Yeung + Reviewed-by: DJ Delorie + +diff --git a/malloc/mtrace.c b/malloc/mtrace.c +index 9064f209ec3b24c6..546d37a26018bf41 100644 +--- a/malloc/mtrace.c ++++ b/malloc/mtrace.c +@@ -121,6 +121,41 @@ lock_and_info (const void *caller, Dl_info *mem) + return res; + } + ++static void tr_freehook (void *, const void *); ++static void * tr_mallochook (size_t, const void *); ++static void * tr_reallochook (void *, size_t, const void *); ++static void * tr_memalignhook (size_t, size_t, const void *); ++ ++/* Set all the default non-trace hooks. */ ++static __always_inline void ++set_default_hooks (void) ++{ ++ __free_hook = tr_old_free_hook; ++ __malloc_hook = tr_old_malloc_hook; ++ __realloc_hook = tr_old_realloc_hook; ++ __memalign_hook = tr_old_memalign_hook; ++} ++ ++/* Set all of the tracing hooks used for mtrace. */ ++static __always_inline void ++set_trace_hooks (void) ++{ ++ __free_hook = tr_freehook; ++ __malloc_hook = tr_mallochook; ++ __realloc_hook = tr_reallochook; ++ __memalign_hook = tr_memalignhook; ++} ++ ++/* Save the current set of hooks as the default hooks. */ ++static __always_inline void ++save_default_hooks (void) ++{ ++ tr_old_free_hook = __free_hook; ++ tr_old_malloc_hook = __malloc_hook; ++ tr_old_realloc_hook = __realloc_hook; ++ tr_old_memalign_hook = __memalign_hook; ++} ++ + static void + tr_freehook (void *ptr, const void *caller) + { +@@ -138,12 +173,12 @@ tr_freehook (void *ptr, const void *caller) + tr_break (); + __libc_lock_lock (lock); + } +- __free_hook = tr_old_free_hook; ++ set_default_hooks (); + if (tr_old_free_hook != NULL) + (*tr_old_free_hook)(ptr, caller); + else + free (ptr); +- __free_hook = tr_freehook; ++ set_trace_hooks (); + __libc_lock_unlock (lock); + } + +@@ -155,12 +190,12 @@ tr_mallochook (size_t size, const void *caller) + Dl_info mem; + Dl_info *info = lock_and_info (caller, &mem); + +- __malloc_hook = tr_old_malloc_hook; ++ set_default_hooks (); + if (tr_old_malloc_hook != NULL) + hdr = (void *) (*tr_old_malloc_hook)(size, caller); + else + hdr = (void *) malloc (size); +- __malloc_hook = tr_mallochook; ++ set_trace_hooks (); + + tr_where (caller, info); + /* We could be printing a NULL here; that's OK. */ +@@ -185,16 +220,12 @@ tr_reallochook (void *ptr, size_t size, const void *caller) + Dl_info mem; + Dl_info *info = lock_and_info (caller, &mem); + +- __free_hook = tr_old_free_hook; +- __malloc_hook = tr_old_malloc_hook; +- __realloc_hook = tr_old_realloc_hook; ++ set_default_hooks (); + if (tr_old_realloc_hook != NULL) + hdr = (void *) (*tr_old_realloc_hook)(ptr, size, caller); + else + hdr = (void *) realloc (ptr, size); +- __free_hook = tr_freehook; +- __malloc_hook = tr_mallochook; +- __realloc_hook = tr_reallochook; ++ set_trace_hooks (); + + tr_where (caller, info); + if (hdr == NULL) +@@ -230,14 +261,12 @@ tr_memalignhook (size_t alignment, size_t size, const void *caller) + Dl_info mem; + Dl_info *info = lock_and_info (caller, &mem); + +- __memalign_hook = tr_old_memalign_hook; +- __malloc_hook = tr_old_malloc_hook; ++ set_default_hooks (); + if (tr_old_memalign_hook != NULL) + hdr = (void *) (*tr_old_memalign_hook)(alignment, size, caller); + else + hdr = (void *) memalign (alignment, size); +- __memalign_hook = tr_memalignhook; +- __malloc_hook = tr_mallochook; ++ set_trace_hooks (); + + tr_where (caller, info); + /* We could be printing a NULL here; that's OK. */ +@@ -305,14 +334,8 @@ mtrace (void) + malloc_trace_buffer = mtb; + setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE); + fprintf (mallstream, "= Start\n"); +- tr_old_free_hook = __free_hook; +- __free_hook = tr_freehook; +- tr_old_malloc_hook = __malloc_hook; +- __malloc_hook = tr_mallochook; +- tr_old_realloc_hook = __realloc_hook; +- __realloc_hook = tr_reallochook; +- tr_old_memalign_hook = __memalign_hook; +- __memalign_hook = tr_memalignhook; ++ save_default_hooks (); ++ set_trace_hooks (); + #ifdef _LIBC + if (!added_atexit_handler) + { +@@ -338,10 +361,7 @@ muntrace (void) + file. */ + FILE *f = mallstream; + mallstream = NULL; +- __free_hook = tr_old_free_hook; +- __malloc_hook = tr_old_malloc_hook; +- __realloc_hook = tr_old_realloc_hook; +- __memalign_hook = tr_old_memalign_hook; ++ set_default_hooks (); + + fprintf (f, "= End\n"); + fclose (f); diff --git a/SOURCES/glibc-rh1764238-1.patch b/SOURCES/glibc-rh1764238-1.patch new file mode 100644 index 0000000..63fc994 --- /dev/null +++ b/SOURCES/glibc-rh1764238-1.patch @@ -0,0 +1,92 @@ +commit dc0afac3252d0c53716ccaf0b424f7769a66d695 +Author: marxin +Date: Wed Feb 20 14:54:35 2019 +0100 + + Add new Fortran vector math header file. + +diff --git a/bits/math-vector-fortran.h b/bits/math-vector-fortran.h +new file mode 100644 +index 0000000000000000..7c1e095094e24571 +--- /dev/null ++++ b/bits/math-vector-fortran.h +@@ -0,0 +1,19 @@ ++! Platform-specific declarations of SIMD math functions for Fortran. -*- f90 -*- ++! Copyright (C) 2019 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 ++! . ++ ++! No SIMD math functions are available for this platform. +diff --git a/math/Makefile b/math/Makefile +index 90b3b68916e12d85..16e68754fc863ea2 100644 +--- a/math/Makefile ++++ b/math/Makefile +@@ -26,6 +26,7 @@ headers := math.h bits/mathcalls.h bits/mathinline.h \ + fpu_control.h complex.h bits/cmathcalls.h fenv.h \ + bits/fenv.h bits/fenvinline.h bits/mathdef.h tgmath.h \ + bits/math-finite.h bits/math-vector.h \ ++ bits/math-vector-fortran.h \ + bits/libm-simd-decl-stubs.h bits/iscanonical.h \ + bits/flt-eval-method.h bits/fp-fast.h bits/fp-logb.h \ + bits/long-double.h bits/mathcalls-helper-functions.h \ +diff --git a/sysdeps/x86/fpu/bits/math-vector-fortran.h b/sysdeps/x86/fpu/bits/math-vector-fortran.h +new file mode 100644 +index 0000000000000000..36051cc73ea03602 +--- /dev/null ++++ b/sysdeps/x86/fpu/bits/math-vector-fortran.h +@@ -0,0 +1,43 @@ ++! Platform-specific declarations of SIMD math functions for Fortran. -*- f90 -*- ++! Copyright (C) 2019 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 ++! . ++ ++!GCC$ builtin (cos) attributes simd (notinbranch) if('x86_64') ++!GCC$ builtin (cosf) attributes simd (notinbranch) if('x86_64') ++!GCC$ builtin (sin) attributes simd (notinbranch) if('x86_64') ++!GCC$ builtin (sinf) attributes simd (notinbranch) if('x86_64') ++!GCC$ builtin (sincos) attributes simd (notinbranch) if('x86_64') ++!GCC$ builtin (sincosf) attributes simd (notinbranch) if('x86_64') ++!GCC$ builtin (log) attributes simd (notinbranch) if('x86_64') ++!GCC$ builtin (logf) attributes simd (notinbranch) if('x86_64') ++!GCC$ builtin (exp) attributes simd (notinbranch) if('x86_64') ++!GCC$ builtin (expf) attributes simd (notinbranch) if('x86_64') ++!GCC$ builtin (pow) attributes simd (notinbranch) if('x86_64') ++!GCC$ builtin (powf) attributes simd (notinbranch) if('x86_64') ++ ++!GCC$ builtin (cos) attributes simd (notinbranch) if('x32') ++!GCC$ builtin (cosf) attributes simd (notinbranch) if('x32') ++!GCC$ builtin (sin) attributes simd (notinbranch) if('x32') ++!GCC$ builtin (sinf) attributes simd (notinbranch) if('x32') ++!GCC$ builtin (sincos) attributes simd (notinbranch) if('x32') ++!GCC$ builtin (sincosf) attributes simd (notinbranch) if('x32') ++!GCC$ builtin (log) attributes simd (notinbranch) if('x32') ++!GCC$ builtin (logf) attributes simd (notinbranch) if('x32') ++!GCC$ builtin (exp) attributes simd (notinbranch) if('x32') ++!GCC$ builtin (expf) attributes simd (notinbranch) if('x32') ++!GCC$ builtin (pow) attributes simd (notinbranch) if('x32') ++!GCC$ builtin (powf) attributes simd (notinbranch) if('x32') diff --git a/SOURCES/glibc-rh1764238-2.patch b/SOURCES/glibc-rh1764238-2.patch new file mode 100644 index 0000000..5cafd01 --- /dev/null +++ b/SOURCES/glibc-rh1764238-2.patch @@ -0,0 +1,56 @@ +commit ae514971341dcc08ec7f8622493a65e7eb1ef9d2 +Author: marxin +Date: Thu Mar 7 09:39:55 2019 +0100 + + Fix location where math-vector-fortran.h is installed. + + 2019-03-07 Martin Liska + + * math/Makefile: Change location where math-vector-fortran.h is + installed. + * math/finclude/math-vector-fortran.h: Move from bits/math-vector-fortran.h. + * sysdeps/x86/fpu/finclude/math-vector-fortran.h: Move + from sysdeps/x86/fpu/bits/math-vector-fortran.h. + * scripts/check-installed-headers.sh: Skip Fortran header files. + * scripts/check-wrapper-headers.py: Likewise. + +Conflicts: + scripts/check-wrapper-headers.py + (Script does not exist downstream, change dropped.) + +diff --git a/math/Makefile b/math/Makefile +index 16e68754fc863ea2..df73d70840b61cd7 100644 +--- a/math/Makefile ++++ b/math/Makefile +@@ -26,7 +26,7 @@ headers := math.h bits/mathcalls.h bits/mathinline.h \ + fpu_control.h complex.h bits/cmathcalls.h fenv.h \ + bits/fenv.h bits/fenvinline.h bits/mathdef.h tgmath.h \ + bits/math-finite.h bits/math-vector.h \ +- bits/math-vector-fortran.h \ ++ finclude/math-vector-fortran.h \ + bits/libm-simd-decl-stubs.h bits/iscanonical.h \ + bits/flt-eval-method.h bits/fp-fast.h bits/fp-logb.h \ + bits/long-double.h bits/mathcalls-helper-functions.h \ +diff --git a/bits/math-vector-fortran.h b/math/finclude/math-vector-fortran.h +similarity index 100% +rename from bits/math-vector-fortran.h +rename to math/finclude/math-vector-fortran.h +diff --git a/scripts/check-installed-headers.sh b/scripts/check-installed-headers.sh +index 4a062e9cdaa57978..7a1969b43a144ebb 100644 +--- a/scripts/check-installed-headers.sh ++++ b/scripts/check-installed-headers.sh +@@ -84,6 +84,10 @@ for header in "$@"; do + (sys/elf.h) + continue;; + ++ # Skip Fortran headers. ++ (finclude/*) ++ continue;; ++ + # sys/sysctl.h is unsupported for x32. + (sys/sysctl.h) + case "$is_x32" in +diff --git a/sysdeps/x86/fpu/bits/math-vector-fortran.h b/sysdeps/x86/fpu/finclude/math-vector-fortran.h +similarity index 100% +rename from sysdeps/x86/fpu/bits/math-vector-fortran.h +rename to sysdeps/x86/fpu/finclude/math-vector-fortran.h diff --git a/SOURCES/glibc-rh1764241.patch b/SOURCES/glibc-rh1764241.patch new file mode 100644 index 0000000..9044857 --- /dev/null +++ b/SOURCES/glibc-rh1764241.patch @@ -0,0 +1,544 @@ +commit 09e1b0e3f6facc1af2dbcfef204f0aaa8718772b +Author: Florian Weimer +Date: Mon May 20 21:54:57 2019 +0200 + + libio: Remove codecvt vtable [BZ #24588] + + The codecvt vtable is not a real vtable because it also contains the + conversion state data. Furthermore, wide stream support was added to + GCC 3.0, after a C++ ABI bump, so there is no compatibility + requirement with libstdc++. + + This change removes several unmangled function pointers which could + be used with a corrupted FILE object to redirect execution. (libio + vtable verification did not cover the codecvt vtable.) + + Reviewed-by: Yann Droneaud + Reviewed-by: Adhemerval Zanella + +diff --git a/libio/fileops.c b/libio/fileops.c +index d2070a856e..daa5a05877 100644 +--- a/libio/fileops.c ++++ b/libio/fileops.c +@@ -331,9 +331,6 @@ _IO_new_file_fopen (FILE *fp, const char *filename, const char *mode, + + cc = fp->_codecvt = &fp->_wide_data->_codecvt; + +- /* The functions are always the same. */ +- *cc = __libio_codecvt; +- + cc->__cd_in.__cd.__nsteps = fcts.towc_nsteps; + cc->__cd_in.__cd.__steps = fcts.towc; + +diff --git a/libio/iofgetpos.c b/libio/iofgetpos.c +index 8032192440..388c4a0708 100644 +--- a/libio/iofgetpos.c ++++ b/libio/iofgetpos.c +@@ -70,8 +70,7 @@ _IO_new_fgetpos (FILE *fp, __fpos_t *posp) + else + { + posp->__pos = pos; +- if (fp->_mode > 0 +- && (*fp->_codecvt->__codecvt_do_encoding) (fp->_codecvt) < 0) ++ if (fp->_mode > 0 && __libio_codecvt_encoding (fp->_codecvt) < 0) + /* This is a stateful encoding, safe the state. */ + posp->__state = fp->_wide_data->_IO_state; + } +diff --git a/libio/iofgetpos64.c b/libio/iofgetpos64.c +index 54de6a8205..6a0ba50d29 100644 +--- a/libio/iofgetpos64.c ++++ b/libio/iofgetpos64.c +@@ -54,8 +54,7 @@ _IO_new_fgetpos64 (FILE *fp, __fpos64_t *posp) + else + { + posp->__pos = pos; +- if (fp->_mode > 0 +- && (*fp->_codecvt->__codecvt_do_encoding) (fp->_codecvt) < 0) ++ if (fp->_mode > 0 && __libio_codecvt_encoding (fp->_codecvt) < 0) + /* This is a stateful encoding, safe the state. */ + posp->__state = fp->_wide_data->_IO_state; + } +diff --git a/libio/iofsetpos.c b/libio/iofsetpos.c +index d7b1abbc61..4df1aae082 100644 +--- a/libio/iofsetpos.c ++++ b/libio/iofsetpos.c +@@ -58,8 +58,7 @@ _IO_new_fsetpos (FILE *fp, const __fpos_t *posp) + else + { + result = 0; +- if (fp->_mode > 0 +- && (*fp->_codecvt->__codecvt_do_encoding) (fp->_codecvt) < 0) ++ if (fp->_mode > 0 && __libio_codecvt_encoding (fp->_codecvt) < 0) + /* This is a stateful encoding, restore the state. */ + fp->_wide_data->_IO_state = posp->__state; + } +diff --git a/libio/iofsetpos64.c b/libio/iofsetpos64.c +index d1865b728e..f382ba0dc1 100644 +--- a/libio/iofsetpos64.c ++++ b/libio/iofsetpos64.c +@@ -48,8 +48,7 @@ _IO_new_fsetpos64 (FILE *fp, const fpos64_t *posp) + else + { + result = 0; +- if (fp->_mode > 0 +- && (*fp->_codecvt->__codecvt_do_encoding) (fp->_codecvt) < 0) ++ if (fp->_mode > 0 && __libio_codecvt_encoding (fp->_codecvt) < 0) + /* This is a stateful encoding, safe the state. */ + fp->_wide_data->_IO_state = posp->__state; + } +diff --git a/libio/iofwide.c b/libio/iofwide.c +index 247cfde3d0..80cb2d5074 100644 +--- a/libio/iofwide.c ++++ b/libio/iofwide.c +@@ -39,44 +39,6 @@ + #include + + +-/* Prototypes of libio's codecvt functions. */ +-static enum __codecvt_result do_out (struct _IO_codecvt *codecvt, +- __mbstate_t *statep, +- const wchar_t *from_start, +- const wchar_t *from_end, +- const wchar_t **from_stop, char *to_start, +- char *to_end, char **to_stop); +-static enum __codecvt_result do_unshift (struct _IO_codecvt *codecvt, +- __mbstate_t *statep, char *to_start, +- char *to_end, char **to_stop); +-static enum __codecvt_result do_in (struct _IO_codecvt *codecvt, +- __mbstate_t *statep, +- const char *from_start, +- const char *from_end, +- const char **from_stop, wchar_t *to_start, +- wchar_t *to_end, wchar_t **to_stop); +-static int do_encoding (struct _IO_codecvt *codecvt); +-static int do_length (struct _IO_codecvt *codecvt, __mbstate_t *statep, +- const char *from_start, +- const char *from_end, size_t max); +-static int do_max_length (struct _IO_codecvt *codecvt); +-static int do_always_noconv (struct _IO_codecvt *codecvt); +- +- +-/* The functions used in `codecvt' for libio are always the same. */ +-const struct _IO_codecvt __libio_codecvt = +-{ +- .__codecvt_destr = NULL, /* Destructor, never used. */ +- .__codecvt_do_out = do_out, +- .__codecvt_do_unshift = do_unshift, +- .__codecvt_do_in = do_in, +- .__codecvt_do_encoding = do_encoding, +- .__codecvt_do_always_noconv = do_always_noconv, +- .__codecvt_do_length = do_length, +- .__codecvt_do_max_length = do_max_length +-}; +- +- + /* Return orientation of stream. If mode is nonzero try to change + the orientation first. */ + #undef _IO_fwide +@@ -118,9 +80,6 @@ _IO_fwide (FILE *fp, int mode) + assert (fcts.towc_nsteps == 1); + assert (fcts.tomb_nsteps == 1); + +- /* The functions are always the same. */ +- *cc = __libio_codecvt; +- + cc->__cd_in.__cd.__nsteps = fcts.towc_nsteps; + cc->__cd_in.__cd.__steps = fcts.towc; + +@@ -150,11 +109,11 @@ _IO_fwide (FILE *fp, int mode) + } + + +-static enum __codecvt_result +-do_out (struct _IO_codecvt *codecvt, __mbstate_t *statep, +- const wchar_t *from_start, const wchar_t *from_end, +- const wchar_t **from_stop, char *to_start, char *to_end, +- char **to_stop) ++enum __codecvt_result ++__libio_codecvt_out (struct _IO_codecvt *codecvt, __mbstate_t *statep, ++ const wchar_t *from_start, const wchar_t *from_end, ++ const wchar_t **from_stop, char *to_start, char *to_end, ++ char **to_stop) + { + enum __codecvt_result result; + +@@ -202,57 +161,11 @@ do_out (struct _IO_codecvt *codecvt, __mbstate_t *statep, + } + + +-static enum __codecvt_result +-do_unshift (struct _IO_codecvt *codecvt, __mbstate_t *statep, +- char *to_start, char *to_end, char **to_stop) +-{ +- enum __codecvt_result result; +- +- struct __gconv_step *gs = codecvt->__cd_out.__cd.__steps; +- int status; +- size_t dummy; +- +- codecvt->__cd_out.__cd.__data[0].__outbuf = (unsigned char *) to_start; +- codecvt->__cd_out.__cd.__data[0].__outbufend = (unsigned char *) to_end; +- codecvt->__cd_out.__cd.__data[0].__statep = statep; +- +- __gconv_fct fct = gs->__fct; +-#ifdef PTR_DEMANGLE +- if (gs->__shlib_handle != NULL) +- PTR_DEMANGLE (fct); +-#endif +- +- status = DL_CALL_FCT (fct, +- (gs, codecvt->__cd_out.__cd.__data, NULL, NULL, +- NULL, &dummy, 1, 0)); +- +- *to_stop = (char *) codecvt->__cd_out.__cd.__data[0].__outbuf; +- +- switch (status) +- { +- case __GCONV_OK: +- case __GCONV_EMPTY_INPUT: +- result = __codecvt_ok; +- break; +- +- case __GCONV_FULL_OUTPUT: +- case __GCONV_INCOMPLETE_INPUT: +- result = __codecvt_partial; +- break; +- +- default: +- result = __codecvt_error; +- break; +- } +- +- return result; +-} +- +- +-static enum __codecvt_result +-do_in (struct _IO_codecvt *codecvt, __mbstate_t *statep, +- const char *from_start, const char *from_end, const char **from_stop, +- wchar_t *to_start, wchar_t *to_end, wchar_t **to_stop) ++enum __codecvt_result ++__libio_codecvt_in (struct _IO_codecvt *codecvt, __mbstate_t *statep, ++ const char *from_start, const char *from_end, ++ const char **from_stop, ++ wchar_t *to_start, wchar_t *to_end, wchar_t **to_stop) + { + enum __codecvt_result result; + +@@ -300,8 +213,8 @@ do_in (struct _IO_codecvt *codecvt, __mbstate_t *statep, + } + + +-static int +-do_encoding (struct _IO_codecvt *codecvt) ++int ++__libio_codecvt_encoding (struct _IO_codecvt *codecvt) + { + /* See whether the encoding is stateful. */ + if (codecvt->__cd_in.__cd.__steps[0].__stateful) +@@ -317,16 +230,10 @@ do_encoding (struct _IO_codecvt *codecvt) + } + + +-static int +-do_always_noconv (struct _IO_codecvt *codecvt) +-{ +- return 0; +-} +- +- +-static int +-do_length (struct _IO_codecvt *codecvt, __mbstate_t *statep, +- const char *from_start, const char *from_end, size_t max) ++int ++__libio_codecvt_length (struct _IO_codecvt *codecvt, __mbstate_t *statep, ++ const char *from_start, const char *from_end, ++ size_t max) + { + int result; + const unsigned char *cp = (const unsigned char *) from_start; +@@ -353,10 +260,3 @@ do_length (struct _IO_codecvt *codecvt, __mbstate_t *statep, + + return result; + } +- +- +-static int +-do_max_length (struct _IO_codecvt *codecvt) +-{ +- return codecvt->__cd_in.__cd.__steps[0].__max_needed_from; +-} +diff --git a/libio/libio.h b/libio/libio.h +index c38095ff77..b985c386a2 100644 +--- a/libio/libio.h ++++ b/libio/libio.h +@@ -116,40 +116,8 @@ struct _IO_marker { + int _pos; + }; + +-/* This is the structure from the libstdc++ codecvt class. */ +-enum __codecvt_result +-{ +- __codecvt_ok, +- __codecvt_partial, +- __codecvt_error, +- __codecvt_noconv +-}; +- +-/* The order of the elements in the following struct must match the order +- of the virtual functions in the libstdc++ codecvt class. */ + struct _IO_codecvt + { +- void (*__codecvt_destr) (struct _IO_codecvt *); +- enum __codecvt_result (*__codecvt_do_out) (struct _IO_codecvt *, +- __mbstate_t *, +- const wchar_t *, +- const wchar_t *, +- const wchar_t **, char *, +- char *, char **); +- enum __codecvt_result (*__codecvt_do_unshift) (struct _IO_codecvt *, +- __mbstate_t *, char *, +- char *, char **); +- enum __codecvt_result (*__codecvt_do_in) (struct _IO_codecvt *, +- __mbstate_t *, +- const char *, const char *, +- const char **, wchar_t *, +- wchar_t *, wchar_t **); +- int (*__codecvt_do_encoding) (struct _IO_codecvt *); +- int (*__codecvt_do_always_noconv) (struct _IO_codecvt *); +- int (*__codecvt_do_length) (struct _IO_codecvt *, __mbstate_t *, +- const char *, const char *, size_t); +- int (*__codecvt_do_max_length) (struct _IO_codecvt *); +- + _IO_iconv_t __cd_in; + _IO_iconv_t __cd_out; + }; +diff --git a/libio/libioP.h b/libio/libioP.h +index 7bdec86a62..66afaa8968 100644 +--- a/libio/libioP.h ++++ b/libio/libioP.h +@@ -476,7 +476,6 @@ extern const struct _IO_jump_t _IO_streambuf_jumps; + extern const struct _IO_jump_t _IO_old_proc_jumps attribute_hidden; + extern const struct _IO_jump_t _IO_str_jumps attribute_hidden; + extern const struct _IO_jump_t _IO_wstr_jumps attribute_hidden; +-extern const struct _IO_codecvt __libio_codecvt attribute_hidden; + extern int _IO_do_write (FILE *, const char *, size_t); + libc_hidden_proto (_IO_do_write) + extern int _IO_new_do_write (FILE *, const char *, size_t); +@@ -932,4 +931,32 @@ IO_validate_vtable (const struct _IO_jump_t *vtable) + return vtable; + } + ++/* Character set conversion. */ ++ ++enum __codecvt_result ++{ ++ __codecvt_ok, ++ __codecvt_partial, ++ __codecvt_error, ++ __codecvt_noconv ++}; ++ ++enum __codecvt_result __libio_codecvt_out (struct _IO_codecvt *, ++ __mbstate_t *, ++ const wchar_t *, ++ const wchar_t *, ++ const wchar_t **, char *, ++ char *, char **) ++ attribute_hidden; ++enum __codecvt_result __libio_codecvt_in (struct _IO_codecvt *, ++ __mbstate_t *, ++ const char *, const char *, ++ const char **, wchar_t *, ++ wchar_t *, wchar_t **) ++ attribute_hidden; ++int __libio_codecvt_encoding (struct _IO_codecvt *) attribute_hidden; ++int __libio_codecvt_length (struct _IO_codecvt *, __mbstate_t *, ++ const char *, const char *, size_t) ++ attribute_hidden; ++ + #endif /* libioP.h. */ +diff --git a/libio/wfileops.c b/libio/wfileops.c +index 69fbb62a02..f1863db638 100644 +--- a/libio/wfileops.c ++++ b/libio/wfileops.c +@@ -72,11 +72,11 @@ _IO_wdo_write (FILE *fp, const wchar_t *data, size_t to_do) + } + + /* Now convert from the internal format into the external buffer. */ +- result = (*cc->__codecvt_do_out) (cc, &fp->_wide_data->_IO_state, +- data, data + to_do, &new_data, +- write_ptr, +- buf_end, +- &write_ptr); ++ result = __libio_codecvt_out (cc, &fp->_wide_data->_IO_state, ++ data, data + to_do, &new_data, ++ write_ptr, ++ buf_end, ++ &write_ptr); + + /* Write out what we produced so far. */ + if (_IO_new_do_write (fp, write_base, write_ptr - write_base) == EOF) +@@ -140,12 +140,12 @@ _IO_wfile_underflow (FILE *fp) + fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state; + fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr = + fp->_wide_data->_IO_buf_base; +- status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state, +- fp->_IO_read_ptr, fp->_IO_read_end, +- &read_stop, +- fp->_wide_data->_IO_read_ptr, +- fp->_wide_data->_IO_buf_end, +- &fp->_wide_data->_IO_read_end); ++ status = __libio_codecvt_in (cd, &fp->_wide_data->_IO_state, ++ fp->_IO_read_ptr, fp->_IO_read_end, ++ &read_stop, ++ fp->_wide_data->_IO_read_ptr, ++ fp->_wide_data->_IO_buf_end, ++ &fp->_wide_data->_IO_read_end); + + fp->_IO_read_base = fp->_IO_read_ptr; + fp->_IO_read_ptr = (char *) read_stop; +@@ -266,11 +266,11 @@ _IO_wfile_underflow (FILE *fp) + naccbuf += to_copy; + from = accbuf; + } +- status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state, +- from, to, &read_ptr_copy, +- fp->_wide_data->_IO_read_end, +- fp->_wide_data->_IO_buf_end, +- &fp->_wide_data->_IO_read_end); ++ status = __libio_codecvt_in (cd, &fp->_wide_data->_IO_state, ++ from, to, &read_ptr_copy, ++ fp->_wide_data->_IO_read_end, ++ fp->_wide_data->_IO_buf_end, ++ &fp->_wide_data->_IO_read_end); + + if (__glibc_unlikely (naccbuf != 0)) + fp->_IO_read_ptr += MAX (0, read_ptr_copy - &accbuf[naccbuf - to_copy]); +@@ -372,12 +372,12 @@ _IO_wfile_underflow_mmap (FILE *fp) + fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state; + fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr = + fp->_wide_data->_IO_buf_base; +- (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state, +- fp->_IO_read_ptr, fp->_IO_read_end, +- &read_stop, +- fp->_wide_data->_IO_read_ptr, +- fp->_wide_data->_IO_buf_end, +- &fp->_wide_data->_IO_read_end); ++ __libio_codecvt_in (cd, &fp->_wide_data->_IO_state, ++ fp->_IO_read_ptr, fp->_IO_read_end, ++ &read_stop, ++ fp->_wide_data->_IO_read_ptr, ++ fp->_wide_data->_IO_buf_end, ++ &fp->_wide_data->_IO_read_end); + + fp->_IO_read_ptr = (char *) read_stop; + +@@ -495,7 +495,7 @@ _IO_wfile_sync (FILE *fp) + struct _IO_codecvt *cv = fp->_codecvt; + off64_t new_pos; + +- int clen = (*cv->__codecvt_do_encoding) (cv); ++ int clen = __libio_codecvt_encoding (cv); + + if (clen > 0) + /* It is easy, a fixed number of input bytes are used for each +@@ -511,9 +511,9 @@ _IO_wfile_sync (FILE *fp) + size_t wnread = (fp->_wide_data->_IO_read_ptr + - fp->_wide_data->_IO_read_base); + fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state; +- nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state, +- fp->_IO_read_base, +- fp->_IO_read_end, wnread); ++ nread = __libio_codecvt_length (cv, &fp->_wide_data->_IO_state, ++ fp->_IO_read_base, ++ fp->_IO_read_end, wnread); + fp->_IO_read_ptr = fp->_IO_read_base + nread; + delta = -(fp->_IO_read_end - fp->_IO_read_base - nread); + } +@@ -548,7 +548,7 @@ adjust_wide_data (FILE *fp, bool do_convert) + { + struct _IO_codecvt *cv = fp->_codecvt; + +- int clen = (*cv->__codecvt_do_encoding) (cv); ++ int clen = __libio_codecvt_encoding (cv); + + /* Take the easy way out for constant length encodings if we don't need to + convert. */ +@@ -565,12 +565,12 @@ adjust_wide_data (FILE *fp, bool do_convert) + { + + fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state; +- status = (*cv->__codecvt_do_in) (cv, &fp->_wide_data->_IO_state, +- fp->_IO_read_base, fp->_IO_read_ptr, +- &read_stop, +- fp->_wide_data->_IO_read_base, +- fp->_wide_data->_IO_buf_end, +- &fp->_wide_data->_IO_read_end); ++ status = __libio_codecvt_in (cv, &fp->_wide_data->_IO_state, ++ fp->_IO_read_base, fp->_IO_read_ptr, ++ &read_stop, ++ fp->_wide_data->_IO_read_base, ++ fp->_wide_data->_IO_buf_end, ++ &fp->_wide_data->_IO_read_end); + + /* Should we return EILSEQ? */ + if (__glibc_unlikely (status == __codecvt_error)) +@@ -648,7 +648,7 @@ do_ftell_wide (FILE *fp) + } + + struct _IO_codecvt *cv = fp->_codecvt; +- int clen = (*cv->__codecvt_do_encoding) (cv); ++ int clen = __libio_codecvt_encoding (cv); + + if (!unflushed_writes) + { +@@ -663,9 +663,9 @@ do_ftell_wide (FILE *fp) + + size_t delta = wide_read_ptr - wide_read_base; + __mbstate_t state = fp->_wide_data->_IO_last_state; +- nread = (*cv->__codecvt_do_length) (cv, &state, +- fp->_IO_read_base, +- fp->_IO_read_end, delta); ++ nread = __libio_codecvt_length (cv, &state, ++ fp->_IO_read_base, ++ fp->_IO_read_end, delta); + offset -= fp->_IO_read_end - fp->_IO_read_base - nread; + } + } +@@ -688,9 +688,8 @@ do_ftell_wide (FILE *fp) + enum __codecvt_result status; + + __mbstate_t state = fp->_wide_data->_IO_last_state; +- status = (*cv->__codecvt_do_out) (cv, &state, +- in, in + delta, &in, +- out, out + outsize, &outstop); ++ status = __libio_codecvt_out (cv, &state, in, in + delta, &in, ++ out, out + outsize, &outstop); + + /* We don't check for __codecvt_partial because it can be + returned on one of two conditions: either the output +@@ -801,7 +800,7 @@ _IO_wfile_seekoff (FILE *fp, off64_t offset, int dir, int mode) + find out which position in the external buffer corresponds to + the current position in the internal buffer. */ + cv = fp->_codecvt; +- clen = (*cv->__codecvt_do_encoding) (cv); ++ clen = __libio_codecvt_encoding (cv); + + if (mode != 0 || !was_writing) + { +@@ -819,10 +818,10 @@ _IO_wfile_seekoff (FILE *fp, off64_t offset, int dir, int mode) + delta = (fp->_wide_data->_IO_read_ptr + - fp->_wide_data->_IO_read_base); + fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state; +- nread = (*cv->__codecvt_do_length) (cv, +- &fp->_wide_data->_IO_state, +- fp->_IO_read_base, +- fp->_IO_read_end, delta); ++ nread = __libio_codecvt_length (cv, ++ &fp->_wide_data->_IO_state, ++ fp->_IO_read_base, ++ fp->_IO_read_end, delta); + fp->_IO_read_ptr = fp->_IO_read_base + nread; + fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr; + offset -= fp->_IO_read_end - fp->_IO_read_base - nread; diff --git a/SOURCES/glibc-rh1764242.patch b/SOURCES/glibc-rh1764242.patch new file mode 100644 index 0000000..b8c9a2f --- /dev/null +++ b/SOURCES/glibc-rh1764242.patch @@ -0,0 +1,81 @@ +commit 4997e8f31e7415652c3dedec672c0e9bf8caa9ca +Author: Adhemerval Zanella +Date: Fri Feb 1 10:39:57 2019 -0200 + + math: Enable some math builtins for clang + + This patch enable the builtin usage for clang for the C99 functions + fpclassify, isfinite, isnormal, isnan, isinf, and sigbit. This allows + clang optimize the calls on frontend instead of call the appropriate + glibc symbols. + + Checked on aarch64-linux-gnu and x86_64-linux-gnu. I checked the supported + version for each builtin based on released version from clang/llvm. + + * math/math.h (fpclassify, isfinite, isnormal, isnan): Use builtin for + clang 2.8. + (signbit): Use builtin for clang 3.3. + (isinf): Use builtin for clang 3.7. + +diff --git a/math/math.h b/math/math.h +index ddee4e408389722f..b3b414f3678e91f7 100644 +--- a/math/math.h ++++ b/math/math.h +@@ -874,7 +874,8 @@ enum + the __SUPPORT_SNAN__ check may be skipped for those versions. */ + + /* Return number of classification appropriate for X. */ +-# if __GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__ \ ++# if ((__GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__) \ ++ || __glibc_clang_prereq (2,8)) \ + && (!defined __OPTIMIZE_SIZE__ || defined __cplusplus) + /* The check for __cplusplus allows the use of the builtin, even + when optimization for size is on. This is provided for +@@ -889,7 +890,7 @@ enum + # endif + + /* Return nonzero value if sign of X is negative. */ +-# if __GNUC_PREREQ (6,0) ++# if __GNUC_PREREQ (6,0) || __glibc_clang_prereq (3,3) + # define signbit(x) __builtin_signbit (x) + # elif defined __cplusplus + /* In C++ mode, __MATH_TG cannot be used, because it relies on +@@ -907,14 +908,16 @@ enum + # endif + + /* Return nonzero value if X is not +-Inf or NaN. */ +-# if __GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__ ++# if (__GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__) \ ++ || __glibc_clang_prereq (2,8) + # define isfinite(x) __builtin_isfinite (x) + # else + # define isfinite(x) __MATH_TG ((x), __finite, (x)) + # endif + + /* Return nonzero value if X is neither zero, subnormal, Inf, nor NaN. */ +-# if __GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__ ++# if (__GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__) \ ++ || __glibc_clang_prereq (2,8) + # define isnormal(x) __builtin_isnormal (x) + # else + # define isnormal(x) (fpclassify (x) == FP_NORMAL) +@@ -922,7 +925,8 @@ enum + + /* Return nonzero value if X is a NaN. We could use `fpclassify' but + we already have this functions `__isnan' and it is faster. */ +-# if __GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__ ++# if (__GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__) \ ++ || __glibc_clang_prereq (2,8) + # define isnan(x) __builtin_isnan (x) + # else + # define isnan(x) __MATH_TG ((x), __isnan, (x)) +@@ -939,7 +943,8 @@ enum + # define isinf(x) \ + (__builtin_types_compatible_p (__typeof (x), _Float128) \ + ? __isinff128 (x) : __builtin_isinf_sign (x)) +-# elif __GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__ ++# elif (__GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__) \ ++ || __glibc_clang_prereq (3,7) + # define isinf(x) __builtin_isinf_sign (x) + # else + # define isinf(x) __MATH_TG ((x), __isinf, (x)) diff --git a/SOURCES/glibc-rh1769304.patch b/SOURCES/glibc-rh1769304.patch new file mode 100644 index 0000000..e78c759 --- /dev/null +++ b/SOURCES/glibc-rh1769304.patch @@ -0,0 +1,740 @@ +commit 711a322a235d4c8177713f11aa59156603b94aeb +Author: Zack Weinberg +Date: Mon Mar 11 10:59:27 2019 -0400 + + Use a proper C tokenizer to implement the obsolete typedefs test. + + The test for obsolete typedefs in installed headers was implemented + using grep, and could therefore get false positives on e.g. “ulong” + in a comment. It was also scanning all of the headers included by + our headers, and therefore testing headers we don’t control, e.g. + Linux kernel headers. + + This patch splits the obsolete-typedef test from + scripts/check-installed-headers.sh to a separate program, + scripts/check-obsolete-constructs.py. Being implemented in Python, + it is feasible to make it tokenize C accurately enough to avoid false + positives on the contents of comments and strings. It also only + examines $(headers) in each subdirectory--all the headers we install, + but not any external dependencies of those headers. Headers whose + installed name starts with finclude/ are ignored, on the assumption + that they contain Fortran. + + It is also feasible to make the new test understand the difference + between _defining_ the obsolete typedefs and _using_ the obsolete + typedefs, which means posix/{bits,sys}/types.h no longer need to be + exempted. This uncovered an actual bug in bits/types.h: __quad_t and + __u_quad_t were being used to define __S64_TYPE, __U64_TYPE, + __SQUAD_TYPE and __UQUAD_TYPE. These are changed to __int64_t and + __uint64_t respectively. This is a safe change, despite the comments + in bits/types.h claiming a difference between __quad_t and __int64_t, + because those comments are incorrect. In all current ABIs, both + __quad_t and __int64_t are ‘long’ when ‘long’ is a 64-bit type, and + ‘long long’ when ‘long’ is a 32-bit type, and similarly for __u_quad_t + and __uint64_t. (Changing the types to be what the comments say they + are would be an ABI break, as it affects C++ name mangling.) This + patch includes a minimal change to make the comments not completely + wrong. + + sys/types.h was defining the legacy BSD u_intN_t typedefs using a + construct that was not necessarily consistent with how the C99 uintN_t + typedefs are defined, and is also too complicated for the new script to + understand (it lexes C relatively accurately, but it does not attempt + to expand preprocessor macros, nor does it do any actual parsing). + This patch cuts all of that out and uses bits/types.h's __uintN_t typedefs + to define u_intN_t instead. This is verified to not change the ABI on + any supported architecture, via the c++-types test, which means u_intN_t + and uintN_t were, in fact, consistent on all supported architectures. + + Reviewed-by: Carlos O'Donell + + * scripts/check-obsolete-constructs.py: New test script. + * scripts/check-installed-headers.sh: Remove tests for + obsolete typedefs, superseded by check-obsolete-constructs.py. + * Rules: Run scripts/check-obsolete-constructs.py over $(headers) + as a special test. Update commentary. + * posix/bits/types.h (__SQUAD_TYPE, __S64_TYPE): Define as __int64_t. + (__UQUAD_TYPE, __U64_TYPE): Define as __uint64_t. + Update commentary. + * posix/sys/types.h (__u_intN_t): Remove. + (u_int8_t): Typedef using __uint8_t. + (u_int16_t): Typedef using __uint16_t. + (u_int32_t): Typedef using __uint32_t. + (u_int64_t): Typedef using __uint64_t. + +Conflicts: + Rules + (textual conflicts due to lack of check-wrapper-headers test.) + +diff --git a/Rules b/Rules +index 5abb7270aa8e24aa..a07dbb8d978b5769 100644 +--- a/Rules ++++ b/Rules +@@ -82,7 +82,8 @@ $(common-objpfx)dummy.c: + common-generated += dummy.o dummy.c + + ifneq "$(headers)" "" +-# Special test of all the installed headers in this directory. ++# Test that all of the headers installed by this directory can be compiled ++# in isolation. + tests-special += $(objpfx)check-installed-headers-c.out + libof-check-installed-headers-c := testsuite + $(objpfx)check-installed-headers-c.out: \ +@@ -93,6 +94,8 @@ $(objpfx)check-installed-headers-c.out: \ + $(evaluate-test) + + ifneq "$(CXX)" "" ++# If a C++ compiler is available, also test that they can be compiled ++# in isolation as C++. + tests-special += $(objpfx)check-installed-headers-cxx.out + libof-check-installed-headers-cxx := testsuite + $(objpfx)check-installed-headers-cxx.out: \ +@@ -101,8 +104,19 @@ $(objpfx)check-installed-headers-cxx.out: \ + "$(CXX) $(filter-out -std=%,$(CXXFLAGS)) -D_ISOMAC $(+includes)" \ + $(headers) > $@; \ + $(evaluate-test) +-endif +-endif ++endif # $(CXX) ++ ++# Test that none of the headers installed by this directory use certain ++# obsolete constructs (e.g. legacy BSD typedefs superseded by stdint.h). ++# This script does not need $(py-env). ++tests-special += $(objpfx)check-obsolete-constructs.out ++libof-check-obsolete-constructs := testsuite ++$(objpfx)check-obsolete-constructs.out: \ ++ $(..)scripts/check-obsolete-constructs.py $(headers) ++ $(PYTHON) $^ > $@ 2>&1; \ ++ $(evaluate-test) ++ ++endif # $(headers) + + # This makes all the auxiliary and test programs. + +diff --git a/posix/bits/types.h b/posix/bits/types.h +index 5e22ce41bf4c29b3..64f344c6e7897491 100644 +--- a/posix/bits/types.h ++++ b/posix/bits/types.h +@@ -86,7 +86,7 @@ __extension__ typedef unsigned long long int __uintmax_t; + 32 -- "natural" 32-bit type (always int) + 64 -- "natural" 64-bit type (long or long long) + LONG32 -- 32-bit type, traditionally long +- QUAD -- 64-bit type, always long long ++ QUAD -- 64-bit type, traditionally long long + WORD -- natural type of __WORDSIZE bits (int or long) + LONGWORD -- type of __WORDSIZE bits, traditionally long + +@@ -112,14 +112,14 @@ __extension__ typedef unsigned long long int __uintmax_t; + #define __SLONGWORD_TYPE long int + #define __ULONGWORD_TYPE unsigned long int + #if __WORDSIZE == 32 +-# define __SQUAD_TYPE __quad_t +-# define __UQUAD_TYPE __u_quad_t ++# define __SQUAD_TYPE __int64_t ++# define __UQUAD_TYPE __uint64_t + # define __SWORD_TYPE int + # define __UWORD_TYPE unsigned int + # define __SLONG32_TYPE long int + # define __ULONG32_TYPE unsigned long int +-# define __S64_TYPE __quad_t +-# define __U64_TYPE __u_quad_t ++# define __S64_TYPE __int64_t ++# define __U64_TYPE __uint64_t + /* We want __extension__ before typedef's that use nonstandard base types + such as `long long' in C89 mode. */ + # define __STD_TYPE __extension__ typedef +diff --git a/posix/sys/types.h b/posix/sys/types.h +index db524d6cd13f0379..47eff1a7b1a91c81 100644 +--- a/posix/sys/types.h ++++ b/posix/sys/types.h +@@ -154,37 +154,20 @@ typedef unsigned int uint; + + #include + +-#if !__GNUC_PREREQ (2, 7) +- + /* These were defined by ISO C without the first `_'. */ +-typedef unsigned char u_int8_t; +-typedef unsigned short int u_int16_t; +-typedef unsigned int u_int32_t; +-# if __WORDSIZE == 64 +-typedef unsigned long int u_int64_t; +-# else +-__extension__ typedef unsigned long long int u_int64_t; +-# endif +- +-typedef int register_t; +- +-#else +- +-/* For GCC 2.7 and later, we can use specific type-size attributes. */ +-# define __u_intN_t(N, MODE) \ +- typedef unsigned int u_int##N##_t __attribute__ ((__mode__ (MODE))) +- +-__u_intN_t (8, __QI__); +-__u_intN_t (16, __HI__); +-__u_intN_t (32, __SI__); +-__u_intN_t (64, __DI__); ++typedef __uint8_t u_int8_t; ++typedef __uint16_t u_int16_t; ++typedef __uint32_t u_int32_t; ++typedef __uint64_t u_int64_t; + ++#if __GNUC_PREREQ (2, 7) + typedef int register_t __attribute__ ((__mode__ (__word__))); +- ++#else ++typedef int register_t; ++#endif + + /* Some code from BIND tests this macro to see if the types above are + defined. */ +-#endif + #define __BIT_TYPES_DEFINED__ 1 + + +diff --git a/scripts/check-installed-headers.sh b/scripts/check-installed-headers.sh +index 7a1969b43a144ebb..c2aeea5aabcc7ffd 100644 +--- a/scripts/check-installed-headers.sh ++++ b/scripts/check-installed-headers.sh +@@ -16,11 +16,9 @@ + # License along with the GNU C Library; if not, see + # . + +-# Check installed headers for cleanliness. For each header, confirm +-# that it's possible to compile a file that includes that header and +-# does nothing else, in several different compilation modes. Also, +-# scan the header for a set of obsolete typedefs that should no longer +-# appear. ++# For each installed header, confirm that it's possible to compile a ++# file that includes that header and does nothing else, in several ++# different compilation modes. + + # These compilation switches assume GCC or compatible, which is probably + # fine since we also assume that when _building_ glibc. +@@ -31,13 +29,6 @@ cxx_modes="-std=c++98 -std=gnu++98 -std=c++11 -std=gnu++11" + # These are probably the most commonly used three. + lib_modes="-D_DEFAULT_SOURCE=1 -D_GNU_SOURCE=1 -D_XOPEN_SOURCE=700" + +-# sys/types.h+bits/types.h have to define the obsolete types. +-# rpc(svc)/* have the obsolete types too deeply embedded in their API +-# to remove. +-skip_obsolete_type_check='*/sys/types.h|*/bits/types.h|*/rpc/*|*/rpcsvc/*' +-obsolete_type_re=\ +-'\<((__)?(quad_t|u(short|int|long|_(char|short|int([0-9]+_t)?|long|quad_t))))\>' +- + if [ $# -lt 3 ]; then + echo "usage: $0 c|c++ \"compile command\" header header header..." >&2 + exit 2 +@@ -46,14 +37,10 @@ case "$1" in + (c) + lang_modes="$c_modes" + cih_test_c=$(mktemp ${TMPDIR-/tmp}/cih_test_XXXXXX.c) +- already="$skip_obsolete_type_check" + ;; + (c++) + lang_modes="$cxx_modes" + cih_test_c=$(mktemp ${TMPDIR-/tmp}/cih_test_XXXXXX.cc) +- # The obsolete-type check can be skipped for C++; it is +- # sufficient to do it for C. +- already="*" + ;; + (*) + echo "usage: $0 c|c++ \"compile command\" header header header..." >&2 +@@ -155,22 +142,8 @@ $expanded_lib_mode + int avoid_empty_translation_unit; + EOF + if $cc_cmd -fsyntax-only $lang_mode "$cih_test_c" 2>&1 +- then +- includes=$($cc_cmd -fsyntax-only -H $lang_mode \ +- "$cih_test_c" 2>&1 | sed -ne 's/^[.][.]* //p') +- for h in $includes; do +- # Don't repeat work. +- eval 'case "$h" in ('"$already"') continue;; esac' +- +- if grep -qE "$obsolete_type_re" "$h"; then +- echo "*** Obsolete types detected:" +- grep -HE "$obsolete_type_re" "$h" +- failed=1 +- fi +- already="$already|$h" +- done +- else +- failed=1 ++ then : ++ else failed=1 + fi + done + done +diff --git a/scripts/check-obsolete-constructs.py b/scripts/check-obsolete-constructs.py +new file mode 100755 +index 0000000000000000..ce5c72251f4d7cc0 +--- /dev/null ++++ b/scripts/check-obsolete-constructs.py +@@ -0,0 +1,466 @@ ++#! /usr/bin/python3 ++# Copyright (C) 2019 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 ++# . ++ ++"""Verifies that installed headers do not use any obsolete constructs: ++ * legacy BSD typedefs superseded by : ++ ushort uint ulong u_char u_short u_int u_long u_intNN_t quad_t u_quad_t ++ (sys/types.h is allowed to _define_ these types, but not to use them ++ to define anything else). ++""" ++ ++import argparse ++import collections ++import re ++import sys ++ ++# Simplified lexical analyzer for C preprocessing tokens. ++# Does not implement trigraphs. ++# Does not implement backslash-newline in the middle of any lexical ++# item other than a string literal. ++# Does not implement universal-character-names in identifiers. ++# Treats prefixed strings (e.g. L"...") as two tokens (L and "...") ++# Accepts non-ASCII characters only within comments and strings. ++ ++# Caution: The order of the outermost alternation matters. ++# STRING must be before BAD_STRING, CHARCONST before BAD_CHARCONST, ++# BLOCK_COMMENT before BAD_BLOCK_COM before PUNCTUATOR, and OTHER must ++# be last. ++# Caution: There should be no capturing groups other than the named ++# captures in the outermost alternation. ++ ++# For reference, these are all of the C punctuators as of C11: ++# [ ] ( ) { } , ; ? ~ ++# ! != * *= / /= ^ ^= = == ++# # ## ++# % %= %> %: %:%: ++# & &= && ++# | |= || ++# + += ++ ++# - -= -- -> ++# . ... ++# : :> ++# < <% <: << <<= <= ++# > >= >> >>= ++ ++# The BAD_* tokens are not part of the official definition of pp-tokens; ++# they match unclosed strings, character constants, and block comments, ++# so that the regex engine doesn't have to backtrack all the way to the ++# beginning of a broken construct and then emit dozens of junk tokens. ++ ++PP_TOKEN_RE_ = re.compile(r""" ++ (?P \"(?:[^\"\\\r\n]|\\(?:[\r\n -~]|\r\n))*\") ++ |(?P \"(?:[^\"\\\r\n]|\\[ -~])*) ++ |(?P \'(?:[^\'\\\r\n]|\\(?:[\r\n -~]|\r\n))*\') ++ |(?P \'(?:[^\'\\\r\n]|\\[ -~])*) ++ |(?P /\*(?:\*(?!/)|[^*])*\*/) ++ |(?P /\*(?:\*(?!/)|[^*])*\*?) ++ |(?P //[^\r\n]*) ++ |(?P [_a-zA-Z][_a-zA-Z0-9]*) ++ |(?P \.?[0-9](?:[0-9a-df-oq-zA-DF-OQ-Z_.]|[eEpP][+-]?)*) ++ |(?P ++ [,;?~(){}\[\]] ++ | [!*/^=]=? ++ | \#\#? ++ | %(?:[=>]|:(?:%:)?)? ++ | &[=&]? ++ |\|[=|]? ++ |\+[=+]? ++ | -[=->]? ++ |\.(?:\.\.)? ++ | :>? ++ | <(?:[%:]|<(?:=|<=?)?)? ++ | >(?:=|>=?)?) ++ |(?P \\(?:\r|\n|\r\n)) ++ |(?P [ \t\n\r\v\f]+) ++ |(?P .) ++""", re.DOTALL | re.VERBOSE) ++ ++HEADER_NAME_RE_ = re.compile(r""" ++ < [^>\r\n]+ > ++ | " [^"\r\n]+ " ++""", re.DOTALL | re.VERBOSE) ++ ++ENDLINE_RE_ = re.compile(r"""\r|\n|\r\n""") ++ ++# based on the sample code in the Python re documentation ++Token_ = collections.namedtuple("Token", ( ++ "kind", "text", "line", "column", "context")) ++Token_.__doc__ = """ ++ One C preprocessing token, comment, or chunk of whitespace. ++ 'kind' identifies the token type, which will be one of: ++ STRING, CHARCONST, BLOCK_COMMENT, LINE_COMMENT, IDENT, ++ PP_NUMBER, PUNCTUATOR, ESCNL, WHITESPACE, HEADER_NAME, ++ or OTHER. The BAD_* alternatives in PP_TOKEN_RE_ are ++ handled within tokenize_c, below. ++ ++ 'text' is the sequence of source characters making up the token; ++ no decoding whatsoever is performed. ++ ++ 'line' and 'column' give the position of the first character of the ++ token within the source file. They are both 1-based. ++ ++ 'context' indicates whether or not this token occurred within a ++ preprocessing directive; it will be None for running text, ++ '' for the leading '#' of a directive line (because '#' ++ all by itself on a line is a "null directive"), or the name of ++ the directive for tokens within a directive line, starting with ++ the IDENT for the name itself. ++""" ++ ++def tokenize_c(file_contents, reporter): ++ """Yield a series of Token objects, one for each preprocessing ++ token, comment, or chunk of whitespace within FILE_CONTENTS. ++ The REPORTER object is expected to have one method, ++ reporter.error(token, message), which will be called to ++ indicate a lexical error at the position of TOKEN. ++ If MESSAGE contains the four-character sequence '{!r}', that ++ is expected to be replaced by repr(token.text). ++ """ ++ ++ Token = Token_ ++ PP_TOKEN_RE = PP_TOKEN_RE_ ++ ENDLINE_RE = ENDLINE_RE_ ++ HEADER_NAME_RE = HEADER_NAME_RE_ ++ ++ line_num = 1 ++ line_start = 0 ++ pos = 0 ++ limit = len(file_contents) ++ directive = None ++ at_bol = True ++ while pos < limit: ++ if directive == "include": ++ mo = HEADER_NAME_RE.match(file_contents, pos) ++ if mo: ++ kind = "HEADER_NAME" ++ directive = "after_include" ++ else: ++ mo = PP_TOKEN_RE.match(file_contents, pos) ++ kind = mo.lastgroup ++ if kind != "WHITESPACE": ++ directive = "after_include" ++ else: ++ mo = PP_TOKEN_RE.match(file_contents, pos) ++ kind = mo.lastgroup ++ ++ text = mo.group() ++ line = line_num ++ column = mo.start() - line_start ++ adj_line_start = 0 ++ # only these kinds can contain a newline ++ if kind in ("WHITESPACE", "BLOCK_COMMENT", "LINE_COMMENT", ++ "STRING", "CHARCONST", "BAD_BLOCK_COM", "ESCNL"): ++ for tmo in ENDLINE_RE.finditer(text): ++ line_num += 1 ++ adj_line_start = tmo.end() ++ if adj_line_start: ++ line_start = mo.start() + adj_line_start ++ ++ # Track whether or not we are scanning a preprocessing directive. ++ if kind == "LINE_COMMENT" or (kind == "WHITESPACE" and adj_line_start): ++ at_bol = True ++ directive = None ++ else: ++ if kind == "PUNCTUATOR" and text == "#" and at_bol: ++ directive = "" ++ elif kind == "IDENT" and directive == "": ++ directive = text ++ at_bol = False ++ ++ # Report ill-formed tokens and rewrite them as their well-formed ++ # equivalents, so downstream processing doesn't have to know about them. ++ # (Rewriting instead of discarding provides better error recovery.) ++ if kind == "BAD_BLOCK_COM": ++ reporter.error(Token("BAD_BLOCK_COM", "", line, column+1, ""), ++ "unclosed block comment") ++ text += "*/" ++ kind = "BLOCK_COMMENT" ++ elif kind == "BAD_STRING": ++ reporter.error(Token("BAD_STRING", "", line, column+1, ""), ++ "unclosed string") ++ text += "\"" ++ kind = "STRING" ++ elif kind == "BAD_CHARCONST": ++ reporter.error(Token("BAD_CHARCONST", "", line, column+1, ""), ++ "unclosed char constant") ++ text += "'" ++ kind = "CHARCONST" ++ ++ tok = Token(kind, text, line, column+1, ++ "include" if directive == "after_include" else directive) ++ # Do not complain about OTHER tokens inside macro definitions. ++ # $ and @ appear in macros defined by headers intended to be ++ # included from assembly language, e.g. sysdeps/mips/sys/asm.h. ++ if kind == "OTHER" and directive != "define": ++ self.error(tok, "stray {!r} in program") ++ ++ yield tok ++ pos = mo.end() ++ ++# ++# Base and generic classes for individual checks. ++# ++ ++class ConstructChecker: ++ """Scan a stream of C preprocessing tokens and possibly report ++ problems with them. The REPORTER object passed to __init__ has ++ one method, reporter.error(token, message), which should be ++ called to indicate a problem detected at the position of TOKEN. ++ If MESSAGE contains the four-character sequence '{!r}' then that ++ will be replaced with a textual representation of TOKEN. ++ """ ++ def __init__(self, reporter): ++ self.reporter = reporter ++ ++ def examine(self, tok): ++ """Called once for each token in a header file. ++ Call self.reporter.error if a problem is detected. ++ """ ++ raise NotImplementedError ++ ++ def eof(self): ++ """Called once at the end of the stream. Subclasses need only ++ override this if it might have something to do.""" ++ pass ++ ++class NoCheck(ConstructChecker): ++ """Generic checker class which doesn't do anything. Substitute this ++ class for a real checker when a particular check should be skipped ++ for some file.""" ++ ++ def examine(self, tok): ++ pass ++ ++# ++# Check for obsolete type names. ++# ++ ++# The obsolete type names we're looking for: ++OBSOLETE_TYPE_RE_ = re.compile(r"""\A ++ (__)? ++ ( quad_t ++ | u(?: short | int | long ++ | _(?: char | short | int(?:[0-9]+_t)? | long | quad_t ))) ++\Z""", re.VERBOSE) ++ ++class ObsoleteNotAllowed(ConstructChecker): ++ """Don't allow any use of the obsolete typedefs.""" ++ def examine(self, tok): ++ if OBSOLETE_TYPE_RE_.match(tok.text): ++ self.reporter.error(tok, "use of {!r}") ++ ++class ObsoletePrivateDefinitionsAllowed(ConstructChecker): ++ """Allow definitions of the private versions of the ++ obsolete typedefs; that is, 'typedef [anything] __obsolete;' ++ """ ++ def __init__(self, reporter): ++ super().__init__(reporter) ++ self.in_typedef = False ++ self.prev_token = None ++ ++ def examine(self, tok): ++ # bits/types.h hides 'typedef' in a macro sometimes. ++ if (tok.kind == "IDENT" ++ and tok.text in ("typedef", "__STD_TYPE") ++ and tok.context is None): ++ self.in_typedef = True ++ elif tok.kind == "PUNCTUATOR" and tok.text == ";" and self.in_typedef: ++ self.in_typedef = False ++ if self.prev_token.kind == "IDENT": ++ m = OBSOLETE_TYPE_RE_.match(self.prev_token.text) ++ if m and m.group(1) != "__": ++ self.reporter.error(self.prev_token, "use of {!r}") ++ self.prev_token = None ++ else: ++ self._check_prev() ++ ++ self.prev_token = tok ++ ++ def eof(self): ++ self._check_prev() ++ ++ def _check_prev(self): ++ if (self.prev_token is not None ++ and self.prev_token.kind == "IDENT" ++ and OBSOLETE_TYPE_RE_.match(self.prev_token.text)): ++ self.reporter.error(self.prev_token, "use of {!r}") ++ ++class ObsoletePublicDefinitionsAllowed(ConstructChecker): ++ """Allow definitions of the public versions of the obsolete ++ typedefs. Only specific forms of definition are allowed: ++ ++ typedef __obsolete obsolete; // identifiers must agree ++ typedef __uintN_t u_intN_t; // N must agree ++ typedef unsigned long int ulong; ++ typedef unsigned short int ushort; ++ typedef unsigned int uint; ++ """ ++ def __init__(self, reporter): ++ super().__init__(reporter) ++ self.typedef_tokens = [] ++ ++ def examine(self, tok): ++ if tok.kind in ("WHITESPACE", "BLOCK_COMMENT", ++ "LINE_COMMENT", "NL", "ESCNL"): ++ pass ++ ++ elif (tok.kind == "IDENT" and tok.text == "typedef" ++ and tok.context is None): ++ if self.typedef_tokens: ++ self.reporter.error(tok, "typedef inside typedef") ++ self._reset() ++ self.typedef_tokens.append(tok) ++ ++ elif tok.kind == "PUNCTUATOR" and tok.text == ";": ++ self._finish() ++ ++ elif self.typedef_tokens: ++ self.typedef_tokens.append(tok) ++ ++ def eof(self): ++ self._reset() ++ ++ def _reset(self): ++ while self.typedef_tokens: ++ tok = self.typedef_tokens.pop(0) ++ if tok.kind == "IDENT" and OBSOLETE_TYPE_RE_.match(tok.text): ++ self.reporter.error(tok, "use of {!r}") ++ ++ def _finish(self): ++ if not self.typedef_tokens: return ++ if self.typedef_tokens[-1].kind == "IDENT": ++ m = OBSOLETE_TYPE_RE_.match(self.typedef_tokens[-1].text) ++ if m: ++ if self._permissible_public_definition(m): ++ self.typedef_tokens.clear() ++ self._reset() ++ ++ def _permissible_public_definition(self, m): ++ if m.group(1) == "__": return False ++ name = m.group(2) ++ toks = self.typedef_tokens ++ ntok = len(toks) ++ if ntok == 3 and toks[1].kind == "IDENT": ++ defn = toks[1].text ++ n = OBSOLETE_TYPE_RE_.match(defn) ++ if n and n.group(1) == "__" and n.group(2) == name: ++ return True ++ ++ if (name[:5] == "u_int" and name[-2:] == "_t" ++ and defn[:6] == "__uint" and defn[-2:] == "_t" ++ and name[5:-2] == defn[6:-2]): ++ return True ++ ++ return False ++ ++ if (name == "ulong" and ntok == 5 ++ and toks[1].kind == "IDENT" and toks[1].text == "unsigned" ++ and toks[2].kind == "IDENT" and toks[2].text == "long" ++ and toks[3].kind == "IDENT" and toks[3].text == "int"): ++ return True ++ ++ if (name == "ushort" and ntok == 5 ++ and toks[1].kind == "IDENT" and toks[1].text == "unsigned" ++ and toks[2].kind == "IDENT" and toks[2].text == "short" ++ and toks[3].kind == "IDENT" and toks[3].text == "int"): ++ return True ++ ++ if (name == "uint" and ntok == 4 ++ and toks[1].kind == "IDENT" and toks[1].text == "unsigned" ++ and toks[2].kind == "IDENT" and toks[2].text == "int"): ++ return True ++ ++ return False ++ ++def ObsoleteTypedefChecker(reporter, fname): ++ """Factory: produce an instance of the appropriate ++ obsolete-typedef checker for FNAME.""" ++ ++ # The obsolete rpc/ and rpcsvc/ headers are allowed to use the ++ # obsolete types, because it would be more trouble than it's ++ # worth to remove them from headers that we intend to stop ++ # installing eventually anyway. ++ if (fname.startswith("rpc/") ++ or fname.startswith("rpcsvc/") ++ or "/rpc/" in fname ++ or "/rpcsvc/" in fname): ++ return NoCheck(reporter) ++ ++ # bits/types.h is allowed to define the __-versions of the ++ # obsolete types. ++ if (fname == "bits/types.h" ++ or fname.endswith("/bits/types.h")): ++ return ObsoletePrivateDefinitionsAllowed(reporter) ++ ++ # sys/types.h is allowed to use the __-versions of the ++ # obsolete types, but only to define the unprefixed versions. ++ if (fname == "sys/types.h" ++ or fname.endswith("/sys/types.h")): ++ return ObsoletePublicDefinitionsAllowed(reporter) ++ ++ return ObsoleteNotAllowed(reporter) ++ ++# ++# Master control ++# ++ ++class HeaderChecker: ++ """Perform all of the checks on each header. This is also the ++ "reporter" object expected by tokenize_c and ConstructChecker. ++ """ ++ def __init__(self): ++ self.fname = None ++ self.status = 0 ++ ++ def error(self, tok, message): ++ self.status = 1 ++ if '{!r}' in message: ++ message = message.format(tok.text) ++ sys.stderr.write("{}:{}:{}: error: {}\n".format( ++ self.fname, tok.line, tok.column, message)) ++ ++ def check(self, fname): ++ self.fname = fname ++ try: ++ with open(fname, "rt") as fp: ++ contents = fp.read() ++ except OSError as e: ++ sys.stderr.write("{}: {}\n".format(fname, e.strerror)) ++ self.status = 1 ++ return ++ ++ typedef_checker = ObsoleteTypedefChecker(self, self.fname) ++ ++ for tok in tokenize_c(contents, self): ++ typedef_checker.examine(tok) ++ ++def main(): ++ ap = argparse.ArgumentParser(description=__doc__) ++ ap.add_argument("headers", metavar="header", nargs="+", ++ help="one or more headers to scan for obsolete constructs") ++ args = ap.parse_args() ++ ++ checker = HeaderChecker() ++ for fname in args.headers: ++ # Headers whose installed name begins with "finclude/" contain ++ # Fortran, not C, and this program should completely ignore them. ++ if not (fname.startswith("finclude/") or "/finclude/" in fname): ++ checker.check(fname) ++ sys.exit(checker.status) ++ ++main() diff --git a/SOURCES/glibc-rh1774021.patch b/SOURCES/glibc-rh1774021.patch new file mode 100644 index 0000000..e298717 --- /dev/null +++ b/SOURCES/glibc-rh1774021.patch @@ -0,0 +1,24 @@ +commit d5dfad4326fc683c813df1e37bbf5cf920591c8e +Author: Marcin Kościelnicki +Date: Thu Nov 21 00:20:15 2019 +0100 + + rtld: Check __libc_enable_secure before honoring LD_PREFER_MAP_32BIT_EXEC (CVE-2019-19126) [BZ #25204] + + The problem was introduced in glibc 2.23, in commit + b9eb92ab05204df772eb4929eccd018637c9f3e9 + ("Add Prefer_MAP_32BIT_EXEC to map executable pages with MAP_32BIT"). + +diff --git a/sysdeps/unix/sysv/linux/x86_64/64/dl-librecon.h b/sysdeps/unix/sysv/linux/x86_64/64/dl-librecon.h +index 194369174df08946..ac694c032e7baf87 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/64/dl-librecon.h ++++ b/sysdeps/unix/sysv/linux/x86_64/64/dl-librecon.h +@@ -31,7 +31,8 @@ + environment variable, LD_PREFER_MAP_32BIT_EXEC. */ + #define EXTRA_LD_ENVVARS \ + case 21: \ +- if (memcmp (envline, "PREFER_MAP_32BIT_EXEC", 21) == 0) \ ++ if (!__libc_enable_secure \ ++ && memcmp (envline, "PREFER_MAP_32BIT_EXEC", 21) == 0) \ + GLRO(dl_x86_cpu_features).feature[index_arch_Prefer_MAP_32BIT_EXEC] \ + |= bit_arch_Prefer_MAP_32BIT_EXEC; \ + break; diff --git a/SOURCES/glibc-rh1775294.patch b/SOURCES/glibc-rh1775294.patch new file mode 100644 index 0000000..1805d6c --- /dev/null +++ b/SOURCES/glibc-rh1775294.patch @@ -0,0 +1,70 @@ +commit bfa864e1645e140da2e1aae3cf0d0ba0674f6eb5 +Author: Emilio Cobos Álvarez +Date: Tue Nov 12 19:18:32 2019 +0100 + + Don't use a custom wrapper macro around __has_include (bug 25189). + + This causes issues when using clang with -frewrite-includes to e.g., + submit the translation unit to a distributed compiler. + + In my case, I was building Firefox using sccache. + + See [1] for a reduced test-case since I initially thought this was a + clang bug, and [2] for more context. + + Apparently doing this is invalid C++ per [cpp.cond], which mentions [3]: + + > The #ifdef and #ifndef directives, and the defined conditional + > inclusion operator, shall treat __has_include and __has_cpp_attribute + > as if they were the names of defined macros. The identifiers + > __has_include and __has_cpp_attribute shall not appear in any context + > not mentioned in this subclause. + + [1]: https://bugs.llvm.org/show_bug.cgi?id=43982 + [2]: https://bugs.llvm.org/show_bug.cgi?id=37990 + [3]: http://eel.is/c++draft/cpp.cond#7.sentence-2 + + Change-Id: Id4b8ee19176a9e4624b533087ba870c418f27e60 + +diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h +index 9e840e602f815d86..3f6fe3cc8563b493 100644 +--- a/misc/sys/cdefs.h ++++ b/misc/sys/cdefs.h +@@ -412,14 +412,6 @@ + # define __glibc_has_attribute(attr) 0 + #endif + +-#ifdef __has_include +-/* Do not use a function-like macro, so that __has_include can inhibit +- macro expansion. */ +-# define __glibc_has_include __has_include +-#else +-# define __glibc_has_include(header) 0 +-#endif +- + #if (!defined _Noreturn \ + && (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) < 201112 \ + && !__GNUC_PREREQ (4,7)) +diff --git a/sysdeps/unix/sysv/linux/bits/statx.h b/sysdeps/unix/sysv/linux/bits/statx.h +index 206878723fd37881..aaccfdc2dc03a1dc 100644 +--- a/sysdeps/unix/sysv/linux/bits/statx.h ++++ b/sysdeps/unix/sysv/linux/bits/statx.h +@@ -26,11 +26,13 @@ + + /* Use "" to work around incorrect macro expansion of the + __has_include argument (GCC PR 80005). */ +-#if __glibc_has_include ("linux/stat.h") +-# include "linux/stat.h" +-# ifdef STATX_TYPE +-# define __statx_timestamp_defined 1 +-# define __statx_defined 1 ++#ifdef __has_include ++# if __has_include ("linux/stat.h") ++# include "linux/stat.h" ++# ifdef STATX_TYPE ++# define __statx_timestamp_defined 1 ++# define __statx_defined 1 ++# endif + # endif + #endif + diff --git a/SOURCES/glibc-rh1777241.patch b/SOURCES/glibc-rh1777241.patch new file mode 100644 index 0000000..e68afdd --- /dev/null +++ b/SOURCES/glibc-rh1777241.patch @@ -0,0 +1,88 @@ +commit bfdb731438206b0f70fe7afa890681155c30b419 +Author: Stefan Liebler +Date: Wed Nov 27 12:35:40 2019 +0100 + + S390: Fix handling of needles crossing a page in strstr z15 ifunc-variant. [BZ #25226] + + If the specified needle crosses a page-boundary, the s390-z15 ifunc variant of + strstr truncates the needle which results in invalid results. + + This is fixed by loading the needle beyond the page boundary to v18 instead of v16. + The bug is sometimes observable in test-strstr.c in check1 and check2 as the + haystack and needle is stored on stack. Thus the needle can be on a page boundary. + + check2 is now extended to test haystack / needles located on stack, at end of page + and on two pages. + + This bug was introduced with commit 6f47401bd5fc71209219779a0426170a9a7395b0 + ("S390: Add arch13 strstr ifunc variant.") and is already released in glibc 2.30. + +diff --git a/string/test-strstr.c b/string/test-strstr.c +index 5861b01b73e4c315..e9e14c1ee605516e 100644 +--- a/string/test-strstr.c ++++ b/string/test-strstr.c +@@ -138,16 +138,45 @@ check1 (void) + static void + check2 (void) + { +- const char s1[] = ", enable_static, \0, enable_shared, "; ++ const char s1_stack[] = ", enable_static, \0, enable_shared, "; ++ const size_t s1_byte_count = 18; ++ const char *s2_stack = &(s1_stack[s1_byte_count]); ++ const size_t s2_byte_count = 18; + char *exp_result; +- char *s2 = (void *) buf1 + page_size - 18; ++ const size_t page_size_real = getpagesize (); + +- strcpy (s2, s1); +- exp_result = stupid_strstr (s1, s1 + 18); ++ /* Haystack at end of page. The following page is protected. */ ++ char *s1_page_end = (void *) buf1 + page_size - s1_byte_count; ++ strcpy (s1_page_end, s1_stack); ++ ++ /* Haystack which crosses a page boundary. ++ Note: page_size is at least 2 * getpagesize. See test_init. */ ++ char *s1_page_cross = (void *) buf1 + page_size_real - 8; ++ strcpy (s1_page_cross, s1_stack); ++ ++ /* Needle at end of page. The following page is protected. */ ++ char *s2_page_end = (void *) buf2 + page_size - s2_byte_count; ++ strcpy (s2_page_end, s2_stack); ++ ++ /* Needle which crosses a page boundary. ++ Note: page_size is at least 2 * getpagesize. See test_init. */ ++ char *s2_page_cross = (void *) buf2 + page_size_real - 8; ++ strcpy (s2_page_cross, s2_stack); ++ ++ exp_result = stupid_strstr (s1_stack, s2_stack); + FOR_EACH_IMPL (impl, 0) + { +- check_result (impl, s1, s1 + 18, exp_result); +- check_result (impl, s2, s1 + 18, exp_result); ++ check_result (impl, s1_stack, s2_stack, exp_result); ++ check_result (impl, s1_stack, s2_page_end, exp_result); ++ check_result (impl, s1_stack, s2_page_cross, exp_result); ++ ++ check_result (impl, s1_page_end, s2_stack, exp_result); ++ check_result (impl, s1_page_end, s2_page_end, exp_result); ++ check_result (impl, s1_page_end, s2_page_cross, exp_result); ++ ++ check_result (impl, s1_page_cross, s2_stack, exp_result); ++ check_result (impl, s1_page_cross, s2_page_end, exp_result); ++ check_result (impl, s1_page_cross, s2_page_cross, exp_result); + } + } + +diff --git a/sysdeps/s390/strstr-arch13.S b/sysdeps/s390/strstr-arch13.S +index 929b026adfeba740..faa969849e09c2e1 100644 +--- a/sysdeps/s390/strstr-arch13.S ++++ b/sysdeps/s390/strstr-arch13.S +@@ -164,7 +164,7 @@ ENTRY(STRSTR_ARCH13) + vfenezb %v19,%v18,%v18 /* Search zero in loaded needle bytes. */ + veclb %v19,%v21 /* Zero index <= max loaded byte index? */ + jle .Lneedle_loaded /* -> v18 contains full needle. */ +- vl %v16,0(%r3) /* Load needle beyond page boundary. */ ++ vl %v18,0(%r3) /* Load needle beyond page boundary. */ + vfenezb %v19,%v18,%v18 + j .Lneedle_loaded + END(STRSTR_ARCH13) diff --git a/SOURCES/nsswitch.conf b/SOURCES/nsswitch.conf deleted file mode 100644 index b49a3b2..0000000 --- a/SOURCES/nsswitch.conf +++ /dev/null @@ -1,56 +0,0 @@ -# -# /etc/nsswitch.conf -# -# An example Name Service Switch config file. This file should be -# sorted with the most-used services at the beginning. -# -# The entry '[NOTFOUND=return]' means that the search for an -# entry should stop if the search in the previous entry turned -# up nothing. Note that if the search failed due to some other reason -# (like no NIS server responding) then the search continues with the -# next entry. -# -# Valid entries include: -# -# nisplus Use NIS+ (NIS version 3) -# nis Use NIS (NIS version 2), also called YP -# dns Use DNS (Domain Name Service) -# files Use the local files in /etc -# db Use the pre-processed /var/db files -# compat Use /etc files plus *_compat pseudo-databases -# hesiod Use Hesiod (DNS) for user lookups -# sss Use sssd (System Security Services Daemon) -# [NOTFOUND=return] Stop searching if not found so far -# -# 'sssd' performs its own 'files'-based caching, so it should -# generally come before 'files'. - -# To use 'db', install the nss_db package, and put the 'db' in front -# of 'files' for entries you want to be looked up first in the -# databases, like this: -# -# passwd: db files -# shadow: db files -# group: db files - -passwd: sss files -shadow: files sss -group: sss files - -hosts: files dns myhostname - -bootparams: files - -ethers: files -netmasks: files -networks: files -protocols: files -rpc: files -services: files sss - -netgroup: sss - -publickey: files - -automount: files sss -aliases: files diff --git a/SPECS/glibc.spec b/SPECS/glibc.spec index 1a0917c..6ce3a78 100644 --- a/SPECS/glibc.spec +++ b/SPECS/glibc.spec @@ -1,6 +1,6 @@ %define glibcsrcdir glibc-2.28 %define glibcversion 2.28 -%define glibcrelease 66%{?dist} +%define glibcrelease 100%{?dist} # Pre-release tarballs are pulled in from git using a command that is # effectively: # @@ -121,7 +121,6 @@ URL: http://www.gnu.org/software/glibc/ Source0: %{?glibc_release_url}%{glibcsrcdir}.tar.xz Source1: build-locale-archive.c Source4: nscd.conf -Source7: nsswitch.conf Source8: power6emul.c Source9: bench.mk Source10: glibc-bench-compare @@ -308,6 +307,93 @@ Patch173: glibc-rh1699194-1.patch Patch174: glibc-rh1699194-2.patch Patch175: glibc-rh1699194-3.patch Patch176: glibc-rh1699194-4.patch +Patch177: glibc-rh1727241-1.patch +Patch178: glibc-rh1727241-2.patch +Patch179: glibc-rh1727241-3.patch +Patch180: glibc-rh1717438.patch +Patch181: glibc-rh1727152.patch +Patch182: glibc-rh1724975.patch +Patch183: glibc-rh1722215.patch +Patch184: glibc-rh1764234-1.patch +Patch185: glibc-rh1764234-2.patch +Patch186: glibc-rh1764234-3.patch +Patch187: glibc-rh1764234-4.patch +Patch188: glibc-rh1764234-5.patch +Patch189: glibc-rh1764234-6.patch +Patch190: glibc-rh1764234-7.patch +Patch191: glibc-rh1764234-8.patch +Patch192: glibc-rh1747505-1.patch +Patch193: glibc-rh1747505-2.patch +Patch194: glibc-rh1747505-3.patch +Patch195: glibc-rh1747505-4.patch +Patch196: glibc-rh1747453.patch +Patch197: glibc-rh1764241.patch +Patch198: glibc-rh1746933-1.patch +Patch199: glibc-rh1746933-2.patch +Patch200: glibc-rh1746933-3.patch +Patch201: glibc-rh1735747-1.patch +Patch202: glibc-rh1735747-2.patch +Patch203: glibc-rh1764226-1.patch +Patch204: glibc-rh1764226-2.patch +Patch205: glibc-rh1764226-3.patch +Patch206: glibc-rh1764218-1.patch +Patch207: glibc-rh1764218-2.patch +Patch208: glibc-rh1764218-3.patch +Patch209: glibc-rh1682954.patch +Patch210: glibc-rh1746928.patch +Patch211: glibc-rh1747502.patch +Patch212: glibc-rh1747502-1.patch +Patch213: glibc-rh1747502-2.patch +Patch214: glibc-rh1747502-3.patch +Patch215: glibc-rh1747502-4.patch +Patch216: glibc-rh1747502-5.patch +Patch217: glibc-rh1747502-6.patch +Patch218: glibc-rh1747502-7.patch +Patch219: glibc-rh1747502-8.patch +Patch220: glibc-rh1747502-9.patch +Patch221: glibc-rh1726638-1.patch +Patch222: glibc-rh1726638-2.patch +Patch223: glibc-rh1726638-3.patch +Patch224: glibc-rh1764238-1.patch +Patch225: glibc-rh1764238-2.patch +Patch226: glibc-rh1764242.patch +Patch227: glibc-rh1769304.patch +Patch228: glibc-rh1749439-1.patch +Patch229: glibc-rh1749439-2.patch +Patch230: glibc-rh1749439-3.patch +Patch231: glibc-rh1749439-4.patch +Patch232: glibc-rh1749439-5.patch +Patch233: glibc-rh1749439-6.patch +Patch234: glibc-rh1749439-7.patch +Patch235: glibc-rh1749439-8.patch +Patch236: glibc-rh1749439-9.patch +Patch237: glibc-rh1749439-10.patch +Patch238: glibc-rh1749439-11.patch +Patch239: glibc-rh1749439-12.patch +Patch240: glibc-rh1749439-13.patch +Patch241: glibc-rh1764231-1.patch +Patch242: glibc-rh1764231-2.patch +Patch243: glibc-rh1764235.patch +Patch244: glibc-rh1361965.patch +Patch245: glibc-rh1764223.patch +Patch246: glibc-rh1764214.patch +Patch247: glibc-rh1774021.patch +Patch248: glibc-rh1775294.patch +Patch249: glibc-rh1777241.patch +Patch250: glibc-rh1410154-1.patch +Patch251: glibc-rh1410154-2.patch +Patch252: glibc-rh1410154-3.patch +Patch253: glibc-rh1410154-4.patch +Patch254: glibc-rh1410154-5.patch +Patch255: glibc-rh1410154-6.patch +Patch256: glibc-rh1410154-7.patch +Patch257: glibc-rh1410154-8.patch +Patch258: glibc-rh1410154-9.patch +Patch259: glibc-rh1410154-10.patch +Patch260: glibc-rh1410154-11.patch +Patch261: glibc-rh1410154-12.patch +Patch262: glibc-rh1410154-13.patch +Patch263: glibc-rh1410154-14.patch ############################################################################## # Continued list of core "glibc" package information: @@ -1190,8 +1276,19 @@ $olddir/build-%{target}/elf/ld.so \ $olddir/build-%{target}/locale/localedef \ --prefix %{glibc_sysroot} --add-to-archive \ eo *_* -# Setup the locale-archive template for use by glibc-all-langpacks. -mv locale-archive{,.tmpl} +# Setup the locale-archive template for use by glibc-all-langpacks. We +# copy the archive in place to keep the size of the file. Even though we +# mark the file with "ghost" the size is used by rpm to compute the +# required free space (see rhbz#1725131). We do this because there is a +# point in the install when build-locale-archive has copied 100% of the +# template into the new locale archive and so this consumes twice the +# amount of diskspace. Note that this doesn't account for copying +# existing compiled locales into the archive, this may consume even more +# disk space and we can't fix that issue. In upstream we have moved away +# from this process, removing build-locale-archive and installing a +# default locale-archive without modification, and leaving compiled +# locales as they are (without inclusion into the archive). +cp locale-archive{,.tmpl} # Create the file lists for the language specific sub-packages: for i in eo *_* do @@ -1219,7 +1316,7 @@ mv %{glibc_sysroot}%{_prefix}/lib/locale/*.filelist . # Install configuration files for services ############################################################################## -install -p -m 644 %{SOURCE7} %{glibc_sysroot}/etc/nsswitch.conf +install -p -m 644 nss/nsswitch.conf %{glibc_sysroot}/etc/nsswitch.conf %ifnarch %{auxarches} # This is for ncsd - in glibc 2.2 @@ -1331,7 +1428,6 @@ rm -f %{glibc_sysroot}%{_infodir}/dir %endif %ifnarch %{auxarches} -truncate -s 0 %{glibc_sysroot}/%{_prefix}/lib/locale/locale-archive mkdir -p %{glibc_sysroot}/var/{db,run}/nscd touch %{glibc_sysroot}/var/{db,run}/nscd/{passwd,group,hosts,services} touch %{glibc_sysroot}/var/run/nscd/{socket,nscd.pid} @@ -2184,6 +2280,111 @@ fi %files -f compat-libpthread-nonshared.filelist -n compat-libpthread-nonshared %changelog +* Fri Dec 13 2019 Florian Weimer - 2.28-100 +- Roll back dynamic linker state on dlopen failure (#1410154) + +* Wed Nov 27 2019 Florian Weimer - 2.28-99 +- s390x: Fix z15 strstr for patterns crossing pages (#1777241) + +* Wed Nov 27 2019 Florian Weimer - 2.28-98 +- Rebuild with new rpm (#1654901) + +* Fri Nov 22 2019 Florian Weimer - 2.28-97 +- Avoid invalid __has_include in (#1775294) + +* Fri Nov 22 2019 Florian Weimer - 2.28-96 +- x86-64: Ignore LD_PREFER_MAP_32BIT_EXEC in SUID binaries (#1774021) + +* Thu Nov 14 2019 DJ Delorie - 2.28-95 +- Fix alignment of TLS variables for tls variant TLS_TCB_AT_TP (#1764214) + +* Thu Nov 14 2019 DJ Delorie - 2.28-94 +- Refuse to dlopen PIE objects (#1764223) + +* Thu Nov 14 2019 Carlos O'Donell - 2.28-93 +- Fix C.UTF-8 locale source ellipsis expressions (#1361965) + +* Thu Nov 14 2019 Carlos O'Donell - 2.28-92 +- Fix hangs during malloc tracing (#1764235) + +* Thu Nov 14 2019 Carlos O'Donell - 2.28-91 +- Support moving versioned symbols between sonames (#1764231) + +* Wed Nov 13 2019 Florian Weimer - 2.28-90 +- Avoid creating stale utmp entries for repeated pututxline (#1749439) + +* Wed Nov 6 2019 Florian Weimer - 2.28-89 +- Backport more precise tokenizer for installed headers test (#1769304) + +* Wed Nov 6 2019 Florian Weimer - 2.28-88 +- math: Enable some math builtins for clang in LLVM Toolset (#1764242) + +* Wed Nov 6 2019 Florian Weimer - 2.28-87 +- Support Fortran vectorized math functions with GCC Toolset 9 (#1764238) + +* Wed Nov 6 2019 Florian Weimer - 2.28-86 +- aarch64: Support STO_AARCH64_VARIANT_PCS, DT_AARCH64_VARIANT_PCS (#1726638) + +* Mon Nov 4 2019 DJ Delorie - 2.28-85 +- Add more test-in-container support (#1747502) + +* Fri Nov 1 2019 DJ Delorie - 2.28-84 +- Fix calling getpwent after endpwent (#1747502) + +* Fri Nov 1 2019 DJ Delorie - 2.28-83 +- nptl: Avoid fork handler lock for async-signal-safe fork (#1746928) + +* Thu Oct 31 2019 DJ Delorie - 2.28-82 +- Call _dl_open_check after relocation (#1682954) + +* Thu Oct 31 2019 Arjun Shankar - 2.28-81 +- Add malloc fastbin tunable (#1764218) + +* Thu Oct 31 2019 Arjun Shankar - 2.28-80 +- Fix race condition in tst-clone3 and add a new ldconfig test, + tst-ldconfig-bad-aux-cache (#1764226) + +* Thu Oct 31 2019 Arjun Shankar - 2.28-79 +- Remove unwanted whitespace from size lines and account for top chunk in + malloc_info output (#1735747) + +* Wed Oct 30 2019 Arjun Shankar - 2.28-78 +- Enhance malloc tcache (#1746933) + +* Tue Oct 29 2019 Patsy Griffin - 2.28-77 +- Don't define initgroups in nsswitch.conf (#1747505) + +* Mon Oct 28 2019 Patsy Griffin - 2.28-76 +- libio: Remove codecvt vtable. (#1764241) + +* Mon Oct 28 2019 Patsy Griffin - 2.28-75 +- Implement --preload option for the dynamic linker.(#1747453) + +* Mon Oct 28 2019 Patsy Griffin - 2.28-74 +- Make nsswitch.conf more distribution friendly. + Improve nscd.conf comments. (#1747505) + +* Fri Oct 25 2019 Patsy Griffin - 2.28-73 +- Update system call names list to Linux 5.3 (#1764234) + +* Mon Jul 22 2019 Carlos O'Donell - 2.28-72 +- Skip wide buffer handling for legacy stdio handles (#1722215) + +* Mon Jul 22 2019 Carlos O'Donell - 2.28-71 +- Remove copy_file_range emulation (#1724975) + +* Mon Jul 22 2019 Carlos O'Donell - 2.28-70 +- Avoid nscd assertion failure during persistent db check (#1727152) + +* Mon Jul 22 2019 Carlos O'Donell - 2.28-69 +- Fix invalid free under valgrind with libdl (#1717438) + +* Thu Jul 18 2019 Carlos O'Donell - 2.28-68 +- Account for size of locale-archive in rpm package (#1725131) + +* Thu Jul 18 2019 Carlos O'Donell - 2.28-67 +- Reject IP addresses with trailing characters in getaddrinfo (#1727241) + * Fri Jun 14 2019 Florian Weimer - 2.28-66 - Avoid header conflict between and (#1699194)