From 72dd7f1877da221bbe328731b65851cb5f56ec4b Mon Sep 17 00:00:00 2001 From: Michael Olbrich Date: Mon, 6 Jul 2015 10:04:07 +0200 Subject: glibc: add more security fixes Signed-off-by: Michael Olbrich --- ...21-Do-not-close-NSS-files-database-during.patch | 226 +++++++++++++++++++++ ...81-resolv-nss_dns-dns-host.c-buffer-overf.patch | 23 +++ patches/glibc-2.20/series | 4 +- 3 files changed, 252 insertions(+), 1 deletion(-) create mode 100644 patches/glibc-2.20/0005-CVE-2014-8121-Do-not-close-NSS-files-database-during.patch create mode 100644 patches/glibc-2.20/0006-CVE-2015-1781-resolv-nss_dns-dns-host.c-buffer-overf.patch diff --git a/patches/glibc-2.20/0005-CVE-2014-8121-Do-not-close-NSS-files-database-during.patch b/patches/glibc-2.20/0005-CVE-2014-8121-Do-not-close-NSS-files-database-during.patch new file mode 100644 index 0000000..17861f7 --- /dev/null +++ b/patches/glibc-2.20/0005-CVE-2014-8121-Do-not-close-NSS-files-database-during.patch @@ -0,0 +1,226 @@ +From: Florian Weimer +Date: Wed, 29 Apr 2015 14:41:25 +0200 +Subject: [PATCH] CVE-2014-8121: Do not close NSS files database during + iteration [BZ #18007] +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Robin Hack discovered Samba would enter an infinite loop processing +certain quota-related requests. We eventually tracked this down to a +glibc issue. + +Running a (simplified) test case under strace shows that /etc/passwd +is continuously opened and closed: + +… +open("/etc/passwd", O_RDONLY|O_CLOEXEC) = 3 +lseek(3, 0, SEEK_CUR) = 0 +read(3, "root:x:0:0:root:/root:/bin/bash\n"..., 4096) = 2717 +lseek(3, 2717, SEEK_SET) = 2717 +close(3) = 0 +open("/etc/passwd", O_RDONLY|O_CLOEXEC) = 3 +lseek(3, 0, SEEK_CUR) = 0 +lseek(3, 0, SEEK_SET) = 0 +read(3, "root:x:0:0:root:/root:/bin/bash\n"..., 4096) = 2717 +lseek(3, 2717, SEEK_SET) = 2717 +close(3) = 0 +open("/etc/passwd", O_RDONLY|O_CLOEXEC) = 3 +lseek(3, 0, SEEK_CUR) = 0 +… + +The lookup function implementation in +nss/nss_files/files-XXX.c:DB_LOOKUP has code to prevent that. It is +supposed skip closing the input file if it was already open. + + /* Reset file pointer to beginning or open file. */ \ + status = internal_setent (keep_stream); \ + \ + if (status == NSS_STATUS_SUCCESS) \ + { \ + /* Tell getent function that we have repositioned the file pointer. */ \ + last_use = getby; \ + \ + while ((status = internal_getent (result, buffer, buflen, errnop \ + H_ERRNO_ARG EXTRA_ARGS_VALUE)) \ + == NSS_STATUS_SUCCESS) \ + { break_if_match } \ + \ + if (! keep_stream) \ + internal_endent (); \ + } \ + +keep_stream is initialized from the stayopen flag in internal_setent. +internal_setent is called from the set*ent implementation as: + + status = internal_setent (stayopen); + +However, for non-host database, this flag is always 0, per the +STAYOPEN magic in nss/getXXent_r.c. + +Thus, the fix is this: + +- status = internal_setent (stayopen); ++ status = internal_setent (1); + +This is not a behavioral change even for the hosts database (where the +application can specify the stayopen flag) because with a call to +sethostent(0), the file handle is still not closed in the +implementation of gethostent. +--- + nss/Makefile | 2 +- + nss/nss_files/files-XXX.c | 2 +- + nss/tst-nss-getpwent.c | 118 ++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 120 insertions(+), 2 deletions(-) + create mode 100644 nss/tst-nss-getpwent.c + +diff --git a/nss/Makefile b/nss/Makefile +index 1fa7f1f397f5..d6f0139bf5c8 100644 +--- a/nss/Makefile ++++ b/nss/Makefile +@@ -39,7 +39,7 @@ install-bin := getent makedb + makedb-modules = xmalloc hash-string + extra-objs += $(makedb-modules:=.o) + +-tests = test-netdb tst-nss-test1 test-digits-dots ++tests = test-netdb tst-nss-test1 test-digits-dots tst-nss-getpwent + xtests = bug-erange + + # Specify rules for the nss_* modules. We have some services. +diff --git a/nss/nss_files/files-XXX.c b/nss/nss_files/files-XXX.c +index 212b938fdf39..cc38174df0c2 100644 +--- a/nss/nss_files/files-XXX.c ++++ b/nss/nss_files/files-XXX.c +@@ -134,7 +134,7 @@ CONCAT(_nss_files_set,ENTNAME) (int stayopen) + + __libc_lock_lock (lock); + +- status = internal_setent (stayopen); ++ status = internal_setent (1); + + if (status == NSS_STATUS_SUCCESS && fgetpos (stream, &position) < 0) + { +diff --git a/nss/tst-nss-getpwent.c b/nss/tst-nss-getpwent.c +new file mode 100644 +index 000000000000..f2e8abce6098 +--- /dev/null ++++ b/nss/tst-nss-getpwent.c +@@ -0,0 +1,118 @@ ++/* Copyright (C) 2015 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 ++ ++int ++do_test (void) ++{ ++ /* Count the number of entries in the password database, and fetch ++ data from the first and last entries. */ ++ size_t count = 0; ++ struct passwd * pw; ++ char *first_name = NULL; ++ uid_t first_uid = 0; ++ char *last_name = NULL; ++ uid_t last_uid = 0; ++ setpwent (); ++ while ((pw = getpwent ()) != NULL) ++ { ++ if (first_name == NULL) ++ { ++ first_name = strdup (pw->pw_name); ++ if (first_name == NULL) ++ { ++ printf ("strdup: %m\n"); ++ return 1; ++ } ++ first_uid = pw->pw_uid; ++ } ++ ++ free (last_name); ++ last_name = strdup (pw->pw_name); ++ if (last_name == NULL) ++ { ++ printf ("strdup: %m\n"); ++ return 1; ++ } ++ last_uid = pw->pw_uid; ++ ++count; ++ } ++ endpwent (); ++ ++ if (count == 0) ++ { ++ printf ("No entries in the password database.\n"); ++ return 0; ++ } ++ ++ /* Try again, this time interleaving with name-based and UID-based ++ lookup operations. The counts do not match if the interleaved ++ lookups affected the enumeration. */ ++ size_t new_count = 0; ++ setpwent (); ++ while ((pw = getpwent ()) != NULL) ++ { ++ if (new_count == count) ++ { ++ printf ("Additional entry in the password database.\n"); ++ return 1; ++ } ++ ++new_count; ++ struct passwd *pw2 = getpwnam (first_name); ++ if (pw2 == NULL) ++ { ++ printf ("getpwnam (%s) failed: %m\n", first_name); ++ return 1; ++ } ++ pw2 = getpwnam (last_name); ++ if (pw2 == NULL) ++ { ++ printf ("getpwnam (%s) failed: %m\n", last_name); ++ return 1; ++ } ++ pw2 = getpwuid (first_uid); ++ if (pw2 == NULL) ++ { ++ printf ("getpwuid (%llu) failed: %m\n", ++ (unsigned long long) first_uid); ++ return 1; ++ } ++ pw2 = getpwuid (last_uid); ++ if (pw2 == NULL) ++ { ++ printf ("getpwuid (%llu) failed: %m\n", ++ (unsigned long long) last_uid); ++ return 1; ++ } ++ } ++ endpwent (); ++ if (new_count < count) ++ { ++ printf ("Missing entry in the password database.\n"); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++#define TEST_FUNCTION do_test () ++#include "../test-skeleton.c" diff --git a/patches/glibc-2.20/0006-CVE-2015-1781-resolv-nss_dns-dns-host.c-buffer-overf.patch b/patches/glibc-2.20/0006-CVE-2015-1781-resolv-nss_dns-dns-host.c-buffer-overf.patch new file mode 100644 index 0000000..3c035a4 --- /dev/null +++ b/patches/glibc-2.20/0006-CVE-2015-1781-resolv-nss_dns-dns-host.c-buffer-overf.patch @@ -0,0 +1,23 @@ +From: Arjun Shankar +Date: Tue, 21 Apr 2015 14:06:31 +0200 +Subject: [PATCH] CVE-2015-1781: resolv/nss_dns/dns-host.c buffer overflow + [BZ#18287] + +--- + resolv/nss_dns/dns-host.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c +index 3258e709d20c..ed997030331c 100644 +--- a/resolv/nss_dns/dns-host.c ++++ b/resolv/nss_dns/dns-host.c +@@ -615,7 +615,8 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype, + int have_to_map = 0; + uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data); + buffer += pad; +- if (__glibc_unlikely (buflen < sizeof (struct host_data) + pad)) ++ buflen = buflen > pad ? buflen - pad : 0; ++ if (__glibc_unlikely (buflen < sizeof (struct host_data))) + { + /* The buffer is too small. */ + too_small: diff --git a/patches/glibc-2.20/series b/patches/glibc-2.20/series index 04144e3..992d079 100644 --- a/patches/glibc-2.20/series +++ b/patches/glibc-2.20/series @@ -5,6 +5,8 @@ 0002-CVE-2012-3406-Stack-overflow-in-vfprintf-BZ-16617.patch 0003-CVE-2014-7817-wordexp-fails-to-honour-WRDE_NOCMD.patch 0004-CVE-2015-1472-wscanf-allocates-too-little-memory.patch +0005-CVE-2014-8121-Do-not-close-NSS-files-database-during.patch +0006-CVE-2015-1781-resolv-nss_dns-dns-host.c-buffer-overf.patch #tag:build-system --start-number 100 0100-add-install-lib-all-target.patch 0101-don-t-regen-docs-if-perl-is-not-found.patch @@ -19,4 +21,4 @@ 0500-Hack-around-mips-args-to-host-gcc.patch #tag:open-glibc-bugs --start-number 600 0600-ARM-fix-PI-futex-breakge-glibc-bug-18463.patch -# 3558b892a89c6287a934fa9cf65be74d - git-ptx-patches magic +# 9b9561d3bd8d2a555c8bae5ece64e366 - git-ptx-patches magic -- cgit v1.2.3