diff --git a/SOURCES/glibc-rh1027101.patch b/SOURCES/glibc-rh1027101.patch new file mode 100644 index 0000000..2b419c9 --- /dev/null +++ b/SOURCES/glibc-rh1027101.patch @@ -0,0 +1,58 @@ +commit 362b47fe09ca9a928d444c7e2f7992f7f61bfc3e +Author: Maxim Kuvyrkov +Date: Tue Dec 24 09:44:50 2013 +1300 + + Fix race in free() of fastbin chunk: BZ #15073 + + Perform sanity check only if we have_lock. Due to lockless nature of fastbins + we need to be careful derefencing pointers to fastbin entries (chunksize(old) + in this case) in multithreaded environments. + + The fix is to add have_lock to the if-condition checks. The rest of the patch + only makes code more readable. + + * malloc/malloc.c (_int_free): Perform sanity check only if we + have_lock. + +Index: b/malloc/malloc.c +=================================================================== +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -3909,25 +3909,29 @@ _int_free(mstate av, mchunkptr p, int ha + unsigned int idx = fastbin_index(size); + fb = &fastbin (av, idx); + +- mchunkptr fd; +- mchunkptr old = *fb; ++ /* Atomically link P to its fastbin: P->FD = *FB; *FB = P; */ ++ mchunkptr old = *fb, old2; + unsigned int old_idx = ~0u; + do + { +- /* Another simple check: make sure the top of the bin is not the +- record we are going to add (i.e., double free). */ ++ /* Check that the top of the bin is not the record we are going to add ++ (i.e., double free). */ + if (__builtin_expect (old == p, 0)) + { + errstr = "double free or corruption (fasttop)"; + goto errout; + } +- if (old != NULL) ++ /* Check that size of fastbin chunk at the top is the same as ++ size of the chunk that we are adding. We can dereference OLD ++ only if we have the lock, otherwise it might have already been ++ deallocated. See use of OLD_IDX below for the actual check. */ ++ if (have_lock && old != NULL) + old_idx = fastbin_index(chunksize(old)); +- p->fd = fd = old; ++ p->fd = old2 = old; + } +- while ((old = catomic_compare_and_exchange_val_rel (fb, p, fd)) != fd); ++ while ((old = catomic_compare_and_exchange_val_rel (fb, p, old2)) != old2); + +- if (fd != NULL && __builtin_expect (old_idx != idx, 0)) ++ if (have_lock && old != NULL && __builtin_expect (old_idx != idx, 0)) + { + errstr = "invalid fastbin entry (free)"; + goto errout; diff --git a/SOURCES/glibc-rh1310530.patch b/SOURCES/glibc-rh1310530.patch new file mode 100644 index 0000000..e78ceb9 --- /dev/null +++ b/SOURCES/glibc-rh1310530.patch @@ -0,0 +1,18 @@ +commit 984c0ea97f649c869130a1ff099098e2b6f70aad +Author: Tim Lammens +Date: Thu Sep 11 10:35:54 2014 +0530 + + Fix memory leak in libio/wfileops.c do_ftell_wide [BZ #17370] + +diff --git a/libio/wfileops.c b/libio/wfileops.c +index f123add..ebc06e8 100644 +--- a/libio/wfileops.c ++++ b/libio/wfileops.c +@@ -711,6 +711,7 @@ do_ftell_wide (_IO_FILE *fp) + return WEOF; + + offset += outstop - out; ++ free (out); + } + + /* We don't trust _IO_read_end to represent the current file offset diff --git a/SOURCES/glibc-rh1320596.patch b/SOURCES/glibc-rh1320596.patch new file mode 100644 index 0000000..09a0cfa --- /dev/null +++ b/SOURCES/glibc-rh1320596.patch @@ -0,0 +1,216 @@ +commit b66d837bb5398795c6b0f651bd5a5d66091d8577 +Author: Florian Weimer +Date: Fri Mar 25 11:49:51 2016 +0100 + + resolv: Always set *resplen2 out parameter in send_dg [BZ #19791] + + Since commit 44d20bca52ace85850012b0ead37b360e3ecd96e (Implement + second fallback mode for DNS requests), there is a code path which + returns early, before *resplen2 is initialized. This happens if the + name server address is immediately recognized as invalid (because of + lack of protocol support, or if it is a broadcast address such + 255.255.255.255, or another invalid address). + + If this happens and *resplen2 was non-zero (which is the case if a + previous query resulted in a failure), __libc_res_nquery would reuse + an existing second answer buffer. This answer has been previously + identified as unusable (for example, it could be an NXDOMAIN + response). Due to the presence of a second answer, no name server + switching will occur. The result is a name resolution failure, + although a successful resolution would have been possible if name + servers have been switched and queries had proceeded along the search + path. + + The above paragraph still simplifies the situation. Before glibc + 2.23, if the second answer needed malloc, the stub resolver would + still attempt to reuse the second answer, but this is not possible + because __libc_res_nsearch has freed it, after the unsuccessful call + to __libc_res_nquerydomain, and set the buffer pointer to NULL. This + eventually leads to an assertion failure in __libc_res_nquery: + + /* Make sure both hp and hp2 are defined */ + assert((hp != NULL) && (hp2 != NULL)); + + If assertions are disabled, the consequence is a NULL pointer + dereference on the next line. + + Starting with glibc 2.23, as a result of commit + e9db92d3acfe1822d56d11abcea5bfc4c41cf6ca (CVE-2015-7547: getaddrinfo() + stack-based buffer overflow (Bug 18665)), the second answer is always + allocated with malloc. This means that the assertion failure happens + with small responses as well because there is no buffer to reuse, as + soon as there is a name resolution failure which triggers a search for + an answer along the search path. + + This commit addresses the issue by ensuring that *resplen2 is + initialized before the send_dg function returns. + + This commit also addresses a bug where an invalid second reply is + incorrectly returned as a valid to the caller. + +Index: glibc-2.17-c758a686/resolv/res_send.c +=================================================================== +--- glibc-2.17-c758a686.orig/resolv/res_send.c ++++ glibc-2.17-c758a686/resolv/res_send.c +@@ -672,6 +672,18 @@ libresolv_hidden_def (res_nsend) + + /* Private */ + ++/* Close the resolver structure, assign zero to *RESPLEN2 if RESPLEN2 ++ is not NULL, and return zero. */ ++static int ++__attribute__ ((warn_unused_result)) ++close_and_return_error (res_state statp, int *resplen2) ++{ ++ __res_iclose(statp, false); ++ if (resplen2 != NULL) ++ *resplen2 = 0; ++ return 0; ++} ++ + /* The send_vc function is responsible for sending a DNS query over TCP + to the nameserver numbered NS from the res_state STATP i.e. + EXT(statp).nssocks[ns]. The function supports sending both IPv4 and +@@ -1159,7 +1171,11 @@ send_dg(res_state statp, + retry_reopen: + retval = reopen (statp, terrno, ns); + if (retval <= 0) +- return retval; ++ { ++ if (resplen2 != NULL) ++ *resplen2 = 0; ++ return retval; ++ } + retry: + evNowTime(&now); + evConsTime(&timeout, seconds, 0); +@@ -1172,8 +1188,6 @@ send_dg(res_state statp, + int recvresp2 = buf2 == NULL; + pfd[0].fd = EXT(statp).nssocks[ns]; + pfd[0].events = POLLOUT; +- if (resplen2 != NULL) +- *resplen2 = 0; + wait: + if (need_recompute) { + recompute_resend: +@@ -1181,9 +1195,7 @@ send_dg(res_state statp, + if (evCmpTime(finish, now) <= 0) { + poll_err_out: + Perror(statp, stderr, "poll", errno); +- err_out: +- __res_iclose(statp, false); +- return (0); ++ return close_and_return_error (statp, resplen2); + } + evSubTime(&timeout, &finish, &now); + need_recompute = 0; +@@ -1230,7 +1242,9 @@ send_dg(res_state statp, + } + + *gotsomewhere = 1; +- return (0); ++ if (resplen2 != NULL) ++ *resplen2 = 0; ++ return 0; + } + if (n < 0) { + if (errno == EINTR) +@@ -1298,7 +1312,7 @@ send_dg(res_state statp, + + fail_sendmmsg: + Perror(statp, stderr, "sendmmsg", errno); +- goto err_out; ++ return close_and_return_error (statp, resplen2); + } + } + else +@@ -1316,7 +1330,7 @@ send_dg(res_state statp, + if (errno == EINTR || errno == EAGAIN) + goto recompute_resend; + Perror(statp, stderr, "send", errno); +- goto err_out; ++ return close_and_return_error (statp, resplen2); + } + just_one: + if (nwritten != 0 || buf2 == NULL || single_request) +@@ -1392,7 +1406,7 @@ send_dg(res_state statp, + goto wait; + } + Perror(statp, stderr, "recvfrom", errno); +- goto err_out; ++ return close_and_return_error (statp, resplen2); + } + *gotsomewhere = 1; + if (__builtin_expect (*thisresplenp < HFIXEDSZ, 0)) { +@@ -1403,7 +1417,7 @@ send_dg(res_state statp, + (stdout, ";; undersized: %d\n", + *thisresplenp)); + *terrno = EMSGSIZE; +- goto err_out; ++ return close_and_return_error (statp, resplen2); + } + if ((recvresp1 || hp->id != anhp->id) + && (recvresp2 || hp2->id != anhp->id)) { +@@ -1452,7 +1466,7 @@ send_dg(res_state statp, + ? *thisanssizp : *thisresplenp); + /* record the error */ + statp->_flags |= RES_F_EDNS0ERR; +- goto err_out; ++ return close_and_return_error (statp, resplen2); + } + #endif + if (!(statp->options & RES_INSECURE2) +@@ -1504,10 +1518,10 @@ send_dg(res_state statp, + goto wait; + } + +- __res_iclose(statp, false); + /* don't retry if called from dig */ + if (!statp->pfcode) +- return (0); ++ return close_and_return_error (statp, resplen2); ++ __res_iclose(statp, false); + } + if (anhp->rcode == NOERROR && anhp->ancount == 0 + && anhp->aa == 0 && anhp->ra == 0 && anhp->arcount == 0) { +@@ -1529,6 +1543,8 @@ send_dg(res_state statp, + __res_iclose(statp, false); + // XXX if we have received one reply we could + // XXX use it and not repeat it over TCP... ++ if (resplen2 != NULL) ++ *resplen2 = 0; + return (1); + } + /* Mark which reply we received. */ +@@ -1544,21 +1560,22 @@ send_dg(res_state statp, + __res_iclose (statp, false); + retval = reopen (statp, terrno, ns); + if (retval <= 0) +- return retval; ++ { ++ if (resplen2 != NULL) ++ *resplen2 = 0; ++ return retval; ++ } + pfd[0].fd = EXT(statp).nssocks[ns]; + } + } + goto wait; + } +- /* +- * All is well, or the error is fatal. Signal that the +- * next nameserver ought not be tried. +- */ ++ /* All is well. We have received both responses (if ++ two responses were requested). */ + return (resplen); +- } else if (pfd[0].revents & (POLLERR | POLLHUP | POLLNVAL)) { +- /* Something went wrong. We can stop trying. */ +- goto err_out; +- } ++ } else if (pfd[0].revents & (POLLERR | POLLHUP | POLLNVAL)) ++ /* Something went wrong. We can stop trying. */ ++ return close_and_return_error (statp, resplen2); + else { + /* poll should not have returned > 0 in this case. */ + abort (); diff --git a/SPECS/glibc.spec b/SPECS/glibc.spec index 4f2ec5b..5a4ec21 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 106%{?dist}.4 +%define glibcrelease 106%{?dist}.6 ############################################################################## # If run_glibc_tests is zero then tests are not run for the build. # You must always set run_glibc_tests to one for production builds. @@ -673,6 +673,16 @@ Patch1619: glibc-rh1284959-3.patch # ppc64le monstartup fix: Patch1620: glibc-rh1249102.patch +# Fix race in free() of fastbin chunk: BZ #15073. +Patch1621: glibc-rh1027101.patch + +# BZ #17370: Memory leak in wide-oriented ftell. +Patch1622: glibc-rh1310530.patch + +# BZ #19791: NULL pointer dereference in stub resolver with unconnectable +# name server addresses +Patch1623: glibc-rh1320596.patch + ############################################################################## # # Patches submitted, but not yet approved upstream. @@ -1320,6 +1330,9 @@ package or when debugging this package. %patch1618 -p1 %patch1619 -p1 %patch1620 -p1 +%patch1621 -p1 +%patch1622 -p1 +%patch1623 -p1 ############################################################################## # %%prep - Additional prep required... @@ -2389,6 +2402,14 @@ rm -f *.filelist* %endif %changelog +* Mon Apr 4 2016 Carlos O'Donell - 2.17-106.6 +- Fix NULL pointer dereference in stub resolver with unconnectable name + server addresses (#1323839). + +* Mon Apr 4 2016 Carlos O'Donell - 2.17-106.5 +- Fix memory leak in ftell for wide-oriented streams (#1323781). +- Avoid race condition in _int_free involving fastbins (#1313308). + * Fri Feb 5 2016 Florian Weimer - 2.17-106.4 - Revert problematic libresolv change, not needed for the CVE-2015-7547 fix (#1296030).