diff --git a/SOURCES/glibc-rh1705899-1.patch b/SOURCES/glibc-rh1705899-1.patch new file mode 100644 index 0000000..9955c76 --- /dev/null +++ b/SOURCES/glibc-rh1705899-1.patch @@ -0,0 +1,466 @@ +commit 2afece36f6006844e87d7cb2fcb1ad8b220b2623 +Author: Florian Weimer +Date: Wed May 16 17:00:35 2018 +0200 + + support: Add TEST_COMPARE_BLOB, support_quote_blob + + The declaration of support_test_compare_blob uses unsigned long int, + to avoid including . + + Reviewed-by: Carlos O'Donell + +(Adjusted for minor conflict in support/Makefile.) + +diff --git a/support/Makefile b/support/Makefile +index 1bda81e55e519a57..fb9f4291d72156df 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -52,9 +52,11 @@ libsupport-routines = \ + support_format_hostent \ + support_format_netent \ + support_isolate_in_subprocess \ ++ support_quote_blob \ + support_record_failure \ + support_run_diff \ + support_shared_allocate \ ++ support_test_compare_blob \ + support_test_compare_failure \ + support_write_file_string \ + support_test_main \ +@@ -150,8 +152,10 @@ tests = \ + tst-support-namespace \ + tst-support_capture_subprocess \ + tst-support_format_dns_packet \ ++ tst-support_quote_blob \ + tst-support_record_failure \ + tst-test_compare \ ++ tst-test_compare_blob \ + tst-xreadlink \ + + ifeq ($(run-built-tests),yes) +diff --git a/support/check.h b/support/check.h +index 2192f38941af2515..b3a4645e9255e90d 100644 +--- a/support/check.h ++++ b/support/check.h +@@ -64,6 +64,8 @@ __BEGIN_DECLS + (1, __FILE__, __LINE__, #expr); \ + }) + ++ ++ + int support_print_failure_impl (const char *file, int line, + const char *format, ...) + __attribute__ ((nonnull (1), format (printf, 3, 4))); +@@ -141,6 +143,26 @@ void support_test_compare_failure (const char *file, int line, + int right_size); + + ++/* Compare [LEFT, LEFT + LEFT_LENGTH) with [RIGHT, RIGHT + ++ RIGHT_LENGTH) and report a test failure if the arrays are ++ different. LEFT_LENGTH and RIGHT_LENGTH are measured in bytes. If ++ the length is null, the corresponding pointer is ignored (i.e., it ++ can be NULL). The blobs should be reasonably short because on ++ mismatch, both are printed. */ ++#define TEST_COMPARE_BLOB(left, left_length, right, right_length) \ ++ (support_test_compare_blob (left, left_length, right, right_length, \ ++ __FILE__, __LINE__, \ ++ #left, #left_length, #right, #right_length)) ++ ++void support_test_compare_blob (const void *left, ++ unsigned long int left_length, ++ const void *right, ++ unsigned long int right_length, ++ const char *file, int line, ++ const char *left_exp, const char *left_len_exp, ++ const char *right_exp, ++ const char *right_len_exp); ++ + /* Internal function called by the test driver. */ + int support_report_failure (int status) + __attribute__ ((weak, warn_unused_result)); +diff --git a/support/support.h b/support/support.h +index bc5827ed87d0d96c..b61fe0735c9204de 100644 +--- a/support/support.h ++++ b/support/support.h +@@ -59,6 +59,12 @@ void support_shared_free (void *); + process on error. */ + void support_write_file_string (const char *path, const char *contents); + ++/* Quote the contents of the byte array starting at BLOB, of LENGTH ++ bytes, in such a way that the result string can be included in a C ++ literal (in single/double quotes, without putting the quotes into ++ the result). */ ++char *support_quote_blob (const void *blob, size_t length); ++ + /* Error-checking wrapper functions which terminate the process on + error. */ + +diff --git a/support/support_quote_blob.c b/support/support_quote_blob.c +new file mode 100644 +index 0000000000000000..d6a678d8d69160a8 +--- /dev/null ++++ b/support/support_quote_blob.c +@@ -0,0 +1,83 @@ ++/* Quote a blob so that it can be used in C literals. ++ Copyright (C) 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 ++ . */ ++ ++#include ++#include ++ ++char * ++support_quote_blob (const void *blob, size_t length) ++{ ++ struct xmemstream out; ++ xopen_memstream (&out); ++ ++ const unsigned char *p = blob; ++ for (size_t i = 0; i < length; ++i) ++ { ++ unsigned char ch = p[i]; ++ ++ /* Use C backslash escapes for those control characters for ++ which they are defined. */ ++ switch (ch) ++ { ++ case '\a': ++ putc_unlocked ('\\', out.out); ++ putc_unlocked ('a', out.out); ++ break; ++ case '\b': ++ putc_unlocked ('\\', out.out); ++ putc_unlocked ('b', out.out); ++ break; ++ case '\f': ++ putc_unlocked ('\\', out.out); ++ putc_unlocked ('f', out.out); ++ break; ++ case '\n': ++ putc_unlocked ('\\', out.out); ++ putc_unlocked ('n', out.out); ++ break; ++ case '\r': ++ putc_unlocked ('\\', out.out); ++ putc_unlocked ('r', out.out); ++ break; ++ case '\t': ++ putc_unlocked ('\\', out.out); ++ putc_unlocked ('t', out.out); ++ break; ++ case '\v': ++ putc_unlocked ('\\', out.out); ++ putc_unlocked ('v', out.out); ++ break; ++ case '\\': ++ case '\'': ++ case '\"': ++ putc_unlocked ('\\', out.out); ++ putc_unlocked (ch, out.out); ++ break; ++ default: ++ if (ch < ' ' || ch > '~') ++ /* Use octal sequences because they are fixed width, ++ unlike hexadecimal sequences. */ ++ fprintf (out.out, "\\%03o", ch); ++ else ++ putc_unlocked (ch, out.out); ++ } ++ } ++ ++ xfclose_memstream (&out); ++ return out.buffer; ++} +diff --git a/support/support_test_compare_blob.c b/support/support_test_compare_blob.c +new file mode 100644 +index 0000000000000000..c5e63d1b9327c9fe +--- /dev/null ++++ b/support/support_test_compare_blob.c +@@ -0,0 +1,76 @@ ++/* Check two binary blobs for equality. ++ Copyright (C) 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static void ++report_length (const char *what, unsigned long int length, const char *expr) ++{ ++ printf (" %s %lu bytes (from %s)\n", what, length, expr); ++} ++ ++static void ++report_blob (const char *what, const unsigned char *blob, ++ unsigned long int length, const char *expr) ++{ ++ if (length > 0) ++ { ++ printf (" %s (evaluated from %s):\n", what, expr); ++ char *quoted = support_quote_blob (blob, length); ++ printf (" \"%s\"\n", quoted); ++ free (quoted); ++ ++ fputs (" ", stdout); ++ for (unsigned long i = 0; i < length; ++i) ++ printf (" %02X", blob[i]); ++ putc ('\n', stdout); ++ } ++} ++ ++void ++support_test_compare_blob (const void *left, unsigned long int left_length, ++ const void *right, unsigned long int right_length, ++ const char *file, int line, ++ const char *left_expr, const char *left_len_expr, ++ const char *right_expr, const char *right_len_expr) ++{ ++ /* No differences are possible if both lengths are null. */ ++ if (left_length == 0 && right_length == 0) ++ return; ++ ++ if (left_length != right_length || left == NULL || right == NULL ++ || memcmp (left, right, left_length) != 0) ++ { ++ support_record_failure (); ++ printf ("%s:%d: error: blob comparison failed\n", file, line); ++ if (left_length == right_length) ++ printf (" blob length: %lu bytes\n", left_length); ++ else ++ { ++ report_length ("left length: ", left_length, left_len_expr); ++ report_length ("right length:", right_length, right_len_expr); ++ } ++ report_blob ("left", left, left_length, left_expr); ++ report_blob ("right", right, right_length, right_expr); ++ } ++} +diff --git a/support/tst-support_quote_blob.c b/support/tst-support_quote_blob.c +new file mode 100644 +index 0000000000000000..5467a190a6e0725c +--- /dev/null ++++ b/support/tst-support_quote_blob.c +@@ -0,0 +1,61 @@ ++/* Test the support_quote_blob function. ++ Copyright (C) 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ /* Check handling of the empty blob, both with and without trailing ++ NUL byte. */ ++ char *p = support_quote_blob ("", 0); ++ TEST_COMPARE (strlen (p), 0); ++ free (p); ++ p = support_quote_blob ("X", 0); ++ TEST_COMPARE (strlen (p), 0); ++ free (p); ++ ++ /* Check escaping of backslash-escaped characters, and lack of ++ escaping for other shell meta-characters. */ ++ p = support_quote_blob ("$()*?`@[]{}~\'\"X", 14); ++ TEST_COMPARE (strcmp (p, "$()*?`@[]{}~\\'\\\""), 0); ++ free (p); ++ ++ /* Check lack of escaping for letters and digits. */ ++#define LETTERS_AND_DIGTS \ ++ "abcdefghijklmnopqrstuvwxyz" \ ++ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ ++ "0123456789" ++ p = support_quote_blob (LETTERS_AND_DIGTS "@", 2 * 26 + 10); ++ TEST_COMPARE (strcmp (p, LETTERS_AND_DIGTS), 0); ++ free (p); ++ ++ /* Check escaping of control characters and other non-printable ++ characters. */ ++ p = support_quote_blob ("\r\n\t\a\b\f\v\1\177\200\377\0@", 14); ++ TEST_COMPARE (strcmp (p, "\\r\\n\\t\\a\\b\\f\\v\\001" ++ "\\177\\200\\377\\000@\\000"), 0); ++ free (p); ++ ++ return 0; ++} ++ ++#include +diff --git a/support/tst-test_compare_blob.c b/support/tst-test_compare_blob.c +new file mode 100644 +index 0000000000000000..aa8643e18227da85 +--- /dev/null ++++ b/support/tst-test_compare_blob.c +@@ -0,0 +1,125 @@ ++/* Basic test for the TEST_COMPARE_BLOB macro. ++ Copyright (C) 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 ++ . */ ++ ++#include ++#include ++#include ++ ++static void ++subprocess (void *closure) ++{ ++ /* These tests should fail. They were chosen to cover differences ++ in length (with the same contents), single-bit mismatches, and ++ mismatching null pointers. */ ++ TEST_COMPARE_BLOB ("", 0, "", 1); /* Line 29. */ ++ TEST_COMPARE_BLOB ("X", 1, "", 1); /* Line 30. */ ++ TEST_COMPARE_BLOB ("abcd", 3, "abcd", 4); /* Line 31. */ ++ TEST_COMPARE_BLOB ("abcd", 4, "abcD", 4); /* Line 32. */ ++ TEST_COMPARE_BLOB ("abcd", 4, NULL, 0); /* Line 33. */ ++ TEST_COMPARE_BLOB (NULL, 0, "abcd", 4); /* Line 34. */ ++} ++ ++/* Same contents, different addresses. */ ++char buffer_abc_1[] = "abc"; ++char buffer_abc_2[] = "abc"; ++ ++static int ++do_test (void) ++{ ++ /* This should succeed. Even if the pointers and array contents are ++ different, zero-length inputs are not different. */ ++ TEST_COMPARE_BLOB ("", 0, "", 0); ++ TEST_COMPARE_BLOB ("", 0, buffer_abc_1, 0); ++ TEST_COMPARE_BLOB (buffer_abc_1, 0, "", 0); ++ TEST_COMPARE_BLOB (NULL, 0, "", 0); ++ TEST_COMPARE_BLOB ("", 0, NULL, 0); ++ TEST_COMPARE_BLOB (NULL, 0, NULL, 0); ++ ++ /* Check equality of blobs containing a single NUL byte. */ ++ TEST_COMPARE_BLOB ("", 1, "", 1); ++ TEST_COMPARE_BLOB ("", 1, &buffer_abc_1[3], 1); ++ ++ /* Check equality of blobs of varying lengths. */ ++ for (size_t i = 0; i <= sizeof (buffer_abc_1); ++i) ++ TEST_COMPARE_BLOB (buffer_abc_1, i, buffer_abc_2, i); ++ ++ struct support_capture_subprocess proc = support_capture_subprocess ++ (&subprocess, NULL); ++ ++ /* Discard the reported error. */ ++ support_record_failure_reset (); ++ ++ puts ("info: *** subprocess output starts ***"); ++ fputs (proc.out.buffer, stdout); ++ puts ("info: *** subprocess output ends ***"); ++ ++ TEST_VERIFY ++ (strcmp (proc.out.buffer, ++"tst-test_compare_blob.c:29: error: blob comparison failed\n" ++" left length: 0 bytes (from 0)\n" ++" right length: 1 bytes (from 1)\n" ++" right (evaluated from \"\"):\n" ++" \"\\000\"\n" ++" 00\n" ++"tst-test_compare_blob.c:30: error: blob comparison failed\n" ++" blob length: 1 bytes\n" ++" left (evaluated from \"X\"):\n" ++" \"X\"\n" ++" 58\n" ++" right (evaluated from \"\"):\n" ++" \"\\000\"\n" ++" 00\n" ++"tst-test_compare_blob.c:31: error: blob comparison failed\n" ++" left length: 3 bytes (from 3)\n" ++" right length: 4 bytes (from 4)\n" ++" left (evaluated from \"abcd\"):\n" ++" \"abc\"\n" ++" 61 62 63\n" ++" right (evaluated from \"abcd\"):\n" ++" \"abcd\"\n" ++" 61 62 63 64\n" ++"tst-test_compare_blob.c:32: error: blob comparison failed\n" ++" blob length: 4 bytes\n" ++" left (evaluated from \"abcd\"):\n" ++" \"abcd\"\n" ++" 61 62 63 64\n" ++" right (evaluated from \"abcD\"):\n" ++" \"abcD\"\n" ++" 61 62 63 44\n" ++"tst-test_compare_blob.c:33: error: blob comparison failed\n" ++" left length: 4 bytes (from 4)\n" ++" right length: 0 bytes (from 0)\n" ++" left (evaluated from \"abcd\"):\n" ++" \"abcd\"\n" ++" 61 62 63 64\n" ++"tst-test_compare_blob.c:34: error: blob comparison failed\n" ++" left length: 0 bytes (from 0)\n" ++" right length: 4 bytes (from 4)\n" ++" right (evaluated from \"abcd\"):\n" ++" \"abcd\"\n" ++" 61 62 63 64\n" ++ ) == 0); ++ ++ /* Check that there is no output on standard error. */ ++ support_capture_subprocess_check (&proc, "TEST_COMPARE_BLOB", ++ 0, sc_allow_stdout); ++ ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-rh1705899-2.patch b/SOURCES/glibc-rh1705899-2.patch new file mode 100644 index 0000000..5e0e669 --- /dev/null +++ b/SOURCES/glibc-rh1705899-2.patch @@ -0,0 +1,50 @@ +commit 5c0202af4b3d588c04bcec7baf05706b21cd7416 +Author: Florian Weimer +Date: Tue Jun 26 12:05:21 2018 +0200 + + support: Add TEST_NO_SETVBUF + + This is sometimes needed for testing stdio streams, where the + setvbuf call in the test driver could interfere with the test. + +diff --git a/support/support_test_main.c b/support/support_test_main.c +index 396385729b6809ad..23429779aca85613 100644 +--- a/support/support_test_main.c ++++ b/support/support_test_main.c +@@ -270,7 +270,8 @@ support_test_main (int argc, char **argv, const struct test_config *config) + timeout = DEFAULT_TIMEOUT; + + /* Make sure we see all message, even those on stdout. */ +- setvbuf (stdout, NULL, _IONBF, 0); ++ if (!config->no_setvbuf) ++ setvbuf (stdout, NULL, _IONBF, 0); + + /* Make sure temporary files are deleted. */ + if (support_delete_temp_files != NULL) +diff --git a/support/test-driver.c b/support/test-driver.c +index 09c8783e4f54d809..9798f16227b9d467 100644 +--- a/support/test-driver.c ++++ b/support/test-driver.c +@@ -140,6 +140,10 @@ main (int argc, char **argv) + test_config.no_mallopt = 1; + #endif + ++#ifdef TEST_NO_SETVBUF ++ test_config.no_setvbuf = 1; ++#endif ++ + #ifdef TIMEOUT + test_config.timeout = TIMEOUT; + #endif +diff --git a/support/test-driver.h b/support/test-driver.h +index 1708d68d608ee4a4..549179b254946390 100644 +--- a/support/test-driver.h ++++ b/support/test-driver.h +@@ -35,6 +35,7 @@ struct test_config + int expected_status; /* Expected exit status. */ + int expected_signal; /* If non-zero, expect termination by signal. */ + char no_mallopt; /* Boolean flag to disable mallopt. */ ++ char no_setvbuf; /* Boolean flag to disable setvbuf. */ + const char *optstring; /* Short command line options. */ + }; + diff --git a/SOURCES/glibc-rh1705899-3.patch b/SOURCES/glibc-rh1705899-3.patch new file mode 100644 index 0000000..3e3fa24 --- /dev/null +++ b/SOURCES/glibc-rh1705899-3.patch @@ -0,0 +1,230 @@ +commit 0262507918cfad7223bf81b8f162b7adc7a2af01 +Author: Florian Weimer +Date: Fri Jun 1 10:43:06 2018 +0200 + + libio: Avoid _allocate_buffer, _free_buffer function pointers [BZ #23236] + + These unmangled function pointers reside on the heap and could + be targeted by exploit writers, effectively bypassing libio vtable + validation. Instead, we ignore these pointers and always call + malloc or free. + + In theory, this is a backwards-incompatible change, but using the + global heap instead of the user-supplied callback functions should + have little application impact. (The old libstdc++ implementation + exposed this functionality via a public, undocumented constructor + in its strstreambuf class.) + + (cherry picked from commit 4e8a6346cd3da2d88bbad745a1769260d36f2783) + +Backported from the upstream release/2.27/master branch. + +diff --git a/debug/vasprintf_chk.c b/debug/vasprintf_chk.c +index a8ca32bad57b4d13..113354749ccf8d9a 100644 +--- a/debug/vasprintf_chk.c ++++ b/debug/vasprintf_chk.c +@@ -55,8 +55,8 @@ __vasprintf_chk (char **result_ptr, int flags, const char *format, + _IO_JUMPS (&sf._sbf) = &_IO_str_jumps; + _IO_str_init_static_internal (&sf, string, init_string_size, string); + sf._sbf._f._flags &= ~_IO_USER_BUF; +- sf._s._allocate_buffer = (_IO_alloc_type) malloc; +- sf._s._free_buffer = (_IO_free_type) free; ++ sf._s._allocate_buffer_unused = (_IO_alloc_type) malloc; ++ sf._s._free_buffer_unused = (_IO_free_type) free; + + /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n + can only come from read-only format strings. */ +diff --git a/libio/memstream.c b/libio/memstream.c +index e18a7756b297c9f4..9a51331e525c3468 100644 +--- a/libio/memstream.c ++++ b/libio/memstream.c +@@ -87,8 +87,8 @@ open_memstream (char **bufloc, _IO_size_t *sizeloc) + _IO_JUMPS ((struct _IO_FILE_plus *) &new_f->fp._sf._sbf) = &_IO_mem_jumps; + _IO_str_init_static_internal (&new_f->fp._sf, buf, _IO_BUFSIZ, buf); + new_f->fp._sf._sbf._f._flags &= ~_IO_USER_BUF; +- new_f->fp._sf._s._allocate_buffer = (_IO_alloc_type) malloc; +- new_f->fp._sf._s._free_buffer = (_IO_free_type) free; ++ new_f->fp._sf._s._allocate_buffer_unused = (_IO_alloc_type) malloc; ++ new_f->fp._sf._s._free_buffer_unused = (_IO_free_type) free; + + new_f->fp.bufloc = bufloc; + new_f->fp.sizeloc = sizeloc; +diff --git a/libio/strfile.h b/libio/strfile.h +index 4ea7548f9fa92638..9cd8e7c466616b52 100644 +--- a/libio/strfile.h ++++ b/libio/strfile.h +@@ -34,8 +34,11 @@ typedef void (*_IO_free_type) (void*); + + struct _IO_str_fields + { +- _IO_alloc_type _allocate_buffer; +- _IO_free_type _free_buffer; ++ /* These members are preserved for ABI compatibility. The glibc ++ implementation always calls malloc/free for user buffers if ++ _IO_USER_BUF or _IO_FLAGS2_USER_WBUF are not set. */ ++ _IO_alloc_type _allocate_buffer_unused; ++ _IO_free_type _free_buffer_unused; + }; + + /* This is needed for the Irix6 N32 ABI, which has a 64 bit off_t type, +@@ -55,10 +58,6 @@ typedef struct _IO_strfile_ + struct _IO_str_fields _s; + } _IO_strfile; + +-/* dynamic: set when the array object is allocated (or reallocated) as +- necessary to hold a character sequence that can change in length. */ +-#define _IO_STR_DYNAMIC(FP) ((FP)->_s._allocate_buffer != (_IO_alloc_type)0) +- + /* frozen: set when the program has requested that the array object not + be altered, reallocated, or freed. */ + #define _IO_STR_FROZEN(FP) ((FP)->_f._IO_file_flags & _IO_USER_BUF) +diff --git a/libio/strops.c b/libio/strops.c +index fdd113a60811e593..129a0f6aeca818fd 100644 +--- a/libio/strops.c ++++ b/libio/strops.c +@@ -61,7 +61,7 @@ _IO_str_init_static_internal (_IO_strfile *sf, char *ptr, _IO_size_t size, + fp->_IO_read_end = end; + } + /* A null _allocate_buffer function flags the strfile as being static. */ +- sf->_s._allocate_buffer = (_IO_alloc_type) 0; ++ sf->_s._allocate_buffer_unused = (_IO_alloc_type) 0; + } + + void +@@ -103,8 +103,7 @@ _IO_str_overflow (_IO_FILE *fp, int c) + _IO_size_t new_size = 2 * old_blen + 100; + if (new_size < old_blen) + return EOF; +- new_buf +- = (char *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (new_size); ++ new_buf = malloc (new_size); + if (new_buf == NULL) + { + /* __ferror(fp) = 1; */ +@@ -113,7 +112,7 @@ _IO_str_overflow (_IO_FILE *fp, int c) + if (old_buf) + { + memcpy (new_buf, old_buf, old_blen); +- (*((_IO_strfile *) fp)->_s._free_buffer) (old_buf); ++ free (old_buf); + /* Make sure _IO_setb won't try to delete _IO_buf_base. */ + fp->_IO_buf_base = NULL; + } +@@ -182,15 +181,14 @@ enlarge_userbuf (_IO_FILE *fp, _IO_off64_t offset, int reading) + + _IO_size_t newsize = offset + 100; + char *oldbuf = fp->_IO_buf_base; +- char *newbuf +- = (char *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (newsize); ++ char *newbuf = malloc (newsize); + if (newbuf == NULL) + return 1; + + if (oldbuf != NULL) + { + memcpy (newbuf, oldbuf, _IO_blen (fp)); +- (*((_IO_strfile *) fp)->_s._free_buffer) (oldbuf); ++ free (oldbuf); + /* Make sure _IO_setb won't try to delete + _IO_buf_base. */ + fp->_IO_buf_base = NULL; +@@ -317,7 +315,7 @@ void + _IO_str_finish (_IO_FILE *fp, int dummy) + { + if (fp->_IO_buf_base && !(fp->_flags & _IO_USER_BUF)) +- (((_IO_strfile *) fp)->_s._free_buffer) (fp->_IO_buf_base); ++ free (fp->_IO_buf_base); + fp->_IO_buf_base = NULL; + + _IO_default_finish (fp, 0); +diff --git a/libio/vasprintf.c b/libio/vasprintf.c +index 282c86fff0a7ae0e..867ef4fe4ca4ec56 100644 +--- a/libio/vasprintf.c ++++ b/libio/vasprintf.c +@@ -54,8 +54,8 @@ _IO_vasprintf (char **result_ptr, const char *format, _IO_va_list args) + _IO_JUMPS (&sf._sbf) = &_IO_str_jumps; + _IO_str_init_static_internal (&sf, string, init_string_size, string); + sf._sbf._f._flags &= ~_IO_USER_BUF; +- sf._s._allocate_buffer = (_IO_alloc_type) malloc; +- sf._s._free_buffer = (_IO_free_type) free; ++ sf._s._allocate_buffer_unused = (_IO_alloc_type) malloc; ++ sf._s._free_buffer_unused = (_IO_free_type) free; + ret = _IO_vfprintf (&sf._sbf._f, format, args); + if (ret < 0) + { +diff --git a/libio/wmemstream.c b/libio/wmemstream.c +index bd6d1798b1685fe9..3a9a681c80a321a7 100644 +--- a/libio/wmemstream.c ++++ b/libio/wmemstream.c +@@ -90,8 +90,8 @@ open_wmemstream (wchar_t **bufloc, _IO_size_t *sizeloc) + _IO_wstr_init_static (&new_f->fp._sf._sbf._f, buf, + _IO_BUFSIZ / sizeof (wchar_t), buf); + new_f->fp._sf._sbf._f._flags2 &= ~_IO_FLAGS2_USER_WBUF; +- new_f->fp._sf._s._allocate_buffer = (_IO_alloc_type) malloc; +- new_f->fp._sf._s._free_buffer = (_IO_free_type) free; ++ new_f->fp._sf._s._allocate_buffer_unused = (_IO_alloc_type) malloc; ++ new_f->fp._sf._s._free_buffer_unused = (_IO_free_type) free; + + new_f->fp.bufloc = bufloc; + new_f->fp.sizeloc = sizeloc; +diff --git a/libio/wstrops.c b/libio/wstrops.c +index 7a9a33ab8763b8ff..a31d0e23341b2aad 100644 +--- a/libio/wstrops.c ++++ b/libio/wstrops.c +@@ -63,7 +63,7 @@ _IO_wstr_init_static (_IO_FILE *fp, wchar_t *ptr, _IO_size_t size, + fp->_wide_data->_IO_read_end = end; + } + /* A null _allocate_buffer function flags the strfile as being static. */ +- (((_IO_strfile *) fp)->_s._allocate_buffer) = (_IO_alloc_type)0; ++ (((_IO_strfile *) fp)->_s._allocate_buffer_unused) = (_IO_alloc_type)0; + } + + _IO_wint_t +@@ -95,9 +95,7 @@ _IO_wstr_overflow (_IO_FILE *fp, _IO_wint_t c) + || __glibc_unlikely (new_size > SIZE_MAX / sizeof (wchar_t))) + return EOF; + +- new_buf +- = (wchar_t *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (new_size +- * sizeof (wchar_t)); ++ new_buf = malloc (new_size * sizeof (wchar_t)); + if (new_buf == NULL) + { + /* __ferror(fp) = 1; */ +@@ -106,7 +104,7 @@ _IO_wstr_overflow (_IO_FILE *fp, _IO_wint_t c) + if (old_buf) + { + __wmemcpy (new_buf, old_buf, old_wblen); +- (*((_IO_strfile *) fp)->_s._free_buffer) (old_buf); ++ free (old_buf); + /* Make sure _IO_setb won't try to delete _IO_buf_base. */ + fp->_wide_data->_IO_buf_base = NULL; + } +@@ -186,16 +184,14 @@ enlarge_userbuf (_IO_FILE *fp, _IO_off64_t offset, int reading) + return 1; + + wchar_t *oldbuf = wd->_IO_buf_base; +- wchar_t *newbuf +- = (wchar_t *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (newsize +- * sizeof (wchar_t)); ++ wchar_t *newbuf = malloc (newsize * sizeof (wchar_t)); + if (newbuf == NULL) + return 1; + + if (oldbuf != NULL) + { + __wmemcpy (newbuf, oldbuf, _IO_wblen (fp)); +- (*((_IO_strfile *) fp)->_s._free_buffer) (oldbuf); ++ free (oldbuf); + /* Make sure _IO_setb won't try to delete + _IO_buf_base. */ + wd->_IO_buf_base = NULL; +@@ -326,7 +322,7 @@ void + _IO_wstr_finish (_IO_FILE *fp, int dummy) + { + if (fp->_wide_data->_IO_buf_base && !(fp->_flags2 & _IO_FLAGS2_USER_WBUF)) +- (((_IO_strfile *) fp)->_s._free_buffer) (fp->_wide_data->_IO_buf_base); ++ free (fp->_wide_data->_IO_buf_base); + fp->_wide_data->_IO_buf_base = NULL; + + _IO_wdefault_finish (fp, 0); diff --git a/SOURCES/glibc-rh1705899-4.patch b/SOURCES/glibc-rh1705899-4.patch new file mode 100644 index 0000000..80c7606 --- /dev/null +++ b/SOURCES/glibc-rh1705899-4.patch @@ -0,0 +1,34 @@ +commit 3bb748257405e94e13de76573a4e9da1cfd961d0 +Author: Florian Weimer +Date: Tue Jul 3 15:54:49 2018 +0200 + + libio: Disable vtable validation in case of interposition [BZ #23313] + + (cherry picked from commit c402355dfa7807b8e0adb27c009135a7e2b9f1b0) + +Backported from the upstream release/2.27/master branch. + +diff --git a/libio/vtables.c b/libio/vtables.c +index e364ea03edbfa75b..d6478e4bab9050ce 100644 +--- a/libio/vtables.c ++++ b/libio/vtables.c +@@ -68,3 +68,19 @@ _IO_vtable_check (void) + + __libc_fatal ("Fatal error: glibc detected an invalid stdio handle\n"); + } ++ ++/* Some variants of libstdc++ interpose _IO_2_1_stdin_ etc. and ++ install their own vtables directly, without calling _IO_init or ++ other functions. Detect this by looking at the vtables values ++ during startup, and disable vtable validation in this case. */ ++#ifdef SHARED ++__attribute__ ((constructor)) ++static void ++check_stdfiles_vtables (void) ++{ ++ if (_IO_2_1_stdin_.vtable != &_IO_file_jumps ++ || _IO_2_1_stdout_.vtable != &_IO_file_jumps ++ || _IO_2_1_stderr_.vtable != &_IO_file_jumps) ++ IO_set_accept_foreign_vtables (&_IO_vtable_check); ++} ++#endif diff --git a/SOURCES/glibc-rh1705899-5.patch b/SOURCES/glibc-rh1705899-5.patch new file mode 100644 index 0000000..1500ba3 --- /dev/null +++ b/SOURCES/glibc-rh1705899-5.patch @@ -0,0 +1,624 @@ +commit 44927211651adde42bbd431ef5ebe568186125e5 +Author: Florian Weimer +Date: Tue Jul 3 17:57:14 2018 +0200 + + libio: Add tst-vtables, tst-vtables-interposed + + (cherry picked from commit 29055464a03c72762969a2e8734d0d05d4d70e58) + + Some adjustments were needed for a tricky multi-inclusion issue related + to libioP.h. + +Backported from the upsteam release/2.27/master branch, adjusted for +lack of tests-internal support downstream. + +diff --git a/libio/Makefile b/libio/Makefile +index 0cef96141209fe99..1e923da42e45c492 100644 +--- a/libio/Makefile ++++ b/libio/Makefile +@@ -61,7 +61,9 @@ tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc \ + bug-memstream1 bug-wmemstream1 \ + tst-setvbuf1 tst-popen1 tst-fgetwc bug-wsetpos tst-fseek \ + tst-fwrite-error tst-ftell-active-handler \ +- tst-ftell-append ++ tst-ftell-append \ ++ tst-vtables tst-vtables-interposed ++ + ifeq (yes,$(build-shared)) + # Add test-fopenloc only if shared library is enabled since it depends on + # shared localedata objects. +diff --git a/libio/tst-vtables-common.c b/libio/tst-vtables-common.c +new file mode 100644 +index 0000000000000000..dc8d89c195b95b8d +--- /dev/null ++++ b/libio/tst-vtables-common.c +@@ -0,0 +1,511 @@ ++/* Test for libio vtables and their validation. Common code. ++ Copyright (C) 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 ++ . */ ++ ++/* This test provides some coverage for how various stdio functions ++ use the vtables in FILE * objects. The focus is mostly on which ++ functions call which methods, not so much on validating data ++ processing. An initial series of tests check that custom vtables ++ do not work without activation through _IO_init. ++ ++ Note: libio vtables are deprecated feature. Do not use this test ++ as a documentation source for writing custom vtables. See ++ fopencookie for a different way of creating custom stdio ++ streams. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Data shared between the test subprocess and the test driver in the ++ parent. Note that *shared is reset at the start of the check_call ++ function. */ ++struct shared ++{ ++ /* Expected file pointer for method calls. */ ++ FILE *fp; ++ ++ /* If true, assume that a call to _IO_init is needed to enable ++ custom vtables. */ ++ bool initially_disabled; ++ ++ /* Requested return value for the methods which have one. */ ++ int return_value; ++ ++ /* A value (usually a character) recorded by some of the methods ++ below. */ ++ int value; ++ ++ /* Likewise, for some data. */ ++ char buffer[16]; ++ size_t buffer_length; ++ ++ /* Total number of method calls. */ ++ unsigned int calls; ++ ++ /* Individual method call counts. */ ++ unsigned int calls_finish; ++ unsigned int calls_overflow; ++ unsigned int calls_underflow; ++ unsigned int calls_uflow; ++ unsigned int calls_pbackfail; ++ unsigned int calls_xsputn; ++ unsigned int calls_xsgetn; ++ unsigned int calls_seekoff; ++ unsigned int calls_seekpos; ++ unsigned int calls_setbuf; ++ unsigned int calls_sync; ++ unsigned int calls_doallocate; ++ unsigned int calls_read; ++ unsigned int calls_write; ++ unsigned int calls_seek; ++ unsigned int calls_close; ++ unsigned int calls_stat; ++ unsigned int calls_showmanyc; ++ unsigned int calls_imbue; ++} *shared; ++ ++/* Method implementations which increment the counters in *shared. */ ++ ++static void ++log_method (FILE *fp, const char *name) ++{ ++ if (test_verbose > 0) ++ printf ("info: %s (%p) called\n", name, fp); ++} ++ ++static void ++method_finish (FILE *fp, int dummy) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_finish; ++} ++ ++static int ++method_overflow (FILE *fp, int ch) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_overflow; ++ shared->value = ch; ++ return shared->return_value; ++} ++ ++static int ++method_underflow (FILE *fp) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_underflow; ++ return shared->return_value; ++} ++ ++static int ++method_uflow (FILE *fp) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_uflow; ++ return shared->return_value; ++} ++ ++static int ++method_pbackfail (FILE *fp, int ch) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_pbackfail; ++ shared->value = ch; ++ return shared->return_value; ++} ++ ++static size_t ++method_xsputn (FILE *fp, const void *data, size_t n) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_xsputn; ++ ++ size_t to_copy = n; ++ if (n > sizeof (shared->buffer)) ++ to_copy = sizeof (shared->buffer); ++ memcpy (shared->buffer, data, to_copy); ++ shared->buffer_length = to_copy; ++ return to_copy; ++} ++ ++static size_t ++method_xsgetn (FILE *fp, void *data, size_t n) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_xsgetn; ++ return 0; ++} ++ ++static off64_t ++method_seekoff (FILE *fp, off64_t offset, int dir, int mode) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_seekoff; ++ return shared->return_value; ++} ++ ++static off64_t ++method_seekpos (FILE *fp, off64_t offset, int mode) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_seekpos; ++ return shared->return_value; ++} ++ ++static FILE * ++method_setbuf (FILE *fp, char *buffer, ssize_t length) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_setbuf; ++ return fp; ++} ++ ++static int ++method_sync (FILE *fp) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_sync; ++ return shared->return_value; ++} ++ ++static int ++method_doallocate (FILE *fp) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_doallocate; ++ return shared->return_value; ++} ++ ++static ssize_t ++method_read (FILE *fp, void *data, ssize_t length) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_read; ++ return shared->return_value; ++} ++ ++static ssize_t ++method_write (FILE *fp, const void *data, ssize_t length) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_write; ++ return shared->return_value; ++} ++ ++static off64_t ++method_seek (FILE *fp, off64_t offset, int mode) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_seek; ++ return shared->return_value; ++} ++ ++static int ++method_close (FILE *fp) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_close; ++ return shared->return_value; ++} ++ ++static int ++method_stat (FILE *fp, void *buffer) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_stat; ++ return shared->return_value; ++} ++ ++static int ++method_showmanyc (FILE *fp) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_showmanyc; ++ return shared->return_value; ++} ++ ++static void ++method_imbue (FILE *fp, void *locale) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_imbue; ++} ++ ++/* Our custom vtable. */ ++ ++static const struct _IO_jump_t jumps = ++{ ++ JUMP_INIT_DUMMY, ++ JUMP_INIT (finish, method_finish), ++ JUMP_INIT (overflow, method_overflow), ++ JUMP_INIT (underflow, method_underflow), ++ JUMP_INIT (uflow, method_uflow), ++ JUMP_INIT (pbackfail, method_pbackfail), ++ JUMP_INIT (xsputn, method_xsputn), ++ JUMP_INIT (xsgetn, method_xsgetn), ++ JUMP_INIT (seekoff, method_seekoff), ++ JUMP_INIT (seekpos, method_seekpos), ++ JUMP_INIT (setbuf, method_setbuf), ++ JUMP_INIT (sync, method_sync), ++ JUMP_INIT (doallocate, method_doallocate), ++ JUMP_INIT (read, method_read), ++ JUMP_INIT (write, method_write), ++ JUMP_INIT (seek, method_seek), ++ JUMP_INIT (close, method_close), ++ JUMP_INIT (stat, method_stat), ++ JUMP_INIT (showmanyc, method_showmanyc), ++ JUMP_INIT (imbue, method_imbue) ++}; ++ ++/* Our file implementation. */ ++ ++struct my_file ++{ ++ FILE f; ++ const struct _IO_jump_t *vtable; ++}; ++ ++struct my_file ++my_file_create (void) ++{ ++ return (struct my_file) ++ { ++ /* Disable locking, so that we do not have to set up a lock ++ pointer. */ ++ .f._flags = _IO_USER_LOCK, ++ ++ /* Copy the offset from the an initialized handle, instead of ++ figuring it out from scratch. */ ++ .f._vtable_offset = stdin->_vtable_offset, ++ ++ .vtable = &jumps, ++ }; ++} ++ ++/* Initial tests which do not enable vtable compatibility. */ ++ ++/* Inhibit GCC optimization of fprintf. */ ++typedef int (*fprintf_type) (FILE *, const char *, ...); ++static const volatile fprintf_type fprintf_ptr = &fprintf; ++ ++static void ++without_compatibility_fprintf (void *closure) ++{ ++ /* This call should abort. */ ++ fprintf_ptr (shared->fp, " "); ++ _exit (1); ++} ++ ++static void ++without_compatibility_fputc (void *closure) ++{ ++ /* This call should abort. */ ++ fputc (' ', shared->fp); ++ _exit (1); ++} ++ ++static void ++without_compatibility_fgetc (void *closure) ++{ ++ /* This call should abort. */ ++ fgetc (shared->fp); ++ _exit (1); ++} ++ ++static void ++without_compatibility_fflush (void *closure) ++{ ++ /* This call should abort. */ ++ fflush (shared->fp); ++ _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 *)) ++{ ++ struct my_file file = my_file_create (); ++ shared->fp = &file.f; ++ shared->return_value = -1; ++ shared->calls = 0; ++ struct support_capture_subprocess proc ++ = support_capture_subprocess (callback, NULL); ++ support_capture_subprocess_check (&proc, name, termination_status, ++ sc_allow_stderr); ++ const char *message ++ = "Fatal error: glibc detected an invalid stdio handle\n"; ++ TEST_COMPARE_BLOB (proc.err.buffer, proc.err.length, ++ message, strlen (message)); ++ TEST_COMPARE (shared->calls, 0); ++ support_capture_subprocess_free (&proc); ++} ++ ++/* The test with vtable validation disabled. */ ++ ++/* This function does not have a prototype in libioP.h to prevent ++ accidental use from within the library (which would disable vtable ++ verification). */ ++void _IO_init (FILE *fp, int flags); ++ ++static void ++with_compatibility_fprintf (void *closure) ++{ ++ TEST_COMPARE (fprintf_ptr (shared->fp, "A%sCD", "B"), 4); ++ TEST_COMPARE (shared->calls, 3); ++ TEST_COMPARE (shared->calls_xsputn, 3); ++ TEST_COMPARE_BLOB (shared->buffer, shared->buffer_length, ++ "CD", 2); ++} ++ ++static void ++with_compatibility_fputc (void *closure) ++{ ++ shared->return_value = '@'; ++ TEST_COMPARE (fputc ('@', shared->fp), '@'); ++ TEST_COMPARE (shared->calls, 1); ++ TEST_COMPARE (shared->calls_overflow, 1); ++ TEST_COMPARE (shared->value, '@'); ++} ++ ++static void ++with_compatibility_fgetc (void *closure) ++{ ++ shared->return_value = 'X'; ++ TEST_COMPARE (fgetc (shared->fp), 'X'); ++ TEST_COMPARE (shared->calls, 1); ++ TEST_COMPARE (shared->calls_uflow, 1); ++} ++ ++static void ++with_compatibility_fflush (void *closure) ++{ ++ TEST_COMPARE (fflush (shared->fp), 0); ++ TEST_COMPARE (shared->calls, 1); ++ TEST_COMPARE (shared->calls_sync, 1); ++} ++ ++/* Call CALLBACK in a subprocess, after setting up a custom file ++ object and updating shared->fp. */ ++static void ++check_call (const char *name, void (*callback) (void *), ++ bool initially_disabled) ++{ ++ *shared = (struct shared) ++ { ++ .initially_disabled = initially_disabled, ++ }; ++ ++ /* Set up a custom file object. */ ++ struct my_file file = my_file_create (); ++ shared->fp = &file.f; ++ if (shared->initially_disabled) ++ _IO_init (shared->fp, file.f._flags); ++ ++ if (test_verbose > 0) ++ printf ("info: calling test %s\n", name); ++ support_isolate_in_subprocess (callback, NULL); ++} ++ ++/* Run the tests. INITIALLY_DISABLED indicates whether custom vtables ++ are disabled when the test starts. */ ++static int ++run_tests (bool initially_disabled) ++{ ++ /* The test relies on fatal error messages being printed to standard ++ error. */ ++ setenv ("LIBC_FATAL_STDERR_", "1", 1); ++ ++ shared = support_shared_allocate (sizeof (*shared)); ++ shared->initially_disabled = initially_disabled; ++ init_termination_status (); ++ ++ if (initially_disabled) ++ { ++ check_for_termination ("fprintf", without_compatibility_fprintf); ++ check_for_termination ("fputc", without_compatibility_fputc); ++ check_for_termination ("fgetc", without_compatibility_fgetc); ++ check_for_termination ("fflush", without_compatibility_fflush); ++ } ++ ++ check_call ("fprintf", with_compatibility_fprintf, initially_disabled); ++ check_call ("fputc", with_compatibility_fputc, initially_disabled); ++ check_call ("fgetc", with_compatibility_fgetc, initially_disabled); ++ check_call ("fflush", with_compatibility_fflush, initially_disabled); ++ ++ support_shared_free (shared); ++ shared = NULL; ++ ++ return 0; ++} +diff --git a/libio/tst-vtables-interposed.c b/libio/tst-vtables-interposed.c +new file mode 100644 +index 0000000000000000..c8f4e8c7c386af39 +--- /dev/null ++++ b/libio/tst-vtables-interposed.c +@@ -0,0 +1,37 @@ ++/* Test for libio vtables and their validation. Enabled through interposition. ++ Copyright (C) 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 ++ . */ ++ ++/* Provide an interposed definition of the standard file handles with ++ our own vtable. stdout/stdin/stderr will not work as a result, but ++ a succesful test does not print anything, so this is fine. */ ++static const struct _IO_jump_t jumps; ++#define _IO_file_jumps jumps ++#include "stdfiles.c" ++ ++#include "tst-vtables-common.c" ++ ++static int ++do_test (void) ++{ ++ return run_tests (false); ++} ++ ++/* Calling setvbuf in the test driver is not supported with our ++ interposed file handles. */ ++#define TEST_NO_SETVBUF ++#include +diff --git a/libio/tst-vtables.c b/libio/tst-vtables.c +new file mode 100644 +index 0000000000000000..f16acf5d23b0fff6 +--- /dev/null ++++ b/libio/tst-vtables.c +@@ -0,0 +1,29 @@ ++/* Test for libio vtables and their validation. Initially disabled case. ++ Copyright (C) 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 ++ . */ ++ ++#include "libioP.h" ++ ++#include "tst-vtables-common.c" ++ ++static int ++do_test (void) ++{ ++ return run_tests (true); ++} ++ ++#include diff --git a/SOURCES/glibc-rh1705899-6.patch b/SOURCES/glibc-rh1705899-6.patch new file mode 100644 index 0000000..4ff1252 --- /dev/null +++ b/SOURCES/glibc-rh1705899-6.patch @@ -0,0 +1,24 @@ +commit 2d1c89a5d7c872a1109768f50e2508cf9a4b0348 +Author: Florian Weimer +Date: Wed Jun 20 09:45:19 2018 +0200 + + libio: Avoid ptrdiff_t overflow in IO_validate_vtable + + If the candidate pointer is sufficiently far away from + __start___libc_IO_vtables, the result might not fit into ptrdiff_t. + +diff --git a/libio/libioP.h b/libio/libioP.h +index b60244ac5fc3d908..f1576381500ffc85 100644 +--- a/libio/libioP.h ++++ b/libio/libioP.h +@@ -957,8 +957,8 @@ IO_validate_vtable (const struct _IO_jump_t *vtable) + /* Fast path: The vtable pointer is within the __libc_IO_vtables + section. */ + uintptr_t section_length = __stop___libc_IO_vtables - __start___libc_IO_vtables; +- const char *ptr = (const char *) vtable; +- uintptr_t offset = ptr - __start___libc_IO_vtables; ++ uintptr_t ptr = (uintptr_t) vtable; ++ uintptr_t offset = ptr - (uintptr_t) __start___libc_IO_vtables; + if (__glibc_unlikely (offset >= section_length)) + /* The vtable pointer is not in the expected section. Use the + slow path, which will terminate the process if necessary. */ diff --git a/SPECS/glibc.spec b/SPECS/glibc.spec index f848b48..e3c3634 100644 --- a/SPECS/glibc.spec +++ b/SPECS/glibc.spec @@ -1,6 +1,6 @@ %define glibcsrcdir glibc-2.17-c758a686 %define glibcversion 2.17 -%define glibcrelease 260%{?dist}.5 +%define glibcrelease 260%{?dist}.6 ############################################################################## # We support the following options: # --with/--without, @@ -1422,6 +1422,12 @@ Patch2753: glibc-rh1661242-1.patch Patch2754: glibc-rh1661242-2.patch Patch2755: glibc-rh1693152-1.patch Patch2756: glibc-rh1693152-2.patch +Patch2757: glibc-rh1705899-1.patch +Patch2758: glibc-rh1705899-2.patch +Patch2759: glibc-rh1705899-3.patch +Patch2760: glibc-rh1705899-4.patch +Patch2761: glibc-rh1705899-5.patch +Patch2762: glibc-rh1705899-6.patch ############################################################################## # @@ -2827,6 +2833,12 @@ package or when debugging this package. %patch2754 -p1 %patch2755 -p1 %patch2756 -p1 +%patch2757 -p1 +%patch2758 -p1 +%patch2759 -p1 +%patch2760 -p1 +%patch2761 -p1 +%patch2762 -p1 ############################################################################## # %%prep - Additional prep required... @@ -3990,6 +4002,9 @@ rm -f *.filelist* %endif %changelog +* Fri May 3 2019 Florian Weimer - 2.17-260.6 +- Backport libio vtable validation improvements (#1705899) + * Tue Apr 30 2019 Florian Weimer - 2.17-260.5 - Use versioned Obsoletes: for nss_db (#1704593)