]> git.ipfire.org Git - ipfire-2.x.git/commitdiff
Merge branch 'bird' into next
authorMichael Tremer <michael.tremer@ipfire.org>
Tue, 8 Mar 2016 22:45:04 +0000 (22:45 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Tue, 8 Mar 2016 22:45:04 +0000 (22:45 +0000)
178 files changed:
config/backup/include
config/dracut/dracut.conf
config/kernel/kernel.config.armv5tel-ipfire-kirkwood
config/kernel/kernel.config.armv5tel-ipfire-multi
config/kernel/kernel.config.armv5tel-ipfire-rpi
config/kernel/kernel.config.i586-ipfire
config/kernel/kernel.config.i586-ipfire-pae
config/kernel/kernel.config.x86_64-ipfire
config/rootfiles/common/bison
config/rootfiles/common/openssh
config/rootfiles/common/xz
config/rootfiles/core/100/exclude [new file with mode: 0644]
config/rootfiles/core/100/filelists/armv5tel/glibc [new symlink]
config/rootfiles/core/100/filelists/armv5tel/linux-kirkwood [new symlink]
config/rootfiles/core/100/filelists/armv5tel/linux-multi [new symlink]
config/rootfiles/core/100/filelists/armv5tel/linux-rpi [new symlink]
config/rootfiles/core/100/filelists/bind [moved from config/rootfiles/core/98/filelists/bind with 100% similarity]
config/rootfiles/core/100/filelists/dnsmasq [moved from config/rootfiles/core/98/filelists/dnsmasq with 100% similarity]
config/rootfiles/core/100/filelists/files [moved from config/rootfiles/core/98/filelists/files with 91% similarity]
config/rootfiles/core/100/filelists/grep [moved from config/rootfiles/core/98/filelists/grep with 100% similarity]
config/rootfiles/core/100/filelists/i586/glibc [new symlink]
config/rootfiles/core/100/filelists/i586/linux [new symlink]
config/rootfiles/core/100/filelists/i586/linux-initrd [new symlink]
config/rootfiles/core/100/filelists/i586/openssl-sse2 [new symlink]
config/rootfiles/core/100/filelists/ntp [moved from config/rootfiles/core/98/filelists/ntp with 100% similarity]
config/rootfiles/core/100/filelists/openssh [moved from config/rootfiles/core/98/filelists/openssh with 100% similarity]
config/rootfiles/core/100/filelists/openssl [new symlink]
config/rootfiles/core/100/filelists/openvpn [moved from config/rootfiles/core/98/filelists/openvpn with 100% similarity]
config/rootfiles/core/100/filelists/sed [moved from config/rootfiles/core/98/filelists/sed with 100% similarity]
config/rootfiles/core/100/filelists/squid [moved from config/rootfiles/core/98/filelists/squid with 100% similarity]
config/rootfiles/core/100/filelists/tzdata [moved from config/rootfiles/core/98/filelists/tzdata with 100% similarity]
config/rootfiles/core/100/filelists/x86_64/glibc [new symlink]
config/rootfiles/core/100/filelists/x86_64/linux [new symlink]
config/rootfiles/core/100/filelists/x86_64/linux-initrd [new symlink]
config/rootfiles/core/100/filelists/xz [new symlink]
config/rootfiles/core/100/meta [moved from config/rootfiles/core/98/meta with 100% similarity]
config/rootfiles/core/100/update.sh [new file with mode: 0644]
config/rootfiles/core/99/exclude [moved from config/rootfiles/core/98/exclude with 100% similarity]
config/rootfiles/core/99/filelists/files [new file with mode: 0644]
config/rootfiles/core/99/filelists/i586/openssl-sse2 [new symlink]
config/rootfiles/core/99/filelists/openssh [new symlink]
config/rootfiles/core/99/filelists/openssl [new symlink]
config/rootfiles/core/99/meta [new file with mode: 0644]
config/rootfiles/core/99/update.sh [moved from config/rootfiles/core/98/update.sh with 86% similarity]
config/rootfiles/oldcore/98/exclude [new file with mode: 0644]
config/rootfiles/oldcore/98/filelists/armv5tel/glibc [new symlink]
config/rootfiles/oldcore/98/filelists/files [new file with mode: 0644]
config/rootfiles/oldcore/98/filelists/i586/glibc [new symlink]
config/rootfiles/oldcore/98/filelists/x86_64/glibc [new symlink]
config/rootfiles/oldcore/98/meta [new file with mode: 0644]
config/rootfiles/oldcore/98/update.sh [new file with mode: 0644]
config/udev/60-net.rules
lfs/Config
lfs/backports
lfs/bison
lfs/dnsmasq
lfs/flash-images
lfs/glibc
lfs/linux
lfs/m4
lfs/openssh
lfs/openssl
lfs/squid
lfs/stunnel
lfs/xz
make.sh
src/initscripts/init.d/functions
src/patches/arm-multi-grsec-compile-fixes.patch
src/patches/dnsmasq-Add-support-to-read-ISC-DHCP-lease-file.patch
src/patches/dnsmasq/001-Add_TTL_parameter_to_--host-record_and_--cname.patch [new file with mode: 0644]
src/patches/dnsmasq/001-include_0_0_0_0_8_in_DNS_rebind_checks.patch [deleted file]
src/patches/dnsmasq/002-Add_--dhcp-ttl_option.patch [new file with mode: 0644]
src/patches/dnsmasq/002-enhance_add_subnet_to_allow_arbitary_subnet_addresses.patch [deleted file]
src/patches/dnsmasq/003-Update_CHANGELOG.patch [new file with mode: 0644]
src/patches/dnsmasq/003-dont_answer_non_auth_queries_for_auth_zones_locally_when_localise_queries_set.patch [deleted file]
src/patches/dnsmasq/004-Add_--tftp-mtu_option.patch [new file with mode: 0644]
src/patches/dnsmasq/004-fix_behaviour_of_empty_dhcp-option.patch [deleted file]
src/patches/dnsmasq/005-Apply_ceiling_of_lease_length_to_TTL_when_--dhcp-ttl_in_use.patch [new file with mode: 0644]
src/patches/dnsmasq/005-suggest_solution_to_ENOMEM_error_with_IPv6_multicast.patch [deleted file]
src/patches/dnsmasq/006-clarify_man_page_on_RDNSS_set_in_router_advertisement.patch [deleted file]
src/patches/dnsmasq/007-handle_signed_dangling_CNAME_replies_to_DS_queries.patch [deleted file]
src/patches/dnsmasq/008-DHCPv6_option_56_does_not_hold_an_address_list.patch [deleted file]
src/patches/dnsmasq/009-Respect_the_--no_resolv_flag_in_inotify_code.patch [deleted file]
src/patches/dnsmasq/010-Rationalise_5e3e464ac4022ee0b3794513abe510817e2cf3ca.patch [deleted file]
src/patches/dnsmasq/011-Catch_errors_from_sendmsg_in_DHCP_code.patch [deleted file]
src/patches/dnsmasq/012-Update_list_of_subnet_for_--bogus-priv.patch [deleted file]
src/patches/dnsmasq/013-Fix_crash_when_empty_address_from_DNS_overlays_A_record_from.patch [deleted file]
src/patches/dnsmasq/014-Handle_unknown_DS_hash_algos_correctly.patch [deleted file]
src/patches/dnsmasq/015-Fix_crash_at_start_up_with_conf-dir.patch [deleted file]
src/patches/dnsmasq/016-Major_rationalisation_of_DNSSEC_validation.patch [deleted file]
src/patches/dnsmasq/017-Abandon_caching_RRSIGs_and_returning_them_from_cache.patch [deleted file]
src/patches/dnsmasq/018-Move_code_which_caches_DS_records_to_a_more_logical_place.patch [deleted file]
src/patches/dnsmasq/019-Generalise_RR-filtering_code_for_use_with_EDNS0.patch [deleted file]
src/patches/dnsmasq/020-DNSSEC_validation_tweak.patch [deleted file]
src/patches/dnsmasq/021-Tweaks_to_EDNS0_handling_in_DNS_replies.patch [deleted file]
src/patches/dnsmasq/022-Tidy_up_DNSSEC_non-existence_code_Check_zone_status_is_NSEC_proof_bad.patch [deleted file]
src/patches/dnsmasq/023-Fix_brace_botch_in_dnssec_validate_ds.patch [deleted file]
src/patches/dnsmasq/024-Do_a_better_job_of_determining_which_DNSSEC_sig_algos_are_supported.patch [deleted file]
src/patches/dnsmasq/025-Major_tidy_up_of_EDNS0_handling_and_computation_use_of_udp.patch [deleted file]
src/patches/dnsmasq/026-More_tweaks_in_handling_unknown_DNSSEC_algorithms.patch [deleted file]
src/patches/dnsmasq/027-Nasty_rare_and_obscure_off-by-one_in_DNSSEC_hostname_cmp.patch [deleted file]
src/patches/dnsmasq/028-Minor_tweak_to_previous_commit.patch [deleted file]
src/patches/dnsmasq/029-NSEC3_check_RFC5155_para_8_2.patch [deleted file]
src/patches/glibc-test-installation.pl-libgcc_s.patch
src/patches/glibc/glibc-rh1023306.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1025933.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1028285.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1039988.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1043557.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1053178.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1054846.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1066724.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1074342.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1074353.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1082379.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1085273.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1085289.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1085312.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1087833.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1088301.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1091915.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1099025-2.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1099025.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1116050-1.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1116050.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1124204.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1125307.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1133810-1.patch [moved from src/patches/glibc/glibc-rh1133809-1.patch with 100% similarity]
src/patches/glibc/glibc-rh1133810-2.patch [moved from src/patches/glibc/glibc-rh1133809-2.patch with 100% similarity]
src/patches/glibc/glibc-rh1138769.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1144019.patch [moved from src/patches/glibc/glibc-rh1207995.patch with 100% similarity]
src/patches/glibc/glibc-rh1144132.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1159167.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1171296.patch [moved from src/patches/glibc/glibc-rh1170121.patch with 100% similarity]
src/patches/glibc/glibc-rh1172044.patch [moved from src/patches/glibc/glibc-rh1139571.patch with 100% similarity]
src/patches/glibc/glibc-rh1176907.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1183534.patch [moved from src/patches/glibc/glibc-rh1183533.patch with 94% similarity]
src/patches/glibc/glibc-rh1195453-avx512.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1207236.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1209376.patch [moved from src/patches/glibc/glibc-rh1209375.patch with 100% similarity]
src/patches/glibc/glibc-rh1256812-2.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1256812-3.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1256812-4.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1256812.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1256890.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1256891.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1291270.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1296031-0.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1296031.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1299319-0.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1299319-1.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh552960.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh629823-2.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh629823.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh663641-2.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh663641-3.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh663641.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh788959-2.patch
src/patches/glibc/glibc-rh834386-2.patch [moved from src/patches/glibc/glibc-rh989558-2.patch with 100% similarity]
src/patches/glibc/glibc-rh834386.patch [moved from src/patches/glibc/glibc-rh989558.patch with 100% similarity]
src/patches/glibc/glibc-rh845218.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh848748.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh851470.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh859965.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh862094.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh863384.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh867679.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh868808.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh905941.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh919562.patch [moved from src/patches/glibc/glibc-rh970992.patch with 100% similarity]
src/patches/glibc/glibc-rh929302.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh970776.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh978098.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh981942.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh988931.patch [new file with mode: 0644]
src/patches/openssl-1.0.2g-disable-sslv2v3.patch [new file with mode: 0644]
src/patches/openssl-disable-sslv2-sslv3.patch [deleted file]
src/patches/squid-3.4-13230.patch [new file with mode: 0644]

index 6ecb930fa77fc5a5d897beb235c2b102b77a1f9c..eb76ebf3621cff07755d1d03c67bbfb962853d19 100644 (file)
@@ -33,7 +33,7 @@
 /var/log/ip-acct/*
 /var/log/rrd/*
 /var/log/rrd/collectd
-/var/log/rrd/vnstat
+/var/log/vnstat
 /etc/sysconfig/firewall.local
 /etc/sysconfig/rc.local
 /root/.gitconfig
index 34e6a667d84600e56b8a38425bd54d7b00c3f243..52bba9c6294eee6532d1f1d54a7fe1abe26bcca8 100644 (file)
@@ -21,6 +21,9 @@
 # additional kernel modules to the default
 #add_drivers+=""
 
+# skip kernel modules (marvell sdio and compat from backports)
+omit_drivers+="libertas libertas_sdio mwifiex mwifiex_sdio compat"
+
 # list of kernel filesystem modules to be included in the generic initramfs
 filesystems+="reiserfs vfat xfs"
 
index a35ec0bec0d0e4287b6dfd13162fd0a8bcc57582..9ec9b978696fcc59b82ca4f7c866145cf8eaaf9c 100644 (file)
@@ -1,6 +1,6 @@
 #
 # Automatically generated file; DO NOT EDIT.
-# Linux/arm 3.14.53 Kernel Configuration
+# Linux/arm 3.14.61 Kernel Configuration
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -194,9 +194,9 @@ CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
 CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
 CONFIG_SECCOMP_FILTER=y
 CONFIG_HAVE_CC_STACKPROTECTOR=y
-# CONFIG_CC_STACKPROTECTOR is not set
+CONFIG_CC_STACKPROTECTOR=y
 # CONFIG_CC_STACKPROTECTOR_NONE is not set
-CONFIG_CC_STACKPROTECTOR_REGULAR=y
+# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
 CONFIG_CC_STACKPROTECTOR_STRONG=y
 CONFIG_HAVE_CONTEXT_TRACKING=y
 CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
index 50106bc001b6223cd224b83bfca702c1c977fe9f..9bb91365bb3f8bf5983b95d65559a38fa9e9d94d 100644 (file)
@@ -1,6 +1,6 @@
 #
 # Automatically generated file; DO NOT EDIT.
-# Linux/arm 3.14.53 Kernel Configuration
+# Linux/arm 3.14.61 Kernel Configuration
 #
 CONFIG_ARM=y
 CONFIG_MIGHT_HAVE_PCI=y
@@ -217,9 +217,9 @@ CONFIG_HAVE_ARCH_JUMP_LABEL=y
 CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
 CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
 CONFIG_HAVE_CC_STACKPROTECTOR=y
-# CONFIG_CC_STACKPROTECTOR is not set
+CONFIG_CC_STACKPROTECTOR=y
 # CONFIG_CC_STACKPROTECTOR_NONE is not set
-CONFIG_CC_STACKPROTECTOR_REGULAR=y
+# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
 CONFIG_CC_STACKPROTECTOR_STRONG=y
 CONFIG_HAVE_CONTEXT_TRACKING=y
 CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
index 5bde32234e4346350a2fc96e30ef85a07bb18a44..2501b14d2c86386c99030471932754e7054e04ca 100644 (file)
@@ -1,6 +1,6 @@
 #
 # Automatically generated file; DO NOT EDIT.
-# Linux/arm 3.14.53 Kernel Configuration
+# Linux/arm 3.14.61 Kernel Configuration
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -194,9 +194,9 @@ CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
 CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
 CONFIG_SECCOMP_FILTER=y
 CONFIG_HAVE_CC_STACKPROTECTOR=y
-# CONFIG_CC_STACKPROTECTOR is not set
+CONFIG_CC_STACKPROTECTOR=y
 # CONFIG_CC_STACKPROTECTOR_NONE is not set
-CONFIG_CC_STACKPROTECTOR_REGULAR=y
+# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
 CONFIG_CC_STACKPROTECTOR_STRONG=y
 CONFIG_HAVE_CONTEXT_TRACKING=y
 CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
index 6a7309ab06a5173c720415feb9f004f2070392f2..8a4007bff7eec6119ab95311cfbb08eabccac1d4 100644 (file)
@@ -1,6 +1,6 @@
 #
 # Automatically generated file; DO NOT EDIT.
-# Linux/x86 3.14.57 Kernel Configuration
+# Linux/x86 3.14.61 Kernel Configuration
 #
 # CONFIG_64BIT is not set
 CONFIG_X86_32=y
@@ -245,9 +245,9 @@ CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
 CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
 CONFIG_SECCOMP_FILTER=y
 CONFIG_HAVE_CC_STACKPROTECTOR=y
-# CONFIG_CC_STACKPROTECTOR is not set
+CONFIG_CC_STACKPROTECTOR=y
 # CONFIG_CC_STACKPROTECTOR_NONE is not set
-CONFIG_CC_STACKPROTECTOR_REGULAR=y
+# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
 CONFIG_CC_STACKPROTECTOR_STRONG=y
 CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
 CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y
index d45c303e57c3da66463daf949e17266324adc04e..55f30240c0aab61afa74bbef5ec99d8277c8e085 100644 (file)
@@ -1,6 +1,6 @@
 #
 # Automatically generated file; DO NOT EDIT.
-# Linux/x86 3.14.57 Kernel Configuration
+# Linux/x86 3.14.61 Kernel Configuration
 #
 # CONFIG_64BIT is not set
 CONFIG_X86_32=y
@@ -244,9 +244,9 @@ CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
 CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
 CONFIG_SECCOMP_FILTER=y
 CONFIG_HAVE_CC_STACKPROTECTOR=y
-# CONFIG_CC_STACKPROTECTOR is not set
+CONFIG_CC_STACKPROTECTOR=y
 # CONFIG_CC_STACKPROTECTOR_NONE is not set
-CONFIG_CC_STACKPROTECTOR_REGULAR=y
+# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
 CONFIG_CC_STACKPROTECTOR_STRONG=y
 CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
 CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y
index 571dad12760dbc72240cd052a51f7af3cc1b52d1..5fa9bde4cca199ec28af37df17b52ea890c19035 100644 (file)
@@ -1,6 +1,6 @@
 #
 # Automatically generated file; DO NOT EDIT.
-# Linux/x86 3.14.57 Kernel Configuration
+# Linux/x86 3.14.61 Kernel Configuration
 #
 CONFIG_64BIT=y
 CONFIG_X86_64=y
@@ -251,9 +251,9 @@ CONFIG_ARCH_WANT_OLD_COMPAT_IPC=y
 CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
 CONFIG_SECCOMP_FILTER=y
 CONFIG_HAVE_CC_STACKPROTECTOR=y
-# CONFIG_CC_STACKPROTECTOR is not set
+CONFIG_CC_STACKPROTECTOR=y
 # CONFIG_CC_STACKPROTECTOR_NONE is not set
-CONFIG_CC_STACKPROTECTOR_REGULAR=y
+# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
 CONFIG_CC_STACKPROTECTOR_STRONG=y
 CONFIG_HAVE_CONTEXT_TRACKING=y
 CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
index ca8d5ee3b3d8e8bf7e5ceef19631b7af77ab4295..2304eca1b879cf4950394e3072e46f68c2976d8d 100644 (file)
@@ -8,6 +8,7 @@
 #usr/share/bison/bison.m4
 #usr/share/bison/c++-skel.m4
 #usr/share/bison/c++.m4
+#usr/share/bison/c-like.m4
 #usr/share/bison/c-skel.m4
 #usr/share/bison/c.m4
 #usr/share/bison/glr.c
 #usr/share/bison/m4sugar/foreach.m4
 #usr/share/bison/m4sugar/m4sugar.m4
 #usr/share/bison/stack.hh
+#usr/share/bison/variant.hh
 #usr/share/bison/xslt
 #usr/share/bison/xslt/bison.xsl
 #usr/share/bison/xslt/xml2dot.xsl
 #usr/share/bison/xslt/xml2text.xsl
 #usr/share/bison/xslt/xml2xhtml.xsl
 #usr/share/bison/yacc.c
+#usr/share/doc/bison-3.0.4
+#usr/share/doc/bison-3.0.4/AUTHORS
+#usr/share/doc/bison-3.0.4/COPYING
+#usr/share/doc/bison-3.0.4/NEWS
+#usr/share/doc/bison-3.0.4/README
+#usr/share/doc/bison-3.0.4/THANKS
+#usr/share/doc/bison-3.0.4/TODO
+#usr/share/doc/bison-3.0.4/examples
+#usr/share/doc/bison-3.0.4/examples/calc++
+#usr/share/doc/bison-3.0.4/examples/calc++/calc++-driver.cc
+#usr/share/doc/bison-3.0.4/examples/calc++/calc++-driver.hh
+#usr/share/doc/bison-3.0.4/examples/calc++/calc++-parser.yy
+#usr/share/doc/bison-3.0.4/examples/calc++/calc++-scanner.ll
+#usr/share/doc/bison-3.0.4/examples/calc++/calc++.cc
+#usr/share/doc/bison-3.0.4/examples/mfcalc
+#usr/share/doc/bison-3.0.4/examples/mfcalc/calc.h
+#usr/share/doc/bison-3.0.4/examples/mfcalc/mfcalc.y
+#usr/share/doc/bison-3.0.4/examples/rpcalc
+#usr/share/doc/bison-3.0.4/examples/rpcalc/rpcalc.y
 #usr/share/info/bison.info
 #usr/share/man/man1/bison.1
 #usr/share/man/man1/yacc.1
index 1b6ded3bab042a1f13f3542c476defc36f6aa569..c33003fe6b3617ee2b5a873b89a2c74084a9fa77 100644 (file)
@@ -14,7 +14,6 @@ etc/ssh/ssh_config
 etc/ssh/sshd_config
 usr/bin/scp
 usr/bin/sftp
-usr/bin/slogin
 usr/bin/ssh
 usr/bin/ssh-add
 usr/bin/ssh-agent
index b4053d9b71c40a42ad15ec9062d9c5e68720bee2..8b71758ffeeb57ba6e86484d92373f997e16a1db 100644 (file)
@@ -41,7 +41,7 @@ usr/bin/xzmore
 #usr/lib/liblzma.la
 usr/lib/liblzma.so
 usr/lib/liblzma.so.5
-usr/lib/liblzma.so.5.2.1
+usr/lib/liblzma.so.5.2.2
 #usr/lib/pkgconfig/liblzma.pc
 #usr/share/doc/xz
 #usr/share/doc/xz/AUTHORS
diff --git a/config/rootfiles/core/100/exclude b/config/rootfiles/core/100/exclude
new file mode 100644 (file)
index 0000000..8e446ce
--- /dev/null
@@ -0,0 +1,26 @@
+boot/config.txt
+etc/alternatives
+etc/collectd.custom
+etc/default/grub
+etc/ipsec.conf
+etc/ipsec.secrets
+etc/ipsec.user.conf
+etc/ipsec.user.secrets
+etc/localtime
+etc/shadow
+etc/snort/snort.conf
+etc/ssh/ssh_config
+etc/ssh/sshd_config
+etc/ssl/openssl.cnf
+etc/sudoers
+etc/sysconfig/firewall.local
+etc/sysconfig/rc.local
+etc/udev/rules.d/30-persistent-network.rules
+srv/web/ipfire/html/proxy.pac
+var/ipfire/dma
+var/ipfire/time
+var/ipfire/ovpn
+var/lib/alternatives
+var/log/cache
+var/state/dhcp/dhcpd.leases
+var/updatecache
diff --git a/config/rootfiles/core/100/filelists/armv5tel/glibc b/config/rootfiles/core/100/filelists/armv5tel/glibc
new file mode 120000 (symlink)
index 0000000..4c70d72
--- /dev/null
@@ -0,0 +1 @@
+../../../../common/armv5tel/glibc
\ No newline at end of file
diff --git a/config/rootfiles/core/100/filelists/armv5tel/linux-kirkwood b/config/rootfiles/core/100/filelists/armv5tel/linux-kirkwood
new file mode 120000 (symlink)
index 0000000..7217107
--- /dev/null
@@ -0,0 +1 @@
+../../../../common/armv5tel/linux-kirkwood
\ No newline at end of file
diff --git a/config/rootfiles/core/100/filelists/armv5tel/linux-multi b/config/rootfiles/core/100/filelists/armv5tel/linux-multi
new file mode 120000 (symlink)
index 0000000..204eb4c
--- /dev/null
@@ -0,0 +1 @@
+../../../../common/armv5tel/linux-multi
\ No newline at end of file
diff --git a/config/rootfiles/core/100/filelists/armv5tel/linux-rpi b/config/rootfiles/core/100/filelists/armv5tel/linux-rpi
new file mode 120000 (symlink)
index 0000000..a651a49
--- /dev/null
@@ -0,0 +1 @@
+../../../../common/armv5tel/linux-rpi
\ No newline at end of file
similarity index 91%
rename from config/rootfiles/core/98/filelists/files
rename to config/rootfiles/core/100/filelists/files
index 3e5063ade5fcc2eec23ab584aa9f51a158ae599e..b3cd418fa3a12682ce7baa14d70c03cfaca91fa2 100644 (file)
@@ -1,9 +1,12 @@
 etc/system-release
 etc/issue
+etc/dracut.conf
 etc/ppp/ip-up
 etc/rc.d/init.d/firewall
+etc/rc.d/init.d/functions
 etc/rc.d/init.d/networking/dhcpcd.exe
 etc/modprobe.d/nf_conntrack.conf
+lib/udev/rules.d/60-net.rules
 srv/web/ipfire/cgi-bin/logs.cgi/firewalllog.dat
 srv/web/ipfire/cgi-bin/logs.cgi/firewalllogcountry.dat
 srv/web/ipfire/cgi-bin/logs.cgi/firewalllogip.dat
diff --git a/config/rootfiles/core/100/filelists/i586/glibc b/config/rootfiles/core/100/filelists/i586/glibc
new file mode 120000 (symlink)
index 0000000..943021f
--- /dev/null
@@ -0,0 +1 @@
+../../../../common/i586/glibc
\ No newline at end of file
diff --git a/config/rootfiles/core/100/filelists/i586/linux b/config/rootfiles/core/100/filelists/i586/linux
new file mode 120000 (symlink)
index 0000000..693ec4b
--- /dev/null
@@ -0,0 +1 @@
+../../../../common/i586/linux
\ No newline at end of file
diff --git a/config/rootfiles/core/100/filelists/i586/linux-initrd b/config/rootfiles/core/100/filelists/i586/linux-initrd
new file mode 120000 (symlink)
index 0000000..32a03e6
--- /dev/null
@@ -0,0 +1 @@
+../../../../common/i586/linux-initrd
\ No newline at end of file
diff --git a/config/rootfiles/core/100/filelists/i586/openssl-sse2 b/config/rootfiles/core/100/filelists/i586/openssl-sse2
new file mode 120000 (symlink)
index 0000000..f424713
--- /dev/null
@@ -0,0 +1 @@
+../../../../common/i586/openssl-sse2
\ No newline at end of file
diff --git a/config/rootfiles/core/100/filelists/openssl b/config/rootfiles/core/100/filelists/openssl
new file mode 120000 (symlink)
index 0000000..e011a92
--- /dev/null
@@ -0,0 +1 @@
+../../../common/openssl
\ No newline at end of file
diff --git a/config/rootfiles/core/100/filelists/x86_64/glibc b/config/rootfiles/core/100/filelists/x86_64/glibc
new file mode 120000 (symlink)
index 0000000..1119099
--- /dev/null
@@ -0,0 +1 @@
+../../../../common/x86_64/glibc
\ No newline at end of file
diff --git a/config/rootfiles/core/100/filelists/x86_64/linux b/config/rootfiles/core/100/filelists/x86_64/linux
new file mode 120000 (symlink)
index 0000000..0615b5b
--- /dev/null
@@ -0,0 +1 @@
+../../../../common/x86_64/linux
\ No newline at end of file
diff --git a/config/rootfiles/core/100/filelists/x86_64/linux-initrd b/config/rootfiles/core/100/filelists/x86_64/linux-initrd
new file mode 120000 (symlink)
index 0000000..1b9fff7
--- /dev/null
@@ -0,0 +1 @@
+../../../../common/x86_64/linux-initrd
\ No newline at end of file
diff --git a/config/rootfiles/core/100/filelists/xz b/config/rootfiles/core/100/filelists/xz
new file mode 120000 (symlink)
index 0000000..734e926
--- /dev/null
@@ -0,0 +1 @@
+../../../common/xz
\ No newline at end of file
diff --git a/config/rootfiles/core/100/update.sh b/config/rootfiles/core/100/update.sh
new file mode 100644 (file)
index 0000000..a547431
--- /dev/null
@@ -0,0 +1,255 @@
+#!/bin/bash
+############################################################################
+#                                                                          #
+# This file is part of the IPFire Firewall.                                #
+#                                                                          #
+# IPFire is free software; you can redistribute it and/or modify           #
+# it under the terms of the GNU General Public License as published by     #
+# the Free Software Foundation; either version 3 of the License, or        #
+# (at your option) any later version.                                      #
+#                                                                          #
+# IPFire 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 General Public License for more details.                             #
+#                                                                          #
+# You should have received a copy of the GNU General Public License        #
+# along with IPFire; if not, write to the Free Software                    #
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA #
+#                                                                          #
+# Copyright (C) 2016 IPFire-Team <info@ipfire.org>.                        #
+#                                                                          #
+############################################################################
+#
+. /opt/pakfire/lib/functions.sh
+/usr/local/bin/backupctrl exclude >/dev/null 2>&1
+
+function find_device() {
+       local mountpoint="${1}"
+
+       local root
+       local dev mp fs flags rest
+       while read -r dev mp fs flags rest; do
+               # Skip unwanted entries
+               [ "${dev}" = "rootfs" ] && continue
+
+               if [ "${mp}" = "${mountpoint}" ] && [ -b "${dev}" ]; then
+                       root="$(basename "${dev}")"
+                       break
+               fi
+       done < /proc/mounts
+
+       # Get the actual device from the partition that holds /
+       while [ -n "${root}" ]; do
+               if [ -e "/sys/block/${root}" ]; then
+                       echo "${root}"
+                       return 0
+               fi
+
+               # Remove last character
+               root="${root::-1}"
+       done
+
+       return 1
+}
+
+
+core=100
+
+function exit_with_error() {
+       # Set last succesfull installed core.
+       echo $(($core-1)) > /opt/pakfire/db/core/mine
+       /usr/bin/logger -p syslog.emerg -t ipfire \
+               "core-update-${core}: $1"
+       exit $2
+}
+
+# Remove old core updates from pakfire cache to save space...
+for (( i=1; i<=$core; i++ ))
+do
+       rm -f /var/cache/pakfire/core-upgrade-*-$i.ipfire
+done
+
+#
+# Do some sanity checks.
+case $(uname -r) in
+       *-ipfire* )
+               # Ok.
+               ;;
+       * )
+               exit_with_error "ERROR cannot update. No IPFire Kernel." 1
+       ;;
+esac
+
+
+#
+#
+KVER="xxxKVERxxx"
+
+# Check diskspace on root
+ROOTSPACE=`df / -Pk | sed "s| * | |g" | cut -d" " -f4 | tail -n 1`
+
+if [ $ROOTSPACE -lt 100000 ]; then
+       exit_with_error "ERROR cannot update because not enough free space on root." 2
+       exit 2
+fi
+
+echo
+echo Update Kernel to $KVER ...
+#
+# Remove old kernel, configs, initrd, modules, dtb's ...
+#
+rm -rf /boot/System.map-*
+rm -rf /boot/config-*
+rm -rf /boot/ipfirerd-*
+rm -rf /boot/initramfs-*
+rm -rf /boot/vmlinuz-*
+rm -rf /boot/uImage-ipfire-*
+rm -rf /boot/uInit-ipfire-*
+rm -rf /boot/dtb-*-ipfire-*
+rm -rf /lib/modules
+
+case "$(uname -m)" in
+       armv*)
+               # Backup uEnv.txt if exist
+               if [ -e /boot/uEnv.txt ]; then
+                       cp -vf /boot/uEnv.txt /boot/uEnv.txt.org
+               fi
+
+               # work around the u-boot folder detection bug
+               mkdir -pv /boot/dtb-$KVER-ipfire-kirkwood
+               mkdir -pv /boot/dtb-$KVER-ipfire-multi
+#to do add touch for arm kernel and initrd here
+               ;;
+esac
+
+# Stop services
+/etc/init.d/snort stop
+/etc/init.d/squid stop
+/etc/init.d/dnsmasq stop
+/etc/init.d/ipsec stop
+/etc/init.d/ntp stop
+/etc/init.d/apache stop
+
+
+# Extract files
+tar xavf /opt/pakfire/tmp/files* --no-overwrite-dir -p --numeric-owner -C /
+
+
+
+# Check diskspace on boot
+BOOTSPACE=`df /boot -Pk | sed "s| * | |g" | cut -d" " -f4 | tail -n 1`
+
+if [ $BOOTSPACE -lt 1000 ]; then
+       case $(uname -r) in
+               *-ipfire-kirkwood )
+                       # Special handling for old kirkwood images.
+                       # (install only kirkwood kernel)
+                       rm -rf /boot/*
+                       # work around the u-boot folder detection bug
+                       mkdir -pv /boot/dtb-$KVER-ipfire-kirkwood
+                       tar xavf /opt/pakfire/tmp/files* --no-overwrite-dir -p \
+                               --numeric-owner -C / --wildcards 'boot/*-kirkwood*'
+                       ;;
+               * )
+                       /etc/init.d/apache start
+                       exit_with_error "FATAL-ERROR space run out on boot. System is not bootable..." 4
+                       ;;
+       esac
+fi
+
+# restart init because the glibc was updated.
+telinit u
+
+# Fix hardening flags in grub
+paxctl -mpexs /usr/bin/grub-script-check
+
+# Regenerate IPsec configuration
+sudo -u nobody /srv/web/ipfire/cgi-bin/vpnmain.cgi
+
+# Update Language cache
+/usr/local/bin/update-lang-cache
+
+#
+# Start services
+#
+/etc/init.d/apache start
+/etc/init.d/ntp start
+/etc/init.d/dnsmasq start
+/etc/init.d/sshd restart
+/etc/init.d/squid start
+/etc/init.d/snort start
+if [ `grep "ENABLED=on" /var/ipfire/vpn/settings` ]; then
+       /etc/init.d/ipsec start
+fi
+
+# Delete old QoS enabled indicator
+rm -f /var/ipfire/qos/enable
+
+# Upadate Kernel version uEnv.txt
+if [ -e /boot/uEnv.txt ]; then
+       sed -i -e "s/KVER=.*/KVER=${KVER}/g" /boot/uEnv.txt
+fi
+
+# call user update script (needed for some arm boards)
+if [ -e /boot/pakfire-kernel-update ]; then
+       /boot/pakfire-kernel-update ${KVER}
+fi
+
+case "$(uname -m)" in
+       i?86)
+               # Force (re)install pae kernel if pae is supported
+               rm -rf /opt/pakfire/db/installed/meta-linux-pae
+               if [ ! "$(grep "^flags.* pae " /proc/cpuinfo)" == "" ]; then
+                       ROOTSPACE=`df / -Pk | sed "s| * | |g" | cut -d" " -f4 | tail -n 1`
+                       BOOTSPACE=`df /boot -Pk | sed "s| * | |g" | cut -d" " -f4 | tail -n 1`
+                       if [ $BOOTSPACE -lt 12000 -o $ROOTSPACE -lt 90000 ]; then
+                               /usr/bin/logger -p syslog.emerg -t ipfire \
+                               "core-update-${core}: WARNING not enough space for pae kernel."
+                       else
+                               echo "Name: linux-pae" > /opt/pakfire/db/installed/meta-linux-pae
+                               echo "ProgVersion: 0" >> /opt/pakfire/db/installed/meta-linux-pae
+                               echo "Release: 0"     >> /opt/pakfire/db/installed/meta-linux-pae
+                       fi
+               fi
+               ;;
+esac
+#
+# After pakfire has ended run it again and update the lists and do upgrade
+#
+echo '#!/bin/bash'                                        >  /tmp/pak_update
+echo 'while [ "$(ps -A | grep " update.sh")" != "" ]; do' >> /tmp/pak_update
+echo '    sleep 1'                                        >> /tmp/pak_update
+echo 'done'                                               >> /tmp/pak_update
+echo 'while [ "$(ps -A | grep " pakfire")" != "" ]; do'   >> /tmp/pak_update
+echo '    sleep 1'                                        >> /tmp/pak_update
+echo 'done'                                               >> /tmp/pak_update
+echo '/opt/pakfire/pakfire update -y --force'             >> /tmp/pak_update
+echo '/opt/pakfire/pakfire upgrade -y'                    >> /tmp/pak_update
+echo '/opt/pakfire/pakfire upgrade -y'                    >> /tmp/pak_update
+echo '/opt/pakfire/pakfire upgrade -y'                    >> /tmp/pak_update
+echo '/usr/bin/logger -p syslog.emerg -t ipfire "Core-upgrade finished. If you use a customized grub/uboot config"' >> /tmp/pak_update
+echo '/usr/bin/logger -p syslog.emerg -t ipfire "Check it before reboot !!!"' >> /tmp/pak_update
+echo '/usr/bin/logger -p syslog.emerg -t ipfire " *** Please reboot... *** "' >> /tmp/pak_update
+echo 'touch /var/run/need_reboot ' >> /tmp/pak_update
+#
+killall -KILL pak_update
+chmod +x /tmp/pak_update
+/tmp/pak_update &
+
+sync
+
+# This update need a reboot...
+touch /var/run/need_reboot
+
+# Finish
+/etc/init.d/fireinfo start
+sendprofile
+# Update grub config to display new core version
+if [ -e /boot/grub/grub.cfg ]; then
+       grub-mkconfig -o /boot/grub/grub.cfg
+fi
+sync
+
+# Don't report the exitcode last command
+exit 0
diff --git a/config/rootfiles/core/99/filelists/files b/config/rootfiles/core/99/filelists/files
new file mode 100644 (file)
index 0000000..76b5b4e
--- /dev/null
@@ -0,0 +1,3 @@
+etc/system-release
+etc/issue
+var/ipfire/backup/include
diff --git a/config/rootfiles/core/99/filelists/i586/openssl-sse2 b/config/rootfiles/core/99/filelists/i586/openssl-sse2
new file mode 120000 (symlink)
index 0000000..f424713
--- /dev/null
@@ -0,0 +1 @@
+../../../../common/i586/openssl-sse2
\ No newline at end of file
diff --git a/config/rootfiles/core/99/filelists/openssh b/config/rootfiles/core/99/filelists/openssh
new file mode 120000 (symlink)
index 0000000..d8c77fd
--- /dev/null
@@ -0,0 +1 @@
+../../../common/openssh
\ No newline at end of file
diff --git a/config/rootfiles/core/99/filelists/openssl b/config/rootfiles/core/99/filelists/openssl
new file mode 120000 (symlink)
index 0000000..e011a92
--- /dev/null
@@ -0,0 +1 @@
+../../../common/openssl
\ No newline at end of file
diff --git a/config/rootfiles/core/99/meta b/config/rootfiles/core/99/meta
new file mode 100644 (file)
index 0000000..d547fa8
--- /dev/null
@@ -0,0 +1 @@
+DEPS=""
similarity index 86%
rename from config/rootfiles/core/98/update.sh
rename to config/rootfiles/core/99/update.sh
index 72c53732aecc232ce97f22d74b85ee410f1abe4d..b57d0a738f20f24e367ef884ba6b2ab25b7df5ed 100644 (file)
@@ -17,7 +17,7 @@
 # along with IPFire; if not, write to the Free Software                    #
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA #
 #                                                                          #
-# Copyright (C) 2015 IPFire-Team <info@ipfire.org>.                        #
+# Copyright (C) 2016 IPFire-Team <info@ipfire.org>.                        #
 #                                                                          #
 ############################################################################
 #
 /usr/local/bin/backupctrl exclude >/dev/null 2>&1
 
 # Remove old core updates from pakfire cache to save space...
-core=98
+core=99
 for (( i=1; i<=$core; i++ ))
 do
        rm -f /var/cache/pakfire/core-upgrade-*-$i.ipfire
 done
 
 # Stop services
-/etc/init.d/squid stop
-/etc/init.d/dnsmasq stop
+
+# remove slogin which is not included in new OpenSSH
+rm /usr/bin/slogin
 
 # Extract files
 extract_files
 
-# Fix hardening flags in grub
-paxctl -mpexs /usr/bin/grub-script-check
-
 # Update Language cache
 # /usr/local/bin/update-lang-cache
 
 # Start services
-/etc/init.d/dnsmasq start
 /etc/init.d/sshd restart
-/etc/init.d/squid start
-
-# Delete old QoS enabled indicator
-rm -f /var/ipfire/qos/enable
+/etc/init.d/apache restart
 
 # This update need a reboot...
-#touch /var/run/need_reboot
+touch /var/run/need_reboot
 
 # Finish
 /etc/init.d/fireinfo start
diff --git a/config/rootfiles/oldcore/98/exclude b/config/rootfiles/oldcore/98/exclude
new file mode 100644 (file)
index 0000000..d87f175
--- /dev/null
@@ -0,0 +1,25 @@
+boot/config.txt
+etc/alternatives
+etc/collectd.custom
+etc/ipsec.conf
+etc/ipsec.secrets
+etc/ipsec.user.conf
+etc/ipsec.user.secrets
+etc/localtime
+etc/shadow
+etc/snort/snort.conf
+etc/ssh/ssh_config
+etc/ssh/sshd_config
+etc/ssl/openssl.cnf
+etc/sudoers
+etc/sysconfig/firewall.local
+etc/sysconfig/rc.local
+etc/udev/rules.d/30-persistent-network.rules
+srv/web/ipfire/html/proxy.pac
+var/ipfire/dma
+var/ipfire/time
+var/ipfire/ovpn
+var/lib/alternatives
+var/log/cache
+var/state/dhcp/dhcpd.leases
+var/updatecache
diff --git a/config/rootfiles/oldcore/98/filelists/armv5tel/glibc b/config/rootfiles/oldcore/98/filelists/armv5tel/glibc
new file mode 120000 (symlink)
index 0000000..4c70d72
--- /dev/null
@@ -0,0 +1 @@
+../../../../common/armv5tel/glibc
\ No newline at end of file
diff --git a/config/rootfiles/oldcore/98/filelists/files b/config/rootfiles/oldcore/98/filelists/files
new file mode 100644 (file)
index 0000000..409e5fe
--- /dev/null
@@ -0,0 +1,2 @@
+etc/system-release
+etc/issue
diff --git a/config/rootfiles/oldcore/98/filelists/i586/glibc b/config/rootfiles/oldcore/98/filelists/i586/glibc
new file mode 120000 (symlink)
index 0000000..943021f
--- /dev/null
@@ -0,0 +1 @@
+../../../../common/i586/glibc
\ No newline at end of file
diff --git a/config/rootfiles/oldcore/98/filelists/x86_64/glibc b/config/rootfiles/oldcore/98/filelists/x86_64/glibc
new file mode 120000 (symlink)
index 0000000..1119099
--- /dev/null
@@ -0,0 +1 @@
+../../../../common/x86_64/glibc
\ No newline at end of file
diff --git a/config/rootfiles/oldcore/98/meta b/config/rootfiles/oldcore/98/meta
new file mode 100644 (file)
index 0000000..d547fa8
--- /dev/null
@@ -0,0 +1 @@
+DEPS=""
diff --git a/config/rootfiles/oldcore/98/update.sh b/config/rootfiles/oldcore/98/update.sh
new file mode 100644 (file)
index 0000000..7e0cc2d
--- /dev/null
@@ -0,0 +1,86 @@
+#!/bin/bash
+############################################################################
+#                                                                          #
+# This file is part of the IPFire Firewall.                                #
+#                                                                          #
+# IPFire is free software; you can redistribute it and/or modify           #
+# it under the terms of the GNU General Public License as published by     #
+# the Free Software Foundation; either version 3 of the License, or        #
+# (at your option) any later version.                                      #
+#                                                                          #
+# IPFire 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 General Public License for more details.                             #
+#                                                                          #
+# You should have received a copy of the GNU General Public License        #
+# along with IPFire; if not, write to the Free Software                    #
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA #
+#                                                                          #
+# Copyright (C) 2016 IPFire-Team <info@ipfire.org>.                        #
+#                                                                          #
+############################################################################
+#
+. /opt/pakfire/lib/functions.sh
+/usr/local/bin/backupctrl exclude >/dev/null 2>&1
+
+# Remove old core updates from pakfire cache to save space...
+core=98
+for (( i=1; i<=$core; i++ ))
+do
+       rm -f /var/cache/pakfire/core-upgrade-*-$i.ipfire
+done
+
+# Stop services
+
+# Extract files
+extract_files
+
+# Bugfixes for core96 updater bugs...
+if [ -e /boot/grub/grub.conf ]; then
+       # legacy grub config on xen or citrix conflicts with grub2 config
+       # and core96 contains an empty file
+       if [ ! -s /boot/grub/grub.cfg ]; then
+               rm /boot/grub/grub.cfg
+       fi
+fi
+
+if [ -e /boot/grub/grub.cfg ]; then
+       # test if serial console is enabled
+       grep "^7:2345" /etc/inittab > /dev/null
+       if [ "${?}" == "0" ]; then
+               # Fix grub config for serial console
+               sed -i /etc/default/grub \
+                       -e "s|\"panic=10\"|\"panic=10 console=ttyS0,115200n8\"|g"
+               sed -i /etc/default/grub \
+                       -e "s|^GRUB_TERMINAL=.*||g"
+               sed -i /etc/default/grub \
+                       -e "s|^GRUB_SERIAL_COMMAND=.*||g"
+               echo "GRUB_TERMINAL=\"serial\"" >> /etc/default/grub
+               echo "GRUB_SERIAL_COMMAND=\"serial --unit=0 --speed=115200\"" >> /etc/default/grub
+       fi
+fi
+
+
+# Update Language cache
+# /usr/local/bin/update-lang-cache
+
+# restart init after glibc update
+telinit u
+
+# Start services
+
+# This update need a reboot...
+touch /var/run/need_reboot
+
+# Finish
+/etc/init.d/fireinfo start
+sendprofile
+# Update grub config to display new core version
+if [ -e /boot/grub/grub.cfg ]; then
+       grub-mkconfig -o /boot/grub/grub.cfg
+fi
+sync
+
+# Don't report the exitcode last command
+exit 0
index dc39ff09b3c6440ef314cf0a8d11fb9460e3cc19..e82320cfe4ddb344cab26f2895ecb9ac0a276a2c 100644 (file)
@@ -4,4 +4,4 @@ ACTION=="add", SUBSYSTEM=="net", PROGRAM="/lib/udev/network-hotplug-rename", RES
 
 # Call a script that will create all virtual devices for a parent device
 # that has just come up.
-ACTION=="add", SUBSYSTEM=="net", PROGRAM="/lib/udev/network-hotplug-vlan"
+ACTION=="add", SUBSYSTEM=="net", RUN+="/lib/udev/network-hotplug-vlan"
index e2396459cff3e3a5a5f9ee11149bc2bd7a2e3c12..75867ff137e0f104584ae890181432089731292f 100644 (file)
@@ -35,7 +35,7 @@
 #
 URL_IPFIRE  = http://source.ipfire.org/source-2.x
 URL_TOOLCHAIN = http://source.ipfire.org/toolchains
-URL_SOURCE = source.ipfire.org:/pub/source/source-2.x
+URL_SOURCE = git.ipfire.org:/pub/source/source-2.x
 
 # Don't change this; it will be overridden by other makefiles where necessary.
 #
index bbaef2c8bb6421bd7d9e5c75687c6a75bbec6efb..39fa9b26bf783c44db92c3fd83ba4226d44984fe 100644 (file)
@@ -81,7 +81,7 @@ $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
 
        # remove replaced kernel modules
        rm -rf /lib/modules/$(KVER)-$(VERSUFIX)/kernel/drivers/net/wireless/rtl818x/rtl8180/rtl8180.ko
-       rm -rf /lib/modules/$(KVER)-$(VERSUFIX)/kernel/drivers/media/platform
+       rm -rf /lib/modules/$(KVER)-$(VERSUFIX)/kernel/drivers/media
 
        @rm -rf $(DIR_APP) && cd $(DIR_SRC) && tar Jxf $(DIR_DL)/$(DL_FILE)
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/backports-3.18.1-1-ipfire-build.patch
index 6b84f419eaec3ff215ba95539a3211ea4aec74c6..322dd26f05fcf133bf8406e1088214808c2ca817 100644 (file)
--- a/lfs/bison
+++ b/lfs/bison
 
 include Config
 
-VER        = 2.5.1
+VER        = 3.0.4
 
 THISAPP    = bison-$(VER)
-DL_FILE    = $(THISAPP).tar.gz
+DL_FILE    = $(THISAPP).tar.xz
 DL_FROM    = $(URL_IPFIRE)
 DIR_APP    = $(DIR_SRC)/$(THISAPP)
 TARGET     = $(DIR_INFO)/$(THISAPP)
@@ -40,7 +40,7 @@ objects =$(DL_FILE)
 
 $(DL_FILE) = $(DL_FROM)/$(DL_FILE)
 
-$(DL_FILE)_MD5 = 8fedf916f1aa2c4a31441d8f8bbc603c
+$(DL_FILE)_MD5 = c342201de104cc9ce0a21e0ad10d4021
 
 install : $(TARGET)
 
@@ -69,10 +69,8 @@ $(subst %,%_MD5,$(objects)) :
 
 $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
        @$(PREBUILD)
-       @rm -rf $(DIR_APP) && cd $(DIR_SRC) && tar zxf $(DIR_DL)/$(DL_FILE)
-       cd $(DIR_APP) && ./configure --prefix=/usr --disable-nls
-       # Disable NLS
-       #cd $(DIR_APP) && echo '#define YYENABLE_NLS 1' >> config.h
+       @rm -rf $(DIR_APP) && cd $(DIR_SRC) && tar axf $(DIR_DL)/$(DL_FILE)
+       cd $(DIR_APP) && ./configure --prefix=/usr --disable-nls --docdir=/usr/share/doc/$(THISAPP)
        cd $(DIR_APP) && make $(MAKETUNING)
        cd $(DIR_APP) && make $(EXTRA_INSTALL) install
        @rm -rf $(DIR_APP)
index 8058663acef3a315904eda108644a9b769c249e6..84585c1e02b3981dfc3e5a1ce143f59b255c4b10 100644 (file)
@@ -1,7 +1,7 @@
 ###############################################################################
 #                                                                             #
 # IPFire.org - A linux based firewall                                         #
-# Copyright (C) 2015  Michael Tremer & Christian Schmidt                      #
+# Copyright (C) 2016  Michael Tremer & Christian Schmidt                      #
 #                                                                             #
 # This program is free software: you can redistribute it and/or modify        #
 # it under the terms of the GNU General Public License as published by        #
@@ -24,7 +24,7 @@
 
 include Config
 
-VER        = 2.75
+VER        = 2.76test10
 
 THISAPP    = dnsmasq-$(VER)
 DL_FILE    = $(THISAPP).tar.xz
@@ -43,7 +43,7 @@ objects = $(DL_FILE)
 
 $(DL_FILE) = $(DL_FROM)/$(DL_FILE)
 
-$(DL_FILE)_MD5 = 887236f1ddde6eb57cdb9d01916c9f72
+$(DL_FILE)_MD5 = 4b51474ed6081b18c61407077f254cf7
 
 install : $(TARGET)
 
@@ -73,35 +73,11 @@ $(subst %,%_MD5,$(objects)) :
 $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
        @$(PREBUILD)
        @rm -rf $(DIR_APP) && cd $(DIR_SRC) && tar axf $(DIR_DL)/$(DL_FILE)
-       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/001-include_0_0_0_0_8_in_DNS_rebind_checks.patch
-       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/002-enhance_add_subnet_to_allow_arbitary_subnet_addresses.patch
-       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/003-dont_answer_non_auth_queries_for_auth_zones_locally_when_localise_queries_set.patch
-       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/004-fix_behaviour_of_empty_dhcp-option.patch
-       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/005-suggest_solution_to_ENOMEM_error_with_IPv6_multicast.patch
-       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/006-clarify_man_page_on_RDNSS_set_in_router_advertisement.patch
-       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/007-handle_signed_dangling_CNAME_replies_to_DS_queries.patch
-       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/008-DHCPv6_option_56_does_not_hold_an_address_list.patch
-       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/009-Respect_the_--no_resolv_flag_in_inotify_code.patch
-       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/010-Rationalise_5e3e464ac4022ee0b3794513abe510817e2cf3ca.patch
-       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/011-Catch_errors_from_sendmsg_in_DHCP_code.patch
-       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/012-Update_list_of_subnet_for_--bogus-priv.patch
-       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/013-Fix_crash_when_empty_address_from_DNS_overlays_A_record_from.patch
-       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/014-Handle_unknown_DS_hash_algos_correctly.patch
-       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/015-Fix_crash_at_start_up_with_conf-dir.patch
-       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/016-Major_rationalisation_of_DNSSEC_validation.patch
-       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/017-Abandon_caching_RRSIGs_and_returning_them_from_cache.patch
-       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/018-Move_code_which_caches_DS_records_to_a_more_logical_place.patch
-       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/019-Generalise_RR-filtering_code_for_use_with_EDNS0.patch
-       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/020-DNSSEC_validation_tweak.patch
-       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/021-Tweaks_to_EDNS0_handling_in_DNS_replies.patch
-       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/022-Tidy_up_DNSSEC_non-existence_code_Check_zone_status_is_NSEC_proof_bad.patch
-       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/023-Fix_brace_botch_in_dnssec_validate_ds.patch
-       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/024-Do_a_better_job_of_determining_which_DNSSEC_sig_algos_are_supported.patch
-       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/025-Major_tidy_up_of_EDNS0_handling_and_computation_use_of_udp.patch
-       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/026-More_tweaks_in_handling_unknown_DNSSEC_algorithms.patch
-       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/027-Nasty_rare_and_obscure_off-by-one_in_DNSSEC_hostname_cmp.patch
-       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/028-Minor_tweak_to_previous_commit.patch
-       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/029-NSEC3_check_RFC5155_para_8_2.patch
+       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/001-Add_TTL_parameter_to_--host-record_and_--cname.patch
+       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/002-Add_--dhcp-ttl_option.patch
+       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/003-Update_CHANGELOG.patch
+       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/004-Add_--tftp-mtu_option.patch
+       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/005-Apply_ceiling_of_lease_length_to_TTL_when_--dhcp-ttl_in_use.patch
        cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq-Add-support-to-read-ISC-DHCP-lease-file.patch
 
        cd $(DIR_APP) && sed -i src/config.h \
index 530bf339b80b95ae2e86bec54ed7a0d91cd212f7..d10fc9bbf93d13b201e2c980b2c15d88557545b5 100644 (file)
@@ -1,7 +1,7 @@
 ###############################################################################
 #                                                                             #
 # IPFire.org - A linux based firewall                                         #
-# Copyright (C) 2007-2014  IPFire Team  <info@ipfire.org>                     #
+# Copyright (C) 2007-2016  IPFire Team  <info@ipfire.org>                     #
 #                                                                             #
 # This program is free software: you can redistribute it and/or modify        #
 # it under the terms of the GNU General Public License as published by        #
@@ -121,9 +121,14 @@ ifeq "$(MACHINE_TYPE)" "arm"
        cp -v /boot/MLO $(MNThdd)/boot/
        cp -v /boot/u-boot.img $(MNThdd)/boot/
        cp -v /boot/zImage-ipfire-multi $(MNThdd)/boot/
+       cp -v /boot/uInit-ipfire-multi $(MNThdd)/boot/
+       cp -v /boot/uImage-ipfire-kirkwood $(MNThdd)/boot/
+       cp -v /boot/uInit-ipfire-kirkwood $(MNThdd)/boot/
+       cp -v /boot/uEnv.txt $(MNThdd)/boot/
        # work around a u-boot bug not find the folders sometimes
        mkdir -pv $(MNThdd)/boot/dtb-$(KVER)-ipfire-multi
        mkdir -pv $(MNThdd)/boot/dtb-$(KVER)-ipfire-kirkwood
+       
        sync
        umount $(MNThdd)/boot
        mount $(PART_BOOT) $(MNThdd)/boot
@@ -182,15 +187,19 @@ endif
        mkdir -pv $(MNThdd)/boot/grub
        chroot $(MNThdd) grub-mkconfig -o /boot/grub/grub.cfg
 
-       # Insert the UUID because grub-mkconfig fails to detect that correctly
+       # Insert the UUID because grub-mkconfig often fails to
+       # detect that correctly
        sed -i $(MNThdd)/boot/grub/grub.cfg \
-               -e "s/root=[a-z0-9\/]*/root=UUID=$$(blkid -o value -s UUID $(PART_ROOT))/g"
+               -e "s/root=[A-Za-z0-9\/=-]*/root=UUID=$$(blkid -o value -s UUID $(PART_ROOT))/g"
 
        # Install GRUB
        grub-install --force --recheck --no-floppy \
                --root-directory=$(MNThdd) $(DEVICE)
 endif
 
+       # Set ramdisk mode to automatic
+       echo RAMDISK_MODE=2 > $(MNThdd)/etc/sysconfig/ramdisk
+
        # Automatically resize the root partition to its maximum size at first boot
        touch $(MNThdd)/.partresize
 
index 56a35333914e9b2209660cca23ca02817652e91e..c0af6fc06cfd7c5b09121208ec21a4dbc7ea1aaf 100644 (file)
--- a/lfs/glibc
+++ b/lfs/glibc
@@ -1,7 +1,7 @@
 ###############################################################################
 #                                                                             #
 # IPFire.org - A linux based firewall                                         #
-# Copyright (C) 2007-2011  IPFire Team  <info@ipfire.org>                     #
+# Copyright (C) 2007-2016  IPFire Team  <info@ipfire.org>                     #
 #                                                                             #
 # This program is free software: you can redistribute it and/or modify        #
 # it under the terms of the GNU General Public License as published by        #
@@ -141,156 +141,222 @@ endif
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-getlogin-r.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-localedata.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-recvmmsg.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh580498.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh582738.patch
+
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh587360.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh582738.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh593396.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh593686.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh601686.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh607010.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh607461.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh615090.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh615701.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh621959.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh623187.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh625893.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh607010.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh630801.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh631011.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh641128.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh642584.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh643822.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh645672.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh580498.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh615090.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh623187.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh646954.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh647448.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh615701.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh652661.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh656014.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh656530.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh657572.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh656014.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh661982.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh667974.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh601686.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh676076.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh676591.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh667974.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh625893.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh681054.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh688720.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh688980.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh689471.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh692177.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh692838.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh694386.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh695595.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh695963.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh696472.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh697421.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh699724.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh700507.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh703480.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh703481.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh705465.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh711927.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh703481.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh694386.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh676591.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh711987.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh712248.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh695595.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh695963.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh713134.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh714823.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh718057.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh726517.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh730379.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh688980.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh712248.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh731042.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh730379.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh700507.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh699724.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh736346.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh737778.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh738665.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh738763.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh739184.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh711927.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh688720.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh726517.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh752122.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh739971.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh740506.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh740506-2.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh749188.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh750531.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh751750.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh752122.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh740506.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh757888.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh766513.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh767146.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh767693.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh767693-2.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh750531.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh749188.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh767746.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh767693.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh740506-2.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh696472.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh771342.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh657572.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh767693-2.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh782585.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh784402.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh697421.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh785984.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh767146.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh766513.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh789209.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh788959.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh788959-2.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh789189.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh789209.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh789238.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh789238-2.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh794817.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh794817-2.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh795498.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh797094-1.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh797094-2.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh804686.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh789238-2.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh795498.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh794817-2.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh804689.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh806404.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh809602.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh808337.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh788959-2.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh808545.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh809602.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh809726.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh833717.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh823909.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh826149.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh827362.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh830127.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh841787.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh809726.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh806404.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh832516.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh830127.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh832694.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh833717.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh837695.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh837918.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh841787.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh843673.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh846342.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh847932.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh848082.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh837918.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh849203.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh849651.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh827362.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh837695.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh804686.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh848082.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh846342.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh852445.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh861167.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh863453.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh864322.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh929388.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh970992.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh989558.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh989558-2.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh919562.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh886968.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh905575.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh905874.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh916986.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh928318.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh947882.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh952422.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh966775.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh834386.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh834386-2.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh862094.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh851470.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh868808.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh552960.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh663641.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh663641-2.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh848748.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh952422.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh663641-3.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh916986.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh970776.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh966778.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh863384.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh629823.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh629823-2.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh947882.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh905874.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh929302.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh928318.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh905575.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh988931.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh970090.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh995972.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1008310.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1019916.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1022022.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1027101.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1027261.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1043557.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1039988.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh995972.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh981942.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1032628.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1027101.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1025933.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh845218.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1044628.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1085273.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1074342.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1085289.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1082379.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1074353.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1019916.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1028285.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1099025.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1087833.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1027261.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh905941.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1054846.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1111460.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1133809-1.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1133809-2.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1139571.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1099025-2.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1133810-1.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1133810-2.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1138769.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1171296.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1172044.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1154563.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1170121.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1183533.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1207995.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1209375.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1125307.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1176907.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1183534.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1159167.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1023306.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1085312.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1091915.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh859965.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1124204.patch
+ifneq "$(MACHINE_TYPE)" "arm"
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh978098.patch
+endif
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1144019.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1053178.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1144132.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1116050.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1116050-1.patch
+ifneq "$(MACHINE_TYPE)" "arm"
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh867679.patch
+endif
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1088301.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1195453-avx512.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1066724.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1209376.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1207236.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1217186.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1256812.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1256812-2.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1256812-3.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1256812-4.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1256890.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1256891.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1291270.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1296031.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1296031-0.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1299319-0.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1299319-1.patch
 
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc-resolv-stack_chk_fail.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc-remove-ctors-dtors-output-sections.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc-test-installation.pl-nss_test1.patch
+
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc-test-installation.pl-libgcc_s.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc-2.12-accept-make-versions-4.0-and-greater.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-mq_open.patch
index ce4553eba04af78248c5f80a2fda481569287e02..b0c26358e5ffa43bc1a5bfbad1de9c03f52747aa 100644 (file)
--- a/lfs/linux
+++ b/lfs/linux
 
 include Config
 
-VER         = 3.14.60
-RPI_PATCHES = 3.14.60-grsec-ipfire1
-A7M_PATCHES = 3.14.60-grsec-ipfire1
-GRS_PATCHES = grsecurity-3.1ipfire-3.14.60-v1.patch.xz
+VER         = 3.14.63
+RPI_PATCHES = 3.14.63-grsec-ipfire1
+A7M_PATCHES = 3.14.63-grsec-ipfire1
+GRS_PATCHES = grsecurity-3.1ipfire-3.14.63-v1.patch.xz
 
 
 THISAPP    = linux-$(VER)
@@ -83,10 +83,10 @@ rpi-patches-$(RPI_PATCHES).patch.xz         = $(URL_IPFIRE)/rpi-patches-$(RPI_PATCHES).
 arm7-multi-patches-$(A7M_PATCHES).patch.xz     = $(URL_IPFIRE)/arm7-multi-patches-$(A7M_PATCHES).patch.xz
 $(GRS_PATCHES)                                 = $(URL_IPFIRE)/$(GRS_PATCHES)
 
-$(DL_FILE)_MD5                                 = 25d623a8a884d055313e16aec59fdd7a
-rpi-patches-$(RPI_PATCHES).patch.xz_MD5                = ed11c924a484646018be8671935407d0
-arm7-multi-patches-$(A7M_PATCHES).patch.xz_MD5 = eafe3ef25946d9d5169dd5af4d280ba5
-$(GRS_PATCHES)_MD5                             = 1b6941fd7cea95acce6575917ed08a31
+$(DL_FILE)_MD5                                 = 6cf8a6b23849f47f511e0e46cfdb6392
+rpi-patches-$(RPI_PATCHES).patch.xz_MD5                = 0d1059c18f4810abbe9aafb6beab445b
+arm7-multi-patches-$(A7M_PATCHES).patch.xz_MD5 = 589eb8703fa2ba2944b2f925b7f7ffb3
+$(GRS_PATCHES)_MD5                             = e84b05c9083fa0eb6bb49facd4f841dc
 
 install : $(TARGET)
 
diff --git a/lfs/m4 b/lfs/m4
index 462022195999eb83e21ca4ff961b588a751eaf61..932cb6d519e7f46e0ac7d7013fa7fd0bc3cd066d 100644 (file)
--- a/lfs/m4
+++ b/lfs/m4
 
 include Config
 
-VER        = 1.4.16
+VER        = 1.4.17
 
 THISAPP    = m4-$(VER)
-DL_FILE    = $(THISAPP).tar.bz2
+DL_FILE    = $(THISAPP).tar.xz
 DL_FROM    = $(URL_IPFIRE)
 DIR_APP    = $(DIR_SRC)/$(THISAPP)
 
@@ -37,12 +37,10 @@ ifeq "$(ROOT)" ""
   TARGET = $(DIR_INFO)/$(THISAPP)
   EXTRA_CONFIG = --prefix=/usr --disable-nls
   EXTRA_MAKE =
-  EXTRA_INSTALL =
 else
   TARGET = $(DIR_INFO)/$(THISAPP)-tools
   EXTRA_CONFIG = --prefix=/tools --disable-nls
   EXTRA_MAKE = 
-  EXTRA_INSTALL = 
 endif
 
 ###############################################################################
@@ -53,7 +51,7 @@ objects = $(DL_FILE)
 
 $(DL_FILE) = $(DL_FROM)/$(DL_FILE)
 
-$(DL_FILE)_MD5 = 8a7cef47fecab6272eb86a6be6363b2f
+$(DL_FILE)_MD5 = 12a3c829301a4fd6586a57d3fcf196dc
 
 install : $(TARGET)
 
@@ -82,9 +80,9 @@ $(subst %,%_MD5,$(objects)) :
 
 $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
        @$(PREBUILD)
-       @rm -rf $(DIR_APP) && cd $(DIR_SRC) && tar jxf $(DIR_DL)/$(DL_FILE)
+       @rm -rf $(DIR_APP) && cd $(DIR_SRC) && tar axf $(DIR_DL)/$(DL_FILE)
        cd $(DIR_APP) && ./configure $(EXTRA_CONFIG)
        cd $(DIR_APP) && make $(MAKETUNING) $(EXTRA_MAKE)
-       cd $(DIR_APP) && make $(EXTRA_INSTALL) install
+       cd $(DIR_APP) && make install
        @rm -rf $(DIR_APP)
        @$(POSTBUILD)
index 546bc7ed8223b83a67effcfed3102ccd069625d9..ab25d6233acbdbc28d6884d1fc5f60c8339053db 100644 (file)
@@ -1,7 +1,7 @@
 ###############################################################################
 #                                                                             #
 # IPFire.org - A linux based firewall                                         #
-# Copyright (C) 2007-2015  IPFire Team  <info@ipfire.org>                     #
+# Copyright (C) 2007-2016  IPFire Team  <info@ipfire.org>                     #
 #                                                                             #
 # This program is free software: you can redistribute it and/or modify        #
 # it under the terms of the GNU General Public License as published by        #
@@ -24,7 +24,7 @@
 
 include Config
 
-VER        = 7.1p2
+VER        = 7.2p1
 
 THISAPP    = openssh-$(VER)
 DL_FILE    = $(THISAPP).tar.gz
@@ -40,7 +40,7 @@ objects = $(DL_FILE)
 
 $(DL_FILE) = $(DL_FROM)/$(DL_FILE)
 
-$(DL_FILE)_MD5 = 4d8547670e2a220d5ef805ad9e47acf2
+$(DL_FILE)_MD5 = b984775f0cfff1f7ff18b8797fce8a28
 
 install : $(TARGET)
 
index c5b71f79769eca934259c1c4bbbf07b6db9dc1c2..eb7352f8cb222fd8672156d68be8ed6bd05eb2a9 100644 (file)
@@ -24,7 +24,7 @@
 
 include Config
 
-VER        = 1.0.2f
+VER        = 1.0.2g
 
 THISAPP    = openssl-$(VER)
 DL_FILE    = $(THISAPP).tar.gz
@@ -53,6 +53,7 @@ CONFIGURE_OPTIONS = \
        zlib-dynamic \
        enable-camellia \
        enable-md2 \
+       enable-ssl2 \
        enable-seed \
        enable-tlsext \
        enable-rfc3779 \
@@ -86,7 +87,7 @@ objects = $(DL_FILE)
 
 $(DL_FILE) = $(DL_FROM)/$(DL_FILE)
 
-$(DL_FILE)_MD5 = b3bf73f507172be9292ea2a8c28b659d
+$(DL_FILE)_MD5 = f3c710c045cdee5fd114feb69feba7aa
 
 install : $(TARGET)
 
@@ -119,7 +120,7 @@ $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/openssl-1.0.0-beta5-enginesdir.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/openssl-1.0.2a-rpmbuild.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/openssl-1.0.1m-weak-ciphers.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/openssl-disable-sslv2-sslv3.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/openssl-1.0.2g-disable-sslv2v3.patch
 
        # i586 specific patches
 ifeq "$(MACHINE)" "i586"
index c2b39357903f10fa03efed70b914950eac444572..997c660bb01af888cbe1f19d1b223c21cc893533 100644 (file)
--- a/lfs/squid
+++ b/lfs/squid
@@ -72,6 +72,7 @@ $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
        @rm -rf $(DIR_APP) && cd $(DIR_SRC) && tar xaf $(DIR_DL)/$(DL_FILE)
        cd $(DIR_APP) && patch -Np0 -i $(DIR_SRC)/src/patches/squid-3.4-13228.patch
        cd $(DIR_APP) && patch -Np0 -i $(DIR_SRC)/src/patches/squid-3.4.14-fix-max-file-descriptors.patch
+       cd $(DIR_APP) && patch -Np0 -i $(DIR_SRC)/src/patches/squid-3.4-13230.patch
        cd $(DIR_APP) && autoreconf -vfi
        cd $(DIR_APP)/libltdl && autoreconf -vfi
 
index f6f27e07592c0eb99e6dae5dd139ba898a2bedea..4585151a86dee01a0e0b5eccf223a32972720fad 100644 (file)
@@ -32,7 +32,7 @@ DL_FROM    = $(URL_IPFIRE)
 DIR_APP    = $(DIR_SRC)/$(THISAPP)
 TARGET     = $(DIR_INFO)/$(THISAPP)
 PROG       = stunnel
-PAK_VER    = 1
+PAK_VER    = 2
 
 DEPS       = ""
 
diff --git a/lfs/xz b/lfs/xz
index c1d3ef789082f374950b9dbf84e777cc07f29ec8..c09cb34486f3d0fd38c7d1b22d3c027fcd582d74 100644 (file)
--- a/lfs/xz
+++ b/lfs/xz
@@ -24,7 +24,7 @@
 
 include Config
 
-VER        = 5.2.1
+VER        = 5.2.2
 
 THISAPP    = xz-$(VER)
 DL_FILE    = $(THISAPP).tar.xz
@@ -47,7 +47,7 @@ objects = $(DL_FILE)
 
 $(DL_FILE) = $(DL_FROM)/$(DL_FILE)
 
-$(DL_FILE)_MD5 = b5e2dd95dc8498cea5354377ed89aa65
+$(DL_FILE)_MD5 = e26772b69940085c0632589ab1d52e64
 
 install : $(TARGET)
 
@@ -77,6 +77,7 @@ $(subst %,%_MD5,$(objects)) :
 $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
        @$(PREBUILD)
        @rm -rf $(DIR_APP) && cd $(DIR_SRC) && tar axf $(DIR_DL)/$(DL_FILE)
+       cd $(DIR_APP) && sed -e '/mf\.buffer = NULL/a next->coder->mf.size = 0;' -i src/liblzma/lz/lz_encoder.c
        cd $(DIR_APP) && ./configure --prefix=$(PREFIX)
        cd $(DIR_APP) && make $(MAKETUNING)
        cd $(DIR_APP) && make install
diff --git a/make.sh b/make.sh
index 3a2c8d311875568bb9c7a3f4a7bbcf094f1d12f3..a612afca2227b0a9485761f731bdfc7e668dd7e0 100755 (executable)
--- a/make.sh
+++ b/make.sh
@@ -25,8 +25,8 @@
 NAME="IPFire"                                                  # Software name
 SNAME="ipfire"                                                 # Short name
 VERSION="2.17"                                                 # Version number
-CORE="98"                                                      # Core Level (Filename)
-PAKFIRE_CORE="97"                                              # Core Level (PAKFIRE)
+CORE="100"                                                     # Core Level (Filename)
+PAKFIRE_CORE="99"                                              # Core Level (PAKFIRE)
 GIT_BRANCH=`git rev-parse --abbrev-ref HEAD`                   # Git Branch
 SLOGAN="www.ipfire.org"                                                # Software slogan
 CONFIG_ROOT=/var/ipfire                                                # Configuration rootdir
index 0d9b013ea0522a239394cbfb9dc0d3124cc65b00..c00f65922c97450e74aae3cc3f0c28f9c36f2251 100644 (file)
@@ -728,7 +728,7 @@ use_ramdisk() {
                2)
                        local mem_avail="$(mem_amount)"
 
-                       if [ ${mem_avail} -ge 490 ]; then
+                       if [ ${mem_avail} -ge 400 ]; then
                                return 0
                        else
                                return 1
index 530d69e2a172149077f913cdaccd90afe687a67f..fb0d39b8023293e6dabb9af24424f135f9156bfd 100644 (file)
@@ -9,3 +9,15 @@
  
  static struct clk_ops dpll1_ck_ops_34xx __initdata = {
        .init           = &omap2_init_clk_clkdm,
+diff -Naur linux-3.14.63-org/net/ipv6/addrconf.c linux-3.14.63/net/ipv6/addrconf.c
+--- linux-3.14.63-org/net/ipv6/addrconf.c      2016-03-04 22:56:07.375481749 +0100
++++ linux-3.14.63/net/ipv6/addrconf.c  2016-03-04 23:08:34.285482105 +0100
+@@ -4818,7 +4818,7 @@
+ {
+       struct inet6_dev *idev = ctl->extra1;
+       int min_mtu = IPV6_MIN_MTU;
+-      struct ctl_table lctl;
++      ctl_table_no_const lctl;
+       lctl = *ctl;
+       lctl.extra1 = &min_mtu;
index f55ebe81e1485ba0cce65047705f1cc0dfd2a6f7..703e94f59283b489d11d9a0752e45e1f85d7b1e7 100644 (file)
@@ -19,7 +19,7 @@
  #ifdef HAVE_DNSSEC
    cache_blockdata_free(crecp);
  #endif
-@@ -1131,7 +1134,7 @@
+@@ -1138,7 +1141,7 @@
    
  } 
  
@@ -28,7 +28,7 @@
  struct in_addr a_record_from_hosts(char *name, time_t now)
  {
    struct crec *crecp = NULL;
-@@ -1274,7 +1277,11 @@
+@@ -1281,7 +1284,11 @@
        else
        crec->ttd = ttd;
        crec->addr.addr = *host_address;
@@ -42,7 +42,7 @@
  
 --- a/src/dnsmasq.c    Thu Jul 30 20:59:06 2015
 +++ b/src/dnsmasq.c    Wed Dec 16 19:38:32 2015
-@@ -982,6 +982,11 @@
+@@ -1013,6 +1013,11 @@
  
          poll_resolv(0, daemon->last_resolv != 0, now);          
          daemon->last_resolv = now;
@@ -56,7 +56,7 @@
  
 --- a/src/dnsmasq.h    Wed Dec 16 19:24:12 2015
 +++ b/src/dnsmasq.h    Wed Dec 16 19:40:11 2015
-@@ -1513,8 +1513,12 @@
+@@ -1514,6 +1514,11 @@
  void poll_listen(int fd, short event);
  int do_poll(int timeout);
  
 +#endif
 --- a/src/option.c     Wed Dec 16 19:24:12 2015
 +++ b/src/option.c     Wed Dec 16 19:42:48 2015
-@@ -1754,7 +1754,7 @@
+@@ -1769,7 +1769,7 @@
        ret_err(_("bad MX target"));
        break;
  
         helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
         dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \
         domain.o dnssec.o blockdata.o tables.o loop.o inotify.o \
--       poll.o rrfilter.o
-+       poll.o rrfilter.o isc.o
+-       poll.o rrfilter.o edns0.o arp.o
++       poll.o rrfilter.o edns0.o arp.o isc.o
  
  hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
         dns-protocol.h radv-protocol.h ip6addr.h
diff --git a/src/patches/dnsmasq/001-Add_TTL_parameter_to_--host-record_and_--cname.patch b/src/patches/dnsmasq/001-Add_TTL_parameter_to_--host-record_and_--cname.patch
new file mode 100644 (file)
index 0000000..86fbc9c
--- /dev/null
@@ -0,0 +1,265 @@
+From df3d54f776a3c9b60735b45c0b7fd88b66a2d5c4 Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon@thekelleys.org.uk>
+Date: Wed, 24 Feb 2016 21:03:38 +0000
+Subject: [PATCH] Add TTL parameter to --host-record and --cname.
+
+---
+ man/dnsmasq.8 |   12 ++++++++++--
+ src/cache.c   |    7 +++++++
+ src/dnsmasq.h |    2 ++
+ src/option.c  |   46 ++++++++++++++++++++++++++++++++++++++--------
+ src/rfc1035.c |    6 +++++-
+ 5 files changed, 62 insertions(+), 11 deletions(-)
+
+diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
+index b782eaf..7bc1394 100644
+--- a/man/dnsmasq.8
++++ b/man/dnsmasq.8
+@@ -529,7 +529,7 @@ zone files: the port, weight and priority numbers are in a different
+ order. More than one SRV record for a given service/domain is allowed,
+ all that match are returned.
+ .TP
+-.B --host-record=<name>[,<name>....],[<IPv4-address>],[<IPv6-address>]
++.B --host-record=<name>[,<name>....],[<IPv4-address>],[<IPv6-address>][,<TTL>]
+ Add A, AAAA and PTR records to the DNS. This adds one or more names to
+ the DNS with associated IPv4 (A) and IPv6 (AAAA) records. A name may
+ appear in more than one 
+@@ -546,6 +546,10 @@ is in effect. Short and long names may appear in the same
+ .B host-record,
+ eg. 
+ .B --host-record=laptop,laptop.thekelleys.org,192.168.0.1,1234::100
++
++If the time-to-live is given, it overrides the default, which is zero
++or the value of --local-ttl. The value is a positive integer and gives 
++the time-to-live in seconds.
+ .TP
+ .B \-Y, --txt-record=<name>[[,<text>],<text>]
+ Return a TXT DNS record. The value of TXT record is a set of strings,
+@@ -559,7 +563,7 @@ Return a PTR DNS record.
+ .B --naptr-record=<name>,<order>,<preference>,<flags>,<service>,<regexp>[,<replacement>]
+ Return an NAPTR DNS record, as specified in RFC3403.
+ .TP
+-.B --cname=<cname>,<target>
++.B --cname=<cname>,<target>[,<TTL>]
+ Return a CNAME record which indicates that <cname> is really
+ <target>. There are significant limitations on the target; it must be a
+ DNS name which is known to dnsmasq from /etc/hosts (or additional
+@@ -568,6 +572,10 @@ hosts files), from DHCP, from --interface-name or from another
+ If the target does not satisfy this
+ criteria, the whole cname is ignored. The cname must be unique, but it
+ is permissable to have more than one cname pointing to the same target.
++
++If the time-to-live is given, it overrides the default, which is zero
++or the value of -local-ttl. The value is a positive integer and gives 
++the time-to-live in seconds.
+ .TP
+ .B --dns-rr=<name>,<RR-number>,[<hex data>]
+ Return an arbitrary DNS Resource Record. The number is the type of the
+diff --git a/src/cache.c b/src/cache.c
+index a9eaa65..4ecd535 100644
+--- a/src/cache.c
++++ b/src/cache.c
+@@ -778,6 +778,7 @@ static void add_hosts_cname(struct crec *target)
+       (crec = whine_malloc(sizeof(struct crec))))
+       {
+       crec->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_CONFIG | F_CNAME;
++      crec->ttd = a->ttl;
+       crec->name.namep = a->alias;
+       crec->addr.cname.target.cache = target;
+       crec->addr.cname.uid = target->uid;
+@@ -981,6 +982,7 @@ int read_hostsfile(char *filename, unsigned int index, int cache_size, struct cr
+                 strcat(cache->name.sname, ".");
+                 strcat(cache->name.sname, domain_suffix);
+                 cache->flags = flags;
++                cache->ttd = daemon->local_ttl;
+                 add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
+                 name_count++;
+               }
+@@ -988,6 +990,7 @@ int read_hostsfile(char *filename, unsigned int index, int cache_size, struct cr
+               {
+                 strcpy(cache->name.sname, canon);
+                 cache->flags = flags;
++                cache->ttd = daemon->local_ttl;
+                 add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
+                 name_count++;
+               }
+@@ -1057,6 +1060,7 @@ void cache_reload(void)
+         ((cache = whine_malloc(sizeof(struct crec)))))
+       {
+         cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG;
++        cache->ttd = a->ttl;
+         cache->name.namep = a->alias;
+         cache->addr.cname.target.int_name = intr;
+         cache->addr.cname.uid = SRC_INTERFACE;
+@@ -1071,6 +1075,7 @@ void cache_reload(void)
+       (cache->addr.ds.keydata = blockdata_alloc(ds->digest, ds->digestlen)))
+       {
+       cache->flags = F_FORWARD | F_IMMORTAL | F_DS | F_CONFIG | F_NAMEP;
++      cache->ttd = daemon->local_ttl;
+       cache->name.namep = ds->name;
+       cache->addr.ds.keylen = ds->digestlen;
+       cache->addr.ds.algo = ds->algo;
+@@ -1095,6 +1100,7 @@ void cache_reload(void)
+           (cache = whine_malloc(sizeof(struct crec))))
+         {
+           cache->name.namep = nl->name;
++          cache->ttd = hr->ttl;
+           cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4 | F_NAMEP | F_CONFIG;
+           add_hosts_entry(cache, (struct all_addr *)&hr->addr, INADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
+         }
+@@ -1103,6 +1109,7 @@ void cache_reload(void)
+           (cache = whine_malloc(sizeof(struct crec))))
+         {
+           cache->name.namep = nl->name;
++          cache->ttd = hr->ttl;
+           cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6 | F_NAMEP | F_CONFIG;
+           add_hosts_entry(cache, (struct all_addr *)&hr->addr6, IN6ADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
+         }
+diff --git a/src/dnsmasq.h b/src/dnsmasq.h
+index 6d1c5ae..6344df5 100644
+--- a/src/dnsmasq.h
++++ b/src/dnsmasq.h
+@@ -308,6 +308,7 @@ struct ptr_record {
+ };
+ struct cname {
++  int ttl;
+   char *alias, *target;
+   struct cname *next;
+ }; 
+@@ -344,6 +345,7 @@ struct auth_zone {
+ struct host_record {
++  int ttl;
+   struct name_list {
+     char *name;
+     struct name_list *next;
+diff --git a/src/option.c b/src/option.c
+index c98bdc9..7c5e6bc 100644
+--- a/src/option.c
++++ b/src/option.c
+@@ -448,20 +448,20 @@ static struct {
+   { LOPT_GEN_NAMES, ARG_DUP, "[=tag:<tag>]", gettext_noop("Generate hostnames based on MAC address for nameless clients."), NULL},
+   { LOPT_PROXY, ARG_DUP, "[=<ipaddr>]...", gettext_noop("Use these DHCP relays as full proxies."), NULL },
+   { LOPT_RELAY, ARG_DUP, "<local-addr>,<server>[,<interface>]", gettext_noop("Relay DHCP requests to a remote server"), NULL},
+-  { LOPT_CNAME, ARG_DUP, "<alias>,<target>", gettext_noop("Specify alias name for LOCAL DNS name."), NULL },
++  { LOPT_CNAME, ARG_DUP, "<alias>,<target>[,<ttl>]", gettext_noop("Specify alias name for LOCAL DNS name."), NULL },
+   { LOPT_PXE_PROMT, ARG_DUP, "<prompt>,[<timeout>]", gettext_noop("Prompt to send to PXE clients."), NULL },
+   { LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL },
+   { LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL },
+   { LOPT_ADD_MAC, ARG_DUP, "[=base64|text]", gettext_noop("Add requestor's MAC address to forwarded DNS queries."), NULL },
+   { LOPT_ADD_SBNET, ARG_ONE, "<v4 pref>[,<v6 pref>]", gettext_noop("Add specified IP subnet to forwarded DNS queries."), NULL },
+-   { LOPT_CPE_ID, ARG_ONE, "<text>", gettext_noop("Add client identification to forwarded DNS queries."), NULL },
++  { LOPT_CPE_ID, ARG_ONE, "<text>", gettext_noop("Add client identification to forwarded DNS queries."), NULL },
+   { LOPT_DNSSEC, OPT_DNSSEC_PROXY, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers."), NULL },
+   { LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to allocate sequential IP addresses to DHCP clients."), NULL },
+   { LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy connection-track mark from queries to upstream connections."), NULL },
+   { LOPT_FQDN, OPT_FQDN_UPDATE, NULL, gettext_noop("Allow DHCP clients to do their own DDNS updates."), NULL },
+   { LOPT_RA, OPT_RA, NULL, gettext_noop("Send router-advertisements for interfaces doing DHCPv6"), NULL },
+   { LOPT_DUID, ARG_ONE, "<enterprise>,<duid>", gettext_noop("Specify DUID_EN-type DHCPv6 server DUID"), NULL },
+-  { LOPT_HOST_REC, ARG_DUP, "<name>,<address>", gettext_noop("Specify host (A/AAAA and PTR) records"), NULL },
++  { LOPT_HOST_REC, ARG_DUP, "<name>,<address>[,<ttl>]", gettext_noop("Specify host (A/AAAA and PTR) records"), NULL },
+   { LOPT_RR, ARG_DUP, "<name>,<RR-number>,[<data>]", gettext_noop("Specify arbitrary DNS resource record"), NULL },
+   { LOPT_CLVERBIND, OPT_CLEVERBIND, NULL, gettext_noop("Bind to interfaces in use - check for new interfaces"), NULL },
+   { LOPT_AUTHSERV, ARG_ONE, "<NS>,<interface>", gettext_noop("Export local names to global DNS"), NULL },
+@@ -3692,12 +3692,15 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
+     case LOPT_CNAME: /* --cname */
+       {
+       struct cname *new;
+-      char *alias;
+-      char *target;
++      char *alias, *target, *ttls;
++      int ttl = -1;
+       if (!(comma = split(arg)))
+         ret_err(gen_err);
+       
++      if ((ttls = split(comma)) && !atoi_check(ttls, &ttl))
++        ret_err(_("bad TTL"));
++      
+       alias = canonicalise_opt(arg);
+       target = canonicalise_opt(comma);
+           
+@@ -3713,6 +3716,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
+           daemon->cnames = new;
+           new->alias = alias;
+           new->target = target;
++          new->ttl = ttl;
+         }
+       
+       break;
+@@ -3913,14 +3917,22 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
+       {
+       struct host_record *new = opt_malloc(sizeof(struct host_record));
+       memset(new, 0, sizeof(struct host_record));
+-      
++      new->ttl = -1;
++
+       if (!arg || !(comma = split(arg)))
+         ret_err(_("Bad host-record"));
+       
+       while (arg)
+         {
+           struct all_addr addr;
+-          if (inet_pton(AF_INET, arg, &addr))
++          char *dig;
++
++          for (dig = arg; *dig != 0; dig++)
++            if (*dig < '0' || *dig > '9')
++              break;
++          if (*dig == 0)
++            new->ttl = atoi(arg);
++          else if (inet_pton(AF_INET, arg, &addr))
+             new->addr = addr.addr.addr4;
+ #ifdef HAVE_IPV6
+           else if (inet_pton(AF_INET6, arg, &addr))
+@@ -4601,7 +4613,25 @@ void read_opts(int argc, char **argv, char *compile_opts)
+           }
+       } 
+     }
+-  
++
++  if (daemon->host_records)
++    {
++      struct host_record *hr;
++      
++      for (hr = daemon->host_records; hr; hr = hr->next)
++      if (hr->ttl == -1)
++        hr->ttl = daemon->local_ttl;
++    }
++
++  if (daemon->cnames)
++    {
++      struct cname *cn;
++      
++      for (cn = daemon->cnames; cn; cn = cn->next)
++      if (cn->ttl == -1)
++        cn->ttl = daemon->local_ttl;
++    }
++
+   if (daemon->if_addrs)
+     {  
+       struct iname *tmp;
+diff --git a/src/rfc1035.c b/src/rfc1035.c
+index 9c0ddb5..3535a71 100644
+--- a/src/rfc1035.c
++++ b/src/rfc1035.c
+@@ -1169,9 +1169,13 @@ static unsigned long crec_ttl(struct crec *crecp, time_t now)
+   /* Return 0 ttl for DHCP entries, which might change
+      before the lease expires. */
+-  if  (crecp->flags & (F_IMMORTAL | F_DHCP))
++  if (crecp->flags & F_DHCP)
+     return daemon->local_ttl;
+   
++  /* Immortal entries other than DHCP are local, and hold TTL in TTD field. */
++  if (crecp->flags & F_IMMORTAL)
++    return crecp->ttd;
++
+   /* Return the Max TTL value if it is lower then the actual TTL */
+   if (daemon->max_ttl == 0 || ((unsigned)(crecp->ttd - now) < daemon->max_ttl))
+     return crecp->ttd - now;
+-- 
+1.7.10.4
+
diff --git a/src/patches/dnsmasq/001-include_0_0_0_0_8_in_DNS_rebind_checks.patch b/src/patches/dnsmasq/001-include_0_0_0_0_8_in_DNS_rebind_checks.patch
deleted file mode 100644 (file)
index 8a2557a..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-From d2aa7dfbb6d1088dcbea9fecc61b9293b320eb95 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Mon, 3 Aug 2015 21:52:12 +0100
-Subject: [PATCH] Include 0.0.0.0/8 in DNS rebind checks.
-
----
- CHANGELOG     |    7 +++++++
- src/rfc1035.c |    3 ++-
- 2 files changed, 9 insertions(+), 1 deletion(-)
-
-diff --git a/CHANGELOG b/CHANGELOG
-index 901da47..3f4026d 100644
---- a/CHANGELOG
-+++ b/CHANGELOG
-@@ -1,3 +1,10 @@
-+version 2.76
-+            Include 0.0.0.0/8 in DNS rebind checks. This range 
-+          translates to hosts on  the local network, or, at 
-+          least, 0.0.0.0 accesses the local host, so could
-+          be targets for DNS rebinding. See RFC 5735 section 3 
-+          for details. Thanks to Stephen Röttger for the bug report.
-+          
- version 2.75
-             Fix reversion on 2.74 which caused 100% CPU use when a 
-           dhcp-script is configured. Thanks to Adrian Davey for
-diff --git a/src/rfc1035.c b/src/rfc1035.c
-index 56647b0..29e9e65 100644
---- a/src/rfc1035.c
-+++ b/src/rfc1035.c
-@@ -728,7 +728,8 @@ int private_net(struct in_addr addr, int ban_localhost)
-   in_addr_t ip_addr = ntohl(addr.s_addr);
-   return
--    (((ip_addr & 0xFF000000) == 0x7F000000) && ban_localhost)  /* 127.0.0.0/8    (loopback) */ || 
-+    (((ip_addr & 0xFF000000) == 0x7F000000) && ban_localhost)  /* 127.0.0.0/8    (loopback) */ ||
-+    ((ip_addr & 0xFF000000) == 0x00000000)  /* RFC 5735 section 3. "here" network */ ||
-     ((ip_addr & 0xFFFF0000) == 0xC0A80000)  /* 192.168.0.0/16 (private)  */ ||
-     ((ip_addr & 0xFF000000) == 0x0A000000)  /* 10.0.0.0/8     (private)  */ ||
-     ((ip_addr & 0xFFF00000) == 0xAC100000)  /* 172.16.0.0/12  (private)  */ ||
--- 
-1.7.10.4
diff --git a/src/patches/dnsmasq/002-Add_--dhcp-ttl_option.patch b/src/patches/dnsmasq/002-Add_--dhcp-ttl_option.patch
new file mode 100644 (file)
index 0000000..45e3b9b
--- /dev/null
@@ -0,0 +1,117 @@
+From 832e47beab95c2918b5264f0504f2fe6fe523e4c Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon@thekelleys.org.uk>
+Date: Wed, 24 Feb 2016 21:24:45 +0000
+Subject: [PATCH] Add --dhcp-ttl option.
+
+---
+ man/dnsmasq.8 |    5 ++++-
+ src/dnsmasq.h |    2 +-
+ src/option.c  |   13 +++++++++++--
+ src/rfc1035.c |    2 +-
+ 4 files changed, 17 insertions(+), 5 deletions(-)
+
+diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
+index 7bc1394..2bcce20 100644
+--- a/man/dnsmasq.8
++++ b/man/dnsmasq.8
+@@ -60,7 +60,7 @@ in the same way as for DHCP-derived names. Note that this does not
+ apply to domain names in cnames, PTR records, TXT records etc.
+ .TP
+ .B \-T, --local-ttl=<time>
+-When replying with information from /etc/hosts or the DHCP leases
++When replying with information from /etc/hosts or configuration or the DHCP leases
+ file dnsmasq by default sets the time-to-live field to zero, meaning
+ that the requester should not itself cache the information. This is
+ the correct thing to do in almost all situations. This option allows a
+@@ -68,6 +68,9 @@ time-to-live (in seconds) to be given for these replies. This will
+ reduce the load on the server at the expense of clients using stale
+ data under some circumstances.
+ .TP
++.B --dhcp-ttl=<time>
++As for --local-ttl, but affects only replies with information from DHCP leases. If both are given, --dhcp-ttl applies for DHCP information, and --local-ttl for others. Setting this to zero eliminates the effect of --local-ttl for DHCP.
++.TP
+ .B --neg-ttl=<time>
+ Negative replies from upstream servers normally contain time-to-live
+ information in SOA records which dnsmasq uses for caching. If the
+diff --git a/src/dnsmasq.h b/src/dnsmasq.h
+index 6344df5..9f73c3b 100644
+--- a/src/dnsmasq.h
++++ b/src/dnsmasq.h
+@@ -955,7 +955,7 @@ extern struct daemon {
+   int max_logs;  /* queue limit */
+   int cachesize, ftabsize;
+   int port, query_port, min_port, max_port;
+-  unsigned long local_ttl, neg_ttl, max_ttl, min_cache_ttl, max_cache_ttl, auth_ttl;
++  unsigned long local_ttl, neg_ttl, max_ttl, min_cache_ttl, max_cache_ttl, auth_ttl, dhcp_ttl, use_dhcp_ttl;
+   char *dns_client_id;
+   struct hostsfile *addn_hosts;
+   struct dhcp_context *dhcp, *dhcp6;
+diff --git a/src/option.c b/src/option.c
+index 7c5e6bc..3f6d162 100644
+--- a/src/option.c
++++ b/src/option.c
+@@ -157,6 +157,7 @@ struct myoption {
+ #define LOPT_MAXPORT       345
+ #define LOPT_CPE_ID        346
+ #define LOPT_SCRIPT_ARP    347
++#define LOPT_DHCPTTL       348
+ #ifdef HAVE_GETOPT_LONG
+ static const struct option opts[] =  
+@@ -319,6 +320,7 @@ static const struct myoption opts[] =
+     { "quiet-ra", 0, 0, LOPT_QUIET_RA },
+     { "dns-loop-detect", 0, 0, LOPT_LOOP_DETECT },
+     { "script-arp", 0, 0, LOPT_SCRIPT_ARP },
++    { "dhcp-ttl", 1, 0 , LOPT_DHCPTTL },
+     { NULL, 0, 0, 0 }
+   };
+@@ -485,9 +487,10 @@ static struct {
+   { LOPT_QUIET_DHCP, OPT_QUIET_DHCP, NULL, gettext_noop("Do not log routine DHCP."), NULL },
+   { LOPT_QUIET_DHCP6, OPT_QUIET_DHCP6, NULL, gettext_noop("Do not log routine DHCPv6."), NULL },
+   { LOPT_QUIET_RA, OPT_QUIET_RA, NULL, gettext_noop("Do not log RA."), NULL },
+-  { LOPT_LOCAL_SERVICE, OPT_LOCAL_SERVICE, NULL, gettext_noop("Accept queries only from directly-connected networks"), NULL },
+-  { LOPT_LOOP_DETECT, OPT_LOOP_DETECT, NULL, gettext_noop("Detect and remove DNS forwarding loops"), NULL },
++  { LOPT_LOCAL_SERVICE, OPT_LOCAL_SERVICE, NULL, gettext_noop("Accept queries only from directly-connected networks."), NULL },
++  { LOPT_LOOP_DETECT, OPT_LOOP_DETECT, NULL, gettext_noop("Detect and remove DNS forwarding loops."), NULL },
+   { LOPT_IGNORE_ADDR, ARG_DUP, "<ipaddr>", gettext_noop("Ignore DNS responses containing ipaddr."), NULL }, 
++  { LOPT_DHCPTTL, ARG_ONE, "<ttl>", gettext_noop("Set TTL in DNS responses with DHCP-derived addresses."), NULL }, 
+   { 0, 0, NULL, NULL, NULL }
+ }; 
+@@ -2580,6 +2583,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
+     case LOPT_MINCTTL: /* --min-cache-ttl */
+     case LOPT_MAXCTTL: /* --max-cache-ttl */
+     case LOPT_AUTHTTL: /* --auth-ttl */
++    case LOPT_DHCPTTL: /* --dhcp-ttl */
+       {
+       int ttl;
+       if (!atoi_check(arg, &ttl))
+@@ -2598,6 +2602,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
+         daemon->max_cache_ttl = (unsigned long)ttl;
+       else if (option == LOPT_AUTHTTL)
+         daemon->auth_ttl = (unsigned long)ttl;
++      else if (option == LOPT_DHCPTTL)
++        {
++          daemon->dhcp_ttl = (unsigned long)ttl;
++          daemon->use_dhcp_ttl = 1;
++        }
+       else
+         daemon->local_ttl = (unsigned long)ttl;
+       break;
+diff --git a/src/rfc1035.c b/src/rfc1035.c
+index 3535a71..8f1e3b4 100644
+--- a/src/rfc1035.c
++++ b/src/rfc1035.c
+@@ -1170,7 +1170,7 @@ static unsigned long crec_ttl(struct crec *crecp, time_t now)
+      before the lease expires. */
+   if (crecp->flags & F_DHCP)
+-    return daemon->local_ttl;
++    return daemon->use_dhcp_ttl ? daemon->dhcp_ttl : daemon->local_ttl;
+   
+   /* Immortal entries other than DHCP are local, and hold TTL in TTD field. */
+   if (crecp->flags & F_IMMORTAL)
+-- 
+1.7.10.4
+
diff --git a/src/patches/dnsmasq/002-enhance_add_subnet_to_allow_arbitary_subnet_addresses.patch b/src/patches/dnsmasq/002-enhance_add_subnet_to_allow_arbitary_subnet_addresses.patch
deleted file mode 100644 (file)
index 2d3d6e4..0000000
+++ /dev/null
@@ -1,271 +0,0 @@
-From a7369bef8abd241c3d85633fa9c870943f091e76 Mon Sep 17 00:00:00 2001
-From: Ed Bardsley <ebardsley@google.com>
-Date: Wed, 5 Aug 2015 21:17:18 +0100
-Subject: [PATCH] Enhance --add-subnet to allow arbitary subnet addresses.
-
----
- CHANGELOG     |    4 ++++
- man/dnsmasq.8 |   32 ++++++++++++++++++++-----------
- src/dnsmasq.h |   13 ++++++++++---
- src/option.c  |   59 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----
- src/rfc1035.c |   39 +++++++++++++++++++++++++++++++-------
- 5 files changed, 121 insertions(+), 26 deletions(-)
-
-diff --git a/CHANGELOG b/CHANGELOG
-index 3f4026d..bbc2834 100644
---- a/CHANGELOG
-+++ b/CHANGELOG
-@@ -4,6 +4,10 @@ version 2.76
-           least, 0.0.0.0 accesses the local host, so could
-           be targets for DNS rebinding. See RFC 5735 section 3 
-           for details. Thanks to Stephen Röttger for the bug report.
-+
-+          Enhance --add-subnet to allow arbitrary subnet addresses.
-+            Thanks to Ed Barsley for the patch.
-+      
-           
- version 2.75
-             Fix reversion on 2.74 which caused 100% CPU use when a 
-diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
-index c8913b5..a23c898 100644
---- a/man/dnsmasq.8
-+++ b/man/dnsmasq.8
-@@ -604,17 +604,27 @@ experimental. Also note that exposing MAC addresses in this way may
- have security and privacy implications. The warning about caching
- given for --add-subnet applies to --add-mac too.
- .TP 
--.B --add-subnet[[=<IPv4 prefix length>],<IPv6 prefix length>]
--Add the subnet address of the requestor to the DNS queries which are
--forwarded upstream. The amount of the address forwarded depends on the
--prefix length parameter: 32 (128 for IPv6) forwards the whole address,
--zero forwards none of it but still marks the request so that no
--upstream nameserver will add client address information either. The
--default is zero for both IPv4 and IPv6. Note that upstream nameservers
--may be configured to return different results based on this
--information, but the dnsmasq cache does not take account. If a dnsmasq
--instance is configured such that different results may be encountered,
--caching should be disabled.
-+.B --add-subnet[[=[<IPv4 address>/]<IPv4 prefix length>][,[<IPv6 address>/]<IPv6 prefix length>]]
-+Add a subnet address to the DNS queries which are forwarded
-+upstream. If an address is specified in the flag, it will be used,
-+otherwise, the address of the requestor will be used. The amount of
-+the address forwarded depends on the prefix length parameter: 32 (128
-+for IPv6) forwards the whole address, zero forwards none of it but
-+still marks the request so that no upstream nameserver will add client
-+address information either. The default is zero for both IPv4 and
-+IPv6. Note that upstream nameservers may be configured to return
-+different results based on this information, but the dnsmasq cache
-+does not take account. If a dnsmasq instance is configured such that
-+different results may be encountered, caching should be disabled.
-+
-+For example,
-+.B --add-subnet=24,96
-+will add the /24 and /96 subnets of the requestor for IPv4 and IPv6 requestors, respectively.
-+.B --add-subnet=1.2.3.4/24
-+will add 1.2.3.0/24 for IPv4 requestors and ::/0 for IPv6 requestors.
-+.B --add-subnet=1.2.3.4/24,1.2.3.4/24
-+will add 1.2.3.0/24 for both IPv4 and IPv6 requestors.
-+
- .TP
- .B \-c, --cache-size=<cachesize>
- Set the size of dnsmasq's cache. The default is 150 names. Setting the cache size to zero disables caching.
-diff --git a/src/dnsmasq.h b/src/dnsmasq.h
-index cf1a782..f42acdb 100644
---- a/src/dnsmasq.h
-+++ b/src/dnsmasq.h
-@@ -541,6 +541,13 @@ struct iname {
-   struct iname *next;
- };
-+/* subnet parameters from command line */
-+struct mysubnet {
-+  union mysockaddr addr;
-+  int addr_used;
-+  int mask;
-+};
-+
- /* resolv-file parms from command-line */
- struct resolvc {
-   struct resolvc *next;
-@@ -935,9 +942,9 @@ extern struct daemon {
-   struct auth_zone *auth_zones;
-   struct interface_name *int_names;
-   char *mxtarget;
--  int addr4_netmask;
--  int addr6_netmask;
--  char *lease_file; 
-+  struct mysubnet *add_subnet4;
-+  struct mysubnet *add_subnet6;
-+  char *lease_file;
-   char *username, *groupname, *scriptuser;
-   char *luascript;
-   char *authserver, *hostmaster;
-diff --git a/src/option.c b/src/option.c
-index ecc2619..746cd11 100644
---- a/src/option.c
-+++ b/src/option.c
-@@ -445,7 +445,7 @@ static struct {
-   { LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL },
-   { LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL },
-   { LOPT_ADD_MAC, OPT_ADD_MAC, NULL, gettext_noop("Add requestor's MAC address to forwarded DNS queries."), NULL },
--  { LOPT_ADD_SBNET, ARG_ONE, "<v4 pref>[,<v6 pref>]", gettext_noop("Add requestor's IP subnet to forwarded DNS queries."), NULL },
-+  { LOPT_ADD_SBNET, ARG_ONE, "<v4 pref>[,<v6 pref>]", gettext_noop("Add specified IP subnet to forwarded DNS queries."), NULL },
-   { LOPT_DNSSEC, OPT_DNSSEC_PROXY, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers."), NULL },
-   { LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to allocate sequential IP addresses to DHCP clients."), NULL },
-   { LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy connection-track mark from queries to upstream connections."), NULL },
-@@ -722,6 +722,20 @@ static void do_usage(void)
- #define ret_err(x) do { strcpy(errstr, (x)); return 0; } while (0)
-+static char *parse_mysockaddr(char *arg, union mysockaddr *addr) 
-+{
-+  if (inet_pton(AF_INET, arg, &addr->in.sin_addr) > 0)
-+    addr->sa.sa_family = AF_INET;
-+#ifdef HAVE_IPV6
-+  else if (inet_pton(AF_INET6, arg, &addr->in6.sin6_addr) > 0)
-+    addr->sa.sa_family = AF_INET6;
-+#endif
-+  else
-+    return _("bad address");
-+   
-+  return NULL;
-+}
-+
- char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_addr, char *interface, int *flags)
- {
-   int source_port = 0, serv_port = NAMESERVER_PORT;
-@@ -1585,7 +1599,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
-           li = match_suffix->next;
-           free(match_suffix->suffix);
-           free(match_suffix);
--        }    
-+        }
-       break;
-       }
-@@ -1593,10 +1607,45 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
-       set_option_bool(OPT_CLIENT_SUBNET);
-       if (arg)
-       {
-+          char *err, *end;
-         comma = split(arg);
--        if (!atoi_check(arg, &daemon->addr4_netmask) || 
--            (comma && !atoi_check(comma, &daemon->addr6_netmask)))
--           ret_err(gen_err);
-+
-+          struct mysubnet* new = opt_malloc(sizeof(struct mysubnet));
-+          if ((end = split_chr(arg, '/')))
-+          {
-+            /* has subnet+len */
-+            err = parse_mysockaddr(arg, &new->addr);
-+            if (err)
-+              ret_err(err);
-+            if (!atoi_check(end, &new->mask))
-+              ret_err(gen_err);
-+            new->addr_used = 1;
-+          } 
-+        else if (!atoi_check(arg, &new->mask))
-+          ret_err(gen_err);
-+          
-+          daemon->add_subnet4 = new;
-+
-+          new = opt_malloc(sizeof(struct mysubnet));
-+          if (comma)
-+            {
-+              if ((end = split_chr(comma, '/')))
-+                {
-+                  /* has subnet+len */
-+                  err = parse_mysockaddr(comma, &new->addr);
-+                  if (err)
-+                    ret_err(err);
-+                  if (!atoi_check(end, &new->mask))
-+                    ret_err(gen_err);
-+                  new->addr_used = 1;
-+                }
-+              else
-+                {
-+                  if (!atoi_check(comma, &new->mask))
-+                    ret_err(gen_err);
-+                }
-+            }
-+          daemon->add_subnet6 = new;
-       }
-       break;
-diff --git a/src/rfc1035.c b/src/rfc1035.c
-index 29e9e65..6a51b30 100644
---- a/src/rfc1035.c
-+++ b/src/rfc1035.c
-@@ -629,26 +629,47 @@ struct subnet_opt {
- #endif
- };
-+static void *get_addrp(union mysockaddr *addr, const short family) 
-+{
-+#ifdef HAVE_IPV6
-+  if (family == AF_INET6)
-+    return &addr->in6.sin6_addr;
-+#endif
-+
-+  return &addr->in.sin_addr;
-+}
-+
- static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
- {
-   /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
-   
-   int len;
-   void *addrp;
-+  int sa_family = source->sa.sa_family;
- #ifdef HAVE_IPV6
-   if (source->sa.sa_family == AF_INET6)
-     {
--      opt->family = htons(2);
--      opt->source_netmask = daemon->addr6_netmask;
--      addrp = &source->in6.sin6_addr;
-+      opt->source_netmask = daemon->add_subnet6->mask;
-+      if (daemon->add_subnet6->addr_used) 
-+      {
-+        sa_family = daemon->add_subnet6->addr.sa.sa_family;
-+        addrp = get_addrp(&daemon->add_subnet6->addr, sa_family);
-+      } 
-+      else 
-+      addrp = &source->in6.sin6_addr;
-     }
-   else
- #endif
-     {
--      opt->family = htons(1);
--      opt->source_netmask = daemon->addr4_netmask;
--      addrp = &source->in.sin_addr;
-+      opt->source_netmask = daemon->add_subnet4->mask;
-+      if (daemon->add_subnet4->addr_used)
-+      {
-+        sa_family = daemon->add_subnet4->addr.sa.sa_family;
-+        addrp = get_addrp(&daemon->add_subnet4->addr, sa_family);
-+      } 
-+      else 
-+      addrp = &source->in.sin_addr;
-     }
-   
-   opt->scope_netmask = 0;
-@@ -656,6 +677,11 @@ static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
-   
-   if (opt->source_netmask != 0)
-     {
-+#ifdef HAVE_IPV6
-+      opt->family = htons(sa_family == AF_INET6 ? 2 : 1);
-+#else
-+      opt->family = htons(1);
-+#endif
-       len = ((opt->source_netmask - 1) >> 3) + 1;
-       memcpy(opt->addr, addrp, len);
-       if (opt->source_netmask & 7)
-@@ -2335,4 +2361,3 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
-   
-   return len;
- }
--
--- 
-1.7.10.4
diff --git a/src/patches/dnsmasq/003-Update_CHANGELOG.patch b/src/patches/dnsmasq/003-Update_CHANGELOG.patch
new file mode 100644 (file)
index 0000000..f04f943
--- /dev/null
@@ -0,0 +1,17 @@
+X-Git-Url: http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=blobdiff_plain;f=CHANGELOG;h=6d9ba490488f80ef565f459cef3c110bdf31212c;hp=14354f2506a7fbf8360cd32c96e1d7ce1bfeb3f9;hb=e06e6e34bffd781b7cefa49b25fb8ae863654ca2;hpb=832e47beab95c2918b5264f0504f2fe6fe523e4c
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 14354f2..6d9ba49 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -48,6 +48,10 @@ version 2.76
+           (ie xx::0 to xx::ffff:ffff:ffff:ffff) 
+           Thanks to Laurent Bendel for spotting this problem.
++          Add support for a TTL parameter in --host-record and
++          --cname.
++
++          Add --dhcp-ttl option.
+ version 2.75
+             Fix reversion on 2.74 which caused 100% CPU use when a 
diff --git a/src/patches/dnsmasq/003-dont_answer_non_auth_queries_for_auth_zones_locally_when_localise_queries_set.patch b/src/patches/dnsmasq/003-dont_answer_non_auth_queries_for_auth_zones_locally_when_localise_queries_set.patch
deleted file mode 100644 (file)
index cfbcdfb..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-From 3a3965ac21b1b759eab8799b6edb09195b671306 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Sun, 9 Aug 2015 17:45:06 +0100
-Subject: [PATCH] Don't answer non-auth queries for auth zones locally when
- --localise-queries set.
-
----
- src/forward.c |    4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/src/forward.c b/src/forward.c
-index 2731b90..b76a974 100644
---- a/src/forward.c
-+++ b/src/forward.c
-@@ -1365,7 +1365,7 @@ void receive_query(struct listener *listen, time_t now)
- #ifdef HAVE_AUTH
-       /* find queries for zones we're authoritative for, and answer them directly */
--      if (!auth_dns)
-+      if (!auth_dns && !option_bool(OPT_LOCALISE))
-       for (zone = daemon->auth_zones; zone; zone = zone->next)
-         if (in_zone(zone, daemon->namebuff, NULL))
-           {
-@@ -1904,7 +1904,7 @@ unsigned char *tcp_request(int confd, time_t now,
-         
- #ifdef HAVE_AUTH
-         /* find queries for zones we're authoritative for, and answer them directly */
--        if (!auth_dns)
-+        if (!auth_dns && !option_bool(OPT_LOCALISE))
-           for (zone = daemon->auth_zones; zone; zone = zone->next)
-             if (in_zone(zone, daemon->namebuff, NULL))
-               {
--- 
-1.7.10.4
diff --git a/src/patches/dnsmasq/004-Add_--tftp-mtu_option.patch b/src/patches/dnsmasq/004-Add_--tftp-mtu_option.patch
new file mode 100644 (file)
index 0000000..c06705a
--- /dev/null
@@ -0,0 +1,136 @@
+From bec366b4041df72b559e713f1c924177676e6eb0 Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon@thekelleys.org.uk>
+Date: Wed, 24 Feb 2016 22:03:26 +0000
+Subject: [PATCH] Add --tftp-mtu option.
+
+---
+ CHANGELOG     |    4 ++++
+ man/dnsmasq.8 |    4 ++++
+ src/dnsmasq.h |    2 +-
+ src/option.c  |   10 +++++++++-
+ src/tftp.c    |   14 ++++++++++++--
+ 5 files changed, 30 insertions(+), 4 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 6d9ba49..9218b8c 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -53,6 +53,10 @@ version 2.76
+           Add --dhcp-ttl option.
++          Add --tftp-mtu option. Thanks to Patrick McLean for the 
++          initial patch.
++
++
+ version 2.75
+             Fix reversion on 2.74 which caused 100% CPU use when a 
+           dhcp-script is configured. Thanks to Adrian Davey for
+diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
+index 2bcce20..3cf48cd 100644
+--- a/man/dnsmasq.8
++++ b/man/dnsmasq.8
+@@ -1810,6 +1810,10 @@ require about (2*n) + 10 descriptors. If
+ .B --tftp-port-range
+ is given, that can affect the number of concurrent connections.
+ .TP
++.B --tftp-mtu=<mtu size>
++Use size as the ceiling of the MTU supported by the intervening network when 
++negotiating TFTP blocksize, overriding the MTU setting of the local interface  if it is larger.
++.TP
+ .B --tftp-no-blocksize
+ Stop the TFTP server from negotiating the "blocksize" option with a
+ client. Some buggy clients request this option but then behave badly
+diff --git a/src/dnsmasq.h b/src/dnsmasq.h
+index 9f73c3b..280ad9d 100644
+--- a/src/dnsmasq.h
++++ b/src/dnsmasq.h
+@@ -975,7 +975,7 @@ extern struct daemon {
+   struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names, *dhcp_gen_names; 
+   struct dhcp_netid_list *force_broadcast, *bootp_dynamic;
+   struct hostsfile *dhcp_hosts_file, *dhcp_opts_file, *dynamic_dirs;
+-  int dhcp_max, tftp_max;
++  int dhcp_max, tftp_max, tftp_mtu;
+   int dhcp_server_port, dhcp_client_port;
+   int start_tftp_port, end_tftp_port; 
+   unsigned int min_leasetime;
+diff --git a/src/option.c b/src/option.c
+index 3f6d162..765965f 100644
+--- a/src/option.c
++++ b/src/option.c
+@@ -158,7 +158,8 @@ struct myoption {
+ #define LOPT_CPE_ID        346
+ #define LOPT_SCRIPT_ARP    347
+ #define LOPT_DHCPTTL       348
+-
++#define LOPT_TFTP_MTU      349
++ 
+ #ifdef HAVE_GETOPT_LONG
+ static const struct option opts[] =  
+ #else
+@@ -244,6 +245,7 @@ static const struct myoption opts[] =
+     { "tftp-unique-root", 0, 0, LOPT_APREF },
+     { "tftp-root", 1, 0, LOPT_PREFIX },
+     { "tftp-max", 1, 0, LOPT_TFTP_MAX },
++    { "tftp-mtu", 1, 0, LOPT_TFTP_MTU },
+     { "tftp-lowercase", 0, 0, LOPT_TFTP_LC },
+     { "ptr-record", 1, 0, LOPT_PTR },
+     { "naptr-record", 1, 0, LOPT_NAPTR },
+@@ -432,6 +434,7 @@ static struct {
+   { LOPT_SECURE, OPT_TFTP_SECURE, NULL, gettext_noop("Allow access only to files owned by the user running dnsmasq."), NULL },
+   { LOPT_TFTP_NO_FAIL, OPT_TFTP_NO_FAIL, NULL, gettext_noop("Do not terminate the service if TFTP directories are inaccessible."), NULL },
+   { LOPT_TFTP_MAX, ARG_ONE, "<integer>", gettext_noop("Maximum number of conncurrent TFTP transfers (defaults to %s)."), "#" },
++  { LOPT_TFTP_MTU, ARG_ONE, "<integer>", gettext_noop("Maximum MTU to use for TFTP transfers."), NULL },
+   { LOPT_NOBLOCK, OPT_TFTP_NOBLOCK, NULL, gettext_noop("Disable the TFTP blocksize extension."), NULL },
+   { LOPT_TFTP_LC, OPT_TFTP_LC, NULL, gettext_noop("Convert TFTP filenames to lowercase"), NULL },
+   { LOPT_TFTPPORTS, ARG_ONE, "<start>,<end>", gettext_noop("Ephemeral port range for use by TFTP transfers."), NULL },
+@@ -2625,6 +2628,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
+       ret_err(gen_err);
+       break;  
++    case LOPT_TFTP_MTU:  /*  --tftp-mtu */
++      if (!atoi_check(arg, &daemon->tftp_mtu))
++      ret_err(gen_err);
++      break;
++
+     case LOPT_PREFIX: /* --tftp-prefix */
+       comma = split(arg);
+       if (comma)
+diff --git a/src/tftp.c b/src/tftp.c
+index 00ed2fc..dc4aa85 100644
+--- a/src/tftp.c
++++ b/src/tftp.c
+@@ -103,8 +103,10 @@ void tftp_request(struct listener *listen, time_t now)
+       if (listen->iface)
+       {
+         addr = listen->iface->addr;
+-        mtu = listen->iface->mtu;
+         name = listen->iface->name;
++        mtu = listen->iface->mtu;
++        if (daemon->tftp_mtu != 0 && daemon->tftp_mtu < mtu)
++          mtu = daemon->tftp_mtu;
+       }
+       else
+       {
+@@ -234,9 +236,17 @@ void tftp_request(struct listener *listen, time_t now)
+       strncpy(ifr.ifr_name, name, IF_NAMESIZE);
+       if (ioctl(listen->tftpfd, SIOCGIFMTU, &ifr) != -1)
+-      mtu = ifr.ifr_mtu;      
++      {
++        mtu = ifr.ifr_mtu;  
++        if (daemon->tftp_mtu != 0 && daemon->tftp_mtu < mtu)
++          mtu = daemon->tftp_mtu;    
++      }
+     }
++  /* Failed to get interface mtu - can use configured value. */
++  if (mtu == 0)
++    mtu = daemon->tftp_mtu;
++
+   if (name)
+     {
+       /* check for per-interface prefix */ 
+-- 
+1.7.10.4
+
diff --git a/src/patches/dnsmasq/004-fix_behaviour_of_empty_dhcp-option.patch b/src/patches/dnsmasq/004-fix_behaviour_of_empty_dhcp-option.patch
deleted file mode 100644 (file)
index 492ada9..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-From 5e3e464ac4022ee0b3794513abe510817e2cf3ca Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Tue, 25 Aug 2015 23:08:39 +0100
-Subject: [PATCH] Fix behaviour of empty dhcp-option=option6:dns-server, which
- should inhibit sending option.
-
----
- src/rfc3315.c |    9 +++++----
- 1 file changed, 5 insertions(+), 4 deletions(-)
-
-diff --git a/src/rfc3315.c b/src/rfc3315.c
-index 2665d0d..3f1f9ee 100644
---- a/src/rfc3315.c
-+++ b/src/rfc3315.c
-@@ -1320,15 +1320,16 @@ static struct dhcp_netid *add_options(struct state *state, int do_refresh)
-       
-       if (opt_cfg->opt == OPTION6_REFRESH_TIME)
-       done_refresh = 1;
-+       
-+      if (opt_cfg->opt == OPTION6_DNS_SERVER)
-+      done_dns = 1;
-       
--      if (opt_cfg->flags & DHOPT_ADDR6)
-+      /* Empty DNS_SERVER option will not set DHOPT_ADDR6 */
-+      if ((opt_cfg->flags & DHOPT_ADDR6) || opt_cfg->opt == OPTION6_DNS_SERVER)
-       {
-         int len, j;
-         struct in6_addr *a;
-         
--        if (opt_cfg->opt == OPTION6_DNS_SERVER)
--          done_dns = 1;
--        
-         for (a = (struct in6_addr *)opt_cfg->val, len = opt_cfg->len, j = 0; 
-              j < opt_cfg->len; j += IN6ADDRSZ, a++)
-           if ((IN6_IS_ADDR_ULA_ZERO(a) && IN6_IS_ADDR_UNSPECIFIED(state->ula_addr)) ||
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/005-Apply_ceiling_of_lease_length_to_TTL_when_--dhcp-ttl_in_use.patch b/src/patches/dnsmasq/005-Apply_ceiling_of_lease_length_to_TTL_when_--dhcp-ttl_in_use.patch
new file mode 100644 (file)
index 0000000..2875d2c
--- /dev/null
@@ -0,0 +1,37 @@
+From 7480aeffc8ad195e9fd8bcf424bae0fab3839d55 Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon@thekelleys.org.uk>
+Date: Fri, 26 Feb 2016 21:58:20 +0000
+Subject: [PATCH] Apply ceiling of lease length to TTL when --dhcp-ttl in use.
+
+---
+ src/rfc1035.c |   12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+diff --git a/src/rfc1035.c b/src/rfc1035.c
+index 8f1e3b4..bed5312 100644
+--- a/src/rfc1035.c
++++ b/src/rfc1035.c
+@@ -1167,10 +1167,18 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int
+ static unsigned long crec_ttl(struct crec *crecp, time_t now)
+ {
+   /* Return 0 ttl for DHCP entries, which might change
+-     before the lease expires. */
++     before the lease expires, unless configured otherwise. */
+   if (crecp->flags & F_DHCP)
+-    return daemon->use_dhcp_ttl ? daemon->dhcp_ttl : daemon->local_ttl;
++    {
++      int conf_ttl = daemon->use_dhcp_ttl ? daemon->dhcp_ttl : daemon->local_ttl;
++      
++      /* Apply ceiling of actual lease length to configured TTL. */
++      if (!(crecp->flags & F_IMMORTAL) && (crecp->ttd - now) < conf_ttl)
++      return crecp->ttd - now;
++      
++      return conf_ttl;
++    }   
+   
+   /* Immortal entries other than DHCP are local, and hold TTL in TTD field. */
+   if (crecp->flags & F_IMMORTAL)
+-- 
+1.7.10.4
+
diff --git a/src/patches/dnsmasq/005-suggest_solution_to_ENOMEM_error_with_IPv6_multicast.patch b/src/patches/dnsmasq/005-suggest_solution_to_ENOMEM_error_with_IPv6_multicast.patch
deleted file mode 100644 (file)
index c7cee60..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-From 9cdcfe9f19ffd45bac4e5b459879bf7c50a287ed Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Wed, 26 Aug 2015 22:38:08 +0100
-Subject: [PATCH] Suggest solution to ENOMEM error with IPv6 multicast.
-
----
- src/network.c |   13 ++++++++++---
- 1 file changed, 10 insertions(+), 3 deletions(-)
-
-diff --git a/src/network.c b/src/network.c
-index a1d90c8..819302f 100644
---- a/src/network.c
-+++ b/src/network.c
-@@ -1076,23 +1076,30 @@ void join_multicast(int dienow)
-           
-           if ((daemon->doing_dhcp6 || daemon->relay6) &&
-               setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
--            err = 1;
-+            err = errno;
-           
-           inet_pton(AF_INET6, ALL_SERVERS, &mreq.ipv6mr_multiaddr);
-           
-           if (daemon->doing_dhcp6 && 
-               setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
--            err = 1;
-+            err = errno;
-           
-           inet_pton(AF_INET6, ALL_ROUTERS, &mreq.ipv6mr_multiaddr);
-           
-           if (daemon->doing_ra &&
-               setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
--            err = 1;
-+            err = errno;
-           
-           if (err)
-             {
-               char *s = _("interface %s failed to join DHCPv6 multicast group: %s");
-+              errno = err;
-+
-+#ifdef HAVE_LINUX_NETWORK
-+              if (errno == ENOMEM)
-+                my_syslog(LOG_ERR, _("try increasing /proc/sys/net/core/optmem_max"));
-+#endif
-+
-               if (dienow)
-                 die(s, iface->name, EC_BADNET);
-               else
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/006-clarify_man_page_on_RDNSS_set_in_router_advertisement.patch b/src/patches/dnsmasq/006-clarify_man_page_on_RDNSS_set_in_router_advertisement.patch
deleted file mode 100644 (file)
index 19c76e6..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-From 20fd11e11a9d09edcea94de135396ae1541fbbab Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Wed, 26 Aug 2015 22:48:13 +0100
-Subject: [PATCH] Clarify man page on RDNSS set in router advertisement.
-
----
- man/dnsmasq.8 |    6 +++---
- 1 file changed, 3 insertions(+), 3 deletions(-)
-
-diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
-index a23c898..d51b10f 100644
---- a/man/dnsmasq.8
-+++ b/man/dnsmasq.8
-@@ -1687,15 +1687,15 @@ creation are handled by a different protocol. When DHCP is in use,
- only a subset of this is needed, and dnsmasq can handle it, using
- existing DHCP configuration to provide most data. When RA is enabled,
- dnsmasq will advertise a prefix for each dhcp-range, with default
--router and recursive DNS server as the relevant link-local address on 
--the machine running dnsmasq. By default, he "managed address" bits are set, and
-+router  as the relevant link-local address on 
-+the machine running dnsmasq. By default, the "managed address" bits are set, and
- the "use SLAAC" bit is reset. This can be changed for individual
- subnets with the mode keywords described in
- .B --dhcp-range.
- RFC6106 DNS parameters are included in the advertisements. By default,
- the relevant link-local address of the machine running dnsmasq is sent
- as recursive DNS server. If provided, the DHCPv6 options dns-server and
--domain-search are used for RDNSS and DNSSL.
-+domain-search are used for the DNS server (RDNSS) and the domain serach list (DNSSL).
- .TP
- .B --ra-param=<interface>,[high|low],[[<ra-interval>],<router lifetime>]
- Set non-default values for router advertisements sent via an
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/007-handle_signed_dangling_CNAME_replies_to_DS_queries.patch b/src/patches/dnsmasq/007-handle_signed_dangling_CNAME_replies_to_DS_queries.patch
deleted file mode 100644 (file)
index 832a22e..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-From 6de81f1250fd323c9155de065d5a9dc200a6f20b Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Wed, 9 Sep 2015 22:51:13 +0100
-Subject: [PATCH] Handle signed dangling CNAME replies to DS queries.
-
----
- src/dnssec.c |    7 ++-----
- 1 file changed, 2 insertions(+), 5 deletions(-)
-
-diff --git a/src/dnssec.c b/src/dnssec.c
-index 4deda24..67ce486 100644
---- a/src/dnssec.c
-+++ b/src/dnssec.c
-@@ -1232,11 +1232,8 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
-    
-   /* If we return STAT_NO_SIG, name contains the name of the DS query */
-   if (val == STAT_NO_SIG)
--    {
--      *keyname = 0;
--      return val;
--    }  
--
-+    return val;
-+  
-   /* If the key needed to validate the DS is on the same domain as the DS, we'll
-      loop getting nowhere. Stop that now. This can happen of the DS answer comes
-      from the DS's zone, and not the parent zone. */
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/008-DHCPv6_option_56_does_not_hold_an_address_list.patch b/src/patches/dnsmasq/008-DHCPv6_option_56_does_not_hold_an_address_list.patch
deleted file mode 100644 (file)
index fdccd0e..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-From 102208df695e886a3086754d32bf7f8c541fbe46 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Thu, 10 Sep 2015 21:50:00 +0100
-Subject: [PATCH] DHCPv6 option 56 does not hold an address list. (RFC 5908).
-
----
- src/dhcp-common.c |    2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/dhcp-common.c b/src/dhcp-common.c
-index bc48f41..8fc171a 100644
---- a/src/dhcp-common.c
-+++ b/src/dhcp-common.c
-@@ -599,7 +599,7 @@ static const struct opttab_t opttab6[] = {
-   { "sntp-server", 31,  OT_ADDR_LIST },
-   { "information-refresh-time", 32, OT_TIME },
-   { "FQDN", 39, OT_INTERNAL | OT_RFC1035_NAME },
--  { "ntp-server", 56,  OT_ADDR_LIST },
-+  { "ntp-server", 56,  0 },
-   { "bootfile-url", 59, OT_NAME },
-   { "bootfile-param", 60, OT_CSTRING },
-   { NULL, 0, 0 }
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/009-Respect_the_--no_resolv_flag_in_inotify_code.patch b/src/patches/dnsmasq/009-Respect_the_--no_resolv_flag_in_inotify_code.patch
deleted file mode 100644 (file)
index 2014fdb..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-From 77607cbea0ad0f876dfb79c8b2c121ee400d57d0 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Thu, 10 Sep 2015 23:08:43 +0100
-Subject: [PATCH] Respect the --no-resolv flag in inotify code.
-
----
- CHANGELOG        |    7 ++++++-
- debian/changelog |    6 ++++++
- src/inotify.c    |    3 +++
- 3 files changed, 15 insertions(+), 1 deletion(-)
-
-diff --git a/CHANGELOG b/CHANGELOG
-index bbc2834..d6e309f 100644
---- a/CHANGELOG
-+++ b/CHANGELOG
-@@ -7,8 +7,13 @@ version 2.76
-           Enhance --add-subnet to allow arbitrary subnet addresses.
-             Thanks to Ed Barsley for the patch.
-+
-+          Respect the --no-resolv flag in inotify code. Fixes bug
-+          which caused dnsmasq to fail to start if a resolv-file 
-+          was a dangling symbolic link, even of --no-resolv set.
-+          Thanks to Alexander Kurtz for spotting the problem.
-+
-       
--          
- version 2.75
-             Fix reversion on 2.74 which caused 100% CPU use when a 
-           dhcp-script is configured. Thanks to Adrian Davey for
-diff --git a/src/inotify.c b/src/inotify.c
-index 52d412f..ef05c58 100644
---- a/src/inotify.c
-+++ b/src/inotify.c
-@@ -90,6 +90,9 @@ void inotify_dnsmasq_init()
-   
-   if (daemon->inotifyfd == -1)
-     die(_("failed to create inotify: %s"), NULL, EC_MISC);
-+
-+  if (option_bool(OPT_NO_RESOLV))
-+    return;
-   
-   for (res = daemon->resolv_files; res; res = res->next)
-     {
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/010-Rationalise_5e3e464ac4022ee0b3794513abe510817e2cf3ca.patch b/src/patches/dnsmasq/010-Rationalise_5e3e464ac4022ee0b3794513abe510817e2cf3ca.patch
deleted file mode 100644 (file)
index 281697f..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-From 27b78d990b7cd901866ad6f1a17b9d633a95fdce Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Sat, 26 Sep 2015 21:40:45 +0100
-Subject: [PATCH] Rationalise 5e3e464ac4022ee0b3794513abe510817e2cf3ca
-
----
- src/rfc3315.c |    3 +--
- 1 file changed, 1 insertion(+), 2 deletions(-)
-
-diff --git a/src/rfc3315.c b/src/rfc3315.c
-index 3f1f9ee..3ed8623 100644
---- a/src/rfc3315.c
-+++ b/src/rfc3315.c
-@@ -1324,8 +1324,7 @@ static struct dhcp_netid *add_options(struct state *state, int do_refresh)
-       if (opt_cfg->opt == OPTION6_DNS_SERVER)
-       done_dns = 1;
-       
--      /* Empty DNS_SERVER option will not set DHOPT_ADDR6 */
--      if ((opt_cfg->flags & DHOPT_ADDR6) || opt_cfg->opt == OPTION6_DNS_SERVER)
-+      if (opt_cfg->flags & DHOPT_ADDR6)
-       {
-         int len, j;
-         struct in6_addr *a;
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/011-Catch_errors_from_sendmsg_in_DHCP_code.patch b/src/patches/dnsmasq/011-Catch_errors_from_sendmsg_in_DHCP_code.patch
deleted file mode 100644 (file)
index 631495f..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-From 98079ea89851da1df4966dfdfa1852a98da02912 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Tue, 13 Oct 2015 20:30:32 +0100
-Subject: [PATCH] Catch errors from sendmsg in DHCP code.  Logs, eg,  iptables
- DROPS of dest 255.255.255.255
-
----
- src/dhcp.c |    7 ++++++-
- 1 file changed, 6 insertions(+), 1 deletion(-)
-
-diff --git a/src/dhcp.c b/src/dhcp.c
-index e6fceb1..1c85e42 100644
---- a/src/dhcp.c
-+++ b/src/dhcp.c
-@@ -452,8 +452,13 @@ void dhcp_packet(time_t now, int pxe_fd)
- #endif
-   
-   while(retry_send(sendmsg(fd, &msg, 0)));
-+
-+  /* This can fail when, eg, iptables DROPS destination 255.255.255.255 */
-+  if (errno != 0)
-+    my_syslog(MS_DHCP | LOG_WARNING, _("Error sending DHCP packet to %s: %s"),
-+            inet_ntoa(dest.sin_addr), strerror(errno));
- }
-- 
-+
- /* check against secondary interface addresses */
- static int check_listen_addrs(struct in_addr local, int if_index, char *label,
-                             struct in_addr netmask, struct in_addr broadcast, void *vparam)
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/012-Update_list_of_subnet_for_--bogus-priv.patch b/src/patches/dnsmasq/012-Update_list_of_subnet_for_--bogus-priv.patch
deleted file mode 100644 (file)
index 3ba98fc..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-From 90477fb79420a34124b66ebd808c578817a30e4c Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Tue, 20 Oct 2015 21:21:32 +0100
-Subject: [PATCH] Update list of subnet for --bogus-priv
-
-RFC6303 specifies & recommends following zones not be forwarded
-to globally facing servers.
-+------------------------------+-----------------------+
-| Zone                         | Description           |
-+------------------------------+-----------------------+
-| 0.IN-ADDR.ARPA               | IPv4 "THIS" NETWORK   |
-| 127.IN-ADDR.ARPA             | IPv4 Loopback NETWORK |
-| 254.169.IN-ADDR.ARPA         | IPv4 LINK LOCAL       |
-| 2.0.192.IN-ADDR.ARPA         | IPv4 TEST-NET-1       |
-| 100.51.198.IN-ADDR.ARPA      | IPv4 TEST-NET-2       |
-| 113.0.203.IN-ADDR.ARPA       | IPv4 TEST-NET-3       |
-| 255.255.255.255.IN-ADDR.ARPA | IPv4 BROADCAST        |
-+------------------------------+-----------------------+
-
-Signed-off-by: Kevin Darbyshire-Bryant <kevin@darbyshire-bryant.me.uk>
----
- src/rfc1035.c |    8 ++++++--
- 1 file changed, 6 insertions(+), 2 deletions(-)
-
-diff --git a/src/rfc1035.c b/src/rfc1035.c
-index 6a51b30..4eb1772 100644
---- a/src/rfc1035.c
-+++ b/src/rfc1035.c
-@@ -756,10 +756,14 @@ int private_net(struct in_addr addr, int ban_localhost)
-   return
-     (((ip_addr & 0xFF000000) == 0x7F000000) && ban_localhost)  /* 127.0.0.0/8    (loopback) */ ||
-     ((ip_addr & 0xFF000000) == 0x00000000)  /* RFC 5735 section 3. "here" network */ ||
--    ((ip_addr & 0xFFFF0000) == 0xC0A80000)  /* 192.168.0.0/16 (private)  */ ||
-     ((ip_addr & 0xFF000000) == 0x0A000000)  /* 10.0.0.0/8     (private)  */ ||
-     ((ip_addr & 0xFFF00000) == 0xAC100000)  /* 172.16.0.0/12  (private)  */ ||
--    ((ip_addr & 0xFFFF0000) == 0xA9FE0000)  /* 169.254.0.0/16 (zeroconf) */ ;
-+    ((ip_addr & 0xFFFF0000) == 0xC0A80000)  /* 192.168.0.0/16 (private)  */ ||
-+    ((ip_addr & 0xFFFF0000) == 0xA9FE0000)  /* 169.254.0.0/16 (zeroconf) */ ||
-+    ((ip_addr & 0xFFFFFF00) == 0xC0000200)  /* 192.0.2.0/24   (test-net) */ ||
-+    ((ip_addr & 0xFFFFFF00) == 0xC6336400)  /* 198.51.100.0/24(test-net) */ ||
-+    ((ip_addr & 0xFFFFFF00) == 0xCB007100)  /* 203.0.113.0/24 (test-net) */ ||
-+    ((ip_addr & 0xFFFFFFFF) == 0xFFFFFFFF)  /* 255.255.255.255/32 (broadcast)*/ ;
- }
- static unsigned char *do_doctor(unsigned char *p, int count, struct dns_header *header, size_t qlen, char *name, int *doctored)
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/013-Fix_crash_when_empty_address_from_DNS_overlays_A_record_from.patch b/src/patches/dnsmasq/013-Fix_crash_when_empty_address_from_DNS_overlays_A_record_from.patch
deleted file mode 100644 (file)
index 736cf38..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-From 41a8d9e99be9f2cc8b02051dd322cb45e0faac87 Mon Sep 17 00:00:00 2001
-From: =?utf8?q?Edwin=20T=C3=B6r=C3=B6k?= <edwin+ml-cerowrt@etorok.net>
-Date: Sat, 14 Nov 2015 17:45:48 +0000
-Subject: [PATCH] Fix crash when empty address from DNS overlays A record from
- hosts.
-
----
- CHANGELOG   |    5 +++++
- src/cache.c |    2 +-
- 2 files changed, 6 insertions(+), 1 deletion(-)
-
-diff --git a/CHANGELOG b/CHANGELOG
-index d6e309f..93c73d0 100644
---- a/CHANGELOG
-+++ b/CHANGELOG
-@@ -13,6 +13,11 @@ version 2.76
-           was a dangling symbolic link, even of --no-resolv set.
-           Thanks to Alexander Kurtz for spotting the problem.
-+          Fix crash when an A or AAAA record is defined locally,
-+          in a hosts file, and an upstream server sends a reply
-+          that the same name is empty. Thanks to Edwin Török for
-+          the patch.
-+
-       
- version 2.75
-             Fix reversion on 2.74 which caused 100% CPU use when a 
-diff --git a/src/cache.c b/src/cache.c
-index 178d654..1b76b67 100644
---- a/src/cache.c
-+++ b/src/cache.c
-@@ -481,7 +481,7 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
-        existing record is for an A or AAAA and
-        the record we're trying to insert is the same, 
-        just drop the insert, but don't error the whole process. */
--      if ((flags & (F_IPV4 | F_IPV6)) && (flags & F_FORWARD))
-+      if ((flags & (F_IPV4 | F_IPV6)) && (flags & F_FORWARD) && addr)
-       {
-         if ((flags & F_IPV4) && (new->flags & F_IPV4) &&
-             new->addr.addr.addr.addr4.s_addr == addr->addr.addr4.s_addr)
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/014-Handle_unknown_DS_hash_algos_correctly.patch b/src/patches/dnsmasq/014-Handle_unknown_DS_hash_algos_correctly.patch
deleted file mode 100644 (file)
index 8b17431..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-From 67ab3285b5d9a1b1e20e034cf272867fdab8a0f9 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Fri, 20 Nov 2015 23:20:47 +0000
-Subject: [PATCH] Handle unknown DS hash algos correctly.
-
-When we can validate a DS RRset, but don't speak the hash algo it
-contains, treat that the same as an NSEC/3 proving that the DS
-doesn't exist. 4025 5.2
----
- src/dnssec.c |   13 +++++++++++++
- 1 file changed, 13 insertions(+)
-
-diff --git a/src/dnssec.c b/src/dnssec.c
-index 67ce486..b4dc14e 100644
---- a/src/dnssec.c
-+++ b/src/dnssec.c
-@@ -1005,6 +1005,19 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
-   if (crecp->flags & F_NEG)
-     return STAT_INSECURE_DS;
-   
-+  /* 4035 5.2 
-+     If the validator does not support any of the algorithms listed in an
-+     authenticated DS RRset, then the resolver has no supported
-+     authentication path leading from the parent to the child.  The
-+     resolver should treat this case as it would the case of an
-+     authenticated NSEC RRset proving that no DS RRset exists,  */
-+  for (recp1 = crecp; recp1; recp1 = cache_find_by_name(recp1, name, now, F_DS))
-+    if (hash_find(ds_digest_name(recp1->addr.ds.digest)))
-+      break;
-+  
-+  if (!recp1)
-+    return STAT_INSECURE_DS;
-+
-   /* NOTE, we need to find ONE DNSKEY which matches the DS */
-   for (valid = 0, j = ntohs(header->ancount); j != 0 && !valid; j--) 
-     {
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/015-Fix_crash_at_start_up_with_conf-dir.patch b/src/patches/dnsmasq/015-Fix_crash_at_start_up_with_conf-dir.patch
deleted file mode 100644 (file)
index a9102c1..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-From 0007ee90646a5a78a96ee729932e89d31c69513a Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Sat, 21 Nov 2015 21:47:41 +0000
-Subject: [PATCH] Fix crash at start up with conf-dir=/path,*
-
-Thanks to Brian Carpenter and American Fuzzy Lop for finding the bug.
----
- src/option.c |   14 ++++++++++----
- 1 file changed, 10 insertions(+), 4 deletions(-)
-
-diff --git a/src/option.c b/src/option.c
-index 746cd11..71beb98 100644
---- a/src/option.c
-+++ b/src/option.c
-@@ -1515,10 +1515,16 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
-               li = opt_malloc(sizeof(struct list));
-               if (*arg == '*')
-                 {
--                  li->next = match_suffix;
--                  match_suffix = li;
--                  /* Have to copy: buffer is overwritten */
--                  li->suffix = opt_string_alloc(arg+1);
-+                  /* "*" with no suffix is a no-op */
-+                  if (arg[1] == 0)
-+                    free(li);
-+                  else
-+                    {
-+                      li->next = match_suffix;
-+                      match_suffix = li;
-+                      /* Have to copy: buffer is overwritten */
-+                      li->suffix = opt_string_alloc(arg+1);
-+                    }
-                 }
-               else
-                 {
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/016-Major_rationalisation_of_DNSSEC_validation.patch b/src/patches/dnsmasq/016-Major_rationalisation_of_DNSSEC_validation.patch
deleted file mode 100644 (file)
index 7f25066..0000000
+++ /dev/null
@@ -1,2209 +0,0 @@
-From 9a31b68b59adcac01016d4026d906b69c4216c01 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Tue, 15 Dec 2015 10:20:39 +0000
-Subject: [PATCH] Major rationalisation of DNSSEC validation.
-
-Much gnarly special-case code removed and replaced with correct
-general implementaion. Checking of zone-status moved to DNSSEC code,
-where it should be, vastly simplifying query-forwarding code.
----
- src/dnsmasq.h |   19 +-
- src/dnssec.c  |  926 ++++++++++++++++++++++++++++++---------------------------
- src/forward.c |  741 ++++++++++-----------------------------------
- 3 files changed, 653 insertions(+), 1033 deletions(-)
-
-diff --git a/src/dnsmasq.h b/src/dnsmasq.h
-index f42acdb..023a1cf 100644
---- a/src/dnsmasq.h
-+++ b/src/dnsmasq.h
-@@ -586,12 +586,8 @@ struct hostsfile {
- #define STAT_NEED_KEY           5
- #define STAT_TRUNCATED          6
- #define STAT_SECURE_WILDCARD    7
--#define STAT_NO_SIG             8
--#define STAT_NO_DS              9
--#define STAT_NO_NS             10
--#define STAT_NEED_DS_NEG       11
--#define STAT_CHASE_CNAME       12
--#define STAT_INSECURE_DS       13
-+#define STAT_OK                 8
-+#define STAT_ABANDONED          9
- #define FREC_NOREBIND           1
- #define FREC_CHECKING_DISABLED  2
-@@ -601,8 +597,7 @@ struct hostsfile {
- #define FREC_AD_QUESTION       32
- #define FREC_DO_QUESTION       64
- #define FREC_ADDED_PHEADER    128
--#define FREC_CHECK_NOSIGN     256
--#define FREC_TEST_PKTSZ       512
-+#define FREC_TEST_PKTSZ       256
- #ifdef HAVE_DNSSEC
- #define HASH_SIZE 20 /* SHA-1 digest size */
-@@ -626,9 +621,7 @@ struct frec {
- #ifdef HAVE_DNSSEC 
-   int class, work_counter;
-   struct blockdata *stash; /* Saved reply, whilst we validate */
--  struct blockdata *orig_domain; /* domain of original query, whilst
--                                  we're seeing is if in unsigned domain */
--  size_t stash_len, name_start, name_len;
-+  size_t stash_len;
-   struct frec *dependent; /* Query awaiting internally-generated DNSKEY or DS query */
-   struct frec *blocking_query; /* Query which is blocking us. */
- #endif
-@@ -1162,8 +1155,8 @@ int in_zone(struct auth_zone *zone, char *name, char **cut);
- size_t dnssec_generate_query(struct dns_header *header, char *end, char *name, int class, int type, union mysockaddr *addr, int edns_pktsz);
- int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t n, char *name, char *keyname, int class);
- int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class);
--int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int *class, int *neganswer, int *nons);
--int dnssec_chase_cname(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname);
-+int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int *class,
-+                        int check_unsigned, int *neganswer, int *nons);
- int dnskey_keytag(int alg, int flags, unsigned char *rdata, int rdlen);
- size_t filter_rrsigs(struct dns_header *header, size_t plen);
- unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name);
-diff --git a/src/dnssec.c b/src/dnssec.c
-index b4dc14e..de7b335 100644
---- a/src/dnssec.c
-+++ b/src/dnssec.c
-@@ -65,8 +65,10 @@ static char *algo_digest_name(int algo)
-     case 8: return "sha256";
-     case 10: return "sha512";
-     case 12: return "gosthash94";
-+#ifndef NO_NETTLE_ECC
-     case 13: return "sha256";
-     case 14: return "sha384";
-+#endif
-     default: return NULL;
-     }
- }
-@@ -592,30 +594,30 @@ static int get_rdata(struct dns_header *header, size_t plen, unsigned char *end,
-     }
- }
--static int expand_workspace(unsigned char ***wkspc, int *sz, int new)
-+static int expand_workspace(unsigned char ***wkspc, int *szp, int new)
- {
-   unsigned char **p;
--  int new_sz = *sz;
--  
--  if (new_sz > new)
-+  int old = *szp;
-+
-+  if (old >= new+1)
-     return 1;
-   if (new >= 100)
-     return 0;
--  new_sz += 5;
-+  new += 5;
-   
--  if (!(p = whine_malloc((new_sz) * sizeof(unsigned char **))))
-+  if (!(p = whine_malloc(new * sizeof(unsigned char **))))
-     return 0;  
-   
--  if (*wkspc)
-+  if (old != 0 && *wkspc)
-     {
--      memcpy(p, *wkspc, *sz * sizeof(unsigned char **));
-+      memcpy(p, *wkspc, old * sizeof(unsigned char **));
-       free(*wkspc);
-     }
-   
-   *wkspc = p;
--  *sz = new_sz;
-+  *szp = new;
-   return 1;
- }
-@@ -706,47 +708,28 @@ static void sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int
-     } while (swap);
- }
--/* Validate a single RRset (class, type, name) in the supplied DNS reply 
--   Return code:
--   STAT_SECURE   if it validates.
--   STAT_SECURE_WILDCARD if it validates and is the result of wildcard expansion.
--   (In this case *wildcard_out points to the "body" of the wildcard within name.) 
--   STAT_NO_SIG no RRsigs found.
--   STAT_INSECURE RRset empty.
--   STAT_BOGUS    signature is wrong, bad packet.
--   STAT_NEED_KEY need DNSKEY to complete validation (name is returned in keyname)
--
--   if key is non-NULL, use that key, which has the algo and tag given in the params of those names,
--   otherwise find the key in the cache.
-+static unsigned char **rrset = NULL, **sigs = NULL;
--   name is unchanged on exit. keyname is used as workspace and trashed.
--*/
--static int validate_rrset(time_t now, struct dns_header *header, size_t plen, int class, int type, 
--                        char *name, char *keyname, char **wildcard_out, struct blockdata *key, int keylen, int algo_in, int keytag_in)
-+/* Get pointers to RRset menbers and signature(s) for same.
-+   Check signatures, and return keyname associated in keyname. */
-+static int explore_rrset(struct dns_header *header, size_t plen, int class, int type, 
-+                       char *name, char *keyname, int *sigcnt, int *rrcnt)
- {
--  static unsigned char **rrset = NULL, **sigs = NULL;
--  static int rrset_sz = 0, sig_sz = 0;
--  
-+  static int rrset_sz = 0, sig_sz = 0; 
-   unsigned char *p;
--  int rrsetidx, sigidx, res, rdlen, j, name_labels;
--  struct crec *crecp = NULL;
--  int type_covered, algo, labels, orig_ttl, sig_expiration, sig_inception, key_tag;
--  u16 *rr_desc = get_desc(type);
-- 
--  if (wildcard_out)
--    *wildcard_out = NULL;
--  
-+  int rrsetidx, sigidx, j, rdlen, res;
-+  int name_labels = count_labels(name); /* For 4035 5.3.2 check */
-+  int gotkey = 0;
-+
-   if (!(p = skip_questions(header, plen)))
-     return STAT_BOGUS;
--  
--  name_labels = count_labels(name); /* For 4035 5.3.2 check */
--  /* look for RRSIGs for this RRset and get pointers to each RR in the set. */
-+   /* look for RRSIGs for this RRset and get pointers to each RR in the set. */
-   for (rrsetidx = 0, sigidx = 0, j = ntohs(header->ancount) + ntohs(header->nscount); 
-        j != 0; j--) 
-     {
-       unsigned char *pstart, *pdata;
--      int stype, sclass;
-+      int stype, sclass, algo, type_covered, labels, sig_expiration, sig_inception;
-       pstart = p;
-       
-@@ -762,14 +745,14 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
-       GETSHORT(rdlen, p);
-       
-       if (!CHECK_LEN(header, p, plen, rdlen))
--      return STAT_BOGUS; 
-+      return 0; 
-       
-       if (res == 1 && sclass == class)
-       {
-         if (stype == type)
-           {
-             if (!expand_workspace(&rrset, &rrset_sz, rrsetidx))
--              return STAT_BOGUS; 
-+              return 0; 
-             
-             rrset[rrsetidx++] = pstart;
-           }
-@@ -777,14 +760,54 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
-         if (stype == T_RRSIG)
-           {
-             if (rdlen < 18)
--              return STAT_BOGUS; /* bad packet */ 
-+              return 0; /* bad packet */ 
-             
-             GETSHORT(type_covered, p);
-+            algo = *p++;
-+            labels = *p++;
-+            p += 4; /* orig_ttl */
-+            GETLONG(sig_expiration, p);
-+            GETLONG(sig_inception, p);
-+            p += 2; /* key_tag */
-             
--            if (type_covered == type)
-+            if (gotkey)
-+              {
-+                /* If there's more than one SIG, ensure they all have same keyname */
-+                if (extract_name(header, plen, &p, keyname, 0, 0) != 1)
-+                  return 0;
-+              }
-+            else
-+              {
-+                gotkey = 1;
-+                
-+                if (!extract_name(header, plen, &p, keyname, 1, 0))
-+                  return 0;
-+                
-+                /* RFC 4035 5.3.1 says that the Signer's Name field MUST equal
-+                   the name of the zone containing the RRset. We can't tell that
-+                   for certain, but we can check that  the RRset name is equal to
-+                   or encloses the signers name, which should be enough to stop 
-+                   an attacker using signatures made with the key of an unrelated 
-+                   zone he controls. Note that the root key is always allowed. */
-+                if (*keyname != 0)
-+                  {
-+                    char *name_start;
-+                    for (name_start = name; !hostname_isequal(name_start, keyname); )
-+                      if ((name_start = strchr(name_start, '.')))
-+                        name_start++; /* chop a label off and try again */
-+                      else
-+                        return 0;
-+                  }
-+              }
-+                
-+            /* Don't count signatures for algos we don't support */
-+            if (check_date_range(sig_inception, sig_expiration) &&
-+                labels <= name_labels &&
-+                type_covered == type && 
-+                algo_digest_name(algo))
-               {
-                 if (!expand_workspace(&sigs, &sig_sz, sigidx))
--                  return STAT_BOGUS; 
-+                  return 0; 
-                 
-                 sigs[sigidx++] = pdata;
-               } 
-@@ -794,17 +817,45 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
-       }
-       
-       if (!ADD_RDLEN(header, p, plen, rdlen))
--      return STAT_BOGUS;
-+      return 0;
-     }
-   
--  /* RRset empty */
--  if (rrsetidx == 0)
--    return STAT_INSECURE; 
-+  *sigcnt = sigidx;
-+  *rrcnt = rrsetidx;
-+
-+  return 1;
-+}
-+
-+/* Validate a single RRset (class, type, name) in the supplied DNS reply 
-+   Return code:
-+   STAT_SECURE   if it validates.
-+   STAT_SECURE_WILDCARD if it validates and is the result of wildcard expansion.
-+   (In this case *wildcard_out points to the "body" of the wildcard within name.) 
-+   STAT_BOGUS    signature is wrong, bad packet.
-+   STAT_NEED_KEY need DNSKEY to complete validation (name is returned in keyname)
-+   STAT_NEED_DS  need DS to complete validation (name is returned in keyname)
-+
-+   if key is non-NULL, use that key, which has the algo and tag given in the params of those names,
-+   otherwise find the key in the cache.
--  /* no RRSIGs */
--  if (sigidx == 0)
--    return STAT_NO_SIG; 
-+   name is unchanged on exit. keyname is used as workspace and trashed.
-+
-+   Call explore_rrset first to find and count RRs and sigs.
-+*/
-+static int validate_rrset(time_t now, struct dns_header *header, size_t plen, int class, int type, int sigidx, int rrsetidx, 
-+                        char *name, char *keyname, char **wildcard_out, struct blockdata *key, int keylen, int algo_in, int keytag_in)
-+{
-+  unsigned char *p;
-+  int rdlen, j, name_labels;
-+  struct crec *crecp = NULL;
-+  int algo, labels, orig_ttl, key_tag;
-+  u16 *rr_desc = get_desc(type);
-+ 
-+  if (wildcard_out)
-+    *wildcard_out = NULL;
-   
-+  name_labels = count_labels(name); /* For 4035 5.3.2 check */
-+
-   /* Sort RRset records into canonical order. 
-      Note that at this point keyname and daemon->workspacename buffs are
-      unused, and used as workspace by the sort. */
-@@ -828,44 +879,16 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
-       algo = *p++;
-       labels = *p++;
-       GETLONG(orig_ttl, p);
--      GETLONG(sig_expiration, p);
--      GETLONG(sig_inception, p);
-+      p += 8; /* sig_expiration, sig_inception already checked */
-       GETSHORT(key_tag, p);
-       
-       if (!extract_name(header, plen, &p, keyname, 1, 0))
-       return STAT_BOGUS;
--      /* RFC 4035 5.3.1 says that the Signer's Name field MUST equal
--       the name of the zone containing the RRset. We can't tell that
--       for certain, but we can check that  the RRset name is equal to
--       or encloses the signers name, which should be enough to stop 
--       an attacker using signatures made with the key of an unrelated 
--       zone he controls. Note that the root key is always allowed. */
--      if (*keyname != 0)
--      {
--        int failed = 0;
--        
--        for (name_start = name; !hostname_isequal(name_start, keyname); )
--          if ((name_start = strchr(name_start, '.')))
--            name_start++; /* chop a label off and try again */
--          else
--            {
--              failed = 1;
--              break;
--            }
--
--        /* Bad sig, try another */
--        if (failed)
--          continue;
--      }
--      
--      /* Other 5.3.1 checks */
--      if (!check_date_range(sig_inception, sig_expiration) ||
--        labels > name_labels ||
--        !(hash = hash_find(algo_digest_name(algo))) ||
-+      if (!(hash = hash_find(algo_digest_name(algo))) ||
-         !hash_init(hash, &ctx, &digest))
-       continue;
--      
-+      
-       /* OK, we have the signature record, see if the relevant DNSKEY is in the cache. */
-       if (!key && !(crecp = cache_find_by_name(NULL, keyname, now, F_DNSKEY)))
-       return STAT_NEED_KEY;
-@@ -971,10 +994,11 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
- /* The DNS packet is expected to contain the answer to a DNSKEY query.
-    Put all DNSKEYs in the answer which are valid into the cache.
-    return codes:
--         STAT_SECURE   At least one valid DNSKEY found and in cache.
--       STAT_BOGUS    No DNSKEYs found, which  can be validated with DS,
--                     or self-sign for DNSKEY RRset is not valid, bad packet.
--       STAT_NEED_DS  DS records to validate a key not found, name in keyname 
-+         STAT_OK           Done, key(s) in cache.
-+       STAT_BOGUS        No DNSKEYs found, which  can be validated with DS,
-+                         or self-sign for DNSKEY RRset is not valid, bad packet.
-+       STAT_NEED_DS      DS records to validate a key not found, name in keyname 
-+       STAT_NEED_DNSKEY  DNSKEY records to validate a key not found, name in keyname 
- */
- int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class)
- {
-@@ -1001,23 +1025,6 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
-       return STAT_NEED_DS;
-     }
-   
--  /* If we've cached that DS provably doesn't exist, result must be INSECURE */
--  if (crecp->flags & F_NEG)
--    return STAT_INSECURE_DS;
--  
--  /* 4035 5.2 
--     If the validator does not support any of the algorithms listed in an
--     authenticated DS RRset, then the resolver has no supported
--     authentication path leading from the parent to the child.  The
--     resolver should treat this case as it would the case of an
--     authenticated NSEC RRset proving that no DS RRset exists,  */
--  for (recp1 = crecp; recp1; recp1 = cache_find_by_name(recp1, name, now, F_DS))
--    if (hash_find(ds_digest_name(recp1->addr.ds.digest)))
--      break;
--  
--  if (!recp1)
--    return STAT_INSECURE_DS;
--
-   /* NOTE, we need to find ONE DNSKEY which matches the DS */
-   for (valid = 0, j = ntohs(header->ancount); j != 0 && !valid; j--) 
-     {
-@@ -1070,7 +1077,8 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
-         void *ctx;
-         unsigned char *digest, *ds_digest;
-         const struct nettle_hash *hash;
--        
-+        int sigcnt, rrcnt;
-+
-         if (recp1->addr.ds.algo == algo && 
-             recp1->addr.ds.keytag == keytag &&
-             recp1->uid == (unsigned int)class &&
-@@ -1088,10 +1096,14 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
-             
-             from_wire(name);
-             
--            if (recp1->addr.ds.keylen == (int)hash->digest_size &&
-+            if (!(recp1->flags & F_NEG) &&
-+                recp1->addr.ds.keylen == (int)hash->digest_size &&
-                 (ds_digest = blockdata_retrieve(recp1->addr.key.keydata, recp1->addr.ds.keylen, NULL)) &&
-                 memcmp(ds_digest, digest, recp1->addr.ds.keylen) == 0 &&
--                validate_rrset(now, header, plen, class, T_DNSKEY, name, keyname, NULL, key, rdlen - 4, algo, keytag) == STAT_SECURE)
-+                explore_rrset(header, plen, class, T_DNSKEY, name, keyname, &sigcnt, &rrcnt) &&
-+                sigcnt != 0 && rrcnt != 0 &&
-+                validate_rrset(now, header, plen, class, T_DNSKEY, sigcnt, rrcnt, name, keyname, 
-+                               NULL, key, rdlen - 4, algo, keytag) == STAT_SECURE)
-               {
-                 valid = 1;
-                 break;
-@@ -1112,7 +1124,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
-       {
-         /* Ensure we have type, class  TTL and length */
-         if (!(rc = extract_name(header, plen, &p, name, 0, 10)))
--          return STAT_INSECURE; /* bad packet */
-+          return STAT_BOGUS; /* bad packet */
-         
-         GETSHORT(qtype, p); 
-         GETSHORT(qclass, p);
-@@ -1198,7 +1210,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
-       
-       /* commit cache insert. */
-       cache_end_insert();
--      return STAT_SECURE;
-+      return STAT_OK;
-     }
-   log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DNSKEY");
-@@ -1207,12 +1219,14 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
- /* The DNS packet is expected to contain the answer to a DS query
-    Put all DSs in the answer which are valid into the cache.
-+   Also handles replies which prove that there's no DS at this location, 
-+   either because the zone is unsigned or this isn't a zone cut. These are
-+   cached too.
-    return codes:
--   STAT_SECURE      At least one valid DS found and in cache.
--   STAT_NO_DS       It's proved there's no DS here.
--   STAT_NO_NS       It's proved there's no DS _or_ NS here.
-+   STAT_OK          At least one valid DS found and in cache.
-    STAT_BOGUS       no DS in reply or not signed, fails validation, bad packet.
-    STAT_NEED_KEY    DNSKEY records to validate a DS not found, name in keyname
-+   STAT_NEED_DS     DS record needed.
- */
- int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class)
-@@ -1230,7 +1244,7 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
-   if (qtype != T_DS || qclass != class)
-     val = STAT_BOGUS;
-   else
--    val = dnssec_validate_reply(now, header, plen, name, keyname, NULL, &neganswer, &nons);
-+    val = dnssec_validate_reply(now, header, plen, name, keyname, NULL, 0, &neganswer, &nons);
-   /* Note dnssec_validate_reply() will have cached positive answers */
-   
-   if (val == STAT_INSECURE)
-@@ -1242,22 +1256,21 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
-   
-   if (!(p = skip_section(p, ntohs(header->ancount), header, plen)))
-     val = STAT_BOGUS;
--   
--  /* If we return STAT_NO_SIG, name contains the name of the DS query */
--  if (val == STAT_NO_SIG)
--    return val;
-   
-   /* If the key needed to validate the DS is on the same domain as the DS, we'll
-      loop getting nowhere. Stop that now. This can happen of the DS answer comes
-      from the DS's zone, and not the parent zone. */
--  if (val == STAT_BOGUS ||  (val == STAT_NEED_KEY && hostname_isequal(name, keyname)))
-+  if (val == STAT_BOGUS || (val == STAT_NEED_KEY && hostname_isequal(name, keyname)))
-     {
-       log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS");
-       return STAT_BOGUS;
-     }
-+  
-+  if (val != STAT_SECURE)
-+    return val;
-   /* By here, the answer is proved secure, and a positive answer has been cached. */
--  if (val == STAT_SECURE && neganswer)
-+  if (neganswer)
-     {
-       int rdlen, flags = F_FORWARD | F_DS | F_NEG | F_DNSSECOK;
-       unsigned long ttl, minttl = ULONG_MAX;
-@@ -1317,15 +1330,14 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
-         
-         cache_end_insert();  
-         
--        log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, nons ? "no delegation" : "no DS");
-+        log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "no DS");
-       }
--
--      return nons ? STAT_NO_NS : STAT_NO_DS; 
-     }
--  return val;
-+  return STAT_OK;
- }
-+
- /* 4034 6.1 */
- static int hostname_cmp(const char *a, const char *b)
- {
-@@ -1452,7 +1464,7 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
-   int mask = 0x80 >> (type & 0x07);
-   if (nons)
--    *nons = 0;
-+    *nons = 1;
-   
-   /* Find NSEC record that proves name doesn't exist */
-   for (i = 0; i < nsec_count; i++)
-@@ -1480,9 +1492,22 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
-         /* rdlen is now length of type map, and p points to it */
-         
-         /* If we can prove that there's no NS record, return that information. */
--        if (nons && rdlen >= 2 && p[0] == 0 && (p[2] & (0x80 >> T_NS)) == 0)
--          *nons = 1;
-+        if (nons && rdlen >= 2 && p[0] == 0 && (p[2] & (0x80 >> T_NS)) != 0)
-+          *nons = 0;
-         
-+        if (rdlen >= 2 && p[0] == 0)
-+          {
-+            /* A CNAME answer would also be valid, so if there's a CNAME is should 
-+               have been returned. */
-+            if ((p[2] & (0x80 >> T_CNAME)) != 0)
-+              return STAT_BOGUS;
-+            
-+            /* If the SOA bit is set for a DS record, then we have the
-+               DS from the wrong side of the delegation. */
-+            if (type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
-+              return STAT_BOGUS;
-+          }
-+
-         while (rdlen >= 2)
-           {
-             if (!CHECK_LEN(header, p, plen, rdlen))
-@@ -1586,7 +1611,7 @@ static int base32_decode(char *in, unsigned char *out)
- static int check_nsec3_coverage(struct dns_header *header, size_t plen, int digest_len, unsigned char *digest, int type,
-                               char *workspace1, char *workspace2, unsigned char **nsecs, int nsec_count, int *nons)
- {
--  int i, hash_len, salt_len, base32_len, rdlen;
-+  int i, hash_len, salt_len, base32_len, rdlen, flags;
-   unsigned char *p, *psave;
-   for (i = 0; i < nsec_count; i++)
-@@ -1599,7 +1624,9 @@ static int check_nsec3_coverage(struct dns_header *header, size_t plen, int dige
-       p += 8; /* class, type, TTL */
-       GETSHORT(rdlen, p);
-       psave = p;
--      p += 4; /* algo, flags, iterations */
-+      p++; /* algo */
-+      flags = *p++; /* flags */
-+      p += 2; /* iterations */
-       salt_len = *p++; /* salt_len */
-       p += salt_len; /* salt */
-       hash_len = *p++; /* p now points to next hashed name */
-@@ -1626,16 +1653,29 @@ static int check_nsec3_coverage(struct dns_header *header, size_t plen, int dige
-                 return 0;
-               
-               /* If we can prove that there's no NS record, return that information. */
--              if (nons && rdlen >= 2 && p[0] == 0 && (p[2] & (0x80 >> T_NS)) == 0)
--                *nons = 1;
-+              if (nons && rdlen >= 2 && p[0] == 0 && (p[2] & (0x80 >> T_NS)) != 0)
-+                *nons = 0;
-               
-+              if (rdlen >= 2 && p[0] == 0)
-+                {
-+                  /* A CNAME answer would also be valid, so if there's a CNAME is should 
-+                     have been returned. */
-+                  if ((p[2] & (0x80 >> T_CNAME)) != 0)
-+                    return 0;
-+                  
-+                  /* If the SOA bit is set for a DS record, then we have the
-+                     DS from the wrong side of the delegation. */
-+                  if (type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
-+                    return 0;
-+                }
-+
-               while (rdlen >= 2)
-                 {
-                   if (p[0] == type >> 8)
-                     {
-                       /* Does the NSEC3 say our type exists? */
-                       if (offset < p[1] && (p[offset+2] & mask) != 0)
--                        return STAT_BOGUS;
-+                        return 0;
-                       
-                       break; /* finshed checking */
-                     }
-@@ -1643,7 +1683,7 @@ static int check_nsec3_coverage(struct dns_header *header, size_t plen, int dige
-                   rdlen -= p[1];
-                   p +=  p[1];
-                 }
--
-+              
-               return 1;
-             }
-           else if (rc < 0)
-@@ -1651,16 +1691,27 @@ static int check_nsec3_coverage(struct dns_header *header, size_t plen, int dige
-               /* Normal case, hash falls between NSEC3 name-hash and next domain name-hash,
-                  wrap around case, name-hash falls between NSEC3 name-hash and end */
-               if (memcmp(p, digest, digest_len) >= 0 || memcmp(workspace2, p, digest_len) >= 0)
--                return 1;
-+                {
-+                  if ((flags & 0x01) && nons) /* opt out */
-+                    *nons = 0;
-+
-+                  return 1;
-+                }
-             }
-           else 
-             {
-               /* wrap around case, name falls between start and next domain name */
-               if (memcmp(workspace2, p, digest_len) >= 0 && memcmp(p, digest, digest_len) >= 0)
--                return 1;
-+                {
-+                  if ((flags & 0x01) && nons) /* opt out */
-+                    *nons = 0;
-+
-+                  return 1;
-+                }
-             }
-         }
-       }
-+
-   return 0;
- }
-@@ -1673,7 +1724,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
-   char *closest_encloser, *next_closest, *wildcard;
-   
-   if (nons)
--    *nons = 0;
-+    *nons = 1;
-   
-   /* Look though the NSEC3 records to find the first one with 
-      an algorithm we support (currently only algo == 1).
-@@ -1813,16 +1864,81 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
-   
-   return STAT_SECURE;
- }
--    
--/* Validate all the RRsets in the answer and authority sections of the reply (4035:3.2.3) */
--/* Returns are the same as validate_rrset, plus the class if the missing key is in *class */
-+
-+/* Check signing status of name.
-+   returns:
-+   STAT_SECURE zone is signed.
-+   STAT_INSECURE zone proved unsigned.
-+   STAT_NEED_DS require DS record of name returned in keyname.
-+   
-+   name returned unaltered.
-+*/
-+static int zone_status(char *name, int class, char *keyname, time_t now)
-+{
-+  int name_start = strlen(name);
-+  struct crec *crecp;
-+  char *p;
-+  
-+  while (1)
-+    {
-+      strcpy(keyname, &name[name_start]);
-+      
-+      if (!(crecp = cache_find_by_name(NULL, keyname, now, F_DS)))
-+      return STAT_NEED_DS;
-+      else
-+      do 
-+        {
-+          if (crecp->uid == (unsigned int)class)
-+            {
-+              /* F_DNSSECOK misused in DS cache records to non-existance of NS record.
-+                 F_NEG && !F_DNSSECOK implies that we've proved there's no DS record here,
-+                 but that's because there's no NS record either, ie this isn't the start
-+                 of a zone. We only prove that the DNS tree below a node is unsigned when
-+                 we prove that we're at a zone cut AND there's no DS record.
-+              */        
-+              if (crecp->flags & F_NEG)
-+                {
-+                  if (crecp->flags & F_DNSSECOK)
-+                    return STAT_INSECURE; /* proved no DS here */
-+                }
-+              else if (!ds_digest_name(crecp->addr.ds.digest) || !algo_digest_name(crecp->addr.ds.algo))
-+                return STAT_INSECURE; /* algo we can't use - insecure */
-+            }
-+        }
-+      while ((crecp = cache_find_by_name(crecp, keyname, now, F_DS)));
-+      
-+      if (name_start == 0)
-+      break;
-+
-+      for (p = &name[name_start-2]; (*p != '.') && (p != name); p--);
-+      
-+      if (p != name)
-+        p++;
-+      
-+      name_start = p - name;
-+    } 
-+
-+  return STAT_SECURE;
-+}
-+       
-+/* Validate all the RRsets in the answer and authority sections of the reply (4035:3.2.3) 
-+   Return code:
-+   STAT_SECURE   if it validates.
-+   STAT_INSECURE at least one RRset not validated, because in unsigned zone.
-+   STAT_BOGUS    signature is wrong, bad packet, no validation where there should be.
-+   STAT_NEED_KEY need DNSKEY to complete validation (name is returned in keyname, class in *class)
-+   STAT_NEED_DS  need DS to complete validation (name is returned in keyname) 
-+*/
- int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, 
--                        int *class, int *neganswer, int *nons)
-+                        int *class, int check_unsigned, int *neganswer, int *nons)
- {
--  unsigned char *ans_start, *qname, *p1, *p2, **nsecs;
--  int type1, class1, rdlen1, type2, class2, rdlen2, qclass, qtype;
--  int i, j, rc, nsec_count, cname_count = CNAME_CHAIN;
--  int nsec_type = 0, have_answer = 0;
-+  static unsigned char **targets = NULL;
-+  static int target_sz = 0;
-+
-+  unsigned char *ans_start, *p1, *p2, **nsecs;
-+  int type1, class1, rdlen1, type2, class2, rdlen2, qclass, qtype, targetidx;
-+  int i, j, rc, nsec_count;
-+  int nsec_type;
-   if (neganswer)
-     *neganswer = 0;
-@@ -1833,70 +1949,51 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
-   if (RCODE(header) != NXDOMAIN && RCODE(header) != NOERROR)
-     return STAT_INSECURE;
--  qname = p1 = (unsigned char *)(header+1);
-+  p1 = (unsigned char *)(header+1);
-   
-+   /* Find all the targets we're looking for answers to.
-+     The zeroth array element is for the query, subsequent ones
-+     for CNAME targets, unless the query is for a CNAME. */
-+
-+  if (!expand_workspace(&targets, &target_sz, 0))
-+    return STAT_BOGUS;
-+  
-+  targets[0] = p1;
-+  targetidx = 1;
-+   
-   if (!extract_name(header, plen, &p1, name, 1, 4))
-     return STAT_BOGUS;
--
-+  
-   GETSHORT(qtype, p1);
-   GETSHORT(qclass, p1);
-   ans_start = p1;
--
--  if (qtype == T_ANY)
--    have_answer = 1;
-  
--  /* Can't validate an RRISG query */
-+  /* Can't validate an RRSIG query */
-   if (qtype == T_RRSIG)
-     return STAT_INSECURE;
-- 
-- cname_loop:
--  for (j = ntohs(header->ancount); j != 0; j--) 
--    {
--      /* leave pointer to missing name in qname */
--           
--      if (!(rc = extract_name(header, plen, &p1, name, 0, 10)))
--      return STAT_BOGUS; /* bad packet */
--      
--      GETSHORT(type2, p1); 
--      GETSHORT(class2, p1);
--      p1 += 4; /* TTL */
--      GETSHORT(rdlen2, p1);
--
--      if (rc == 1 && qclass == class2)
--      {
--        /* Do we have an answer for the question? */
--        if (type2 == qtype)
--          {
--            have_answer = 1;
--            break;
--          }
--        else if (type2 == T_CNAME)
--          {
--            qname = p1;
--            
--            /* looped CNAMES */
--            if (!cname_count-- || !extract_name(header, plen, &p1, name, 1, 0))
--              return STAT_BOGUS;
--             
--            p1 = ans_start;
--            goto cname_loop;
--          }
--      } 
--
--      if (!ADD_RDLEN(header, p1, plen, rdlen2))
--      return STAT_BOGUS;
--    }
--   
--  if (neganswer && !have_answer)
--    *neganswer = 1;
-   
--  /* No data, therefore no sigs */
--  if (ntohs(header->ancount) + ntohs(header->nscount) == 0)
--    {
--      *keyname = 0;
--      return STAT_NO_SIG;
--    }
--
-+  if (qtype != T_CNAME)
-+    for (j = ntohs(header->ancount); j != 0; j--) 
-+      {
-+      if (!(p1 = skip_name(p1, header, plen, 10)))
-+        return STAT_BOGUS; /* bad packet */
-+      
-+      GETSHORT(type2, p1); 
-+      p1 += 6; /* class, TTL */
-+      GETSHORT(rdlen2, p1);  
-+      
-+      if (type2 == T_CNAME)
-+        {
-+          if (!expand_workspace(&targets, &target_sz, targetidx))
-+            return STAT_BOGUS;
-+          
-+          targets[targetidx++] = p1; /* pointer to target name */
-+        }
-+      
-+      if (!ADD_RDLEN(header, p1, plen, rdlen2))
-+        return STAT_BOGUS;
-+      }
-+  
-   for (p1 = ans_start, i = 0; i < ntohs(header->ancount) + ntohs(header->nscount); i++)
-     {
-       if (!extract_name(header, plen, &p1, name, 1, 10))
-@@ -1931,7 +2028,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
-         /* Not done, validate now */
-         if (j == i)
-           {
--            int ttl, keytag, algo, digest, type_covered;
-+            int ttl, keytag, algo, digest, type_covered, sigcnt, rrcnt;
-             unsigned char *psave;
-             struct all_addr a;
-             struct blockdata *key;
-@@ -1939,143 +2036,186 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
-             char *wildname;
-             int have_wildcard = 0;
--            rc = validate_rrset(now, header, plen, class1, type1, name, keyname, &wildname, NULL, 0, 0, 0);
--            
--            if (rc == STAT_SECURE_WILDCARD)
--              {
--                have_wildcard = 1;
--
--                /* An attacker replay a wildcard answer with a different
--                   answer and overlay a genuine RR. To prove this
--                   hasn't happened, the answer must prove that
--                   the gennuine record doesn't exist. Check that here. */
--                if (!nsec_type && !(nsec_type = find_nsec_records(header, plen, &nsecs, &nsec_count, class1)))
--                  return STAT_BOGUS; /* No NSECs or bad packet */
--                
--                if (nsec_type == T_NSEC)
--                  rc = prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, type1, NULL);
--                else
--                  rc = prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename, 
--                                                 keyname, name, type1, wildname, NULL);
--                
--                if (rc != STAT_SECURE)
--                  return rc;
--              } 
--            else if (rc != STAT_SECURE)
--              {
--                if (class)
--                  *class = class1; /* Class for DS or DNSKEY */
-+            if (!explore_rrset(header, plen, class1, type1, name, keyname, &sigcnt, &rrcnt))
-+              return STAT_BOGUS;
--                if (rc == STAT_NO_SIG)
-+            /* No signatures for RRset. We can be configured to assume this is OK and return a INSECURE result. */
-+            if (sigcnt == 0)
-+              {
-+                if (check_unsigned)
-                   {
--                    /* If we dropped off the end of a CNAME chain, return
--                       STAT_NO_SIG and the last name is keyname. This is used for proving non-existence
--                       if DS records in CNAME chains. */
--                    if (cname_count == CNAME_CHAIN || i < ntohs(header->ancount)) 
--                      /* No CNAME chain, or no sig in answer section, return empty name. */
--                      *keyname = 0;
--                    else if (!extract_name(header, plen, &qname, keyname, 1, 0))
--                      return STAT_BOGUS;
-+                    rc = zone_status(name, class1, keyname, now);
-+                    if (rc == STAT_SECURE)
-+                      rc = STAT_BOGUS;
-+                     if (class)
-+                       *class = class1; /* Class for NEED_DS or NEED_DNSKEY */
-                   }
-- 
-+                else 
-+                  rc = STAT_INSECURE; 
-+                
-                 return rc;
-               }
-             
--            /* Cache RRsigs in answer section, and if we just validated a DS RRset, cache it */
--            cache_start_insert();
-+            /* explore_rrset() gives us key name from sigs in keyname.
-+               Can't overwrite name here. */
-+            strcpy(daemon->workspacename, keyname);
-+            rc = zone_status(daemon->workspacename, class1, keyname, now);
-+            if (rc != STAT_SECURE)
-+              {
-+                /* Zone is insecure, don't need to validate RRset */
-+                if (class)
-+                  *class = class1; /* Class for NEED_DS or NEED_DNSKEY */
-+                return rc;
-+              } 
-+            
-+            rc = validate_rrset(now, header, plen, class1, type1, sigcnt, rrcnt, name, keyname, &wildname, NULL, 0, 0, 0);
-             
--            for (p2 = ans_start, j = 0; j < ntohs(header->ancount); j++)
-+            if (rc == STAT_BOGUS || rc == STAT_NEED_KEY || rc == STAT_NEED_DS)
-               {
--                if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
--                  return STAT_BOGUS; /* bad packet */
-+                if (class)
-+                  *class = class1; /* Class for DS or DNSKEY */
-+                return rc;
-+              } 
-+            else 
-+              {
-+                /* rc is now STAT_SECURE or STAT_SECURE_WILDCARD */
-+               
-+                /* Note if we've validated either the answer to the question
-+                   or the target of a CNAME. Any not noted will need NSEC or
-+                   to be in unsigned space. */
-+
-+                for (j = 0; j <targetidx; j++)
-+                  if ((p2 = targets[j]))
-+                    {
-+                      if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
-+                        return STAT_BOGUS; /* bad packet */
-+                      
-+                      if (class1 == qclass && rc == 1 && (type1 == T_CNAME || type1 == qtype || qtype == T_ANY ))
-+                        targets[j] = NULL;
-+                    }
-+                          
-+                if (rc == STAT_SECURE_WILDCARD)
-+                  {
-+                    have_wildcard = 1;
-                     
--                GETSHORT(type2, p2);
--                GETSHORT(class2, p2);
--                GETLONG(ttl, p2);
--                GETSHORT(rdlen2, p2);
--                     
--                if (!CHECK_LEN(header, p2, plen, rdlen2))
--                  return STAT_BOGUS; /* bad packet */
--                
--                if (class2 == class1 && rc == 1)
--                  { 
--                    psave = p2;
-+                    /* An attacker replay a wildcard answer with a different
-+                       answer and overlay a genuine RR. To prove this
-+                       hasn't happened, the answer must prove that
-+                       the gennuine record doesn't exist. Check that here. */
-+                    if (!(nsec_type = find_nsec_records(header, plen, &nsecs, &nsec_count, class1)))
-+                      return STAT_BOGUS; /* No NSECs or bad packet */
-+                    
-+                    /* Note that we may not yet have validated the NSEC/NSEC3 RRsets. Since the check
-+                       below returns either SECURE or BOGUS, that's not a problem. If the RRsets later fail
-+                       we'll return BOGUS then. */
--                    if (type1 == T_DS && type2 == T_DS)
--                      {
--                        if (rdlen2 < 4)
--                          return STAT_BOGUS; /* bad packet */
--                        
--                        GETSHORT(keytag, p2);
--                        algo = *p2++;
--                        digest = *p2++;
--                        
--                        /* Cache needs to known class for DNSSEC stuff */
--                        a.addr.dnssec.class = class2;
--                        
--                        if ((key = blockdata_alloc((char*)p2, rdlen2 - 4)))
--                          {
--                            if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DS | F_DNSSECOK)))
--                              blockdata_free(key);
--                            else
--                              {
--                                a.addr.keytag = keytag;
--                                log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u");
--                                crecp->addr.ds.digest = digest;
--                                crecp->addr.ds.keydata = key;
--                                crecp->addr.ds.algo = algo;
--                                crecp->addr.ds.keytag = keytag;
--                                crecp->addr.ds.keylen = rdlen2 - 4; 
--                              } 
--                          }
--                      }
--                    else if (type2 == T_RRSIG)
--                      {
--                        if (rdlen2 < 18)
--                          return STAT_BOGUS; /* bad packet */
-+                    if (nsec_type == T_NSEC)
-+                      rc = prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, type1, NULL);
-+                    else
-+                      rc = prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename, 
-+                                                     keyname, name, type1, wildname, NULL);
-+                    
-+                    if (rc == STAT_BOGUS)
-+                      return rc;
-+                  } 
-+                
-+                /* Cache RRsigs in answer section, and if we just validated a DS RRset, cache it */
-+                /* Also note if the RRset is the answer to the question, or the target of a CNAME */
-+                cache_start_insert();
-+                
-+                for (p2 = ans_start, j = 0; j < ntohs(header->ancount); j++)
-+                  {
-+                    if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
-+                      return STAT_BOGUS; /* bad packet */
-+                    
-+                    GETSHORT(type2, p2);
-+                    GETSHORT(class2, p2);
-+                    GETLONG(ttl, p2);
-+                    GETSHORT(rdlen2, p2);
-+                    
-+                    if (!CHECK_LEN(header, p2, plen, rdlen2))
-+                      return STAT_BOGUS; /* bad packet */
-+                    
-+                    if (class2 == class1 && rc == 1)
-+                      { 
-+                        psave = p2;
-                         
--                        GETSHORT(type_covered, p2);
--
--                        if (type_covered == type1 && 
--                            (type_covered == T_A || type_covered == T_AAAA ||
--                             type_covered == T_CNAME || type_covered == T_DS || 
--                             type_covered == T_DNSKEY || type_covered == T_PTR)) 
-+                        if (type1 == T_DS && type2 == T_DS)
-                           {
--                            a.addr.dnssec.type = type_covered;
--                            a.addr.dnssec.class = class1;
-+                            if (rdlen2 < 4)
-+                              return STAT_BOGUS; /* bad packet */
-                             
--                            algo = *p2++;
--                            p2 += 13; /* labels, orig_ttl, expiration, inception */
-                             GETSHORT(keytag, p2);
-+                            algo = *p2++;
-+                            digest = *p2++;
-+                            
-+                            /* Cache needs to known class for DNSSEC stuff */
-+                            a.addr.dnssec.class = class2;
-                             
--                            /* We don't cache sigs for wildcard answers, because to reproduce the
--                               answer from the cache will require one or more NSEC/NSEC3 records 
--                               which we don't cache. The lack of the RRSIG ensures that a query for
--                               this RRset asking for a secure answer will always be forwarded. */
--                            if (!have_wildcard && (key = blockdata_alloc((char*)psave, rdlen2)))
-+                            if ((key = blockdata_alloc((char*)p2, rdlen2 - 4)))
-                               {
--                                if (!(crecp = cache_insert(name, &a, now, ttl,  F_FORWARD | F_DNSKEY | F_DS)))
-+                                if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DS | F_DNSSECOK)))
-                                   blockdata_free(key);
-                                 else
-                                   {
--                                    crecp->addr.sig.keydata = key;
--                                    crecp->addr.sig.keylen = rdlen2;
--                                    crecp->addr.sig.keytag = keytag;
--                                    crecp->addr.sig.type_covered = type_covered;
--                                    crecp->addr.sig.algo = algo;
-+                                    a.addr.keytag = keytag;
-+                                    log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u");
-+                                    crecp->addr.ds.digest = digest;
-+                                    crecp->addr.ds.keydata = key;
-+                                    crecp->addr.ds.algo = algo;
-+                                    crecp->addr.ds.keytag = keytag;
-+                                    crecp->addr.ds.keylen = rdlen2 - 4; 
-+                                  } 
-+                              }
-+                          }
-+                        else if (type2 == T_RRSIG)
-+                          {
-+                            if (rdlen2 < 18)
-+                              return STAT_BOGUS; /* bad packet */
-+                            
-+                            GETSHORT(type_covered, p2);
-+                            
-+                            if (type_covered == type1 && 
-+                                (type_covered == T_A || type_covered == T_AAAA ||
-+                                 type_covered == T_CNAME || type_covered == T_DS || 
-+                                 type_covered == T_DNSKEY || type_covered == T_PTR)) 
-+                              {
-+                                a.addr.dnssec.type = type_covered;
-+                                a.addr.dnssec.class = class1;
-+                                
-+                                algo = *p2++;
-+                                p2 += 13; /* labels, orig_ttl, expiration, inception */
-+                                GETSHORT(keytag, p2);
-+                                
-+                                /* We don't cache sigs for wildcard answers, because to reproduce the
-+                                   answer from the cache will require one or more NSEC/NSEC3 records 
-+                                   which we don't cache. The lack of the RRSIG ensures that a query for
-+                                   this RRset asking for a secure answer will always be forwarded. */
-+                                if (!have_wildcard && (key = blockdata_alloc((char*)psave, rdlen2)))
-+                                  {
-+                                    if (!(crecp = cache_insert(name, &a, now, ttl,  F_FORWARD | F_DNSKEY | F_DS)))
-+                                      blockdata_free(key);
-+                                    else
-+                                      {
-+                                        crecp->addr.sig.keydata = key;
-+                                        crecp->addr.sig.keylen = rdlen2;
-+                                        crecp->addr.sig.keytag = keytag;
-+                                        crecp->addr.sig.type_covered = type_covered;
-+                                        crecp->addr.sig.algo = algo;
-+                                      }
-                                   }
-                               }
-                           }
-+                        
-+                        p2 = psave;
-                       }
-                     
--                    p2 = psave;
-+                    if (!ADD_RDLEN(header, p2, plen, rdlen2))
-+                      return STAT_BOGUS; /* bad packet */
-                   }
-                 
--                if (!ADD_RDLEN(header, p2, plen, rdlen2))
--                  return STAT_BOGUS; /* bad packet */
-+                cache_end_insert();
-               }
--                
--            cache_end_insert();
-           }
-       }
-@@ -2083,143 +2223,49 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
-       return STAT_BOGUS;
-     }
--  /* OK, all the RRsets validate, now see if we have a NODATA or NXDOMAIN reply */
--  if (have_answer)
--    return STAT_SECURE;
--     
--  /* NXDOMAIN or NODATA reply, prove that (name, class1, type1) can't exist */
--  /* First marshall the NSEC records, if we've not done it previously */
--  if (!nsec_type && !(nsec_type = find_nsec_records(header, plen, &nsecs, &nsec_count, qclass)))
--    {
--      /* No NSEC records. If we dropped off the end of a CNAME chain, return
--       STAT_NO_SIG and the last name is keyname. This is used for proving non-existence
--       if DS records in CNAME chains. */
--      if (cname_count == CNAME_CHAIN) /* No CNAME chain, return empty name. */
--      *keyname = 0;
--      else if (!extract_name(header, plen, &qname, keyname, 1, 0))
--      return STAT_BOGUS;
--      return STAT_NO_SIG; /* No NSECs, this is probably a dangling CNAME pointing into
--                           an unsigned zone. Return STAT_NO_SIG to cause this to be proved. */
--    }
--   
--  /* Get name of missing answer */
--  if (!extract_name(header, plen, &qname, name, 1, 0))
--    return STAT_BOGUS;
--  
--  if (nsec_type == T_NSEC)
--    return prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, qtype, nons);
--  else
--    return prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, qtype, NULL, nons);
--}
--
--/* Chase the CNAME chain in the packet until the first record which _doesn't validate.
--   Needed for proving answer in unsigned space.
--   Return STAT_NEED_* 
--          STAT_BOGUS - error
--          STAT_INSECURE - name of first non-secure record in name 
--*/
--int dnssec_chase_cname(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname)
--{
--  unsigned char *p = (unsigned char *)(header+1);
--  int type, class, qclass, rdlen, j, rc;
--  int cname_count = CNAME_CHAIN;
--  char *wildname;
--
--  /* Get question */
--  if (!extract_name(header, plen, &p, name, 1, 4))
--    return STAT_BOGUS;
--  
--  p +=2; /* type */
--  GETSHORT(qclass, p);
--
--  while (1)
--    {
--      for (j = ntohs(header->ancount); j != 0; j--) 
--      {
--        if (!(rc = extract_name(header, plen, &p, name, 0, 10)))
--          return STAT_BOGUS; /* bad packet */
--        
--        GETSHORT(type, p); 
--        GETSHORT(class, p);
--        p += 4; /* TTL */
--        GETSHORT(rdlen, p);
--
--        /* Not target, loop */
--        if (rc == 2 || qclass != class)
--          {
--            if (!ADD_RDLEN(header, p, plen, rdlen))
--              return STAT_BOGUS;
--            continue;
--          }
--        
--        /* Got to end of CNAME chain. */
--        if (type != T_CNAME)
--          return STAT_INSECURE;
--        
--        /* validate CNAME chain, return if insecure or need more data */
--        rc = validate_rrset(now, header, plen, class, type, name, keyname, &wildname, NULL, 0, 0, 0);
--         
--        if (rc == STAT_SECURE_WILDCARD)
--          {
--            int nsec_type, nsec_count, i;
--            unsigned char **nsecs;
--
--            /* An attacker can replay a wildcard answer with a different
--               answer and overlay a genuine RR. To prove this
--               hasn't happened, the answer must prove that
--               the genuine record doesn't exist. Check that here. */
--            if (!(nsec_type = find_nsec_records(header, plen, &nsecs, &nsec_count, class)))
--              return STAT_BOGUS; /* No NSECs or bad packet */
--            
--            /* Note that we're called here because something didn't validate in validate_reply,
--               so we can't assume that any NSEC records have been validated. We do them by steam here */
--
--            for (i = 0; i < nsec_count; i++)
--              {
--                unsigned char *p1 = nsecs[i];
--                
--                if (!extract_name(header, plen, &p1, daemon->workspacename, 1, 0))
--                  return STAT_BOGUS;
--
--                rc = validate_rrset(now, header, plen, class, nsec_type, daemon->workspacename, keyname, NULL, NULL, 0, 0, 0);
-+  /* OK, all the RRsets validate, now see if we have a missing answer or CNAME target. */
-+  for (j = 0; j <targetidx; j++)
-+    if ((p2 = targets[j]))
-+      {
-+      if (neganswer)
-+        *neganswer = 1;
--                /* NSECs can't be wildcards. */
--                if (rc == STAT_SECURE_WILDCARD)
--                  rc = STAT_BOGUS;
-+      if (!extract_name(header, plen, &p2, name, 1, 10))
-+        return STAT_BOGUS; /* bad packet */
-+          
-+      /* NXDOMAIN or NODATA reply, unanswered question is (name, qclass, qtype) */
--                if (rc != STAT_SECURE)
-+      /* For anything other than a DS record, this situation is OK if either
-+         the answer is in an unsigned zone, or there's a NSEC records. */
-+      if (!(nsec_type = find_nsec_records(header, plen, &nsecs, &nsec_count, qclass)))
-+        {
-+          /* Empty DS without NSECS */
-+          if (qtype == T_DS)
-+            return STAT_BOGUS;
-+          else
-+            {
-+              rc = zone_status(name, qclass, keyname, now);
-+              if (rc != STAT_SECURE)
-+                {
-+                  if (class)
-+                    *class = qclass; /* Class for NEED_DS or NEED_DNSKEY */
-                   return rc;
--              }
--
--            if (nsec_type == T_NSEC)
--              rc = prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, type, NULL);
--            else
--              rc = prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename, 
--                                             keyname, name, type, wildname, NULL);
--            
--            if (rc != STAT_SECURE)
--              return rc;
--          }
--        
--        if (rc != STAT_SECURE)
--          {
--            if (rc == STAT_NO_SIG)
--              rc = STAT_INSECURE;
--            return rc;
--          }
-+                } 
-+              
-+              return STAT_BOGUS; /* signed zone, no NSECs */
-+            }
-+        }
--        /* Loop down CNAME chain/ */
--        if (!cname_count-- || 
--            !extract_name(header, plen, &p, name, 1, 0) ||
--            !(p = skip_questions(header, plen)))
--          return STAT_BOGUS;
--        
--        break;
--      }
-+        if (nsec_type == T_NSEC)
-+        rc = prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, qtype, nons);
-+      else
-+        rc = prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, qtype, NULL, nons);
--      /* End of CNAME chain */
--      return STAT_INSECURE;   
--    }
-+      if (rc != STAT_SECURE)
-+        return rc;
-+      }
-+  
-+  return STAT_SECURE;
- }
-diff --git a/src/forward.c b/src/forward.c
-index b76a974..dd22a62 100644
---- a/src/forward.c
-+++ b/src/forward.c
-@@ -23,15 +23,6 @@ static struct frec *lookup_frec_by_sender(unsigned short id,
- static unsigned short get_id(void);
- static void free_frec(struct frec *f);
--#ifdef HAVE_DNSSEC
--static int tcp_key_recurse(time_t now, int status, struct dns_header *header, size_t n, 
--                         int class, char *name, char *keyname, struct server *server, int *keycount);
--static int do_check_sign(struct frec *forward, int status, time_t now, char *name, char *keyname);
--static int send_check_sign(struct frec *forward, time_t now, struct dns_header *header, size_t plen, 
--                         char *name, char *keyname);
--#endif
--
--
- /* Send a UDP packet with its source address set as "source" 
-    unless nowild is true, when we just send it with the kernel default */
- int send_from(int fd, int nowild, char *packet, size_t len, 
-@@ -825,236 +816,142 @@ void reply_query(int fd, int family, time_t now)
- #ifdef HAVE_DNSSEC
-       if (server && option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISABLED))
-       {
--        int status;
-+        int status = 0;
-         /* We've had a reply already, which we're validating. Ignore this duplicate */
-         if (forward->blocking_query)
-           return;
--
--        if (header->hb3 & HB3_TC)
--          {
--            /* Truncated answer can't be validated.
-+        
-+         /* Truncated answer can't be validated.
-                If this is an answer to a DNSSEC-generated query, we still
-                need to get the client to retry over TCP, so return
-                an answer with the TC bit set, even if the actual answer fits.
-             */
--            status = STAT_TRUNCATED;
--          }
--        else if (forward->flags & FREC_DNSKEY_QUERY)
--          status = dnssec_validate_by_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
--        else if (forward->flags & FREC_DS_QUERY)
--          {
--            status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
--            /* Provably no DS, everything below is insecure, even if signatures are offered */
--            if (status == STAT_NO_DS)
--              /* We only cache sigs when we've validated a reply.
--                 Avoid caching a reply with sigs if there's a vaildated break in the 
--                 DS chain, so we don't return replies from cache missing sigs. */
--                      status = STAT_INSECURE_DS;
--            else if (status == STAT_NO_SIG)
--                {
--                  if (option_bool(OPT_DNSSEC_NO_SIGN))
--                    {
--                    status = send_check_sign(forward, now, header, n, daemon->namebuff, daemon->keyname);
--                    if (status == STAT_INSECURE)
--                      status = STAT_INSECURE_DS;
--                  }
--                else
--                  status = STAT_INSECURE_DS;
--              }
--              else if (status == STAT_NO_NS)
--              status = STAT_BOGUS;
--          }
--        else if (forward->flags & FREC_CHECK_NOSIGN)
--          {
--            status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
--            if (status != STAT_NEED_KEY)
--              status = do_check_sign(forward, status, now, daemon->namebuff, daemon->keyname);
--          }
--        else
-+        if (header->hb3 & HB3_TC)
-+          status = STAT_TRUNCATED;
-+        
-+        while (1)
-           {
--            status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class, NULL, NULL);
--            if (status == STAT_NO_SIG)
-+            /* As soon as anything returns BOGUS, we stop and unwind, to do otherwise
-+               would invite infinite loops, since the answers to DNSKEY and DS queries
-+               will not be cached, so they'll be repeated. */
-+            if (status != STAT_BOGUS && status != STAT_TRUNCATED && status != STAT_ABANDONED)
-               {
--                if (option_bool(OPT_DNSSEC_NO_SIGN))
--                  status = send_check_sign(forward, now, header, n, daemon->namebuff, daemon->keyname);
-+                if (forward->flags & FREC_DNSKEY_QUERY)
-+                  status = dnssec_validate_by_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
-+                else if (forward->flags & FREC_DS_QUERY)
-+                  status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
-                 else
--                  status = STAT_INSECURE;
-+                  status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class, 
-+                                                 option_bool(OPT_DNSSEC_NO_SIGN), NULL, NULL);
-               }
--          }
--        /* Can't validate, as we're missing key data. Put this
--           answer aside, whilst we get that. */     
--        if (status == STAT_NEED_DS || status == STAT_NEED_DS_NEG || status == STAT_NEED_KEY)
--          {
--            struct frec *new, *orig;
--            
--            /* Free any saved query */
--            if (forward->stash)
--              blockdata_free(forward->stash);
--            
--            /* Now save reply pending receipt of key data */
--            if (!(forward->stash = blockdata_alloc((char *)header, n)))
--              return;
--            forward->stash_len = n;
-             
--          anotherkey:       
--            /* Find the original query that started it all.... */
--            for (orig = forward; orig->dependent; orig = orig->dependent);
--
--            if (--orig->work_counter == 0 || !(new = get_new_frec(now, NULL, 1)))
--              status = STAT_INSECURE;
--            else
-+            /* Can't validate, as we're missing key data. Put this
-+               answer aside, whilst we get that. */     
-+            if (status == STAT_NEED_DS || status == STAT_NEED_KEY)
-               {
--                int fd;
--                struct frec *next = new->next;
--                *new = *forward; /* copy everything, then overwrite */
--                new->next = next;
--                new->blocking_query = NULL;
--                new->sentto = server;
--                new->rfd4 = NULL;
--                new->orig_domain = NULL;
--#ifdef HAVE_IPV6
--                new->rfd6 = NULL;
--#endif
--                new->flags &= ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_CHECK_NOSIGN);
-+                struct frec *new, *orig;
-                 
--                new->dependent = forward; /* to find query awaiting new one. */
--                forward->blocking_query = new; /* for garbage cleaning */
--                /* validate routines leave name of required record in daemon->keyname */
--                if (status == STAT_NEED_KEY)
--                  {
--                    new->flags |= FREC_DNSKEY_QUERY; 
--                    nn = dnssec_generate_query(header, ((char *) header) + daemon->packet_buff_sz,
--                                               daemon->keyname, forward->class, T_DNSKEY, &server->addr, server->edns_pktsz);
--                  }
--                else 
--                  {
--                    if (status == STAT_NEED_DS_NEG)
--                      new->flags |= FREC_CHECK_NOSIGN;
--                    else
--                      new->flags |= FREC_DS_QUERY;
--                    nn = dnssec_generate_query(header,((char *) header) + daemon->packet_buff_sz,
--                                               daemon->keyname, forward->class, T_DS, &server->addr, server->edns_pktsz);
--                  }
--                if ((hash = hash_questions(header, nn, daemon->namebuff)))
--                  memcpy(new->hash, hash, HASH_SIZE);
--                new->new_id = get_id();
--                header->id = htons(new->new_id);
--                /* Save query for retransmission */
--                if (!(new->stash = blockdata_alloc((char *)header, nn)))
-+                /* Free any saved query */
-+                if (forward->stash)
-+                  blockdata_free(forward->stash);
-+                
-+                /* Now save reply pending receipt of key data */
-+                if (!(forward->stash = blockdata_alloc((char *)header, n)))
-                   return;
--                    
--                new->stash_len = nn;
-+                forward->stash_len = n;
-                 
--                /* Don't resend this. */
--                daemon->srv_save = NULL;
-+                /* Find the original query that started it all.... */
-+                for (orig = forward; orig->dependent; orig = orig->dependent);
-                 
--                if (server->sfd)
--                  fd = server->sfd->fd;
-+                if (--orig->work_counter == 0 || !(new = get_new_frec(now, NULL, 1)))
-+                  status = STAT_ABANDONED;
-                 else
-                   {
--                    fd = -1;
-+                    int fd;
-+                    struct frec *next = new->next;
-+                    *new = *forward; /* copy everything, then overwrite */
-+                    new->next = next;
-+                    new->blocking_query = NULL;
-+                    new->sentto = server;
-+                    new->rfd4 = NULL;
- #ifdef HAVE_IPV6
--                    if (server->addr.sa.sa_family == AF_INET6)
-+                    new->rfd6 = NULL;
-+#endif
-+                    new->flags &= ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY);
-+                    
-+                    new->dependent = forward; /* to find query awaiting new one. */
-+                    forward->blocking_query = new; /* for garbage cleaning */
-+                    /* validate routines leave name of required record in daemon->keyname */
-+                    if (status == STAT_NEED_KEY)
-+                      {
-+                        new->flags |= FREC_DNSKEY_QUERY; 
-+                        nn = dnssec_generate_query(header, ((char *) header) + daemon->packet_buff_sz,
-+                                                   daemon->keyname, forward->class, T_DNSKEY, &server->addr, server->edns_pktsz);
-+                      }
-+                    else 
-                       {
--                        if (new->rfd6 || (new->rfd6 = allocate_rfd(AF_INET6)))
--                          fd = new->rfd6->fd;
-+                        new->flags |= FREC_DS_QUERY;
-+                        nn = dnssec_generate_query(header,((char *) header) + daemon->packet_buff_sz,
-+                                                   daemon->keyname, forward->class, T_DS, &server->addr, server->edns_pktsz);
-                       }
-+                    if ((hash = hash_questions(header, nn, daemon->namebuff)))
-+                      memcpy(new->hash, hash, HASH_SIZE);
-+                    new->new_id = get_id();
-+                    header->id = htons(new->new_id);
-+                    /* Save query for retransmission */
-+                    new->stash = blockdata_alloc((char *)header, nn);
-+                    new->stash_len = nn;
-+                    
-+                    /* Don't resend this. */
-+                    daemon->srv_save = NULL;
-+                    
-+                    if (server->sfd)
-+                      fd = server->sfd->fd;
-                     else
-+                      {
-+                        fd = -1;
-+#ifdef HAVE_IPV6
-+                        if (server->addr.sa.sa_family == AF_INET6)
-+                          {
-+                            if (new->rfd6 || (new->rfd6 = allocate_rfd(AF_INET6)))
-+                              fd = new->rfd6->fd;
-+                          }
-+                        else
- #endif
-+                          {
-+                            if (new->rfd4 || (new->rfd4 = allocate_rfd(AF_INET)))
-+                              fd = new->rfd4->fd;
-+                          }
-+                      }
-+                    
-+                    if (fd != -1)
-                       {
--                        if (new->rfd4 || (new->rfd4 = allocate_rfd(AF_INET)))
--                          fd = new->rfd4->fd;
-+                        while (retry_send(sendto(fd, (char *)header, nn, 0, 
-+                                                 &server->addr.sa, 
-+                                                 sa_len(&server->addr)))); 
-+                        server->queries++;
-                       }
--                  }
--                
--                if (fd != -1)
--                  {
--                    while (retry_send(sendto(fd, (char *)header, nn, 0, 
--                                             &server->addr.sa, 
--                                             sa_len(&server->addr)))); 
--                    server->queries++;
--                  }
--                
-+                  }             
-                 return;
-               }
--          }
-         
--        /* Ok, we reached far enough up the chain-of-trust that we can validate something.
--           Now wind back down, pulling back answers which wouldn't previously validate
--           and validate them with the new data. Note that if an answer needs multiple
--           keys to validate, we may find another key is needed, in which case we set off
--           down another branch of the tree. Once we get to the original answer 
--           (FREC_DNSSEC_QUERY not set) and it validates, return it to the original requestor. */
--        while (forward->dependent)
--          {
-+            /* Validated original answer, all done. */
-+            if (!forward->dependent)
-+              break;
-+            
-+            /* validated subsdiary query, (and cached result)
-+               pop that and return to the previous query we were working on. */
-             struct frec *prev = forward->dependent;
-             free_frec(forward);
-             forward = prev;
-             forward->blocking_query = NULL; /* already gone */
-             blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
-             n = forward->stash_len;
--            
--            if (status == STAT_SECURE)
--              {
--                if (forward->flags & FREC_DNSKEY_QUERY)
--                  status = dnssec_validate_by_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
--                else if (forward->flags & FREC_DS_QUERY)
--                  {
--                    status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
--                     /* Provably no DS, everything below is insecure, even if signatures are offered */
--                    if (status == STAT_NO_DS)
--                      /* We only cache sigs when we've validated a reply.
--                         Avoid caching a reply with sigs if there's a vaildated break in the 
--                         DS chain, so we don't return replies from cache missing sigs. */
--                      status = STAT_INSECURE_DS;
--                     else if (status == STAT_NO_SIG)
--                       {
--                         if (option_bool(OPT_DNSSEC_NO_SIGN))
--                           {
--                             status = send_check_sign(forward, now, header, n, daemon->namebuff, daemon->keyname); 
--                             if (status == STAT_INSECURE)
--                               status = STAT_INSECURE_DS;
--                           }
--                         else
--                           status = STAT_INSECURE_DS;
--                       }
--                     else if (status == STAT_NO_NS)
--                       status = STAT_BOGUS;
--                  }
--                else if (forward->flags & FREC_CHECK_NOSIGN)
--                  {
--                    status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
--                    if (status != STAT_NEED_KEY)
--                      status = do_check_sign(forward, status, now, daemon->namebuff, daemon->keyname);
--                  }
--                else
--                  {
--                    status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class, NULL, NULL);   
--                    if (status == STAT_NO_SIG)
--                      {
--                        if (option_bool(OPT_DNSSEC_NO_SIGN))
--                          status = send_check_sign(forward, now, header, n, daemon->namebuff, daemon->keyname);
--                        else
--                          status = STAT_INSECURE;
--                      }
--                  }
--             
--                if (status == STAT_NEED_DS || status == STAT_NEED_DS_NEG || status == STAT_NEED_KEY)
--                  goto anotherkey;
--              }
-           }
-+      
-         
-         no_cache_dnssec = 0;
--
--        if (status == STAT_INSECURE_DS)
--          {
--            /* We only cache sigs when we've validated a reply.
--               Avoid caching a reply with sigs if there's a vaildated break in the 
--               DS chain, so we don't return replies from cache missing sigs. */
--            status = STAT_INSECURE;
--            no_cache_dnssec = 1;
--          }
-         
-         if (status == STAT_TRUNCATED)
-           header->hb3 |= HB3_TC;
-@@ -1062,7 +959,7 @@ void reply_query(int fd, int family, time_t now)
-           {
-             char *result, *domain = "result";
-             
--            if (forward->work_counter == 0)
-+            if (status == STAT_ABANDONED)
-               {
-                 result = "ABANDONED";
-                 status = STAT_BOGUS;
-@@ -1072,7 +969,7 @@ void reply_query(int fd, int family, time_t now)
-             
-             if (status == STAT_BOGUS && extract_request(header, n, daemon->namebuff, NULL))
-               domain = daemon->namebuff;
--
-+            
-             log_query(F_KEYTAG | F_SECSTAT, domain, NULL, result);
-           }
-         
-@@ -1415,315 +1312,49 @@ void receive_query(struct listener *listen, time_t now)
- }
- #ifdef HAVE_DNSSEC
--
--/* UDP: we've got an unsigned answer, return STAT_INSECURE if we can prove there's no DS
--   and therefore the answer shouldn't be signed, or STAT_BOGUS if it should be, or 
--   STAT_NEED_DS_NEG and keyname if we need to do the query. */
--static int send_check_sign(struct frec *forward, time_t now, struct dns_header *header, size_t plen, 
--                         char *name, char *keyname)
--{
--  int status = dnssec_chase_cname(now, header, plen, name, keyname);
--  
--  if (status != STAT_INSECURE)
--    return status;
--
--  /* Store the domain we're trying to check. */
--  forward->name_start = strlen(name);
--  forward->name_len = forward->name_start + 1;
--  if (!(forward->orig_domain = blockdata_alloc(name, forward->name_len)))
--    return STAT_BOGUS;
--  
--  return do_check_sign(forward, 0, now, name, keyname);
--}
-- 
--/* We either have a a reply (header non-NULL, or we need to start by looking in the cache */ 
--static int do_check_sign(struct frec *forward, int status, time_t now, char *name, char *keyname)
--{
--  /* get domain we're checking back from blockdata store, it's stored on the original query. */
--  while (forward->dependent && !forward->orig_domain)
--    forward = forward->dependent;
--
--  blockdata_retrieve(forward->orig_domain, forward->name_len, name);
--  
--  while (1)
--    {
--      char *p; 
--
--      if (status == 0)
--      {
--        struct crec *crecp;
--
--        /* Haven't received answer, see if in cache */
--        if (!(crecp = cache_find_by_name(NULL, &name[forward->name_start], now, F_DS)))
--          {
--            /* put name of DS record we're missing into keyname */
--            strcpy(keyname, &name[forward->name_start]);
--            /* and wait for reply to arrive */
--            return STAT_NEED_DS_NEG;
--          }
--
--        /* F_DNSSECOK misused in DS cache records to non-existance of NS record */ 
--        if (!(crecp->flags & F_NEG))
--          status = STAT_SECURE;
--        else if (crecp->flags & F_DNSSECOK)
--          status = STAT_NO_DS;
--        else
--          status = STAT_NO_NS;
--      }
--      
--      /* Have entered non-signed part of DNS tree. */ 
--      if (status == STAT_NO_DS)
--      return forward->dependent ? STAT_INSECURE_DS : STAT_INSECURE;
--
--      if (status == STAT_BOGUS)
--      return STAT_BOGUS;
--
--      if (status == STAT_NO_SIG && *keyname != 0)
--      {
--        /* There is a validated CNAME chain that doesn't end in a DS record. Start 
--           the search again in that domain. */
--        blockdata_free(forward->orig_domain);
--        forward->name_start = strlen(keyname);
--        forward->name_len = forward->name_start + 1;
--        if (!(forward->orig_domain = blockdata_alloc(keyname, forward->name_len)))
--          return STAT_BOGUS;
--        
--        strcpy(name, keyname);
--        status = 0; /* force to cache when we iterate. */
--        continue;
--      }
--      
--      /* There's a proven DS record, or we're within a zone, where there doesn't need
--       to be a DS record. Add a name and try again. 
--       If we've already tried the whole name, then fail */
--
--      if (forward->name_start == 0)
--      return STAT_BOGUS;
--      
--      for (p = &name[forward->name_start-2]; (*p != '.') && (p != name); p--);
--      
--      if (p != name)
--      p++;
--      
--      forward->name_start = p - name;
--      status = 0; /* force to cache when we iterate. */
--    }
--}
--
--/* Move down from the root, until we find a signed non-existance of a DS, in which case
--   an unsigned answer is OK, or we find a signed DS, in which case there should be 
--   a signature, and the answer is BOGUS */
--static int  tcp_check_for_unsigned_zone(time_t now, struct dns_header *header, size_t plen, int class, char *name, 
--                                      char *keyname, struct server *server, int *keycount)
--{
--  size_t m;
--  unsigned char *packet, *payload;
--  u16 *length;
--  int status, name_len;
--  struct blockdata *block;
--
--  char *name_start;
--
--  /* Get first insecure entry in CNAME chain */
--  status = tcp_key_recurse(now, STAT_CHASE_CNAME, header, plen, class, name, keyname, server, keycount);
--  if (status == STAT_BOGUS)
--    return STAT_BOGUS;
--  
--  if (!(packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16))))
--    return STAT_BOGUS;
--  
--  payload = &packet[2];
--  header = (struct dns_header *)payload;
--  length = (u16 *)packet;
--
--  /* Stash the name away, since the buffer will be trashed when we recurse */
--  name_len = strlen(name) + 1;
--  name_start = name + name_len - 1;
--  
--  if (!(block = blockdata_alloc(name, name_len)))
--    {
--      free(packet);
--      return STAT_BOGUS;
--    }
--
--  while (1)
--    {
--      unsigned char c1, c2;
--      struct crec *crecp;
--
--      if (--(*keycount) == 0)
--      {
--        free(packet);
--        blockdata_free(block);
--        return STAT_BOGUS;    
--      }
--      
--      while ((crecp = cache_find_by_name(NULL, name_start, now, F_DS)))
--      {      
--        if ((crecp->flags & F_NEG) && (crecp->flags & F_DNSSECOK))
--          {
--            /* Found a secure denial of DS - delegation is indeed insecure */
--            free(packet);
--            blockdata_free(block);
--            return STAT_INSECURE;
--          }
--      
--        /* Here, either there's a secure DS, or no NS and no DS, and therefore no delegation.
--           Add another label and continue. */
-- 
--        if (name_start == name)
--          {
--            free(packet);
--            blockdata_free(block);
--            return STAT_BOGUS; /* run out of labels */
--          }
--        
--        name_start -= 2;
--        while (*name_start != '.' && name_start != name) 
--          name_start--;
--        if (name_start != name)
--          name_start++;
--      }
--      
--      /* Can't find it in the cache, have to send a query */
--
--      m = dnssec_generate_query(header, ((char *) header) + 65536, name_start, class, T_DS, &server->addr, server->edns_pktsz);
--      
--      *length = htons(m);
--      
--      if (read_write(server->tcpfd, packet, m + sizeof(u16), 0) &&
--        read_write(server->tcpfd, &c1, 1, 1) &&
--        read_write(server->tcpfd, &c2, 1, 1) &&
--        read_write(server->tcpfd, payload, (c1 << 8) | c2, 1))
--      {
--        m = (c1 << 8) | c2;
--        
--        /* Note this trashes all three name workspaces */
--        status = tcp_key_recurse(now, STAT_NEED_DS_NEG, header, m, class, name, keyname, server, keycount);
--        
--        if (status == STAT_NO_DS)
--          {
--            /* Found a secure denial of DS - delegation is indeed insecure */
--            free(packet);
--            blockdata_free(block);
--            return STAT_INSECURE;
--          }
--        
--        if (status == STAT_NO_SIG && *keyname != 0)
--          {
--            /* There is a validated CNAME chain that doesn't end in a DS record. Start 
--               the search again in that domain. */
--            blockdata_free(block);
--            name_len = strlen(keyname) + 1;
--            name_start = name + name_len - 1;
--            
--            if (!(block = blockdata_alloc(keyname, name_len)))
--              return STAT_BOGUS;
--            
--            strcpy(name, keyname);
--            continue;
--          }
--        
--        if (status == STAT_BOGUS)
--          {
--            free(packet);
--            blockdata_free(block);
--            return STAT_BOGUS;
--          }
--        
--        /* Here, either there's a secure DS, or no NS and no DS, and therefore no delegation.
--           Add another label and continue. */
--        
--        /* Get name we're checking back. */
--        blockdata_retrieve(block, name_len, name);
--        
--        if (name_start == name)
--          {
--            free(packet);
--            blockdata_free(block);
--            return STAT_BOGUS; /* run out of labels */
--          }
--        
--        name_start -= 2;
--        while (*name_start != '.' && name_start != name) 
--          name_start--;
--        if (name_start != name)
--          name_start++;
--      }
--      else
--      {
--        /* IO failure */
--        free(packet);
--        blockdata_free(block);
--        return STAT_BOGUS; /* run out of labels */
--      }
--    }
--}
--
- static int tcp_key_recurse(time_t now, int status, struct dns_header *header, size_t n, 
-                          int class, char *name, char *keyname, struct server *server, int *keycount)
- {
-   /* Recurse up the key heirarchy */
-   int new_status;
-+  unsigned char *packet = NULL;
-+  size_t m; 
-+  unsigned char *payload = NULL;
-+  struct dns_header *new_header = NULL;
-+  u16 *length = NULL;
-+  unsigned char c1, c2;
--  /* limit the amount of work we do, to avoid cycling forever on loops in the DNS */
--  if (--(*keycount) == 0)
--    return STAT_INSECURE;
--  
--  if (status == STAT_NEED_KEY)
--    new_status = dnssec_validate_by_ds(now, header, n, name, keyname, class);
--  else if (status == STAT_NEED_DS || status == STAT_NEED_DS_NEG)
-+  while (1)
-     {
--      new_status = dnssec_validate_ds(now, header, n, name, keyname, class);
--      if (status == STAT_NEED_DS)
-+      /* limit the amount of work we do, to avoid cycling forever on loops in the DNS */
-+      if (--(*keycount) == 0)
-+      new_status = STAT_ABANDONED;
-+      else if (status == STAT_NEED_KEY)
-+      new_status = dnssec_validate_by_ds(now, header, n, name, keyname, class);
-+      else if (status == STAT_NEED_DS)
-+      new_status = dnssec_validate_ds(now, header, n, name, keyname, class);
-+      else 
-+      new_status = dnssec_validate_reply(now, header, n, name, keyname, &class, option_bool(OPT_DNSSEC_NO_SIGN), NULL, NULL);
-+      
-+      if (new_status != STAT_NEED_DS && new_status != STAT_NEED_KEY)
-+      break;
-+
-+      /* Can't validate because we need a key/DS whose name now in keyname.
-+       Make query for same, and recurse to validate */
-+      if (!packet)
-       {
--        if (new_status == STAT_NO_DS)
--          new_status = STAT_INSECURE_DS;
--        if (new_status == STAT_NO_SIG)
--         {
--           if (option_bool(OPT_DNSSEC_NO_SIGN))
--             {
--               new_status = tcp_check_for_unsigned_zone(now, header, n, class, name, keyname, server, keycount);
--               if (new_status == STAT_INSECURE)
--                 new_status = STAT_INSECURE_DS;
--             }
--           else
--             new_status = STAT_INSECURE_DS;
--         }
--        else if (new_status == STAT_NO_NS)
--          new_status = STAT_BOGUS;
-+        packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
-+        payload = &packet[2];
-+        new_header = (struct dns_header *)payload;
-+        length = (u16 *)packet;
-       }
--    }
--  else if (status == STAT_CHASE_CNAME)
--    new_status = dnssec_chase_cname(now, header, n, name, keyname);
--  else 
--    {
--      new_status = dnssec_validate_reply(now, header, n, name, keyname, &class, NULL, NULL);
-       
--      if (new_status == STAT_NO_SIG)
-+      if (!packet)
-       {
--        if (option_bool(OPT_DNSSEC_NO_SIGN))
--          new_status = tcp_check_for_unsigned_zone(now, header, n, class, name, keyname, server, keycount);
--        else
--          new_status = STAT_INSECURE;
-+        new_status = STAT_ABANDONED;
-+        break;
-       }
--    }
--
--  /* Can't validate because we need a key/DS whose name now in keyname.
--     Make query for same, and recurse to validate */
--  if (new_status == STAT_NEED_DS || new_status == STAT_NEED_KEY)
--    {
--      size_t m; 
--      unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
--      unsigned char *payload = &packet[2];
--      struct dns_header *new_header = (struct dns_header *)payload;
--      u16 *length = (u16 *)packet;
--      unsigned char c1, c2;
--       
--      if (!packet)
--      return STAT_INSECURE;
--
--    another_tcp_key:
-+       
-       m = dnssec_generate_query(new_header, ((char *) new_header) + 65536, keyname, class, 
-                               new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS, &server->addr, server->edns_pktsz);
-       
-@@ -1733,65 +1364,22 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
-         !read_write(server->tcpfd, &c1, 1, 1) ||
-         !read_write(server->tcpfd, &c2, 1, 1) ||
-         !read_write(server->tcpfd, payload, (c1 << 8) | c2, 1))
--      new_status = STAT_INSECURE;
--      else
-       {
--        m = (c1 << 8) | c2;
--        
--        new_status = tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server, keycount);
--        
--        if (new_status == STAT_SECURE)
--          {
--            /* Reached a validated record, now try again at this level.
--               Note that we may get ANOTHER NEED_* if an answer needs more than one key.
--               If so, go round again. */
--            
--            if (status == STAT_NEED_KEY)
--              new_status = dnssec_validate_by_ds(now, header, n, name, keyname, class);
--            else if (status == STAT_NEED_DS || status == STAT_NEED_DS_NEG)
--              {
--                new_status = dnssec_validate_ds(now, header, n, name, keyname, class);
--                if (status == STAT_NEED_DS)
--                  {
--                    if (new_status == STAT_NO_DS)
--                      new_status = STAT_INSECURE_DS;
--                    else if (new_status == STAT_NO_SIG)
--                      {
--                        if (option_bool(OPT_DNSSEC_NO_SIGN))
--                          {
--                            new_status = tcp_check_for_unsigned_zone(now, header, n, class, name, keyname, server, keycount); 
--                            if (new_status == STAT_INSECURE)
--                              new_status = STAT_INSECURE_DS;
--                          }
--                        else
--                          new_status = STAT_INSECURE_DS;
--                      }
--                    else if (new_status == STAT_NO_NS)
--                      new_status = STAT_BOGUS;
--                  }
--              }
--            else if (status == STAT_CHASE_CNAME)
--              new_status = dnssec_chase_cname(now, header, n, name, keyname);
--            else 
--              {
--                new_status = dnssec_validate_reply(now, header, n, name, keyname, &class, NULL, NULL);
--                
--                if (new_status == STAT_NO_SIG)
--                  {
--                    if (option_bool(OPT_DNSSEC_NO_SIGN))
--                      new_status = tcp_check_for_unsigned_zone(now, header, n, class, name, keyname, server, keycount);
--                    else
--                      new_status = STAT_INSECURE;
--                  }
--              }
--            
--            if (new_status == STAT_NEED_DS || new_status == STAT_NEED_KEY)
--              goto another_tcp_key;
--          }
-+        new_status = STAT_ABANDONED;
-+        break;
-       }
-+
-+      m = (c1 << 8) | c2;
-       
--      free(packet);
-+      new_status = tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server, keycount);
-+      
-+      if (new_status != STAT_OK)
-+      break;
-     }
-+
-+  if (packet)
-+    free(packet);
-+    
-   return new_status;
- }
- #endif
-@@ -2075,19 +1663,10 @@ unsigned char *tcp_request(int confd, time_t now,
-                     if (option_bool(OPT_DNSSEC_VALID) && !checking_disabled)
-                       {
-                         int keycount = DNSSEC_WORK; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */
--                        int status = tcp_key_recurse(now, STAT_TRUNCATED, header, m, 0, daemon->namebuff, daemon->keyname, last_server, &keycount);
-+                        int status = tcp_key_recurse(now, STAT_OK, header, m, 0, daemon->namebuff, daemon->keyname, last_server, &keycount);
-                         char *result, *domain = "result";
--
--                        if (status == STAT_INSECURE_DS)
--                          {
--                            /* We only cache sigs when we've validated a reply.
--                               Avoid caching a reply with sigs if there's a vaildated break in the 
--                               DS chain, so we don't return replies from cache missing sigs. */
--                            status = STAT_INSECURE;
--                            no_cache_dnssec = 1;
--                          }
-                         
--                        if (keycount == 0)
-+                        if (status == STAT_ABANDONED)
-                           {
-                             result = "ABANDONED";
-                             status = STAT_BOGUS;
-@@ -2179,7 +1758,6 @@ static struct frec *allocate_frec(time_t now)
-       f->dependent = NULL;
-       f->blocking_query = NULL;
-       f->stash = NULL;
--      f->orig_domain = NULL;
- #endif
-       daemon->frec_list = f;
-     }
-@@ -2248,12 +1826,6 @@ static void free_frec(struct frec *f)
-       f->stash = NULL;
-     }
--  if (f->orig_domain)
--    {
--      blockdata_free(f->orig_domain);
--      f->orig_domain = NULL;
--    }
--
-   /* Anything we're waiting on is pointless now, too */
-   if (f->blocking_query)
-     free_frec(f->blocking_query);
-@@ -2281,14 +1853,23 @@ struct frec *get_new_frec(time_t now, int *wait, int force)
-       target = f;
-     else 
-       {
--      if (difftime(now, f->time) >= 4*TIMEOUT)
--        {
--          free_frec(f);
--          target = f;
--        }
--      
--      if (!oldest || difftime(f->time, oldest->time) <= 0)
--        oldest = f;
-+#ifdef HAVE_DNSSEC
-+          /* Don't free DNSSEC sub-queries here, as we may end up with
-+             dangling references to them. They'll go when their "real" query 
-+             is freed. */
-+          if (!f->dependent)
-+#endif
-+            {
-+              if (difftime(now, f->time) >= 4*TIMEOUT)
-+                {
-+                  free_frec(f);
-+                  target = f;
-+                }
-+           
-+          
-+              if (!oldest || difftime(f->time, oldest->time) <= 0)
-+                oldest = f;
-+            }
-       }
-   if (target)
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/017-Abandon_caching_RRSIGs_and_returning_them_from_cache.patch b/src/patches/dnsmasq/017-Abandon_caching_RRSIGs_and_returning_them_from_cache.patch
deleted file mode 100644 (file)
index 5ffaf97..0000000
+++ /dev/null
@@ -1,612 +0,0 @@
-From 93be5b1e023b0c661e1ec2cd6d811a8ec9055c49 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Tue, 15 Dec 2015 12:04:40 +0000
-Subject: [PATCH] Abandon caching RRSIGs and returning them from cache.
-
-The list of exceptions to being able to locally answer
-cached data for validated records when DNSSEC data is requested
-was getting too long, so don't ever do that. This means
-that the cache no longer has to hold RRSIGS and allows
-us to lose lots of code. Note that cached validated
-answers are still returned as long as do=0
----
- src/cache.c   |   38 ++---------
- src/dnsmasq.h |   10 +--
- src/dnssec.c  |   94 ++++-----------------------
- src/rfc1035.c |  197 ++++++---------------------------------------------------
- 4 files changed, 42 insertions(+), 297 deletions(-)
-
-diff --git a/src/cache.c b/src/cache.c
-index 1b76b67..51ba7cc 100644
---- a/src/cache.c
-+++ b/src/cache.c
-@@ -189,12 +189,7 @@ static void cache_hash(struct crec *crecp)
- static void cache_blockdata_free(struct crec *crecp)
- {
-   if (crecp->flags & F_DNSKEY)
--    {
--      if (crecp->flags & F_DS)
--      blockdata_free(crecp->addr.sig.keydata);
--      else
--      blockdata_free(crecp->addr.key.keydata);
--    }
-+    blockdata_free(crecp->addr.key.keydata);
-   else if ((crecp->flags & F_DS) && !(crecp->flags & F_NEG))
-     blockdata_free(crecp->addr.ds.keydata);
- }
-@@ -369,13 +364,8 @@ static struct crec *cache_scan_free(char *name, struct all_addr *addr, time_t no
-               }
-             
- #ifdef HAVE_DNSSEC
--            /* Deletion has to be class-sensitive for DS, DNSKEY, RRSIG, also 
--               type-covered sensitive for  RRSIG */
--            if ((flags & (F_DNSKEY | F_DS)) &&
--                (flags & (F_DNSKEY | F_DS)) == (crecp->flags & (F_DNSKEY | F_DS)) &&
--                crecp->uid == addr->addr.dnssec.class &&
--                (!((flags & (F_DS | F_DNSKEY)) == (F_DS | F_DNSKEY)) || 
--                 crecp->addr.sig.type_covered == addr->addr.dnssec.type))
-+            /* Deletion has to be class-sensitive for DS and DNSKEY */
-+            if ((flags & crecp->flags & (F_DNSKEY | F_DS)) && crecp->uid == addr->addr.dnssec.class)
-               {
-                 if (crecp->flags & F_CONFIG)
-                   return crecp;
-@@ -532,13 +522,9 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
-           struct all_addr free_addr = new->addr.addr;;
- #ifdef HAVE_DNSSEC
--          /* For DNSSEC records, addr holds class and type_covered for RRSIG */
-+          /* For DNSSEC records, addr holds class. */
-           if (new->flags & (F_DS | F_DNSKEY))
--            {
--              free_addr.addr.dnssec.class = new->uid;
--              if ((new->flags & (F_DS | F_DNSKEY)) == (F_DS | F_DNSKEY))
--                free_addr.addr.dnssec.type = new->addr.sig.type_covered;
--            }
-+            free_addr.addr.dnssec.class = new->uid;
- #endif
-           
-           free_avail = 1; /* Must be free space now. */
-@@ -653,9 +639,6 @@ struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi
-         if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp))
-           {
-             if ((crecp->flags & F_FORWARD) && 
--#ifdef HAVE_DNSSEC
--                (((crecp->flags & (F_DNSKEY | F_DS)) == (prot & (F_DNSKEY | F_DS))) || (prot & F_NSIGMATCH)) &&
--#endif
-                 (crecp->flags & prot) &&
-                 hostname_isequal(cache_get_name(crecp), name))
-               {
-@@ -713,9 +696,6 @@ struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi
-   if (ans && 
-       (ans->flags & F_FORWARD) &&
--#ifdef HAVE_DNSSEC
--      (((ans->flags & (F_DNSKEY | F_DS)) == (prot & (F_DNSKEY | F_DS))) || (prot & F_NSIGMATCH)) &&
--#endif
-       (ans->flags & prot) &&     
-       hostname_isequal(cache_get_name(ans), name))
-     return ans;
-@@ -1472,11 +1452,7 @@ void dump_cache(time_t now)
- #ifdef HAVE_DNSSEC
-           else if (cache->flags & F_DS)
-             {
--              if (cache->flags & F_DNSKEY)
--                /* RRSIG */
--                sprintf(a, "%5u %3u %s", cache->addr.sig.keytag,
--                        cache->addr.sig.algo, querystr("", cache->addr.sig.type_covered));
--              else if (!(cache->flags & F_NEG))
-+              if (!(cache->flags & F_NEG))
-                 sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag,
-                         cache->addr.ds.algo, cache->addr.ds.digest);
-             }
-@@ -1502,8 +1478,6 @@ void dump_cache(time_t now)
-           else if (cache->flags & F_CNAME)
-             t = "C";
- #ifdef HAVE_DNSSEC
--          else if ((cache->flags & (F_DS | F_DNSKEY)) == (F_DS | F_DNSKEY))
--            t = "G"; /* DNSKEY and DS set -> RRISG */
-           else if (cache->flags & F_DS)
-             t = "S";
-           else if (cache->flags & F_DNSKEY)
-diff --git a/src/dnsmasq.h b/src/dnsmasq.h
-index 023a1cf..4344cae 100644
---- a/src/dnsmasq.h
-+++ b/src/dnsmasq.h
-@@ -398,14 +398,9 @@ struct crec {
-       unsigned char algo;
-       unsigned char digest; 
-     } ds; 
--    struct {
--      struct blockdata *keydata;
--      unsigned short keylen, type_covered, keytag;
--      char algo;
--    } sig;
-   } addr;
-   time_t ttd; /* time to die */
--  /* used as class if DNSKEY/DS/RRSIG, index to source for F_HOSTS */
-+  /* used as class if DNSKEY/DS, index to source for F_HOSTS */
-   unsigned int uid; 
-   unsigned short flags;
-   union {
-@@ -445,8 +440,7 @@ struct crec {
- #define F_SECSTAT   (1u<<24)
- #define F_NO_RR     (1u<<25)
- #define F_IPSET     (1u<<26)
--#define F_NSIGMATCH (1u<<27)
--#define F_NOEXTRA   (1u<<28)
-+#define F_NOEXTRA   (1u<<27)
- /* Values of uid in crecs with F_CONFIG bit set. */
- #define SRC_INTERFACE 0
-diff --git a/src/dnssec.c b/src/dnssec.c
-index de7b335..1ae03a6 100644
---- a/src/dnssec.c
-+++ b/src/dnssec.c
-@@ -1004,7 +1004,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
- {
-   unsigned char *psave, *p = (unsigned char *)(header+1);
-   struct crec *crecp, *recp1;
--  int rc, j, qtype, qclass, ttl, rdlen, flags, algo, valid, keytag, type_covered;
-+  int rc, j, qtype, qclass, ttl, rdlen, flags, algo, valid, keytag;
-   struct blockdata *key;
-   struct all_addr a;
-@@ -1115,7 +1115,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
-   if (valid)
-     {
--      /* DNSKEY RRset determined to be OK, now cache it and the RRsigs that sign it. */
-+      /* DNSKEY RRset determined to be OK, now cache it. */
-       cache_start_insert();
-       
-       p = skip_questions(header, plen);
-@@ -1155,7 +1155,10 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
-                 if ((key = blockdata_alloc((char*)p, rdlen - 4)))
-                   {
-                     if (!(recp1 = cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSKEY | F_DNSSECOK)))
--                      blockdata_free(key);
-+                      {
-+                        blockdata_free(key);
-+                        return STAT_BOGUS;
-+                      }
-                     else
-                       {
-                         a.addr.keytag = keytag;
-@@ -1169,38 +1172,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
-                       }
-                   }
-               }
--            else if (qtype == T_RRSIG)
--              {
--                /* RRSIG, cache if covers DNSKEY RRset */
--                if (rdlen < 18)
--                  return STAT_BOGUS; /* bad packet */
--                
--                GETSHORT(type_covered, p);
--                
--                if (type_covered == T_DNSKEY)
--                  {
--                    a.addr.dnssec.class = class;
--                    a.addr.dnssec.type = type_covered;
--                    
--                    algo = *p++;
--                    p += 13; /* labels, orig_ttl, expiration, inception */
--                    GETSHORT(keytag, p);      
--                    if ((key = blockdata_alloc((char*)psave, rdlen)))
--                      {
--                        if (!(crecp = cache_insert(name, &a, now, ttl,  F_FORWARD | F_DNSKEY | F_DS)))
--                          blockdata_free(key);
--                        else
--                          {
--                            crecp->addr.sig.keydata = key;
--                            crecp->addr.sig.keylen = rdlen;
--                            crecp->addr.sig.keytag = keytag;
--                            crecp->addr.sig.type_covered = type_covered;
--                            crecp->addr.sig.algo = algo;
--                          }
--                      }
--                  }
--              }
--            
-+                    
-             p = psave;
-           }
-@@ -1326,7 +1298,8 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
-         cache_start_insert();
-         
-         a.addr.dnssec.class = class;
--        cache_insert(name, &a, now, ttl, flags);
-+        if (!cache_insert(name, &a, now, ttl, flags))
-+          return STAT_BOGUS;
-         
-         cache_end_insert();  
-         
-@@ -2028,14 +2001,13 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
-         /* Not done, validate now */
-         if (j == i)
-           {
--            int ttl, keytag, algo, digest, type_covered, sigcnt, rrcnt;
-+            int ttl, keytag, algo, digest, sigcnt, rrcnt;
-             unsigned char *psave;
-             struct all_addr a;
-             struct blockdata *key;
-             struct crec *crecp;
-             char *wildname;
--            int have_wildcard = 0;
--
-+            
-             if (!explore_rrset(header, plen, class1, type1, name, keyname, &sigcnt, &rrcnt))
-               return STAT_BOGUS;
-@@ -2096,8 +2068,6 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
-                           
-                 if (rc == STAT_SECURE_WILDCARD)
-                   {
--                    have_wildcard = 1;
--                    
-                     /* An attacker replay a wildcard answer with a different
-                        answer and overlay a genuine RR. To prove this
-                        hasn't happened, the answer must prove that
-@@ -2119,7 +2089,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
-                       return rc;
-                   } 
-                 
--                /* Cache RRsigs in answer section, and if we just validated a DS RRset, cache it */
-+                /* If we just validated a DS RRset, cache it */
-                 /* Also note if the RRset is the answer to the question, or the target of a CNAME */
-                 cache_start_insert();
-                 
-@@ -2168,45 +2138,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
-                                   } 
-                               }
-                           }
--                        else if (type2 == T_RRSIG)
--                          {
--                            if (rdlen2 < 18)
--                              return STAT_BOGUS; /* bad packet */
--                            
--                            GETSHORT(type_covered, p2);
--                            
--                            if (type_covered == type1 && 
--                                (type_covered == T_A || type_covered == T_AAAA ||
--                                 type_covered == T_CNAME || type_covered == T_DS || 
--                                 type_covered == T_DNSKEY || type_covered == T_PTR)) 
--                              {
--                                a.addr.dnssec.type = type_covered;
--                                a.addr.dnssec.class = class1;
--                                
--                                algo = *p2++;
--                                p2 += 13; /* labels, orig_ttl, expiration, inception */
--                                GETSHORT(keytag, p2);
--                                
--                                /* We don't cache sigs for wildcard answers, because to reproduce the
--                                   answer from the cache will require one or more NSEC/NSEC3 records 
--                                   which we don't cache. The lack of the RRSIG ensures that a query for
--                                   this RRset asking for a secure answer will always be forwarded. */
--                                if (!have_wildcard && (key = blockdata_alloc((char*)psave, rdlen2)))
--                                  {
--                                    if (!(crecp = cache_insert(name, &a, now, ttl,  F_FORWARD | F_DNSKEY | F_DS)))
--                                      blockdata_free(key);
--                                    else
--                                      {
--                                        crecp->addr.sig.keydata = key;
--                                        crecp->addr.sig.keylen = rdlen2;
--                                        crecp->addr.sig.keytag = keytag;
--                                        crecp->addr.sig.type_covered = type_covered;
--                                        crecp->addr.sig.algo = algo;
--                                      }
--                                  }
--                              }
--                          }
--                        
-+
-                         p2 = psave;
-                       }
-                     
-diff --git a/src/rfc1035.c b/src/rfc1035.c
-index 4eb1772..def8fa0 100644
---- a/src/rfc1035.c
-+++ b/src/rfc1035.c
-@@ -1275,11 +1275,9 @@ int check_for_local_domain(char *name, time_t now)
-   struct naptr *naptr;
-   /* Note: the call to cache_find_by_name is intended to find any record which matches
--     ie A, AAAA, CNAME, DS. Because RRSIG records are marked by setting both F_DS and F_DNSKEY,
--     cache_find_by name ordinarily only returns records with an exact match on those bits (ie
--     for the call below, only DS records). The F_NSIGMATCH bit changes this behaviour */
-+     ie A, AAAA, CNAME. */
--  if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME | F_DS | F_NO_RR | F_NSIGMATCH)) &&
-+  if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME |F_NO_RR)) &&
-       (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
-     return 1;
-   
-@@ -1566,9 +1564,11 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
-       GETSHORT(flags, pheader);
-       
-       if ((sec_reqd = flags & 0x8000))
--      *do_bit = 1;/* do bit */ 
-+      {
-+        *do_bit = 1;/* do bit */ 
-+        *ad_reqd = 1;
-+      }
--      *ad_reqd = 1;
-       dryrun = 1;
-     }
-@@ -1636,98 +1636,6 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
-           }
-       }
--#ifdef HAVE_DNSSEC
--      if (option_bool(OPT_DNSSEC_VALID) && (qtype == T_DNSKEY || qtype == T_DS))
--      {
--        int gotone = 0;
--        struct blockdata *keydata;
--
--        /* Do we have RRSIG? Can't do DS or DNSKEY otherwise. */
--        if (sec_reqd)
--          {
--            crecp = NULL;
--            while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY | F_DS)))
--              if (crecp->uid == qclass && crecp->addr.sig.type_covered == qtype)
--                break;
--          }
--        
--        if (!sec_reqd || crecp)
--          {
--            if (qtype == T_DS)
--              {
--                crecp = NULL;
--                while ((crecp = cache_find_by_name(crecp, name, now, F_DS)))
--                  if (crecp->uid == qclass)
--                    {
--                      gotone = 1; 
--                      if (!dryrun)
--                        {
--                          if (crecp->flags & F_NEG)
--                            {
--                              if (crecp->flags & F_NXDOMAIN)
--                                nxdomain = 1;
--                              log_query(F_UPSTREAM, name, NULL, "no DS");     
--                            }
--                          else if ((keydata = blockdata_retrieve(crecp->addr.ds.keydata, crecp->addr.ds.keylen, NULL)))
--                            {                                               
--                              struct all_addr a;
--                              a.addr.keytag =  crecp->addr.ds.keytag;
--                              log_query(F_KEYTAG | (crecp->flags & F_CONFIG), name, &a, "DS keytag %u");
--                              if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
--                                                      crec_ttl(crecp, now), &nameoffset,
--                                                      T_DS, qclass, "sbbt", 
--                                                      crecp->addr.ds.keytag, crecp->addr.ds.algo, 
--                                                      crecp->addr.ds.digest, crecp->addr.ds.keylen, keydata))
--                                anscount++;
--                              
--                            } 
--                        }
--                    }
--              }
--            else /* DNSKEY */
--              {
--                crecp = NULL;
--                while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY)))
--                  if (crecp->uid == qclass)
--                    {
--                      gotone = 1;
--                      if (!dryrun && (keydata = blockdata_retrieve(crecp->addr.key.keydata, crecp->addr.key.keylen, NULL)))
--                        {                                                   
--                          struct all_addr a;
--                          a.addr.keytag =  crecp->addr.key.keytag;
--                          log_query(F_KEYTAG | (crecp->flags & F_CONFIG), name, &a, "DNSKEY keytag %u");
--                          if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
--                                                  crec_ttl(crecp, now), &nameoffset,
--                                                  T_DNSKEY, qclass, "sbbt", 
--                                                  crecp->addr.key.flags, 3, crecp->addr.key.algo, crecp->addr.key.keylen, keydata))
--                            anscount++;
--                        }
--                    }
--              }
--          }
--        
--        /* Now do RRSIGs */
--        if (gotone)
--          {
--            ans = 1;
--            auth = 0;
--            if (!dryrun && sec_reqd)
--              {
--                crecp = NULL;
--                while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY | F_DS)))
--                  if (crecp->uid == qclass && crecp->addr.sig.type_covered == qtype &&
--                      (keydata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL)))
--                    {
--                      add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
--                                          crec_ttl(crecp, now), &nameoffset,
--                                          T_RRSIG, qclass, "t", crecp->addr.sig.keylen, keydata);
--                      anscount++;
--                    }
--              }
--          }
--      }
--#endif             
--      
-       if (qclass == C_IN)
-       {
-         struct txt_record *t;
-@@ -1736,6 +1644,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
-           if ((t->class == qtype || qtype == T_ANY) && hostname_isequal(name, t->name))
-             {
-               ans = 1;
-+              sec_data = 0;
-               if (!dryrun)
-                 {
-                   log_query(F_CONFIG | F_RRNAME, name, NULL, "<RR>");
-@@ -1792,6 +1701,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
-             
-             if (intr)
-               {
-+                sec_data = 0;
-                 ans = 1;
-                 if (!dryrun)
-                   {
-@@ -1805,6 +1715,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
-             else if (ptr)
-               {
-                 ans = 1;
-+                sec_data = 0;
-                 if (!dryrun)
-                   {
-                     log_query(F_CONFIG | F_RRNAME, name, NULL, "<PTR>");
-@@ -1819,38 +1730,8 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
-               }
-             else if ((crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
-               {
--                if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && sec_reqd)
--                  {
--                    if (!option_bool(OPT_DNSSEC_VALID) || ((crecp->flags & F_NEG) && (crecp->flags & F_DNSSECOK)))
--                      crecp = NULL;
--#ifdef HAVE_DNSSEC
--                    else if (crecp->flags & F_DNSSECOK)
--                      {
--                        int gotsig = 0;
--                        struct crec *rr_crec = NULL;
--
--                        while ((rr_crec = cache_find_by_name(rr_crec, name, now, F_DS | F_DNSKEY)))
--                          {
--                            if (rr_crec->addr.sig.type_covered == T_PTR && rr_crec->uid == C_IN)
--                              {
--                                char *sigdata = blockdata_retrieve(rr_crec->addr.sig.keydata, rr_crec->addr.sig.keylen, NULL);
--                                gotsig = 1;
--                                
--                                if (!dryrun && 
--                                    add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
--                                                        rr_crec->ttd - now, &nameoffset,
--                                                        T_RRSIG, C_IN, "t", crecp->addr.sig.keylen, sigdata))
--                                  anscount++;
--                              }
--                          } 
--                        
--                        if (!gotsig)
--                          crecp = NULL;
--                      }
--#endif
--                  }
--
--                if (crecp)
-+                /* Don't use cache when DNSSEC data required. */
-+                if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !sec_reqd || !(crecp->flags & F_DNSSECOK))
-                   {
-                     do 
-                       { 
-@@ -1860,19 +1741,19 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
-                         
-                         if (!(crecp->flags & F_DNSSECOK))
-                           sec_data = 0;
--                        
-+                         
-+                        ans = 1;
-+                         
-                         if (crecp->flags & F_NEG)
-                           {
--                            ans = 1;
-                             auth = 0;
-                             if (crecp->flags & F_NXDOMAIN)
-                               nxdomain = 1;
-                             if (!dryrun)
-                               log_query(crecp->flags & ~F_FORWARD, name, &addr, NULL);
-                           }
--                        else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd || option_bool(OPT_DNSSEC_VALID))
-+                        else
-                           {
--                            ans = 1;
-                             if (!(crecp->flags & (F_HOSTS | F_DHCP)))
-                               auth = 0;
-                             if (!dryrun)
-@@ -1892,6 +1773,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
-             else if (is_rev_synth(is_arpa, &addr, name))
-               {
-                 ans = 1;
-+                sec_data = 0;
-                 if (!dryrun)
-                   {
-                     log_query(F_CONFIG | F_REVERSE | is_arpa, name, &addr, NULL); 
-@@ -1908,6 +1790,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
-               {
-                 /* if not in cache, enabled and private IPV4 address, return NXDOMAIN */
-                 ans = 1;
-+                sec_data = 0;
-                 nxdomain = 1;
-                 if (!dryrun)
-                   log_query(F_CONFIG | F_REVERSE | F_IPV4 | F_NEG | F_NXDOMAIN, 
-@@ -1955,6 +1838,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
-                 if (i == 4)
-                   {
-                     ans = 1;
-+                    sec_data = 0;
-                     if (!dryrun)
-                       {
-                         addr.addr.addr4.s_addr = htonl(a);
-@@ -1993,6 +1877,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
-                               continue;
- #endif        
-                             ans = 1;  
-+                            sec_data = 0;
-                             if (!dryrun)
-                               {
-                                 gotit = 1;
-@@ -2032,48 +1917,8 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
-                     crecp = save;
-                   }
--                /* If the client asked for DNSSEC and we can't provide RRSIGs, either
--                   because we've not doing DNSSEC or the cached answer is signed by negative,
--                   don't answer from the cache, forward instead. */
--                if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && sec_reqd)
--                  {
--                    if (!option_bool(OPT_DNSSEC_VALID) || ((crecp->flags & F_NEG) && (crecp->flags & F_DNSSECOK)))
--                      crecp = NULL;
--#ifdef HAVE_DNSSEC
--                    else if (crecp->flags & F_DNSSECOK)
--                      {
--                        /* We're returning validated data, need to return the RRSIG too. */
--                        struct crec *rr_crec = NULL;
--                        int sigtype = type;
--                        /* The signature may have expired even though the data is still in cache, 
--                           forward instead of answering from cache if so. */
--                        int gotsig = 0;
--                        
--                        if (crecp->flags & F_CNAME)
--                          sigtype = T_CNAME;
--                        
--                        while ((rr_crec = cache_find_by_name(rr_crec, name, now, F_DS | F_DNSKEY)))
--                          {
--                            if (rr_crec->addr.sig.type_covered == sigtype && rr_crec->uid == C_IN)
--                              {
--                                char *sigdata = blockdata_retrieve(rr_crec->addr.sig.keydata, rr_crec->addr.sig.keylen, NULL);
--                                gotsig = 1;
--                                
--                                if (!dryrun && 
--                                    add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
--                                                        rr_crec->ttd - now, &nameoffset,
--                                                        T_RRSIG, C_IN, "t", rr_crec->addr.sig.keylen, sigdata))
--                                  anscount++;
--                              }
--                          }
--                        
--                        if (!gotsig)
--                          crecp = NULL;
--                      }
--#endif
--                  }            
--
--                if (crecp)
-+                /* If the client asked for DNSSEC  don't use cached data. */
-+                if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !sec_reqd || !(crecp->flags & F_DNSSECOK))
-                   do
-                     { 
-                       /* don't answer wildcard queries with data not from /etc/hosts
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/018-Move_code_which_caches_DS_records_to_a_more_logical_place.patch b/src/patches/dnsmasq/018-Move_code_which_caches_DS_records_to_a_more_logical_place.patch
deleted file mode 100644 (file)
index ff055f7..0000000
+++ /dev/null
@@ -1,269 +0,0 @@
-From d64c81fff7faf4392b688223ef3a617c5c07e7dc Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Tue, 15 Dec 2015 16:11:06 +0000
-Subject: [PATCH] Move code which caches DS records to a more logical place.
-
----
- src/dnssec.c |  179 +++++++++++++++++++++++++++++-----------------------------
- 1 file changed, 90 insertions(+), 89 deletions(-)
-
-diff --git a/src/dnssec.c b/src/dnssec.c
-index 1ae03a6..359231f 100644
---- a/src/dnssec.c
-+++ b/src/dnssec.c
-@@ -1204,7 +1204,10 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
- int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class)
- {
-   unsigned char *p = (unsigned char *)(header+1);
--  int qtype, qclass, val, i, neganswer, nons;
-+  int qtype, qclass, rc, i, neganswer, nons;
-+  int aclass, atype, rdlen;
-+  unsigned long ttl;
-+  struct all_addr a;
-   if (ntohs(header->qdcount) != 1 ||
-       !(p = skip_name(p, header, plen, 4)))
-@@ -1214,40 +1217,100 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
-   GETSHORT(qclass, p);
-   if (qtype != T_DS || qclass != class)
--    val = STAT_BOGUS;
-+    rc = STAT_BOGUS;
-   else
--    val = dnssec_validate_reply(now, header, plen, name, keyname, NULL, 0, &neganswer, &nons);
-+    rc = dnssec_validate_reply(now, header, plen, name, keyname, NULL, 0, &neganswer, &nons);
-   /* Note dnssec_validate_reply() will have cached positive answers */
-   
--  if (val == STAT_INSECURE)
--    val = STAT_BOGUS;
--
-+  if (rc == STAT_INSECURE)
-+    rc = STAT_BOGUS;
-+ 
-   p = (unsigned char *)(header+1);
-   extract_name(header, plen, &p, name, 1, 4);
-   p += 4; /* qtype, qclass */
-   
--  if (!(p = skip_section(p, ntohs(header->ancount), header, plen)))
--    val = STAT_BOGUS;
--  
-   /* If the key needed to validate the DS is on the same domain as the DS, we'll
-      loop getting nowhere. Stop that now. This can happen of the DS answer comes
-      from the DS's zone, and not the parent zone. */
--  if (val == STAT_BOGUS || (val == STAT_NEED_KEY && hostname_isequal(name, keyname)))
-+  if (rc == STAT_BOGUS || (rc == STAT_NEED_KEY && hostname_isequal(name, keyname)))
-     {
-       log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS");
-       return STAT_BOGUS;
-     }
-   
--  if (val != STAT_SECURE)
--    return val;
--
--  /* By here, the answer is proved secure, and a positive answer has been cached. */
--  if (neganswer)
-+  if (rc != STAT_SECURE)
-+    return rc;
-+   
-+  if (!neganswer)
-     {
--      int rdlen, flags = F_FORWARD | F_DS | F_NEG | F_DNSSECOK;
--      unsigned long ttl, minttl = ULONG_MAX;
--      struct all_addr a;
-+      cache_start_insert();
-+      
-+      for (i = 0; i < ntohs(header->ancount); i++)
-+      {
-+        if (!(rc = extract_name(header, plen, &p, name, 0, 10)))
-+          return STAT_BOGUS; /* bad packet */
-+        
-+        GETSHORT(atype, p);
-+        GETSHORT(aclass, p);
-+        GETLONG(ttl, p);
-+        GETSHORT(rdlen, p);
-+        
-+        if (!CHECK_LEN(header, p, plen, rdlen))
-+          return STAT_BOGUS; /* bad packet */
-+        
-+        if (aclass == class && atype == T_DS && rc == 1)
-+          { 
-+            int algo, digest, keytag;
-+            unsigned char *psave = p;
-+            struct blockdata *key;
-+            struct crec *crecp;
-+            if (rdlen < 4)
-+              return STAT_BOGUS; /* bad packet */
-+            
-+            GETSHORT(keytag, p);
-+            algo = *p++;
-+            digest = *p++;
-+            
-+            /* Cache needs to known class for DNSSEC stuff */
-+            a.addr.dnssec.class = class;
-+            
-+            if ((key = blockdata_alloc((char*)p, rdlen - 4)))
-+              {
-+                if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DS | F_DNSSECOK)))
-+                  {
-+                    blockdata_free(key);
-+                    return STAT_BOGUS;
-+                  }
-+                else
-+                  {
-+                    a.addr.keytag = keytag;
-+                    log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u");
-+                    crecp->addr.ds.digest = digest;
-+                    crecp->addr.ds.keydata = key;
-+                    crecp->addr.ds.algo = algo;
-+                    crecp->addr.ds.keytag = keytag;
-+                    crecp->addr.ds.keylen = rdlen - 4; 
-+                  } 
-+              }
-+            
-+            p = psave;
-+            
-+            if (!ADD_RDLEN(header, p, plen, rdlen))
-+              return STAT_BOGUS; /* bad packet */
-+          }
-+        
-+        cache_end_insert();
-+      }
-+    }
-+  else
-+    {
-+      int flags = F_FORWARD | F_DS | F_NEG | F_DNSSECOK;
-+      unsigned long minttl = ULONG_MAX;
-+      
-+      if (!(p = skip_section(p, ntohs(header->ancount), header, plen)))
-+      return STAT_BOGUS;
-+      
-       if (RCODE(header) == NXDOMAIN)
-       flags |= F_NXDOMAIN;
-       
-@@ -1261,20 +1324,20 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
-         if (!(p = skip_name(p, header, plen, 0)))
-           return STAT_BOGUS;
-         
--        GETSHORT(qtype, p); 
--        GETSHORT(qclass, p);
-+        GETSHORT(atype, p); 
-+        GETSHORT(aclass, p);
-         GETLONG(ttl, p);
-         GETSHORT(rdlen, p);
--
-+        
-         if (!CHECK_LEN(header, p, plen, rdlen))
-           return STAT_BOGUS; /* bad packet */
--          
--        if (qclass != class || qtype != T_SOA)
-+        
-+        if (aclass != class || atype != T_SOA)
-           {
-             p += rdlen;
-             continue;
-           }
--           
-+        
-         if (ttl < minttl)
-           minttl = ttl;
-         
-@@ -1306,7 +1369,7 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
-         log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "no DS");
-       }
-     }
--
-+      
-   return STAT_OK;
- }
-@@ -2001,11 +2064,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
-         /* Not done, validate now */
-         if (j == i)
-           {
--            int ttl, keytag, algo, digest, sigcnt, rrcnt;
--            unsigned char *psave;
--            struct all_addr a;
--            struct blockdata *key;
--            struct crec *crecp;
-+            int sigcnt, rrcnt;
-             char *wildname;
-             
-             if (!explore_rrset(header, plen, class1, type1, name, keyname, &sigcnt, &rrcnt))
-@@ -2032,6 +2091,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
-                Can't overwrite name here. */
-             strcpy(daemon->workspacename, keyname);
-             rc = zone_status(daemon->workspacename, class1, keyname, now);
-+
-             if (rc != STAT_SECURE)
-               {
-                 /* Zone is insecure, don't need to validate RRset */
-@@ -2088,65 +2148,6 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
-                     if (rc == STAT_BOGUS)
-                       return rc;
-                   } 
--                
--                /* If we just validated a DS RRset, cache it */
--                /* Also note if the RRset is the answer to the question, or the target of a CNAME */
--                cache_start_insert();
--                
--                for (p2 = ans_start, j = 0; j < ntohs(header->ancount); j++)
--                  {
--                    if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
--                      return STAT_BOGUS; /* bad packet */
--                    
--                    GETSHORT(type2, p2);
--                    GETSHORT(class2, p2);
--                    GETLONG(ttl, p2);
--                    GETSHORT(rdlen2, p2);
--                    
--                    if (!CHECK_LEN(header, p2, plen, rdlen2))
--                      return STAT_BOGUS; /* bad packet */
--                    
--                    if (class2 == class1 && rc == 1)
--                      { 
--                        psave = p2;
--                        
--                        if (type1 == T_DS && type2 == T_DS)
--                          {
--                            if (rdlen2 < 4)
--                              return STAT_BOGUS; /* bad packet */
--                            
--                            GETSHORT(keytag, p2);
--                            algo = *p2++;
--                            digest = *p2++;
--                            
--                            /* Cache needs to known class for DNSSEC stuff */
--                            a.addr.dnssec.class = class2;
--                            
--                            if ((key = blockdata_alloc((char*)p2, rdlen2 - 4)))
--                              {
--                                if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DS | F_DNSSECOK)))
--                                  blockdata_free(key);
--                                else
--                                  {
--                                    a.addr.keytag = keytag;
--                                    log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u");
--                                    crecp->addr.ds.digest = digest;
--                                    crecp->addr.ds.keydata = key;
--                                    crecp->addr.ds.algo = algo;
--                                    crecp->addr.ds.keytag = keytag;
--                                    crecp->addr.ds.keylen = rdlen2 - 4; 
--                                  } 
--                              }
--                          }
--
--                        p2 = psave;
--                      }
--                    
--                    if (!ADD_RDLEN(header, p2, plen, rdlen2))
--                      return STAT_BOGUS; /* bad packet */
--                  }
--                
--                cache_end_insert();
-               }
-           }
-       }
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/019-Generalise_RR-filtering_code_for_use_with_EDNS0.patch b/src/patches/dnsmasq/019-Generalise_RR-filtering_code_for_use_with_EDNS0.patch
deleted file mode 100644 (file)
index 0a4942a..0000000
+++ /dev/null
@@ -1,755 +0,0 @@
-From c2bcd1e183bcc5fdd63811c045355fc57e36ecfd Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Tue, 15 Dec 2015 17:25:21 +0000
-Subject: [PATCH] Generalise RR-filtering code, for use with EDNS0.
-
----
- Makefile       |    3 +-
- bld/Android.mk |    2 +-
- src/dnsmasq.h  |    5 +
- src/dnssec.c   |  307 +-------------------------------------------------
- src/forward.c  |    2 +-
- src/rrfilter.c |  339 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 6 files changed, 349 insertions(+), 309 deletions(-)
- create mode 100644 src/rrfilter.c
-
-diff --git a/Makefile b/Makefile
-index 4c87ea9..b664160 100644
---- a/Makefile
-+++ b/Makefile
-@@ -73,7 +73,8 @@ objs = cache.o rfc1035.o util.o option.o forward.o network.o \
-        dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
-        helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
-        dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \
--       domain.o dnssec.o blockdata.o tables.o loop.o inotify.o poll.o
-+       domain.o dnssec.o blockdata.o tables.o loop.o inotify.o \
-+       poll.o rrfilter.o
- hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
-        dns-protocol.h radv-protocol.h ip6addr.h
-diff --git a/bld/Android.mk b/bld/Android.mk
-index 5364ee7..67b9c4b 100644
---- a/bld/Android.mk
-+++ b/bld/Android.mk
-@@ -10,7 +10,7 @@ LOCAL_SRC_FILES :=  bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
-                   dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
-                   radv.c slaac.c auth.c ipset.c domain.c \
-                   dnssec.c dnssec-openssl.c blockdata.c tables.c \
--                  loop.c inotify.c poll.c
-+                  loop.c inotify.c poll.c rrfilter.c
- LOCAL_MODULE := dnsmasq
-diff --git a/src/dnsmasq.h b/src/dnsmasq.h
-index 4344cae..39a930c 100644
---- a/src/dnsmasq.h
-+++ b/src/dnsmasq.h
-@@ -1513,3 +1513,8 @@ int poll_check(int fd, short event);
- void poll_listen(int fd, short event);
- int do_poll(int timeout);
-+/* rrfilter.c */
-+size_t rrfilter(struct dns_header *header, size_t plen, int mode);
-+u16 *rrfilter_desc(int type);
-+int expand_workspace(unsigned char ***wkspc, int *szp, int new);
-+
-diff --git a/src/dnssec.c b/src/dnssec.c
-index 359231f..fa3eb81 100644
---- a/src/dnssec.c
-+++ b/src/dnssec.c
-@@ -507,50 +507,6 @@ static int check_date_range(unsigned long date_start, unsigned long date_end)
-     && serial_compare_32(curtime, date_end) == SERIAL_LT;
- }
--static u16 *get_desc(int type)
--{
--  /* List of RRtypes which include domains in the data.
--     0 -> domain
--     integer -> no of plain bytes
--     -1 -> end
--
--     zero is not a valid RRtype, so the final entry is returned for
--     anything which needs no mangling.
--  */
--  
--  static u16 rr_desc[] = 
--    { 
--      T_NS, 0, -1, 
--      T_MD, 0, -1,
--      T_MF, 0, -1,
--      T_CNAME, 0, -1,
--      T_SOA, 0, 0, -1,
--      T_MB, 0, -1,
--      T_MG, 0, -1,
--      T_MR, 0, -1,
--      T_PTR, 0, -1,
--      T_MINFO, 0, 0, -1,
--      T_MX, 2, 0, -1,
--      T_RP, 0, 0, -1,
--      T_AFSDB, 2, 0, -1,
--      T_RT, 2, 0, -1,
--      T_SIG, 18, 0, -1,
--      T_PX, 2, 0, 0, -1,
--      T_NXT, 0, -1,
--      T_KX, 2, 0, -1,
--      T_SRV, 6, 0, -1,
--      T_DNAME, 0, -1,
--      0, -1 /* wildcard/catchall */
--    }; 
--  
--  u16 *p = rr_desc;
--  
--  while (*p != type && *p != 0)
--    while (*p++ != (u16)-1);
--
--  return p+1;
--}
--
- /* Return bytes of canonicalised rdata, when the return value is zero, the remaining 
-    data, pointed to by *p, should be used raw. */
- static int get_rdata(struct dns_header *header, size_t plen, unsigned char *end, char *buff, int bufflen,
-@@ -594,34 +550,6 @@ static int get_rdata(struct dns_header *header, size_t plen, unsigned char *end,
-     }
- }
--static int expand_workspace(unsigned char ***wkspc, int *szp, int new)
--{
--  unsigned char **p;
--  int old = *szp;
--
--  if (old >= new+1)
--    return 1;
--
--  if (new >= 100)
--    return 0;
--
--  new += 5;
--  
--  if (!(p = whine_malloc(new * sizeof(unsigned char **))))
--    return 0;  
--  
--  if (old != 0 && *wkspc)
--    {
--      memcpy(p, *wkspc, old * sizeof(unsigned char **));
--      free(*wkspc);
--    }
--  
--  *wkspc = p;
--  *szp = new;
--
--  return 1;
--}
--
- /* Bubble sort the RRset into the canonical order. 
-    Note that the byte-streams from two RRs may get unsynced: consider 
-    RRs which have two domain-names at the start and then other data.
-@@ -849,7 +777,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
-   int rdlen, j, name_labels;
-   struct crec *crecp = NULL;
-   int algo, labels, orig_ttl, key_tag;
--  u16 *rr_desc = get_desc(type);
-+  u16 *rr_desc = rrfilter_desc(type);
-  
-   if (wildcard_out)
-     *wildcard_out = NULL;
-@@ -2266,239 +2194,6 @@ size_t dnssec_generate_query(struct dns_header *header, char *end, char *name, i
-   return ret;
- }
--/* Go through a domain name, find "pointers" and fix them up based on how many bytes
--   we've chopped out of the packet, or check they don't point into an elided part.  */
--static int check_name(unsigned char **namep, struct dns_header *header, size_t plen, int fixup, unsigned char **rrs, int rr_count)
--{
--  unsigned char *ansp = *namep;
--
--  while(1)
--    {
--      unsigned int label_type;
--      
--      if (!CHECK_LEN(header, ansp, plen, 1))
--      return 0;
--      
--      label_type = (*ansp) & 0xc0;
--
--      if (label_type == 0xc0)
--      {
--        /* pointer for compression. */
--        unsigned int offset;
--        int i;
--        unsigned char *p;
--        
--        if (!CHECK_LEN(header, ansp, plen, 2))
--          return 0;
--
--        offset = ((*ansp++) & 0x3f) << 8;
--        offset |= *ansp++;
--
--        p = offset + (unsigned char *)header;
--        
--        for (i = 0; i < rr_count; i++)
--          if (p < rrs[i])
--            break;
--          else
--            if (i & 1)
--              offset -= rrs[i] - rrs[i-1];
--
--        /* does the pointer end up in an elided RR? */
--        if (i & 1)
--          return 0;
--
--        /* No, scale the pointer */
--        if (fixup)
--          {
--            ansp -= 2;
--            *ansp++ = (offset >> 8) | 0xc0;
--            *ansp++ = offset & 0xff;
--          }
--        break;
--      }
--      else if (label_type == 0x80)
--      return 0; /* reserved */
--      else if (label_type == 0x40)
--      {
--        /* Extended label type */
--        unsigned int count;
--        
--        if (!CHECK_LEN(header, ansp, plen, 2))
--          return 0;
--        
--        if (((*ansp++) & 0x3f) != 1)
--          return 0; /* we only understand bitstrings */
--        
--        count = *(ansp++); /* Bits in bitstring */
--        
--        if (count == 0) /* count == 0 means 256 bits */
--          ansp += 32;
--        else
--          ansp += ((count-1)>>3)+1;
--      }
--      else
--      { /* label type == 0 Bottom six bits is length */
--        unsigned int len = (*ansp++) & 0x3f;
--        
--        if (!ADD_RDLEN(header, ansp, plen, len))
--          return 0;
--
--        if (len == 0)
--          break; /* zero length label marks the end. */
--      }
--    }
--
--  *namep = ansp;
--
--  return 1;
--}
--
--/* Go through RRs and check or fixup the domain names contained within */
--static int check_rrs(unsigned char *p, struct dns_header *header, size_t plen, int fixup, unsigned char **rrs, int rr_count)
--{
--  int i, type, class, rdlen;
--  unsigned char *pp;
--  
--  for (i = 0; i < ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount); i++)
--    {
--      pp = p;
--
--      if (!(p = skip_name(p, header, plen, 10)))
--      return 0;
--      
--      GETSHORT(type, p); 
--      GETSHORT(class, p);
--      p += 4; /* TTL */
--      GETSHORT(rdlen, p);
--
--      if (type != T_NSEC && type != T_NSEC3 && type != T_RRSIG)
--      {
--        /* fixup name of RR */
--        if (!check_name(&pp, header, plen, fixup, rrs, rr_count))
--          return 0;
--        
--        if (class == C_IN)
--          {
--            u16 *d;
-- 
--            for (pp = p, d = get_desc(type); *d != (u16)-1; d++)
--              {
--                if (*d != 0)
--                  pp += *d;
--                else if (!check_name(&pp, header, plen, fixup, rrs, rr_count))
--                  return 0;
--              }
--          }
--      }
--      
--      if (!ADD_RDLEN(header, p, plen, rdlen))
--      return 0;
--    }
--  
--  return 1;
--}
--      
--
--size_t filter_rrsigs(struct dns_header *header, size_t plen)
--{
--  static unsigned char **rrs;
--  static int rr_sz = 0;
--  
--  unsigned char *p = (unsigned char *)(header+1);
--  int i, rdlen, qtype, qclass, rr_found, chop_an, chop_ns, chop_ar;
--
--  if (ntohs(header->qdcount) != 1 ||
--      !(p = skip_name(p, header, plen, 4)))
--    return plen;
--  
--  GETSHORT(qtype, p);
--  GETSHORT(qclass, p);
--
--  /* First pass, find pointers to start and end of all the records we wish to elide:
--     records added for DNSSEC, unless explicity queried for */
--  for (rr_found = 0, chop_ns = 0, chop_an = 0, chop_ar = 0, i = 0; 
--       i < ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount);
--       i++)
--    {
--      unsigned char *pstart = p;
--      int type, class;
--
--      if (!(p = skip_name(p, header, plen, 10)))
--      return plen;
--      
--      GETSHORT(type, p); 
--      GETSHORT(class, p);
--      p += 4; /* TTL */
--      GETSHORT(rdlen, p);
--      
--      if ((type == T_NSEC || type == T_NSEC3 || type == T_RRSIG) && 
--        (type != qtype || class != qclass))
--      {
--        if (!expand_workspace(&rrs, &rr_sz, rr_found + 1))
--          return plen; 
--        
--        rrs[rr_found++] = pstart;
--
--        if (!ADD_RDLEN(header, p, plen, rdlen))
--          return plen;
--        
--        rrs[rr_found++] = p;
--        
--        if (i < ntohs(header->ancount))
--          chop_an++;
--        else if (i < (ntohs(header->nscount) + ntohs(header->ancount)))
--          chop_ns++;
--        else
--          chop_ar++;
--      }
--      else if (!ADD_RDLEN(header, p, plen, rdlen))
--      return plen;
--    }
--  
--  /* Nothing to do. */
--  if (rr_found == 0)
--    return plen;
--
--  /* Second pass, look for pointers in names in the records we're keeping and make sure they don't
--     point to records we're going to elide. This is theoretically possible, but unlikely. If
--     it happens, we give up and leave the answer unchanged. */
--  p = (unsigned char *)(header+1);
--  
--  /* question first */
--  if (!check_name(&p, header, plen, 0, rrs, rr_found))
--    return plen;
--  p += 4; /* qclass, qtype */
--  
--  /* Now answers and NS */
--  if (!check_rrs(p, header, plen, 0, rrs, rr_found))
--    return plen;
--  
--  /* Third pass, elide records */
--  for (p = rrs[0], i = 1; i < rr_found; i += 2)
--    {
--      unsigned char *start = rrs[i];
--      unsigned char *end = (i != rr_found - 1) ? rrs[i+1] : ((unsigned char *)(header+1)) + plen;
--      
--      memmove(p, start, end-start);
--      p += end-start;
--    }
--     
--  plen = p - (unsigned char *)header;
--  header->ancount = htons(ntohs(header->ancount) - chop_an);
--  header->nscount = htons(ntohs(header->nscount) - chop_ns);
--  header->arcount = htons(ntohs(header->arcount) - chop_ar);
--
--  /* Fourth pass, fix up pointers in the remaining records */
--  p = (unsigned char *)(header+1);
--  
--  check_name(&p, header, plen, 1, rrs, rr_found);
--  p += 4; /* qclass, qtype */
--  
--  check_rrs(p, header, plen, 1, rrs, rr_found);
--  
--  return plen;
--}
--
- unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name)
- {
-   int q;
-diff --git a/src/forward.c b/src/forward.c
-index dd22a62..3e801c8 100644
---- a/src/forward.c
-+++ b/src/forward.c
-@@ -662,7 +662,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
-   /* If the requestor didn't set the DO bit, don't return DNSSEC info. */
-   if (!do_bit)
--    n = filter_rrsigs(header, n);
-+    n = rrfilter(header, n, 1);
- #endif
-   /* do this after extract_addresses. Ensure NODATA reply and remove
-diff --git a/src/rrfilter.c b/src/rrfilter.c
-new file mode 100644
-index 0000000..ae12261
---- /dev/null
-+++ b/src/rrfilter.c
-@@ -0,0 +1,339 @@
-+/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+
-+   This program is free software; you can redistribute it and/or modify
-+   it under the terms of the GNU General Public License as published by
-+   the Free Software Foundation; version 2 dated June, 1991, or
-+   (at your option) version 3 dated 29 June, 2007.
-+ 
-+   This program 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 General Public License for more details.
-+     
-+   You should have received a copy of the GNU General Public License
-+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-+*/
-+
-+/* Code to safely remove RRs from an DNS answer */ 
-+
-+#include "dnsmasq.h"
-+
-+/* Go through a domain name, find "pointers" and fix them up based on how many bytes
-+   we've chopped out of the packet, or check they don't point into an elided part.  */
-+static int check_name(unsigned char **namep, struct dns_header *header, size_t plen, int fixup, unsigned char **rrs, int rr_count)
-+{
-+  unsigned char *ansp = *namep;
-+
-+  while(1)
-+    {
-+      unsigned int label_type;
-+      
-+      if (!CHECK_LEN(header, ansp, plen, 1))
-+      return 0;
-+      
-+      label_type = (*ansp) & 0xc0;
-+
-+      if (label_type == 0xc0)
-+      {
-+        /* pointer for compression. */
-+        unsigned int offset;
-+        int i;
-+        unsigned char *p;
-+        
-+        if (!CHECK_LEN(header, ansp, plen, 2))
-+          return 0;
-+
-+        offset = ((*ansp++) & 0x3f) << 8;
-+        offset |= *ansp++;
-+
-+        p = offset + (unsigned char *)header;
-+        
-+        for (i = 0; i < rr_count; i++)
-+          if (p < rrs[i])
-+            break;
-+          else
-+            if (i & 1)
-+              offset -= rrs[i] - rrs[i-1];
-+
-+        /* does the pointer end up in an elided RR? */
-+        if (i & 1)
-+          return 0;
-+
-+        /* No, scale the pointer */
-+        if (fixup)
-+          {
-+            ansp -= 2;
-+            *ansp++ = (offset >> 8) | 0xc0;
-+            *ansp++ = offset & 0xff;
-+          }
-+        break;
-+      }
-+      else if (label_type == 0x80)
-+      return 0; /* reserved */
-+      else if (label_type == 0x40)
-+      {
-+        /* Extended label type */
-+        unsigned int count;
-+        
-+        if (!CHECK_LEN(header, ansp, plen, 2))
-+          return 0;
-+        
-+        if (((*ansp++) & 0x3f) != 1)
-+          return 0; /* we only understand bitstrings */
-+        
-+        count = *(ansp++); /* Bits in bitstring */
-+        
-+        if (count == 0) /* count == 0 means 256 bits */
-+          ansp += 32;
-+        else
-+          ansp += ((count-1)>>3)+1;
-+      }
-+      else
-+      { /* label type == 0 Bottom six bits is length */
-+        unsigned int len = (*ansp++) & 0x3f;
-+        
-+        if (!ADD_RDLEN(header, ansp, plen, len))
-+          return 0;
-+
-+        if (len == 0)
-+          break; /* zero length label marks the end. */
-+      }
-+    }
-+
-+  *namep = ansp;
-+
-+  return 1;
-+}
-+
-+/* Go through RRs and check or fixup the domain names contained within */
-+static int check_rrs(unsigned char *p, struct dns_header *header, size_t plen, int fixup, unsigned char **rrs, int rr_count)
-+{
-+  int i, j, type, class, rdlen;
-+  unsigned char *pp;
-+  
-+  for (i = 0; i < ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount); i++)
-+    {
-+      pp = p;
-+
-+      if (!(p = skip_name(p, header, plen, 10)))
-+      return 0;
-+      
-+      GETSHORT(type, p); 
-+      GETSHORT(class, p);
-+      p += 4; /* TTL */
-+      GETSHORT(rdlen, p);
-+
-+      /* If this RR is to be elided, don't fix up its contents */
-+      for (j = 0; j < rr_count; j += 2)
-+      if (rrs[j] == pp)
-+        break;
-+
-+      if (j >= rr_count)
-+      {
-+        /* fixup name of RR */
-+        if (!check_name(&pp, header, plen, fixup, rrs, rr_count))
-+          return 0;
-+        
-+        if (class == C_IN)
-+          {
-+            u16 *d;
-+ 
-+            for (pp = p, d = rrfilter_desc(type); *d != (u16)-1; d++)
-+              {
-+                if (*d != 0)
-+                  pp += *d;
-+                else if (!check_name(&pp, header, plen, fixup, rrs, rr_count))
-+                  return 0;
-+              }
-+          }
-+      }
-+      
-+      if (!ADD_RDLEN(header, p, plen, rdlen))
-+      return 0;
-+    }
-+  
-+  return 1;
-+}
-+      
-+
-+/* mode is 0 to remove EDNS0, 1 to filter DNSSEC RRs */
-+size_t rrfilter(struct dns_header *header, size_t plen, int mode)
-+{
-+  static unsigned char **rrs;
-+  static int rr_sz = 0;
-+
-+  unsigned char *p = (unsigned char *)(header+1);
-+  int i, rdlen, qtype, qclass, rr_found, chop_an, chop_ns, chop_ar;
-+
-+  if (ntohs(header->qdcount) != 1 ||
-+      !(p = skip_name(p, header, plen, 4)))
-+    return plen;
-+  
-+  GETSHORT(qtype, p);
-+  GETSHORT(qclass, p);
-+
-+  /* First pass, find pointers to start and end of all the records we wish to elide:
-+     records added for DNSSEC, unless explicity queried for */
-+  for (rr_found = 0, chop_ns = 0, chop_an = 0, chop_ar = 0, i = 0; 
-+       i < ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount);
-+       i++)
-+    {
-+      unsigned char *pstart = p;
-+      int type, class;
-+
-+      if (!(p = skip_name(p, header, plen, 10)))
-+      return plen;
-+      
-+      GETSHORT(type, p); 
-+      GETSHORT(class, p);
-+      p += 4; /* TTL */
-+      GETSHORT(rdlen, p);
-+        
-+      if (!ADD_RDLEN(header, p, plen, rdlen))
-+      return plen;
-+
-+      /* Don't remove the answer. */
-+      if (i < ntohs(header->ancount) && type == qtype && class == qclass)
-+      continue;
-+      
-+      if (mode == 0) /* EDNS */
-+      {
-+        /* EDNS mode, remove T_OPT from additional section only */
-+        if (i < (ntohs(header->nscount) + ntohs(header->ancount)) || type != T_OPT)
-+          continue;
-+      }
-+      else if (type != T_NSEC && type != T_NSEC3 && type != T_RRSIG)
-+      /* DNSSEC mode, remove SIGs and NSECs from all three sections. */
-+      continue;
-+      
-+      
-+      if (!expand_workspace(&rrs, &rr_sz, rr_found + 1))
-+      return plen; 
-+      
-+      rrs[rr_found++] = pstart;
-+      rrs[rr_found++] = p;
-+      
-+      if (i < ntohs(header->ancount))
-+      chop_an++;
-+      else if (i < (ntohs(header->nscount) + ntohs(header->ancount)))
-+      chop_ns++;
-+      else
-+      chop_ar++;
-+    }
-+  
-+  /* Nothing to do. */
-+  if (rr_found == 0)
-+    return plen;
-+
-+  /* Second pass, look for pointers in names in the records we're keeping and make sure they don't
-+     point to records we're going to elide. This is theoretically possible, but unlikely. If
-+     it happens, we give up and leave the answer unchanged. */
-+  p = (unsigned char *)(header+1);
-+  
-+  /* question first */
-+  if (!check_name(&p, header, plen, 0, rrs, rr_found))
-+    return plen;
-+  p += 4; /* qclass, qtype */
-+  
-+  /* Now answers and NS */
-+  if (!check_rrs(p, header, plen, 0, rrs, rr_found))
-+    return plen;
-+  
-+  /* Third pass, elide records */
-+  for (p = rrs[0], i = 1; i < rr_found; i += 2)
-+    {
-+      unsigned char *start = rrs[i];
-+      unsigned char *end = (i != rr_found - 1) ? rrs[i+1] : ((unsigned char *)(header+1)) + plen;
-+      
-+      memmove(p, start, end-start);
-+      p += end-start;
-+    }
-+     
-+  plen = p - (unsigned char *)header;
-+  header->ancount = htons(ntohs(header->ancount) - chop_an);
-+  header->nscount = htons(ntohs(header->nscount) - chop_ns);
-+  header->arcount = htons(ntohs(header->arcount) - chop_ar);
-+
-+  /* Fourth pass, fix up pointers in the remaining records */
-+  p = (unsigned char *)(header+1);
-+  
-+  check_name(&p, header, plen, 1, rrs, rr_found);
-+  p += 4; /* qclass, qtype */
-+  
-+  check_rrs(p, header, plen, 1, rrs, rr_found);
-+  
-+  return plen;
-+}
-+
-+/* This is used in the DNSSEC code too, hence it's exported */
-+u16 *rrfilter_desc(int type)
-+{
-+  /* List of RRtypes which include domains in the data.
-+     0 -> domain
-+     integer -> no of plain bytes
-+     -1 -> end
-+
-+     zero is not a valid RRtype, so the final entry is returned for
-+     anything which needs no mangling.
-+  */
-+  
-+  static u16 rr_desc[] = 
-+    { 
-+      T_NS, 0, -1, 
-+      T_MD, 0, -1,
-+      T_MF, 0, -1,
-+      T_CNAME, 0, -1,
-+      T_SOA, 0, 0, -1,
-+      T_MB, 0, -1,
-+      T_MG, 0, -1,
-+      T_MR, 0, -1,
-+      T_PTR, 0, -1,
-+      T_MINFO, 0, 0, -1,
-+      T_MX, 2, 0, -1,
-+      T_RP, 0, 0, -1,
-+      T_AFSDB, 2, 0, -1,
-+      T_RT, 2, 0, -1,
-+      T_SIG, 18, 0, -1,
-+      T_PX, 2, 0, 0, -1,
-+      T_NXT, 0, -1,
-+      T_KX, 2, 0, -1,
-+      T_SRV, 6, 0, -1,
-+      T_DNAME, 0, -1,
-+      0, -1 /* wildcard/catchall */
-+    }; 
-+  
-+  u16 *p = rr_desc;
-+  
-+  while (*p != type && *p != 0)
-+    while (*p++ != (u16)-1);
-+
-+  return p+1;
-+}
-+
-+int expand_workspace(unsigned char ***wkspc, int *szp, int new)
-+{
-+  unsigned char **p;
-+  int old = *szp;
-+
-+  if (old >= new+1)
-+    return 1;
-+
-+  if (new >= 100)
-+    return 0;
-+
-+  new += 5;
-+  
-+  if (!(p = whine_malloc(new * sizeof(unsigned char **))))
-+    return 0;  
-+  
-+  if (old != 0 && *wkspc)
-+    {
-+      memcpy(p, *wkspc, old * sizeof(unsigned char **));
-+      free(*wkspc);
-+    }
-+  
-+  *wkspc = p;
-+  *szp = new;
-+
-+  return 1;
-+}
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/020-DNSSEC_validation_tweak.patch b/src/patches/dnsmasq/020-DNSSEC_validation_tweak.patch
deleted file mode 100644 (file)
index ffb412b..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-From 2dbba34b2c1289a108f876c78b84889f2a93115d Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Wed, 16 Dec 2015 13:41:58 +0000
-Subject: [PATCH] DNSSEC validation tweak.
-
-A zone which has at least one key with an algorithm we don't
-support should be considered as insecure.
----
- src/dnssec.c |   82 ++++++++++++++++++++++++++++++++++++++--------------------
- 1 file changed, 54 insertions(+), 28 deletions(-)
-
-diff --git a/src/dnssec.c b/src/dnssec.c
-index fa3eb81..dc563e0 100644
---- a/src/dnssec.c
-+++ b/src/dnssec.c
-@@ -763,10 +763,10 @@ static int explore_rrset(struct dns_header *header, size_t plen, int class, int
-    STAT_NEED_KEY need DNSKEY to complete validation (name is returned in keyname)
-    STAT_NEED_DS  need DS to complete validation (name is returned in keyname)
--   if key is non-NULL, use that key, which has the algo and tag given in the params of those names,
-+   If key is non-NULL, use that key, which has the algo and tag given in the params of those names,
-    otherwise find the key in the cache.
--   name is unchanged on exit. keyname is used as workspace and trashed.
-+   Name is unchanged on exit. keyname is used as workspace and trashed.
-    Call explore_rrset first to find and count RRs and sigs.
- */
-@@ -919,6 +919,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
-   return STAT_BOGUS;
- }
-  
-+
- /* The DNS packet is expected to contain the answer to a DNSKEY query.
-    Put all DNSKEYs in the answer which are valid into the cache.
-    return codes:
-@@ -1831,15 +1832,15 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
- /* Check signing status of name.
-    returns:
--   STAT_SECURE zone is signed.
--   STAT_INSECURE zone proved unsigned.
--   STAT_NEED_DS require DS record of name returned in keyname.
--   
-+   STAT_SECURE      zone is signed.
-+   STAT_INSECURE    zone proved unsigned.
-+   STAT_NEED_DS     require DS record of name returned in keyname.
-+   STAT_NEED_DNSKEY require DNSKEY record of name returned in keyname.
-    name returned unaltered.
- */
- static int zone_status(char *name, int class, char *keyname, time_t now)
- {
--  int name_start = strlen(name);
-+  int secure_ds, name_start = strlen(name);
-   struct crec *crecp;
-   char *p;
-   
-@@ -1850,27 +1851,52 @@ static int zone_status(char *name, int class, char *keyname, time_t now)
-       if (!(crecp = cache_find_by_name(NULL, keyname, now, F_DS)))
-       return STAT_NEED_DS;
-       else
--      do 
--        {
--          if (crecp->uid == (unsigned int)class)
--            {
--              /* F_DNSSECOK misused in DS cache records to non-existance of NS record.
--                 F_NEG && !F_DNSSECOK implies that we've proved there's no DS record here,
--                 but that's because there's no NS record either, ie this isn't the start
--                 of a zone. We only prove that the DNS tree below a node is unsigned when
--                 we prove that we're at a zone cut AND there's no DS record.
--              */        
--              if (crecp->flags & F_NEG)
--                {
--                  if (crecp->flags & F_DNSSECOK)
--                    return STAT_INSECURE; /* proved no DS here */
--                }
--              else if (!ds_digest_name(crecp->addr.ds.digest) || !algo_digest_name(crecp->addr.ds.algo))
--                return STAT_INSECURE; /* algo we can't use - insecure */
--            }
--        }
--      while ((crecp = cache_find_by_name(crecp, keyname, now, F_DS)));
--      
-+      {
-+        secure_ds = 0;
-+        
-+        do 
-+          {
-+            if (crecp->uid == (unsigned int)class)
-+              {
-+                /* F_DNSSECOK misused in DS cache records to non-existance of NS record.
-+                   F_NEG && !F_DNSSECOK implies that we've proved there's no DS record here,
-+                   but that's because there's no NS record either, ie this isn't the start
-+                   of a zone. We only prove that the DNS tree below a node is unsigned when
-+                   we prove that we're at a zone cut AND there's no DS record.
-+                */      
-+                if (crecp->flags & F_NEG)
-+                  {
-+                    if (crecp->flags & F_DNSSECOK)
-+                      return STAT_INSECURE; /* proved no DS here */
-+                  }
-+                else if (!ds_digest_name(crecp->addr.ds.digest) || !algo_digest_name(crecp->addr.ds.algo))
-+                  return STAT_INSECURE; /* algo we can't use - insecure */
-+                else
-+                  secure_ds = 1;
-+              }
-+          }
-+        while ((crecp = cache_find_by_name(crecp, keyname, now, F_DS)));
-+      }
-+
-+      if (secure_ds)
-+      {
-+        /* We've found only DS records that attest to the DNSKEY RRset in the zone, so we believe
-+           that RRset is good. Furthermore the DNSKEY whose hash is proved by the DS record is
-+           one we can use. However the DNSKEY RRset may contain more than one key and
-+           one of the other keys may use an algorithm we don't support. If that's 
-+           the case the zone is insecure for us. */
-+        
-+        if (!(crecp = cache_find_by_name(NULL, keyname, now, F_DNSKEY)))
-+          return STAT_NEED_KEY;
-+
-+        do 
-+          {
-+            if (crecp->uid == (unsigned int)class && !algo_digest_name(crecp->addr.key.algo))
-+              return STAT_INSECURE;
-+          }
-+        while ((crecp = cache_find_by_name(crecp, keyname, now, F_DNSKEY)));
-+      }
-+
-       if (name_start == 0)
-       break;
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/021-Tweaks_to_EDNS0_handling_in_DNS_replies.patch b/src/patches/dnsmasq/021-Tweaks_to_EDNS0_handling_in_DNS_replies.patch
deleted file mode 100644 (file)
index c3c74cc..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-From dd4ad9ac7ea6d51dcc34a1f2cd2da14efbb87714 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Thu, 17 Dec 2015 10:44:58 +0000
-Subject: [PATCH] Tweaks to EDNS0 handling in DNS replies.
-
----
- src/dnssec.c  |   20 +++++++++-----------
- src/rfc1035.c |   57 +++++++++++++++++++++++++++++++++------------------------
- 2 files changed, 42 insertions(+), 35 deletions(-)
-
-diff --git a/src/dnssec.c b/src/dnssec.c
-index dc563e0..012b2a6 100644
---- a/src/dnssec.c
-+++ b/src/dnssec.c
-@@ -2129,18 +2129,16 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
-           /* Empty DS without NSECS */
-           if (qtype == T_DS)
-             return STAT_BOGUS;
--          else
-+          
-+          rc = zone_status(name, qclass, keyname, now);
-+          if (rc != STAT_SECURE)
-             {
--              rc = zone_status(name, qclass, keyname, now);
--              if (rc != STAT_SECURE)
--                {
--                  if (class)
--                    *class = qclass; /* Class for NEED_DS or NEED_DNSKEY */
--                  return rc;
--                } 
--              
--              return STAT_BOGUS; /* signed zone, no NSECs */
--            }
-+              if (class)
-+                *class = qclass; /* Class for NEED_DS or NEED_DNSKEY */
-+              return rc;
-+            } 
-+          
-+          return STAT_BOGUS; /* signed zone, no NSECs */
-         }
-         if (nsec_type == T_NSEC)
-diff --git a/src/rfc1035.c b/src/rfc1035.c
-index def8fa0..188d05f 100644
---- a/src/rfc1035.c
-+++ b/src/rfc1035.c
-@@ -1539,7 +1539,13 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
-   int nxdomain = 0, auth = 1, trunc = 0, sec_data = 1;
-   struct mx_srv_record *rec;
-   size_t len;
-- 
-+  
-+  if (ntohs(header->ancount) != 0 ||
-+      ntohs(header->nscount) != 0 ||
-+      ntohs(header->qdcount) == 0 || 
-+      OPCODE(header) != QUERY )
-+    return 0;
-+  
-   /* Don't return AD set if checking disabled. */
-   if (header->hb4 & HB4_CD)
-     sec_data = 0;
-@@ -1548,33 +1554,32 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
-   *ad_reqd = header->hb4 & HB4_AD;
-   *do_bit = 0;
--  /* If there is an RFC2671 pseudoheader then it will be overwritten by
-+  /* If there is an  additional data section then it will be overwritten by
-      partial replies, so we have to do a dry run to see if we can answer
--     the query. We check to see if the do bit is set, if so we always
--     forward rather than answering from the cache, which doesn't include
--     security information, unless we're in DNSSEC validation mode. */
-+     the query. */
--  if (find_pseudoheader(header, qlen, NULL, &pheader, NULL))
--    { 
--      unsigned short flags;
--      
--      have_pseudoheader = 1;
-+  if (ntohs(header->arcount) != 0)
-+    {
-+      dryrun = 1;
--      pheader += 4; /* udp size, ext_rcode */
--      GETSHORT(flags, pheader);
--      
--      if ((sec_reqd = flags & 0x8000))
--      {
--        *do_bit = 1;/* do bit */ 
--        *ad_reqd = 1;
-+      /* If there's an additional section, there might be an EDNS(0) pseudoheader */
-+      if (find_pseudoheader(header, qlen, NULL, &pheader, NULL))
-+      { 
-+        unsigned short flags;
-+        
-+        have_pseudoheader = 1;
-+        
-+        pheader += 4; /* udp size, ext_rcode */
-+        GETSHORT(flags, pheader);
-+        
-+        if ((sec_reqd = flags & 0x8000))
-+          {
-+            *do_bit = 1;/* do bit */ 
-+            *ad_reqd = 1;
-+          }
-       }
--
--      dryrun = 1;
-     }
--  if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
--    return 0;
--  
-   for (rec = daemon->mxnames; rec; rec = rec->next)
-     rec->offset = 0;
-   
-@@ -1730,8 +1735,12 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
-               }
-             else if ((crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
-               {
--                /* Don't use cache when DNSSEC data required. */
--                if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !sec_reqd || !(crecp->flags & F_DNSSECOK))
-+                /* Don't use cache when DNSSEC data required, unless we know that
-+                   the zone is unsigned, which implies that we're doing
-+                   validation. */
-+                if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || 
-+                    !sec_reqd || 
-+                    (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))
-                   {
-                     do 
-                       { 
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/022-Tidy_up_DNSSEC_non-existence_code_Check_zone_status_is_NSEC_proof_bad.patch b/src/patches/dnsmasq/022-Tidy_up_DNSSEC_non-existence_code_Check_zone_status_is_NSEC_proof_bad.patch
deleted file mode 100644 (file)
index 60503e9..0000000
+++ /dev/null
@@ -1,409 +0,0 @@
-From b40f26c0199235073abc37e1e1d6ed93bed372f5 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Thu, 17 Dec 2015 11:57:26 +0000
-Subject: [PATCH] Tidy up DNSSEC non-existence code. Check zone status is NSEC
- proof bad.
-
----
- src/dnssec.c |  207 +++++++++++++++++++++++++---------------------------------
- 1 file changed, 90 insertions(+), 117 deletions(-)
-
-diff --git a/src/dnssec.c b/src/dnssec.c
-index 012b2a6..ddae497 100644
---- a/src/dnssec.c
-+++ b/src/dnssec.c
-@@ -1367,59 +1367,6 @@ static int hostname_cmp(const char *a, const char *b)
-     }
- }
--/* Find all the NSEC or NSEC3 records in a reply.
--   return an array of pointers to them. */
--static int find_nsec_records(struct dns_header *header, size_t plen, unsigned char ***nsecsetp, int *nsecsetl, int class_reqd)
--{
--  static unsigned char **nsecset = NULL;
--  static int nsecset_sz = 0;
--  
--  int type_found = 0;
--  unsigned char *p = skip_questions(header, plen);
--  int type, class, rdlen, i, nsecs_found;
--
--  /* Move to NS section */
--  if (!p || !(p = skip_section(p, ntohs(header->ancount), header, plen)))
--    return 0;
--  
--  for (nsecs_found = 0, i = ntohs(header->nscount); i != 0; i--)
--    {
--      unsigned char *pstart = p;
--      
--      if (!(p = skip_name(p, header, plen, 10)))
--      return 0;
--      
--      GETSHORT(type, p); 
--      GETSHORT(class, p);
--      p += 4; /* TTL */
--      GETSHORT(rdlen, p);
--
--      if (class == class_reqd && (type == T_NSEC || type == T_NSEC3))
--      {
--        /* No mixed NSECing 'round here, thankyouverymuch */
--        if (type_found == T_NSEC && type == T_NSEC3)
--          return 0;
--        if (type_found == T_NSEC3 && type == T_NSEC)
--          return 0;
--
--        type_found = type;
--
--        if (!expand_workspace(&nsecset, &nsecset_sz, nsecs_found))
--          return 0; 
--        
--        nsecset[nsecs_found++] = pstart;
--      }
--      
--      if (!ADD_RDLEN(header, p, plen, rdlen))
--      return 0;
--    }
--  
--  *nsecsetp = nsecset;
--  *nsecsetl = nsecs_found;
--  
--  return type_found;
--}
--
- static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsigned char **nsecs, int nsec_count,
-                                   char *workspace1, char *workspace2, char *name, int type, int *nons)
- {
-@@ -1436,12 +1383,12 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
-     {
-       p = nsecs[i];
-       if (!extract_name(header, plen, &p, workspace1, 1, 10))
--      return STAT_BOGUS;
-+      return 0;
-       p += 8; /* class, type, TTL */
-       GETSHORT(rdlen, p);
-       psave = p;
-       if (!extract_name(header, plen, &p, workspace2, 1, 10))
--      return STAT_BOGUS;
-+      return 0;
-       
-       rc = hostname_cmp(workspace1, name);
-       
-@@ -1449,7 +1396,7 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
-       {
-         /* 4035 para 5.4. Last sentence */
-         if (type == T_NSEC || type == T_RRSIG)
--          return STAT_SECURE;
-+          return 1;
-         /* NSEC with the same name as the RR we're testing, check
-            that the type in question doesn't appear in the type map */
-@@ -1465,24 +1412,24 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
-             /* A CNAME answer would also be valid, so if there's a CNAME is should 
-                have been returned. */
-             if ((p[2] & (0x80 >> T_CNAME)) != 0)
--              return STAT_BOGUS;
-+              return 0;
-             
-             /* If the SOA bit is set for a DS record, then we have the
-                DS from the wrong side of the delegation. */
-             if (type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
--              return STAT_BOGUS;
-+              return 0;
-           }
-         while (rdlen >= 2)
-           {
-             if (!CHECK_LEN(header, p, plen, rdlen))
--              return STAT_BOGUS;
-+              return 0;
-             
-             if (p[0] == type >> 8)
-               {
-                 /* Does the NSEC say our type exists? */
-                 if (offset < p[1] && (p[offset+2] & mask) != 0)
--                  return STAT_BOGUS;
-+                  return 0;
-                 
-                 break; /* finshed checking */
-               }
-@@ -1491,24 +1438,24 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
-             p +=  p[1];
-           }
-         
--        return STAT_SECURE;
-+        return 1;
-       }
-       else if (rc == -1)
-       {
-         /* Normal case, name falls between NSEC name and next domain name,
-            wrap around case, name falls between NSEC name (rc == -1) and end */
-         if (hostname_cmp(workspace2, name) >= 0 || hostname_cmp(workspace1, workspace2) >= 0)
--          return STAT_SECURE;
-+          return 1;
-       }
-       else 
-       {
-         /* wrap around case, name falls between start and next domain name */
-         if (hostname_cmp(workspace1, workspace2) >= 0 && hostname_cmp(workspace2, name) >=0 )
--          return STAT_SECURE;
-+          return 1;
-       }
-     }
-   
--  return STAT_BOGUS;
-+  return 0;
- }
- /* return digest length, or zero on error */
-@@ -1701,7 +1648,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
-   for (i = 0; i < nsec_count; i++)
-     {
-       if (!(p = skip_name(nsecs[i], header, plen, 15)))
--      return STAT_BOGUS; /* bad packet */
-+      return 0; /* bad packet */
-       
-       p += 10; /* type, class, TTL, rdlen */
-       algo = *p++;
-@@ -1712,14 +1659,14 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
-   /* No usable NSEC3s */
-   if (i == nsec_count)
--    return STAT_BOGUS;
-+    return 0;
-   p++; /* flags */
-   GETSHORT (iterations, p);
-   salt_len = *p++;
-   salt = p;
-   if (!CHECK_LEN(header, salt, plen, salt_len))
--    return STAT_BOGUS; /* bad packet */
-+    return 0; /* bad packet */
-     
-   /* Now prune so we only have NSEC3 records with same iterations, salt and algo */
-   for (i = 0; i < nsec_count; i++)
-@@ -1730,7 +1677,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
-       nsecs[i] = NULL; /* Speculative, will be restored if OK. */
-       
-       if (!(p = skip_name(nsec3p, header, plen, 15)))
--      return STAT_BOGUS; /* bad packet */
-+      return 0; /* bad packet */
-       
-       p += 10; /* type, class, TTL, rdlen */
-       
-@@ -1747,7 +1694,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
-       continue;
-       
-       if (!CHECK_LEN(header, p, plen, salt_len))
--      return STAT_BOGUS; /* bad packet */
-+      return 0; /* bad packet */
-       if (memcmp(p, salt, salt_len) != 0)
-       continue;
-@@ -1758,13 +1705,13 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
-   /* Algo is checked as 1 above */
-   if (!(hash = hash_find("sha1")))
--    return STAT_BOGUS;
-+    return 0;
-   if ((digest_len = hash_name(name, &digest, hash, salt, salt_len, iterations)) == 0)
--    return STAT_BOGUS;
-+    return 0;
-   
-   if (check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, nons))
--    return STAT_SECURE;
-+    return 1;
-   /* Can't find an NSEC3 which covers the name directly, we need the "closest encloser NSEC3" 
-      or an answer inferred from a wildcard record. */
-@@ -1780,14 +1727,14 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
-       break;
-       if ((digest_len = hash_name(closest_encloser, &digest, hash, salt, salt_len, iterations)) == 0)
--      return STAT_BOGUS;
-+      return 0;
-       
-       for (i = 0; i < nsec_count; i++)
-       if ((p = nsecs[i]))
-         {
-           if (!extract_name(header, plen, &p, workspace1, 1, 0) ||
-               !(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
--            return STAT_BOGUS;
-+            return 0;
-         
-           if (digest_len == base32_len &&
-               memcmp(digest, workspace2, digest_len) == 0)
-@@ -1802,32 +1749,81 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
-   while ((closest_encloser = strchr(closest_encloser, '.')));
-   
-   if (!closest_encloser)
--    return STAT_BOGUS;
-+    return 0;
-   
-   /* Look for NSEC3 that proves the non-existence of the next-closest encloser */
-   if ((digest_len = hash_name(next_closest, &digest, hash, salt, salt_len, iterations)) == 0)
--    return STAT_BOGUS;
-+    return 0;
-   if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL))
--    return STAT_BOGUS;
-+    return 0;
-   
-   /* Finally, check that there's no seat of wildcard synthesis */
-   if (!wildname)
-     {
-       if (!(wildcard = strchr(next_closest, '.')) || wildcard == next_closest)
--      return STAT_BOGUS;
-+      return 0;
-       
-       wildcard--;
-       *wildcard = '*';
-       
-       if ((digest_len = hash_name(wildcard, &digest, hash, salt, salt_len, iterations)) == 0)
--      return STAT_BOGUS;
-+      return 0;
-       
-       if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL))
--      return STAT_BOGUS;
-+      return 0;
-     }
-   
--  return STAT_SECURE;
-+  return 1;
-+}
-+
-+static int prove_non_existence(struct dns_header *header, size_t plen, char *keyname, char *name, int qtype, int qclass, char *wildname, int *nons)
-+{
-+  static unsigned char **nsecset = NULL;
-+  static int nsecset_sz = 0;
-+  
-+  int type_found = 0;
-+  unsigned char *p = skip_questions(header, plen);
-+  int type, class, rdlen, i, nsecs_found;
-+  
-+  /* Move to NS section */
-+  if (!p || !(p = skip_section(p, ntohs(header->ancount), header, plen)))
-+    return 0;
-+  
-+  for (nsecs_found = 0, i = ntohs(header->nscount); i != 0; i--)
-+    {
-+      unsigned char *pstart = p;
-+      
-+      if (!(p = skip_name(p, header, plen, 10)))
-+      return 0;
-+      
-+      GETSHORT(type, p); 
-+      GETSHORT(class, p);
-+      p += 4; /* TTL */
-+      GETSHORT(rdlen, p);
-+
-+      if (class == qclass && (type == T_NSEC || type == T_NSEC3))
-+      {
-+        /* No mixed NSECing 'round here, thankyouverymuch */
-+        if (type_found != 0 && type_found != type)
-+          return 0;
-+
-+        type_found = type;
-+
-+        if (!expand_workspace(&nsecset, &nsecset_sz, nsecs_found))
-+          return 0; 
-+        
-+        nsecset[nsecs_found++] = pstart;
-+      }
-+      
-+      if (!ADD_RDLEN(header, p, plen, rdlen))
-+      return 0;
-+    }
-+  
-+  if (type_found == T_NSEC)
-+    return prove_non_existence_nsec(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, nons);
-+  else
-+    return prove_non_existence_nsec3(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, wildname, nons);
- }
- /* Check signing status of name.
-@@ -1925,10 +1921,9 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
-   static unsigned char **targets = NULL;
-   static int target_sz = 0;
--  unsigned char *ans_start, *p1, *p2, **nsecs;
-+  unsigned char *ans_start, *p1, *p2;
-   int type1, class1, rdlen1, type2, class2, rdlen2, qclass, qtype, targetidx;
--  int i, j, rc, nsec_count;
--  int nsec_type;
-+  int i, j, rc;
-   if (neganswer)
-     *neganswer = 0;
-@@ -2080,28 +2075,15 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
-                         targets[j] = NULL;
-                     }
-                           
--                if (rc == STAT_SECURE_WILDCARD)
--                  {
--                    /* An attacker replay a wildcard answer with a different
--                       answer and overlay a genuine RR. To prove this
--                       hasn't happened, the answer must prove that
--                       the gennuine record doesn't exist. Check that here. */
--                    if (!(nsec_type = find_nsec_records(header, plen, &nsecs, &nsec_count, class1)))
--                      return STAT_BOGUS; /* No NSECs or bad packet */
--                    
--                    /* Note that we may not yet have validated the NSEC/NSEC3 RRsets. Since the check
--                       below returns either SECURE or BOGUS, that's not a problem. If the RRsets later fail
--                       we'll return BOGUS then. */
--
--                    if (nsec_type == T_NSEC)
--                      rc = prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, type1, NULL);
--                    else
--                      rc = prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename, 
--                                                     keyname, name, type1, wildname, NULL);
--                    
--                    if (rc == STAT_BOGUS)
--                      return rc;
--                  } 
-+                 /* An attacker replay a wildcard answer with a different
-+                    answer and overlay a genuine RR. To prove this
-+                    hasn't happened, the answer must prove that
-+                    the gennuine record doesn't exist. Check that here. 
-+                    Note that we may not yet have validated the NSEC/NSEC3 RRsets. 
-+                    That's not a problem since if the RRsets later fail
-+                    we'll return BOGUS then. */
-+                if (rc == STAT_SECURE_WILDCARD && !prove_non_existence(header, plen, keyname, name, type1, class1, wildname, NULL))
-+                  return STAT_BOGUS;
-               }
-           }
-       }
-@@ -2124,14 +2106,13 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
-       /* For anything other than a DS record, this situation is OK if either
-          the answer is in an unsigned zone, or there's a NSEC records. */
--      if (!(nsec_type = find_nsec_records(header, plen, &nsecs, &nsec_count, qclass)))
-+      if (!prove_non_existence(header, plen, keyname, name, qtype, qclass, NULL, nons))
-         {
-           /* Empty DS without NSECS */
-           if (qtype == T_DS)
-             return STAT_BOGUS;
-           
--          rc = zone_status(name, qclass, keyname, now);
--          if (rc != STAT_SECURE)
-+          if ((rc = zone_status(name, qclass, keyname, now)) != STAT_SECURE)
-             {
-               if (class)
-                 *class = qclass; /* Class for NEED_DS or NEED_DNSKEY */
-@@ -2140,14 +2121,6 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
-           
-           return STAT_BOGUS; /* signed zone, no NSECs */
-         }
--
--        if (nsec_type == T_NSEC)
--        rc = prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, qtype, nons);
--      else
--        rc = prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, qtype, NULL, nons);
--
--      if (rc != STAT_SECURE)
--        return rc;
-       }
-   
-   return STAT_SECURE;
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/023-Fix_brace_botch_in_dnssec_validate_ds.patch b/src/patches/dnsmasq/023-Fix_brace_botch_in_dnssec_validate_ds.patch
deleted file mode 100644 (file)
index eda6fbd..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-From 3b799c826db05fc2da1c6d15cbe372e394209d27 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Thu, 17 Dec 2015 16:58:04 +0000
-Subject: [PATCH] Fix brace botch in dnssec_validate_ds()
-MIME-Version: 1.0
-Content-Type: text/plain; charset=utf8
-Content-Transfer-Encoding: 8bit
-
-Thanks to MichaÅ\82 KÄ\99pieÅ\84 for spotting this.
----
- src/dnssec.c |   34 +++++++++++++++++-----------------
- 1 file changed, 17 insertions(+), 17 deletions(-)
-
-diff --git a/src/dnssec.c b/src/dnssec.c
-index ddae497..1f8c954 100644
---- a/src/dnssec.c
-+++ b/src/dnssec.c
-@@ -923,11 +923,11 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
- /* The DNS packet is expected to contain the answer to a DNSKEY query.
-    Put all DNSKEYs in the answer which are valid into the cache.
-    return codes:
--         STAT_OK           Done, key(s) in cache.
--       STAT_BOGUS        No DNSKEYs found, which  can be validated with DS,
--                         or self-sign for DNSKEY RRset is not valid, bad packet.
--       STAT_NEED_DS      DS records to validate a key not found, name in keyname 
--       STAT_NEED_DNSKEY  DNSKEY records to validate a key not found, name in keyname 
-+         STAT_OK        Done, key(s) in cache.
-+       STAT_BOGUS     No DNSKEYs found, which  can be validated with DS,
-+                      or self-sign for DNSKEY RRset is not valid, bad packet.
-+       STAT_NEED_DS   DS records to validate a key not found, name in keyname 
-+       STAT_NEED_KEY  DNSKEY records to validate a key not found, name in keyname 
- */
- int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class)
- {
-@@ -1224,13 +1224,13 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
-               }
-             
-             p = psave;
--            
--            if (!ADD_RDLEN(header, p, plen, rdlen))
--              return STAT_BOGUS; /* bad packet */
-           }
--        
--        cache_end_insert();
-+        if (!ADD_RDLEN(header, p, plen, rdlen))
-+          return STAT_BOGUS; /* bad packet */
-       }
-+
-+      cache_end_insert();
-+
-     }
-   else
-     {
-@@ -1828,10 +1828,10 @@ static int prove_non_existence(struct dns_header *header, size_t plen, char *key
- /* Check signing status of name.
-    returns:
--   STAT_SECURE      zone is signed.
--   STAT_INSECURE    zone proved unsigned.
--   STAT_NEED_DS     require DS record of name returned in keyname.
--   STAT_NEED_DNSKEY require DNSKEY record of name returned in keyname.
-+   STAT_SECURE   zone is signed.
-+   STAT_INSECURE zone proved unsigned.
-+   STAT_NEED_DS  require DS record of name returned in keyname.
-+   STAT_NEED_KEY require DNSKEY record of name returned in keyname.
-    name returned unaltered.
- */
- static int zone_status(char *name, int class, char *keyname, time_t now)
-@@ -2028,7 +2028,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
-                     if (rc == STAT_SECURE)
-                       rc = STAT_BOGUS;
-                      if (class)
--                       *class = class1; /* Class for NEED_DS or NEED_DNSKEY */
-+                       *class = class1; /* Class for NEED_DS or NEED_KEY */
-                   }
-                 else 
-                   rc = STAT_INSECURE; 
-@@ -2045,7 +2045,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
-               {
-                 /* Zone is insecure, don't need to validate RRset */
-                 if (class)
--                  *class = class1; /* Class for NEED_DS or NEED_DNSKEY */
-+                  *class = class1; /* Class for NEED_DS or NEED_KEY */
-                 return rc;
-               } 
-             
-@@ -2115,7 +2115,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
-           if ((rc = zone_status(name, qclass, keyname, now)) != STAT_SECURE)
-             {
-               if (class)
--                *class = qclass; /* Class for NEED_DS or NEED_DNSKEY */
-+                *class = qclass; /* Class for NEED_DS or NEED_KEY */
-               return rc;
-             } 
-           
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/024-Do_a_better_job_of_determining_which_DNSSEC_sig_algos_are_supported.patch b/src/patches/dnsmasq/024-Do_a_better_job_of_determining_which_DNSSEC_sig_algos_are_supported.patch
deleted file mode 100644 (file)
index abcae5c..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-From 14a4ae883d51130d33da7133287e8867c64bab65 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Thu, 17 Dec 2015 17:23:03 +0000
-Subject: [PATCH] Do a better job of determining which DNSSEC sig algos are
- supported.
-
----
- src/dnssec.c |   52 +++++++++++++++++++++++++++++++++++++---------------
- 1 file changed, 37 insertions(+), 15 deletions(-)
-
-diff --git a/src/dnssec.c b/src/dnssec.c
-index 1f8c954..82394ee 100644
---- a/src/dnssec.c
-+++ b/src/dnssec.c
-@@ -65,10 +65,9 @@ static char *algo_digest_name(int algo)
-     case 8: return "sha256";
-     case 10: return "sha512";
-     case 12: return "gosthash94";
--#ifndef NO_NETTLE_ECC
-     case 13: return "sha256";
-     case 14: return "sha384";
--#endif
-+
-     default: return NULL;
-     }
- }
-@@ -129,13 +128,15 @@ static int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char
- }
-   
- static int dnsmasq_rsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
--                            unsigned char *digest, int algo)
-+                            unsigned char *digest, size_t digest_len, int algo)
- {
-   unsigned char *p;
-   size_t exp_len;
-   
-   static struct rsa_public_key *key = NULL;
-   static mpz_t sig_mpz;
-+
-+  (void)digest_len;
-   
-   if (key == NULL)
-     {
-@@ -181,7 +182,7 @@ static int dnsmasq_rsa_verify(struct blockdata *key_data, unsigned int key_len,
- }  
- static int dnsmasq_dsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
--                            unsigned char *digest, int algo)
-+                            unsigned char *digest, size_t digest_len, int algo)
- {
-   unsigned char *p;
-   unsigned int t;
-@@ -189,6 +190,8 @@ static int dnsmasq_dsa_verify(struct blockdata *key_data, unsigned int key_len,
-   static struct dsa_public_key *key = NULL;
-   static struct dsa_signature *sig_struct;
-   
-+  (void)digest_len;
-+
-   if (key == NULL)
-     {
-       if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))) || 
-@@ -292,26 +295,45 @@ static int dnsmasq_ecdsa_verify(struct blockdata *key_data, unsigned int key_len
- } 
- #endif 
--static int verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
--                unsigned char *digest, size_t digest_len, int algo)
-+static int (*verify_func(int algo))(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
-+                                  unsigned char *digest, size_t digest_len, int algo)
- {
--  (void)digest_len;
--
-+    
-+  /* Enure at runtime that we have support for this digest */
-+  if (!hash_find(algo_digest_name(algo)))
-+    return NULL;
-+  
-+  /* This switch defines which sig algorithms we support, can't introspect Nettle for that. */
-   switch (algo)
-     {
-     case 1: case 5: case 7: case 8: case 10:
--      return dnsmasq_rsa_verify(key_data, key_len, sig, sig_len, digest, algo);
-+      return dnsmasq_rsa_verify;
-       
-     case 3: case 6: 
--      return dnsmasq_dsa_verify(key_data, key_len, sig, sig_len, digest, algo);
-+      return dnsmasq_dsa_verify;
-  
- #ifndef NO_NETTLE_ECC   
-     case 13: case 14:
--      return dnsmasq_ecdsa_verify(key_data, key_len, sig, sig_len, digest, digest_len, algo);
-+      return dnsmasq_ecdsa_verify;
- #endif
-     }
-   
--  return 0;
-+  return NULL;
-+}
-+
-+static int verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
-+                unsigned char *digest, size_t digest_len, int algo)
-+{
-+
-+  int (*func)(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
-+            unsigned char *digest, size_t digest_len, int algo);
-+  
-+  func = verify_func(algo);
-+  
-+  if (!func)
-+    return 0;
-+
-+  return (*func)(key_data, key_len, sig, sig_len, digest, digest_len, algo);
- }
- /* Convert from presentation format to wire format, in place.
-@@ -732,7 +754,7 @@ static int explore_rrset(struct dns_header *header, size_t plen, int class, int
-             if (check_date_range(sig_inception, sig_expiration) &&
-                 labels <= name_labels &&
-                 type_covered == type && 
--                algo_digest_name(algo))
-+                verify_func(algo))
-               {
-                 if (!expand_workspace(&sigs, &sig_sz, sigidx))
-                   return 0; 
-@@ -1865,7 +1887,7 @@ static int zone_status(char *name, int class, char *keyname, time_t now)
-                     if (crecp->flags & F_DNSSECOK)
-                       return STAT_INSECURE; /* proved no DS here */
-                   }
--                else if (!ds_digest_name(crecp->addr.ds.digest) || !algo_digest_name(crecp->addr.ds.algo))
-+                else if (!hash_find(ds_digest_name(crecp->addr.ds.digest)) || !verify_func(crecp->addr.ds.algo))
-                   return STAT_INSECURE; /* algo we can't use - insecure */
-                 else
-                   secure_ds = 1;
-@@ -1887,7 +1909,7 @@ static int zone_status(char *name, int class, char *keyname, time_t now)
-         do 
-           {
--            if (crecp->uid == (unsigned int)class && !algo_digest_name(crecp->addr.key.algo))
-+            if (crecp->uid == (unsigned int)class && !verify_func(crecp->addr.key.algo))
-               return STAT_INSECURE;
-           }
-         while ((crecp = cache_find_by_name(crecp, keyname, now, F_DNSKEY)));
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/025-Major_tidy_up_of_EDNS0_handling_and_computation_use_of_udp.patch b/src/patches/dnsmasq/025-Major_tidy_up_of_EDNS0_handling_and_computation_use_of_udp.patch
deleted file mode 100644 (file)
index c016e73..0000000
+++ /dev/null
@@ -1,643 +0,0 @@
-From fa14bec83b2db010fd076910fddab56957b9375d Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Sun, 20 Dec 2015 17:12:16 +0000
-Subject: [PATCH] Major tidy up of EDNS0 handling and computation/use of udp
- packet size.
-
----
- src/auth.c     |    8 ++-
- src/dnsmasq.h  |    7 ++-
- src/dnssec.c   |    1 -
- src/forward.c  |  184 ++++++++++++++++++++++++++++++++++++++++----------------
- src/netlink.c  |    3 +-
- src/rfc1035.c  |   81 +++++++------------------
- src/rrfilter.c |    2 +-
- 7 files changed, 168 insertions(+), 118 deletions(-)
-
-diff --git a/src/auth.c b/src/auth.c
-index 2b0b7d6..85bd5e7 100644
---- a/src/auth.c
-+++ b/src/auth.c
-@@ -81,7 +81,8 @@ int in_zone(struct auth_zone *zone, char *name, char **cut)
- }
--size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr, int local_query) 
-+size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr, 
-+                 int local_query, int do_bit, int have_pseudoheader) 
- {
-   char *name = daemon->namebuff;
-   unsigned char *p, *ansp;
-@@ -820,6 +821,11 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
-   header->ancount = htons(anscount);
-   header->nscount = htons(authcount);
-   header->arcount = htons(0);
-+
-+  /* Advertise our packet size limit in our reply */
-+  if (have_pseudoheader)
-+    return add_pseudoheader(header,  ansp - (unsigned char *)header, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit);
-+
-   return ansp - (unsigned char *)header;
- }
-   
-diff --git a/src/dnsmasq.h b/src/dnsmasq.h
-index 39a930c..abb34c5 100644
---- a/src/dnsmasq.h
-+++ b/src/dnsmasq.h
-@@ -1113,7 +1113,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *namebuff,
-                     int no_cache, int secure, int *doctored);
- size_t answer_request(struct dns_header *header, char *limit, size_t qlen,  
-                     struct in_addr local_addr, struct in_addr local_netmask, 
--                    time_t now, int *ad_reqd, int *do_bit);
-+                    time_t now, int ad_reqd, int do_bit, int have_pseudoheader);
- int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name, 
-                            struct bogus_addr *addr, time_t now);
- int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr);
-@@ -1123,6 +1123,8 @@ int check_for_local_domain(char *name, time_t now);
- unsigned int questions_crc(struct dns_header *header, size_t plen, char *buff);
- size_t resize_packet(struct dns_header *header, size_t plen, 
-                 unsigned char *pheader, size_t hlen);
-+size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit, 
-+                      unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do);
- size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3);
- size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, union mysockaddr *source);
- #ifdef HAVE_DNSSEC
-@@ -1141,7 +1143,8 @@ int private_net(struct in_addr addr, int ban_localhost);
- /* auth.c */
- #ifdef HAVE_AUTH
- size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, 
--                 time_t now, union mysockaddr *peer_addr, int local_query);
-+                 time_t now, union mysockaddr *peer_addr, int local_query,
-+                 int do_bit, int have_pseudoheader);
- int in_zone(struct auth_zone *zone, char *name, char **cut);
- #endif
-diff --git a/src/dnssec.c b/src/dnssec.c
-index 82394ee..299ca64 100644
---- a/src/dnssec.c
-+++ b/src/dnssec.c
-@@ -67,7 +67,6 @@ static char *algo_digest_name(int algo)
-     case 12: return "gosthash94";
-     case 13: return "sha256";
-     case 14: return "sha384";
--
-     default: return NULL;
-     }
- }
-diff --git a/src/forward.c b/src/forward.c
-index 3e801c8..041353c 100644
---- a/src/forward.c
-+++ b/src/forward.c
-@@ -244,7 +244,6 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
-   void *hash = &crc;
- #endif
-  unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
-- unsigned char *pheader;
-  (void)do_bit;
-@@ -264,7 +263,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
-        there's no point retrying the query, retry the key query instead...... */
-       if (forward->blocking_query)
-       {
--        int fd;
-+        int fd, is_sign;
-+        unsigned char *pheader;
-         
-         forward->flags &= ~FREC_TEST_PKTSZ;
-         
-@@ -276,8 +276,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
-         blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
-         plen = forward->stash_len;
-         
--        if (find_pseudoheader(header, plen, NULL, &pheader, NULL))
--          PUTSHORT((forward->flags & FREC_TEST_PKTSZ) ? SAFE_PKTSZ : forward->sentto->edns_pktsz, pheader);
-+        if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign) && !is_sign)
-+          PUTSHORT(SAFE_PKTSZ, pheader);
-         if (forward->sentto->addr.sa.sa_family == AF_INET) 
-           log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, "retry", (struct all_addr *)&forward->sentto->addr.in.sin_addr, "dnssec");
-@@ -394,32 +394,40 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
-       forward->log_id = daemon->log_id;
-       
-       if (option_bool(OPT_ADD_MAC))
--      plen = add_mac(header, plen, ((char *) header) + daemon->packet_buff_sz, &forward->source);
--      
-+      {
-+        size_t new = add_mac(header, plen, ((char *) header) + daemon->packet_buff_sz, &forward->source);
-+        if (new != plen)
-+          {
-+            plen = new;
-+            forward->flags |= FREC_ADDED_PHEADER;
-+          }
-+      }
-+
-       if (option_bool(OPT_CLIENT_SUBNET))
-       {
-         size_t new = add_source_addr(header, plen, ((char *) header) + daemon->packet_buff_sz, &forward->source); 
-         if (new != plen)
-           {
-             plen = new;
--            forward->flags |= FREC_HAS_SUBNET;
-+            forward->flags |= FREC_HAS_SUBNET | FREC_ADDED_PHEADER;
-           }
-       }
- #ifdef HAVE_DNSSEC
-       if (option_bool(OPT_DNSSEC_VALID))
-       {
--        size_t new_plen = add_do_bit(header, plen, ((char *) header) + daemon->packet_buff_sz);
-+        size_t new = add_do_bit(header, plen, ((char *) header) + daemon->packet_buff_sz);
-        
-+        if (new != plen)
-+          forward->flags |= FREC_ADDED_PHEADER;
-+
-+        plen = new;
-+            
-         /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
-            this allows it to select auth servers when one is returning bad data. */
-         if (option_bool(OPT_DNSSEC_DEBUG))
-           header->hb4 |= HB4_CD;
--        if (new_plen != plen)
--          forward->flags |= FREC_ADDED_PHEADER;
--
--        plen = new_plen;
-       }
- #endif
-       
-@@ -469,10 +477,23 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
-                   }
- #endif
-               }
--
--            if (find_pseudoheader(header, plen, NULL, &pheader, NULL))
--              PUTSHORT((forward->flags & FREC_TEST_PKTSZ) ? SAFE_PKTSZ : start->edns_pktsz, pheader);
-             
-+#ifdef HAVE_DNSSEC
-+            if (option_bool(OPT_DNSSEC_VALID) && !do_bit)
-+              {
-+                /* Difficult one here. If our client didn't send EDNS0, we will have set the UDP
-+                   packet size to 512. But that won't provide space for the RRSIGS in many cases.
-+                   The RRSIGS will be stripped out before the answer goes back, so the packet should
-+                   shrink again. So, if we added a do-bit, bump the udp packet size to the value
-+                   known to be OK for this server. Maybe check returned size after stripping and set
-+                   the truncated bit? */                
-+                unsigned char *pheader;
-+                int is_sign;
-+                if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign))
-+                  PUTSHORT(start->edns_pktsz, pheader);
-+              }
-+#endif
-+
-             if (retry_send(sendto(fd, (char *)header, plen, 0,
-                                   &start->addr.sa,
-                                   sa_len(&start->addr))))
-@@ -563,30 +584,34 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
-     }
- #endif
-   
--  /* If upstream is advertising a larger UDP packet size
--     than we allow, trim it so that we don't get overlarge
--     requests for the client. We can't do this for signed packets. */
--
-   if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign)))
-     {
--      unsigned short udpsz;
--      unsigned char *psave = sizep;
--      
--      GETSHORT(udpsz, sizep);
--
--      if (!is_sign && udpsz > daemon->edns_pktsz)
--      PUTSHORT(daemon->edns_pktsz, psave);
--      
-       if (check_subnet && !check_source(header, plen, pheader, query_source))
-       {
-         my_syslog(LOG_WARNING, _("discarding DNS reply: subnet option mismatch"));
-         return 0;
-       }
-       
--      if (added_pheader)
-+      if (!is_sign)
-       {
--        pheader = 0; 
--        header->arcount = htons(0);
-+        if (added_pheader)
-+          {
-+            /* client didn't send EDNS0, we added one, strip it off before returning answer. */
-+            n = rrfilter(header, n, 0);
-+            pheader = NULL;
-+          }
-+        else
-+          {
-+            /* If upstream is advertising a larger UDP packet size
-+               than we allow, trim it so that we don't get overlarge
-+               requests for the client. We can't do this for signed packets. */
-+            unsigned short udpsz;
-+            unsigned char *psave = sizep;
-+            
-+            GETSHORT(udpsz, sizep);
-+            if (udpsz > daemon->edns_pktsz)
-+              PUTSHORT(daemon->edns_pktsz, psave);
-+          }
-       }
-     }
-   
-@@ -655,14 +680,16 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
-     }
-   if (option_bool(OPT_DNSSEC_VALID))
--    header->hb4 &= ~HB4_AD;
--  
--  if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure)
--    header->hb4 |= HB4_AD;
--
--  /* If the requestor didn't set the DO bit, don't return DNSSEC info. */
--  if (!do_bit)
--    n = rrfilter(header, n, 1);
-+    {
-+      header->hb4 &= ~HB4_AD;
-+      
-+      if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure)
-+      header->hb4 |= HB4_AD;
-+      
-+      /* If the requestor didn't set the DO bit, don't return DNSSEC info. */
-+      if (!do_bit)
-+      n = rrfilter(header, n, 1);
-+    }
- #endif
-   /* do this after extract_addresses. Ensure NODATA reply and remove
-@@ -761,8 +788,14 @@ void reply_query(int fd, int family, time_t now)
-         if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
-           {
-             header->hb3 &= ~(HB3_QR | HB3_AA | HB3_TC);
--            header->hb4 &= ~(HB4_RA | HB4_RCODE);
--            forward_query(-1, NULL, NULL, 0, header, nn, now, forward, 0, 0);
-+            header->hb4 &= ~(HB4_RA | HB4_RCODE | HB4_CD | HB4_AD);
-+            if (forward->flags |= FREC_CHECKING_DISABLED)
-+              header->hb4 |= HB4_CD;
-+            if (forward->flags |= FREC_AD_QUESTION)
-+              header->hb4 |= HB4_AD;
-+            if (forward->flags & FREC_DO_QUESTION)
-+              add_do_bit(header, nn,  (char *)pheader + plen);
-+            forward_query(-1, NULL, NULL, 0, header, nn, now, forward, forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION);
-             return;
-           }
-       }
-@@ -1007,12 +1040,13 @@ void receive_query(struct listener *listen, time_t now)
- {
-   struct dns_header *header = (struct dns_header *)daemon->packet;
-   union mysockaddr source_addr;
--  unsigned short type;
-+  unsigned char *pheader;
-+  unsigned short type, udp_size = PACKETSZ; /* default if no EDNS0 */
-   struct all_addr dst_addr;
-   struct in_addr netmask, dst_addr_4;
-   size_t m;
-   ssize_t n;
--  int if_index = 0, auth_dns = 0;
-+  int if_index = 0, auth_dns = 0, do_bit = 0, have_pseudoheader = 0;
- #ifdef HAVE_AUTH
-   int local_auth = 0;
- #endif
-@@ -1279,10 +1313,30 @@ void receive_query(struct listener *listen, time_t now)
- #endif
-     }
-   
-+  if (find_pseudoheader(header, (size_t)n, NULL, &pheader, NULL))
-+    { 
-+      unsigned short flags;
-+      
-+      have_pseudoheader = 1;
-+      GETSHORT(udp_size, pheader);
-+      pheader += 2; /* ext_rcode */
-+      GETSHORT(flags, pheader);
-+      
-+      if (flags & 0x8000)
-+      do_bit = 1;/* do bit */ 
-+      
-+      /* If the client provides an EDNS0 UDP size, use that to limit our reply.
-+       (bounded by the maximum configured). If no EDNS0, then it
-+       defaults to 512 */
-+      if (udp_size > daemon->edns_pktsz)
-+      udp_size = daemon->edns_pktsz;
-+    }
-+
- #ifdef HAVE_AUTH
-   if (auth_dns)
-     {
--      m = answer_auth(header, ((char *) header) + daemon->packet_buff_sz, (size_t)n, now, &source_addr, local_auth);
-+      m = answer_auth(header, ((char *) header) + udp_size, (size_t)n, now, &source_addr, 
-+                    local_auth, do_bit, have_pseudoheader);
-       if (m >= 1)
-       {
-         send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
-@@ -1293,9 +1347,13 @@ void receive_query(struct listener *listen, time_t now)
-   else
- #endif
-     {
--      int ad_reqd, do_bit;
--      m = answer_request(header, ((char *) header) + daemon->packet_buff_sz, (size_t)n, 
--                       dst_addr_4, netmask, now, &ad_reqd, &do_bit);
-+      int ad_reqd = do_bit;
-+       /* RFC 6840 5.7 */
-+      if (header->hb4 & HB4_AD)
-+      ad_reqd = 1;
-+
-+      m = answer_request(header, ((char *) header) + udp_size, (size_t)n, 
-+                       dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader);
-       
-       if (m >= 1)
-       {
-@@ -1397,7 +1455,7 @@ unsigned char *tcp_request(int confd, time_t now,
- #ifdef HAVE_AUTH
-   int local_auth = 0;
- #endif
--  int checking_disabled, ad_question, do_bit, added_pheader = 0;
-+  int checking_disabled, do_bit, added_pheader = 0, have_pseudoheader = 0;
-   int check_subnet, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
-   size_t m;
-   unsigned short qtype;
-@@ -1414,6 +1472,7 @@ unsigned char *tcp_request(int confd, time_t now,
-   union mysockaddr peer_addr;
-   socklen_t peer_len = sizeof(union mysockaddr);
-   int query_count = 0;
-+  unsigned char *pheader;
-   if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
-     return packet;
-@@ -1508,15 +1567,35 @@ unsigned char *tcp_request(int confd, time_t now,
-       else
-       dst_addr_4.s_addr = 0;
-       
-+      do_bit = 0;
-+
-+      if (find_pseudoheader(header, (size_t)size, NULL, &pheader, NULL))
-+      { 
-+        unsigned short flags;
-+        
-+        have_pseudoheader = 1;
-+        pheader += 4; /* udp_size, ext_rcode */
-+        GETSHORT(flags, pheader);
-+      
-+        if (flags & 0x8000)
-+          do_bit = 1;/* do bit */ 
-+      }
-+
- #ifdef HAVE_AUTH
-       if (auth_dns)
--      m = answer_auth(header, ((char *) header) + 65536, (size_t)size, now, &peer_addr, local_auth);
-+      m = answer_auth(header, ((char *) header) + 65536, (size_t)size, now, &peer_addr, 
-+                      local_auth, do_bit, have_pseudoheader);
-       else
- #endif
-       {
--        /* m > 0 if answered from cache */
--        m = answer_request(header, ((char *) header) + 65536, (size_t)size, 
--                           dst_addr_4, netmask, now, &ad_question, &do_bit);
-+         int ad_reqd = do_bit;
-+         /* RFC 6840 5.7 */
-+         if (header->hb4 & HB4_AD)
-+           ad_reqd = 1;
-+         
-+         /* m > 0 if answered from cache */
-+         m = answer_request(header, ((char *) header) + 65536, (size_t)size, 
-+                            dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader);
-         
-         /* Do this by steam now we're not in the select() loop */
-         check_log_writer(1); 
-@@ -1615,6 +1694,7 @@ unsigned char *tcp_request(int confd, time_t now,
-                           }
-                         
- #ifdef HAVE_DNSSEC
-+                        added_pheader = 0;                      
-                         if (option_bool(OPT_DNSSEC_VALID))
-                           {
-                             size_t new_size = add_do_bit(header, size, ((char *) header) + 65536);
-@@ -1719,7 +1799,7 @@ unsigned char *tcp_request(int confd, time_t now,
-                     m = process_reply(header, now, last_server, (unsigned int)m, 
-                                       option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer,
--                                      ad_question, do_bit, added_pheader, check_subnet, &peer_addr); 
-+                                      ad_reqd, do_bit, added_pheader, check_subnet, &peer_addr); 
-                     
-                     break;
-                   }
-diff --git a/src/netlink.c b/src/netlink.c
-index 753784d..3376d68 100644
---- a/src/netlink.c
-+++ b/src/netlink.c
-@@ -288,7 +288,8 @@ int iface_enumerate(int family, void *parm, int (*callback)())
-               rta = RTA_NEXT(rta, len1);
-             }
--          if (inaddr && mac && callback_ok)
-+          if (!(neigh->ndm_state & (NUD_NOARP | NUD_INCOMPLETE | NUD_FAILED)) &&
-+              inaddr && mac && callback_ok)
-             if (!((*callback)(neigh->ndm_family, inaddr, mac, maclen, parm)))
-               callback_ok = 0;
-         }
-diff --git a/src/rfc1035.c b/src/rfc1035.c
-index 188d05f..18858a8 100644
---- a/src/rfc1035.c
-+++ b/src/rfc1035.c
-@@ -489,8 +489,8 @@ struct macparm {
-   union mysockaddr *l3;
- };
-  
--static size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit, 
--                             int optno, unsigned char *opt, size_t optlen, int set_do)
-+size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit, 
-+                      unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do)
- { 
-   unsigned char *lenp, *datap, *p;
-   int rdlen, is_sign;
-@@ -508,7 +508,7 @@ static size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned
-       return plen;
-       *p++ = 0; /* empty name */
-       PUTSHORT(T_OPT, p);
--      PUTSHORT(SAFE_PKTSZ, p); /* max packet length, this will be overwritten */
-+      PUTSHORT(udp_sz, p); /* max packet length, 512 if not given in EDNS0 header */
-       PUTSHORT(0, p);    /* extended RCODE and version */
-       PUTSHORT(set_do ? 0x8000 : 0, p); /* DO flag */
-       lenp = p;
-@@ -594,7 +594,7 @@ static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *p
-   if (!match)
-     return 1; /* continue */
--  parm->plen = add_pseudoheader(parm->header, parm->plen, parm->limit,  EDNS0_OPTION_MAC, (unsigned char *)mac, maclen, 0);
-+  parm->plen = add_pseudoheader(parm->header, parm->plen, parm->limit, PACKETSZ, EDNS0_OPTION_MAC, (unsigned char *)mac, maclen, 0);
-   
-   return 0; /* done */
- }           
-@@ -603,12 +603,6 @@ size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysock
- {
-   struct macparm parm;
-      
--/* Must have an existing pseudoheader as the only ar-record, 
--   or have no ar-records. Must also not be signed */
--   
--  if (ntohs(header->arcount) > 1)
--    return plen;
--
-   parm.header = header;
-   parm.limit = (unsigned char *)limit;
-   parm.plen = plen;
-@@ -699,13 +693,13 @@ size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, unio
-   struct subnet_opt opt;
-   
-   len = calc_subnet_opt(&opt, source);
--  return add_pseudoheader(header, plen, (unsigned char *)limit, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0);
-+  return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0);
- }
- #ifdef HAVE_DNSSEC
- size_t add_do_bit(struct dns_header *header, size_t plen, char *limit)
- {
--  return add_pseudoheader(header, plen, (unsigned char *)limit, 0, NULL, 0, 1);
-+  return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, 0, NULL, 0, 1);
- }
- #endif
-@@ -1525,16 +1519,16 @@ static unsigned long crec_ttl(struct crec *crecp, time_t now)
- /* return zero if we can't answer from cache, or packet size if we can */
- size_t answer_request(struct dns_header *header, char *limit, size_t qlen,  
-                     struct in_addr local_addr, struct in_addr local_netmask, 
--                    time_t now, int *ad_reqd, int *do_bit) 
-+                    time_t now, int ad_reqd, int do_bit, int have_pseudoheader) 
- {
-   char *name = daemon->namebuff;
--  unsigned char *p, *ansp, *pheader;
-+  unsigned char *p, *ansp;
-   unsigned int qtype, qclass;
-   struct all_addr addr;
-   int nameoffset;
-   unsigned short flag;
-   int q, ans, anscount = 0, addncount = 0;
--  int dryrun = 0, sec_reqd = 0, have_pseudoheader = 0;
-+  int dryrun = 0;
-   struct crec *crecp;
-   int nxdomain = 0, auth = 1, trunc = 0, sec_data = 1;
-   struct mx_srv_record *rec;
-@@ -1550,35 +1544,11 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
-   if (header->hb4 & HB4_CD)
-     sec_data = 0;
-   
--  /* RFC 6840 5.7 */
--  *ad_reqd = header->hb4 & HB4_AD;
--  *do_bit = 0;
--
-   /* If there is an  additional data section then it will be overwritten by
-      partial replies, so we have to do a dry run to see if we can answer
-      the query. */
--
-   if (ntohs(header->arcount) != 0)
--    {
--      dryrun = 1;
--
--      /* If there's an additional section, there might be an EDNS(0) pseudoheader */
--      if (find_pseudoheader(header, qlen, NULL, &pheader, NULL))
--      { 
--        unsigned short flags;
--        
--        have_pseudoheader = 1;
--        
--        pheader += 4; /* udp size, ext_rcode */
--        GETSHORT(flags, pheader);
--        
--        if ((sec_reqd = flags & 0x8000))
--          {
--            *do_bit = 1;/* do bit */ 
--            *ad_reqd = 1;
--          }
--      }
--    }
-+    dryrun = 1;
-   for (rec = daemon->mxnames; rec; rec = rec->next)
-     rec->offset = 0;
-@@ -1603,11 +1573,6 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
-       GETSHORT(qtype, p); 
-       GETSHORT(qclass, p);
--      /* Don't filter RRSIGS from answers to ANY queries, even if do-bit
--       not set. */
--      if (qtype == T_ANY)
--      *do_bit = 1;
--
-       ans = 0; /* have we answered this question */
-       
-       if (qtype == T_TXT || qtype == T_ANY)
-@@ -1739,7 +1704,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
-                    the zone is unsigned, which implies that we're doing
-                    validation. */
-                 if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || 
--                    !sec_reqd || 
-+                    !do_bit || 
-                     (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))
-                   {
-                     do 
-@@ -1927,7 +1892,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
-                   }
-                 /* If the client asked for DNSSEC  don't use cached data. */
--                if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !sec_reqd || !(crecp->flags & F_DNSSECOK))
-+                if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !do_bit || !(crecp->flags & F_DNSSECOK))
-                   do
-                     { 
-                       /* don't answer wildcard queries with data not from /etc/hosts
-@@ -1961,17 +1926,12 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
-                       
-                       if (crecp->flags & F_NEG)
-                         {
--                          /* We don't cache NSEC records, so if a DNSSEC-validated negative answer
--                             is cached and the client wants DNSSEC, forward rather than answering from the cache */
--                          if (!sec_reqd || !(crecp->flags & F_DNSSECOK))
--                            {
--                              ans = 1;
--                              auth = 0;
--                              if (crecp->flags & F_NXDOMAIN)
--                                nxdomain = 1;
--                              if (!dryrun)
--                                log_query(crecp->flags, name, NULL, NULL);
--                            }
-+                          ans = 1;
-+                          auth = 0;
-+                          if (crecp->flags & F_NXDOMAIN)
-+                            nxdomain = 1;
-+                          if (!dryrun)
-+                            log_query(crecp->flags, name, NULL, NULL);
-                         }
-                       else 
-                         {
-@@ -2209,10 +2169,11 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
-   len = ansp - (unsigned char *)header;
-   
-+  /* Advertise our packet size limit in our reply */
-   if (have_pseudoheader)
--    len = add_pseudoheader(header, len, (unsigned char *)limit, 0, NULL, 0, sec_reqd);
-+    len = add_pseudoheader(header, len, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit);
-   
--  if (*ad_reqd && sec_data)
-+  if (ad_reqd && sec_data)
-     header->hb4 |= HB4_AD;
-   else
-     header->hb4 &= ~HB4_AD;
-diff --git a/src/rrfilter.c b/src/rrfilter.c
-index ae12261..b26b39f 100644
---- a/src/rrfilter.c
-+++ b/src/rrfilter.c
-@@ -243,7 +243,7 @@ size_t rrfilter(struct dns_header *header, size_t plen, int mode)
-   for (p = rrs[0], i = 1; i < rr_found; i += 2)
-     {
-       unsigned char *start = rrs[i];
--      unsigned char *end = (i != rr_found - 1) ? rrs[i+1] : ((unsigned char *)(header+1)) + plen;
-+      unsigned char *end = (i != rr_found - 1) ? rrs[i+1] : ((unsigned char *)header) + plen;
-       
-       memmove(p, start, end-start);
-       p += end-start;
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/026-More_tweaks_in_handling_unknown_DNSSEC_algorithms.patch b/src/patches/dnsmasq/026-More_tweaks_in_handling_unknown_DNSSEC_algorithms.patch
deleted file mode 100644 (file)
index 910921b..0000000
+++ /dev/null
@@ -1,262 +0,0 @@
-From d67ecac59d58f249707d26e38d49c29b552af4d8 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Sun, 20 Dec 2015 20:44:23 +0000
-Subject: [PATCH] More tweaks in handling unknown DNSSEC algorithms.
-
----
- src/dnssec.c |  128 +++++++++++++++++++++++++++++-----------------------------
- 1 file changed, 63 insertions(+), 65 deletions(-)
-
-diff --git a/src/dnssec.c b/src/dnssec.c
-index 299ca64..e09f304 100644
---- a/src/dnssec.c
-+++ b/src/dnssec.c
-@@ -70,7 +70,17 @@ static char *algo_digest_name(int algo)
-     default: return NULL;
-     }
- }
--      
-+  
-+/* http://www.iana.org/assignments/dnssec-nsec3-parameters/dnssec-nsec3-parameters.xhtml */
-+static char *nsec3_digest_name(int digest)
-+{
-+  switch (digest)
-+    {
-+    case 1: return "sha1";
-+    default: return NULL;
-+    }
-+}
-+ 
- /* Find pointer to correct hash function in nettle library */
- static const struct nettle_hash *hash_find(char *name)
- {
-@@ -667,7 +677,6 @@ static int explore_rrset(struct dns_header *header, size_t plen, int class, int
-   static int rrset_sz = 0, sig_sz = 0; 
-   unsigned char *p;
-   int rrsetidx, sigidx, j, rdlen, res;
--  int name_labels = count_labels(name); /* For 4035 5.3.2 check */
-   int gotkey = 0;
-   if (!(p = skip_questions(header, plen)))
-@@ -678,7 +687,7 @@ static int explore_rrset(struct dns_header *header, size_t plen, int class, int
-        j != 0; j--) 
-     {
-       unsigned char *pstart, *pdata;
--      int stype, sclass, algo, type_covered, labels, sig_expiration, sig_inception;
-+      int stype, sclass, type_covered;
-       pstart = p;
-       
-@@ -712,12 +721,7 @@ static int explore_rrset(struct dns_header *header, size_t plen, int class, int
-               return 0; /* bad packet */ 
-             
-             GETSHORT(type_covered, p);
--            algo = *p++;
--            labels = *p++;
--            p += 4; /* orig_ttl */
--            GETLONG(sig_expiration, p);
--            GETLONG(sig_inception, p);
--            p += 2; /* key_tag */
-+            p += 16; /* algo, labels, orig_ttl, sig_expiration, sig_inception, key_tag */
-             
-             if (gotkey)
-               {
-@@ -749,11 +753,8 @@ static int explore_rrset(struct dns_header *header, size_t plen, int class, int
-                   }
-               }
-                 
--            /* Don't count signatures for algos we don't support */
--            if (check_date_range(sig_inception, sig_expiration) &&
--                labels <= name_labels &&
--                type_covered == type && 
--                verify_func(algo))
-+            
-+            if (type_covered == type)
-               {
-                 if (!expand_workspace(&sigs, &sig_sz, sigidx))
-                   return 0; 
-@@ -795,7 +796,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
-                         char *name, char *keyname, char **wildcard_out, struct blockdata *key, int keylen, int algo_in, int keytag_in)
- {
-   unsigned char *p;
--  int rdlen, j, name_labels;
-+  int rdlen, j, name_labels, sig_expiration, sig_inception;
-   struct crec *crecp = NULL;
-   int algo, labels, orig_ttl, key_tag;
-   u16 *rr_desc = rrfilter_desc(type);
-@@ -828,13 +829,16 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
-       algo = *p++;
-       labels = *p++;
-       GETLONG(orig_ttl, p);
--      p += 8; /* sig_expiration, sig_inception already checked */
-+      GETLONG(sig_expiration, p);
-+      GETLONG(sig_inception, p);
-       GETSHORT(key_tag, p);
-       
-       if (!extract_name(header, plen, &p, keyname, 1, 0))
-       return STAT_BOGUS;
--      if (!(hash = hash_find(algo_digest_name(algo))) ||
-+      if (!check_date_range(sig_inception, sig_expiration) ||
-+        labels > name_labels ||
-+        !(hash = hash_find(algo_digest_name(algo))) ||
-         !hash_init(hash, &ctx, &digest))
-       continue;
-       
-@@ -1112,7 +1116,10 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
-                     else
-                       {
-                         a.addr.keytag = keytag;
--                        log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %u");
-+                        if (verify_func(algo))
-+                          log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %u");
-+                        else
-+                          log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %u (not supported)");
-                         
-                         recp1->addr.key.keylen = rdlen - 4;
-                         recp1->addr.key.keydata = key;
-@@ -1235,7 +1242,11 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
-                 else
-                   {
-                     a.addr.keytag = keytag;
--                    log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u");
-+                    if (hash_find(ds_digest_name(digest)) && verify_func(algo))
-+                      log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u");
-+                    else
-+                      log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u (not supported)");
-+                    
-                     crecp->addr.ds.digest = digest;
-                     crecp->addr.ds.keydata = key;
-                     crecp->addr.ds.algo = algo;
-@@ -1660,7 +1671,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
-     *nons = 1;
-   
-   /* Look though the NSEC3 records to find the first one with 
--     an algorithm we support (currently only algo == 1).
-+     an algorithm we support.
-      Take the algo, iterations, and salt of that record
-      as the ones we're going to use, and prune any 
-@@ -1674,7 +1685,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
-       p += 10; /* type, class, TTL, rdlen */
-       algo = *p++;
-       
--      if (algo == 1)
-+      if ((hash = hash_find(nsec3_digest_name(algo))))
-       break; /* known algo */
-     }
-@@ -1724,10 +1735,6 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
-       nsecs[i] = nsec3p;
-     }
--  /* Algo is checked as 1 above */
--  if (!(hash = hash_find("sha1")))
--    return 0;
--
-   if ((digest_len = hash_name(name, &digest, hash, salt, salt_len, iterations)) == 0)
-     return 0;
-   
-@@ -1843,8 +1850,10 @@ static int prove_non_existence(struct dns_header *header, size_t plen, char *key
-   
-   if (type_found == T_NSEC)
-     return prove_non_existence_nsec(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, nons);
--  else
-+  else if (type_found == T_NSEC3)
-     return prove_non_existence_nsec3(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, wildname, nons);
-+  else
-+    return 0;
- }
- /* Check signing status of name.
-@@ -1857,7 +1866,7 @@ static int prove_non_existence(struct dns_header *header, size_t plen, char *key
- */
- static int zone_status(char *name, int class, char *keyname, time_t now)
- {
--  int secure_ds, name_start = strlen(name);
-+  int name_start = strlen(name);
-   struct crec *crecp;
-   char *p;
-   
-@@ -1867,51 +1876,40 @@ static int zone_status(char *name, int class, char *keyname, time_t now)
-       
-       if (!(crecp = cache_find_by_name(NULL, keyname, now, F_DS)))
-       return STAT_NEED_DS;
-+      
-+       /* F_DNSSECOK misused in DS cache records to non-existance of NS record.
-+        F_NEG && !F_DNSSECOK implies that we've proved there's no DS record here,
-+        but that's because there's no NS record either, ie this isn't the start
-+        of a zone. We only prove that the DNS tree below a node is unsigned when
-+        we prove that we're at a zone cut AND there's no DS record. */
-+      if (crecp->flags & F_NEG)
-+      {
-+        if (crecp->flags & F_DNSSECOK)
-+          return STAT_INSECURE; /* proved no DS here */
-+      }
-       else
-       {
--        secure_ds = 0;
--        
-+        int gotone = 0;
-+
-+        /* If all the DS records have digest and/or sig algos we don't support,
-+           then the zone is insecure. Note that if an algo
-+           appears in the DS, then RRSIGs for that algo MUST
-+           exist for each RRset: 4035 para 2.2  So if we find
-+           a DS here with digest and sig we can do, we're entitled
-+           to assume we can validate the zone and if we can't later,
-+           because an RRSIG is missing we return BOGUS.
-+        */
-         do 
-           {
--            if (crecp->uid == (unsigned int)class)
--              {
--                /* F_DNSSECOK misused in DS cache records to non-existance of NS record.
--                   F_NEG && !F_DNSSECOK implies that we've proved there's no DS record here,
--                   but that's because there's no NS record either, ie this isn't the start
--                   of a zone. We only prove that the DNS tree below a node is unsigned when
--                   we prove that we're at a zone cut AND there's no DS record.
--                */      
--                if (crecp->flags & F_NEG)
--                  {
--                    if (crecp->flags & F_DNSSECOK)
--                      return STAT_INSECURE; /* proved no DS here */
--                  }
--                else if (!hash_find(ds_digest_name(crecp->addr.ds.digest)) || !verify_func(crecp->addr.ds.algo))
--                  return STAT_INSECURE; /* algo we can't use - insecure */
--                else
--                  secure_ds = 1;
--              }
-+            if (crecp->uid == (unsigned int)class &&
-+                hash_find(ds_digest_name(crecp->addr.ds.digest)) &&
-+                verify_func(crecp->addr.ds.algo))
-+              gotone = 1;
-           }
-         while ((crecp = cache_find_by_name(crecp, keyname, now, F_DS)));
--      }
--
--      if (secure_ds)
--      {
--        /* We've found only DS records that attest to the DNSKEY RRset in the zone, so we believe
--           that RRset is good. Furthermore the DNSKEY whose hash is proved by the DS record is
--           one we can use. However the DNSKEY RRset may contain more than one key and
--           one of the other keys may use an algorithm we don't support. If that's 
--           the case the zone is insecure for us. */
--        
--        if (!(crecp = cache_find_by_name(NULL, keyname, now, F_DNSKEY)))
--          return STAT_NEED_KEY;
--        do 
--          {
--            if (crecp->uid == (unsigned int)class && !verify_func(crecp->addr.key.algo))
--              return STAT_INSECURE;
--          }
--        while ((crecp = cache_find_by_name(crecp, keyname, now, F_DNSKEY)));
-+        if (!gotone)
-+          return STAT_INSECURE;
-       }
-       if (name_start == 0)
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/027-Nasty_rare_and_obscure_off-by-one_in_DNSSEC_hostname_cmp.patch b/src/patches/dnsmasq/027-Nasty_rare_and_obscure_off-by-one_in_DNSSEC_hostname_cmp.patch
deleted file mode 100644 (file)
index 031339e..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-From 3e86d316c4bb406ed813aa5256615c8a95cac6d8 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Sun, 20 Dec 2015 20:50:05 +0000
-Subject: [PATCH] Nasty, rare and obscure off-by-one in DNSSEC hostname_cmp().
-
----
- src/dnssec.c |    4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/src/dnssec.c b/src/dnssec.c
-index e09f304..29848e1 100644
---- a/src/dnssec.c
-+++ b/src/dnssec.c
-@@ -1394,8 +1394,8 @@ static int hostname_cmp(const char *a, const char *b)
-       if (sb == b)
-       return 1;
-       
--      ea = sa--;
--      eb = sb--;
-+      ea = --sa;
-+      eb = --sb;
-     }
- }
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/028-Minor_tweak_to_previous_commit.patch b/src/patches/dnsmasq/028-Minor_tweak_to_previous_commit.patch
deleted file mode 100644 (file)
index f3758fc..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-From a86fdf437ecc29398f9715ceb5240442a17ac014 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Sun, 20 Dec 2015 21:19:20 +0000
-Subject: [PATCH] Minor tweak to previous commit.
-
----
- src/dnssec.c |    6 ++----
- 1 file changed, 2 insertions(+), 4 deletions(-)
-
-diff --git a/src/dnssec.c b/src/dnssec.c
-index 29848e1..9fa64b6 100644
---- a/src/dnssec.c
-+++ b/src/dnssec.c
-@@ -1889,8 +1889,6 @@ static int zone_status(char *name, int class, char *keyname, time_t now)
-       }
-       else
-       {
--        int gotone = 0;
--
-         /* If all the DS records have digest and/or sig algos we don't support,
-            then the zone is insecure. Note that if an algo
-            appears in the DS, then RRSIGs for that algo MUST
-@@ -1904,11 +1902,11 @@ static int zone_status(char *name, int class, char *keyname, time_t now)
-             if (crecp->uid == (unsigned int)class &&
-                 hash_find(ds_digest_name(crecp->addr.ds.digest)) &&
-                 verify_func(crecp->addr.ds.algo))
--              gotone = 1;
-+              break;
-           }
-         while ((crecp = cache_find_by_name(crecp, keyname, now, F_DS)));
--        if (!gotone)
-+        if (!crecp)
-           return STAT_INSECURE;
-       }
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/029-NSEC3_check_RFC5155_para_8_2.patch b/src/patches/dnsmasq/029-NSEC3_check_RFC5155_para_8_2.patch
deleted file mode 100644 (file)
index 33219d2..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-From ce5732e84fc46d7f99c152f736cfb4ef5ec98a01 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Sun, 20 Dec 2015 21:39:19 +0000
-Subject: [PATCH] NSEC3 check: RFC5155 para 8.2
-
----
- src/dnssec.c |    8 ++++++--
- 1 file changed, 6 insertions(+), 2 deletions(-)
-
-diff --git a/src/dnssec.c b/src/dnssec.c
-index 9fa64b6..486e422 100644
---- a/src/dnssec.c
-+++ b/src/dnssec.c
-@@ -1704,7 +1704,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
-   for (i = 0; i < nsec_count; i++)
-     {
-       unsigned char *nsec3p = nsecs[i];
--      int this_iter;
-+      int this_iter, flags;
-       nsecs[i] = NULL; /* Speculative, will be restored if OK. */
-       
-@@ -1716,8 +1716,12 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
-       if (*p++ != algo)
-       continue;
-  
--      p++; /* flags */
-+      flags = *p++; /* flags */
-       
-+      /* 5155 8.2 */
-+      if (flags != 0 && flags != 1)
-+      continue;
-+
-       GETSHORT(this_iter, p);
-       if (this_iter != iterations)
-       continue;
--- 
-1.7.10.4
-
index a63d5d826d84e688401058291ab2c986fe8abf9b..2221353398b6dcd871ac9ca50aec846599c5bdf0 100644 (file)
@@ -1,13 +1,8 @@
-From 6e236b92765cdafb46d19e4907471699accc8269 Mon Sep 17 00:00:00 2001
-From: Siddhesh Poyarekar <siddhesh@redhat.com>
-Date: Thu, 26 Apr 2012 09:18:48 +0530
-Subject: [PATCH] move libgcc_s soname definition to shlib-versions
-
-diff --git a/nptl/sysdeps/pthread/unwind-forcedunwind.c b/nptl/sysdeps/pthread/unwind-forcedunwind.c
-index adce6e7..60dfbe6 100644
---- a/nptl/sysdeps/pthread/unwind-forcedunwind.c
-+++ b/nptl/sysdeps/pthread/unwind-forcedunwind.c
-@@ -21,7 +21,7 @@
+diff -Naur glibc-2.12-2-gc4ccff1.org/nptl/sysdeps/pthread/unwind-forcedunwind.c glibc-2.12-2-gc4ccff1/nptl/sysdeps/pthread/unwind-forcedunwind.c
+index db56428..495f4b7 100644
+--- glibc-2.12-2-gc4ccff1.org/nptl/sysdeps/pthread/unwind-forcedunwind.c
++++ glibc-2.12-2-gc4ccff1/nptl/sysdeps/pthread/unwind-forcedunwind.c
+@@ -22,7 +22,7 @@
  #include <unwind.h>
  #include <pthreadP.h>
  #include <sysdep.h>
@@ -16,12 +11,11 @@ index adce6e7..60dfbe6 100644
  
  static void *libgcc_s_handle;
  static void (*libgcc_s_resume) (struct _Unwind_Exception *exc);
-diff --git a/scripts/test-installation.pl b/scripts/test-installation.pl
-index c4f3d6d..1b22086 100755
---- a/scripts/test-installation.pl
-+++ b/scripts/test-installation.pl
-
-@@ -105,9 +105,10 @@ while (<SOVERSIONS>) {
+diff -Naur glibc-2.12-2-gc4ccff1.org/scripts/test-installation.pl glibc-2.12-2-gc4ccff1/scripts/test-installation.pl
+index 25a919b..3f409ab 100755
+--- glibc-2.12-2-gc4ccff1.org/scripts/test-installation.pl
++++ glibc-2.12-2-gc4ccff1/scripts/test-installation.pl
+@@ -106,9 +106,10 @@ while (<SOVERSIONS>) {
      # - libnss1_* from glibc-compat add-on
      # - libthread_db since it contains unresolved references
      # - it's just a test NSS module
@@ -33,11 +27,11 @@ index c4f3d6d..1b22086 100755
        $link_libs .= " -l$name";
        $versions{$name} = $version;
      }
-diff --git a/shlib-versions b/shlib-versions
-index c530a44..840e08f 100644
---- a/shlib-versions
-+++ b/shlib-versions
-@@ -124,3 +124,7 @@ sparc64.*-.*-.*            libBrokenLocale=1       GLIBC_2.2
+diff -Naur glibc-2.12-2-gc4ccff1.org/shlib-versions glibc-2.12-2-gc4ccff1/shlib-versions
+index d3e8407..ac98e49 100644
+--- glibc-2.12-2-gc4ccff1.org/shlib-versions
++++ glibc-2.12-2-gc4ccff1/shlib-versions
+@@ -138,3 +138,7 @@ sparc64.*-.*-.*            libBrokenLocale=1       GLIBC_2.2
  
  # The asynchronous name lookup library.
  .*-.*-.*              libanl=1
@@ -45,10 +39,10 @@ index c530a44..840e08f 100644
 +# This defines the libgcc soname version this glibc is to load for
 +# asynchronous cancellation to work correctly.
 +.*-.*-.*              libgcc_s=1
-diff --git a/sysdeps/generic/framestate.c b/sysdeps/generic/framestate.c
-index 3638bbe..3bad5b5 100644
---- a/sysdeps/generic/framestate.c
-+++ b/sysdeps/generic/framestate.c
+diff -Naur glibc-2.12-2-gc4ccff1.org/sysdeps/generic/framestate.c glibc-2.12-2-gc4ccff1/sysdeps/generic/framestate.c
+index 80375bb..edc3539 100644
+--- glibc-2.12-2-gc4ccff1.org/sysdeps/generic/framestate.c
++++ glibc-2.12-2-gc4ccff1/sysdeps/generic/framestate.c
 @@ -1,5 +1,5 @@
  /* __frame_state_for unwinder helper function wrapper.
 -   Copyright (C) 2001, 2003 Free Software Foundation, Inc.
@@ -56,7 +50,7 @@ index 3638bbe..3bad5b5 100644
     This file is part of the GNU C Library.
     Contributed by Jakub Jelinek <jakub@redhat.com>, 2001.
  
-@@ -23,7 +23,7 @@
+@@ -24,7 +24,7 @@
  #define __frame_state_for fallback_frame_state_for
  #include <unwind-dw2.c>
  #undef __frame_state_for
@@ -65,33 +59,30 @@ index 3638bbe..3bad5b5 100644
  
  typedef struct frame_state * (*framesf)(void *pc, struct frame_state *);
  struct frame_state *__frame_state_for (void *pc,
-diff --git a/sysdeps/generic/libgcc_s.h b/sysdeps/generic/libgcc_s.h
+diff -Naur glibc-2.12-2-gc4ccff1.org/sysdeps/generic/libgcc_s.h glibc-2.12-2-gc4ccff1.org/sysdeps/generic/libgcc_s.h
 deleted file mode 100644
 index e74a103..0000000
---- a/sysdeps/generic/libgcc_s.h
+--- glibc-2.12-2-gc4ccff1.org/sysdeps/generic/libgcc_s.h
 +++ /dev/null
 @@ -1,2 +0,0 @@
 -/* Name of libgcc_s library provided by gcc.  */
 -#define LIBGCC_S_SO "libgcc_s.so.1"
-diff --git a/sysdeps/gnu/unwind-resume.c b/sysdeps/gnu/unwind-resume.c
-index 1d3e33f..6afaebd 100644
---- a/sysdeps/gnu/unwind-resume.c
-+++ b/sysdeps/gnu/unwind-resume.c
+diff -Naur glibc-2.12-2-gc4ccff1.org/sysdeps/gnu/unwind-resume.c glibc-2.12-2-gc4ccff1/sysdeps/gnu/unwind-resume.c
+index f8ff0c4..dab4370 100644
+--- glibc-2.12-2-gc4ccff1.org/sysdeps/gnu/unwind-resume.c
++++ glibc-2.12-2-gc4ccff1/sysdeps/gnu/unwind-resume.c
 @@ -1,4 +1,4 @@
 -/* Copyright (C) 2003 Free Software Foundation, Inc.
 +/* Copyright (C) 2003-2012 Free Software Foundation, Inc.
     This file is part of the GNU C Library.
     Contributed by Jakub Jelinek <jakub@redhat.com>.
  
-@@ -19,7 +19,7 @@
- #include <dlfcn.h>
- #include <stdio.h>
+@@ -22,7 +22,7 @@
  #include <unwind.h>
+ #include <pthreadP.h>
+ #include <sysdep.h>
 -#include <libgcc_s.h>
 +#include <gnu/lib-names.h>
  
+ static void *libgcc_s_handle;
  static void (*libgcc_s_resume) (struct _Unwind_Exception *exc);
- static _Unwind_Reason_Code (*libgcc_s_personality)
--- 
-1.7.3.4
-
diff --git a/src/patches/glibc/glibc-rh1023306.patch b/src/patches/glibc/glibc-rh1023306.patch
new file mode 100644 (file)
index 0000000..738052d
--- /dev/null
@@ -0,0 +1,64 @@
+diff -pruN glibc-2.17-c758a686/nptl/Makefile glibc-2.17-c758a686.new/nptl/Makefile
+--- glibc-2.17-c758a686/nptl/Makefile  2013-07-31 11:51:24.882747234 +0530
++++ glibc-2.17-c758a686.new/nptl/Makefile      2013-07-31 11:58:55.964731526 +0530
+@@ -276,10 +276,7 @@ gen-as-const-headers = pthread-errnos.sy
+ LDFLAGS-tst-cond24 = -lrt
+ LDFLAGS-tst-cond25 = -lrt
+-# The size is 1MB + 4KB.  The extra 4KB has been added to prevent allocatestack
+-# from resizing the input size to avoid the 64K aliasing conflict on Intel
+-# processors.
+-DEFAULT_STACKSIZE=1052672
++DEFAULT_STACKSIZE=1048576
+ CFLAGS-tst-default-attr.c = -DDEFAULT_STACKSIZE=$(DEFAULT_STACKSIZE)
+ tst-default-attr-ENV = GLIBC_PTHREAD_STACKSIZE=$(DEFAULT_STACKSIZE)
+diff -pruN glibc-2.17-c758a686/nptl/tst-default-attr.c glibc-2.17-c758a686.new/nptl/tst-default-attr.c
+--- glibc-2.17-c758a686/nptl/tst-default-attr.c        2013-07-31 11:51:24.885747234 +0530
++++ glibc-2.17-c758a686.new/nptl/tst-default-attr.c    2013-07-31 12:18:10.016691337 +0530
+@@ -38,6 +38,7 @@
+ /* DEFAULT_STACKSIZE macro is defined in the Makefile.  */
+ static size_t stacksize = DEFAULT_STACKSIZE;
++long int pagesize;
+ static int
+ verify_stacksize_result (pthread_attr_t *attr)
+@@ -46,12 +47,20 @@ verify_stacksize_result (pthread_attr_t
+   RETURN_IF_FAIL (pthread_attr_getstacksize, attr, &stack);
+-  if (stacksize != stack)
++  /* pthread_create perturbs the stack size by a page if it aligns to 64K to
++     avoid the 64K aliasing conflict.  We cannot simply add 4K to the size in
++     the Makefile because it breaks the test on powerpc since the page size
++     there is 64K, resulting in a resize in __pthread_initialize_minimal.
++     Hence, our check is to ensure that the stack size is not more than a page
++     more than the requested size.  */
++  if (stack < stacksize || stack > stacksize + pagesize)
+     {
+       printf ("failed to set default stacksize (%zu, %zu)\n", stacksize, stack);
+       return 1;
+     }
++  printf ("Requested %zu and got %zu\n", stacksize, stack);
++
+   return 0;
+ }
+@@ -101,6 +110,15 @@ run_threads (void)
+ static int
+ do_test (void)
+ {
++  pthread_attr_t attr;
++
++  pagesize = sysconf (_SC_PAGESIZE);
++  if (pagesize < 0)
++    {
++      printf ("sysconf failed: %s\n", strerror (errno));
++      return 1;
++    }
++
+   RETURN_IF_FAIL (run_threads);
+   return 0;
+ }
diff --git a/src/patches/glibc/glibc-rh1025933.patch b/src/patches/glibc/glibc-rh1025933.patch
new file mode 100644 (file)
index 0000000..9dc98b9
--- /dev/null
@@ -0,0 +1,287 @@
+commit 0699f766b10c86912b75f35bef697106b70c1cf6
+Author: Carlos O'Donell <carlos@redhat.com>
+Date:   Thu Apr 10 18:31:53 2014 -0400
+
+    nscd: Make SELinux checks dynamic.
+    
+    The SELinux team has indicated to me that glibc's SELinux checks
+    in nscd are not being carried out as they would expect the API
+    to be used today. They would like to move away from static header
+    defines for class and permissions and instead use dynamic checks
+    at runtime that provide an answer which is dependent on the runtime
+    status of SELinux i.e. more dynamic.
+    
+    The following patch is a minimal change that moves us forward in
+    this direction.
+    
+    It does the following:
+    
+    * Stop checking for SELinux headers that define NSCD__SHMEMHOST.
+      Check only for the presence or absence of the library.
+    
+    * Don't encode the specific SELinux permission constants into a
+      table at build time, and instead use the symbolic name for the
+      permission as expected.
+    
+    * Lookup the "What do we do if we don't know this permission?"
+      policy and use that if we find SELinux's policy is older than
+      the glibc policy e.g. we make a request for a permission that
+      SELinux doesn't know about.
+    
+    * Lastly, translate the class and permission and then make
+      the permission check. This is done every time we lookup
+      a permission, and this is the expected way to use the API.
+      SELinux will optimize this for us, and we expect the network
+      latencies to hide these extra library calls.
+    
+    Tested on x86, x86-64, and via Fedora Rawhide since November 2013.
+    
+    See:
+    https://sourceware.org/ml/libc-alpha/2014-04/msg00179.html
+
+diff --git a/configure b/configure
+index abefcdb..8b0b222 100755
+--- a/configure
++++ b/configure
+@@ -7774,64 +7774,10 @@ else
+   have_selinux=no
+ fi
+-  # See if we have the SELinux header with the NSCD permissions in it.
+-  if test x$have_selinux = xyes ; then
+-    { $as_echo "$as_me:$LINENO: checking for NSCD Flask permissions in selinux/av_permissions.h" >&5
+-$as_echo_n "checking for NSCD Flask permissions in selinux/av_permissions.h... " >&6; }
+-    cat >conftest.$ac_ext <<_ACEOF
+-/* confdefs.h.  */
+-_ACEOF
+-cat confdefs.h >>conftest.$ac_ext
+-cat >>conftest.$ac_ext <<_ACEOF
+-/* end confdefs.h.  */
+-#include <selinux/av_permissions.h>
+-int
+-main ()
+-{
+-#ifdef NSCD__SHMEMHOST
+-                   return 0;
+-                   #else
+-                   #error NSCD__SHMEMHOST not defined
+-                   #endif
+-  ;
+-  return 0;
+-}
+-_ACEOF
+-rm -f conftest.$ac_objext
+-if { (ac_try="$ac_compile"
+-case "(($ac_try" in
+-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+-  *) ac_try_echo=$ac_try;;
+-esac
+-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+-$as_echo "$ac_try_echo") >&5
+-  (eval "$ac_compile") 2>conftest.er1
+-  ac_status=$?
+-  grep -v '^ *+' conftest.er1 >conftest.err
+-  rm -f conftest.er1
+-  cat conftest.err >&5
+-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+-  (exit $ac_status); } && {
+-       test -z "$ac_c_werror_flag" ||
+-       test ! -s conftest.err
+-       } && test -s conftest.$ac_objext; then
+-  have_selinux=yes
+-else
+-  $as_echo "$as_me: failed program was:" >&5
+-sed 's/^/| /' conftest.$ac_ext >&5
+-
+-      have_selinux=no
+-fi
+-
+-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+-    { $as_echo "$as_me:$LINENO: result: $have_selinux" >&5
+-$as_echo "$have_selinux" >&6; }
+-  fi
+-
+   if test x$with_selinux = xyes ; then
+     if test x$have_selinux = xno ; then
+-      { { $as_echo "$as_me:$LINENO: error: SELinux explicitly required, but sufficiently recent SELinux library not found" >&5
+-$as_echo "$as_me: error: SELinux explicitly required, but sufficiently recent SELinux library not found" >&2;}
++      { { $as_echo "$as_me:$LINENO: error: SELinux explicitly required, but SELinux library not found" >&5
++$as_echo "$as_me: error: SELinux explicitly required, but SELinux library not found" >&2;}
+    { (exit 1); exit 1; }; }
+     fi
+   fi
+diff --git a/configure.in b/configure.in
+index 6291872..97a9591 100644
+--- a/configure.in
++++ b/configure.in
+@@ -1945,22 +1945,9 @@ else
+   # See if we have the SELinux library
+   AC_CHECK_LIB(selinux, is_selinux_enabled,
+              have_selinux=yes, have_selinux=no)
+-  # See if we have the SELinux header with the NSCD permissions in it.
+-  if test x$have_selinux = xyes ; then
+-    AC_MSG_CHECKING([for NSCD Flask permissions in selinux/av_permissions.h])
+-    AC_TRY_COMPILE([#include <selinux/av_permissions.h>],
+-                  [#ifdef NSCD__SHMEMHOST
+-                   return 0;
+-                   #else
+-                   #error NSCD__SHMEMHOST not defined
+-                   #endif],
+-                  have_selinux=yes, have_selinux=no)
+-    AC_MSG_RESULT($have_selinux)
+-  fi
+-
+   if test x$with_selinux = xyes ; then
+     if test x$have_selinux = xno ; then
+-      AC_MSG_ERROR([SELinux explicitly required, but sufficiently recent SELinux library not found])
++      AC_MSG_ERROR([SELinux explicitly required, but SELinux library not found])
+     fi
+   fi
+ fi
+diff --git a/nscd/selinux.c b/nscd/selinux.c
+index 46b0ea9..9a8a5a8 100644
+--- a/nscd/selinux.c
++++ b/nscd/selinux.c
+@@ -28,7 +28,6 @@
+ #include <syslog.h>
+ #include <unistd.h>
+ #include <sys/prctl.h>
+-#include <selinux/av_permissions.h>
+ #include <selinux/avc.h>
+ #include <selinux/flask.h>
+ #include <selinux/selinux.h>
+@@ -44,35 +43,31 @@
+ /* Global variable to tell if the kernel has SELinux support.  */
+ int selinux_enabled;
+-/* Define mappings of access vector permissions to request types.  */
+-static const access_vector_t perms[LASTREQ] =
++/* Define mappings of request type to AVC permission name.  */
++static const char *perms[LASTREQ] =
+ {
+-  [GETPWBYNAME] = NSCD__GETPWD,
+-  [GETPWBYUID] = NSCD__GETPWD,
+-  [GETGRBYNAME] = NSCD__GETGRP,
+-  [GETGRBYGID] = NSCD__GETGRP,
+-  [GETHOSTBYNAME] = NSCD__GETHOST,
+-  [GETHOSTBYNAMEv6] = NSCD__GETHOST,
+-  [GETHOSTBYADDR] = NSCD__GETHOST,
+-  [GETHOSTBYADDRv6] = NSCD__GETHOST,
+-  [GETSTAT] = NSCD__GETSTAT,
+-  [SHUTDOWN] = NSCD__ADMIN,
+-  [INVALIDATE] = NSCD__ADMIN,
+-  [GETFDPW] = NSCD__SHMEMPWD,
+-  [GETFDGR] = NSCD__SHMEMGRP,
+-  [GETFDHST] = NSCD__SHMEMHOST,
+-  [GETAI] = NSCD__GETHOST,
+-  [INITGROUPS] = NSCD__GETGRP,
+-#ifdef NSCD__GETSERV
+-  [GETSERVBYNAME] = NSCD__GETSERV,
+-  [GETSERVBYPORT] = NSCD__GETSERV,
+-  [GETFDSERV] = NSCD__SHMEMSERV,
+-#endif
+-#ifdef NSCD__GETNETGRP
+-  [GETNETGRENT] = NSCD__GETNETGRP,
+-  [INNETGR] = NSCD__GETNETGRP,
+-  [GETFDNETGR] = NSCD__SHMEMNETGRP,
+-#endif
++  [GETPWBYNAME] = "getpwd",
++  [GETPWBYUID] = "getpwd",
++  [GETGRBYNAME] = "getgrp",
++  [GETGRBYGID] = "getgrp",
++  [GETHOSTBYNAME] = "gethost",
++  [GETHOSTBYNAMEv6] = "gethost",
++  [GETHOSTBYADDR] = "gethost",
++  [GETHOSTBYADDRv6] = "gethost",
++  [SHUTDOWN] = "admin",
++  [GETSTAT] = "getstat",
++  [INVALIDATE] = "admin",
++  [GETFDPW] = "shmempwd",
++  [GETFDGR] = "shmemgrp",
++  [GETFDHST] = "shmemhost",
++  [GETAI] = "gethost",
++  [INITGROUPS] = "getgrp",
++  [GETSERVBYNAME] = "getserv",
++  [GETSERVBYPORT] = "getserv",
++  [GETFDSERV] = "shmemserv",
++  [GETNETGRENT] = "getnetgrp",
++  [INNETGR] = "getnetgrp",
++  [GETFDNETGR] = "shmemnetgrp",
+ };
+ /* Store an entry ref to speed AVC decisions.  */
+@@ -344,7 +339,16 @@ nscd_avc_init (void)
+ /* Check the permission from the caller (via getpeercon) to nscd.
+-   Returns 0 if access is allowed, 1 if denied, and -1 on error.  */
++   Returns 0 if access is allowed, 1 if denied, and -1 on error.
++
++   The SELinux policy, enablement, and permission bits are all dynamic and the
++   caching done by glibc is not entirely correct.  This nscd support should be
++   rewritten to use selinux_check_permission.  A rewrite is risky though and
++   requires some refactoring.  Currently we use symbolic mappings instead of
++   compile time constants (which SELinux upstream says are going away), and we
++   use security_deny_unknown to determine what to do if selinux-policy* doesn't
++   have a definition for the the permission or object class we are looking
++   up.  */
+ int
+ nscd_request_avc_has_perm (int fd, request_type req)
+ {
+@@ -354,6 +358,33 @@ nscd_request_avc_has_perm (int fd, request_type req)
+   security_id_t ssid = NULL;
+   security_id_t tsid = NULL;
+   int rc = -1;
++  security_class_t sc_nscd;
++  access_vector_t perm;
++  int avc_deny_unknown;
++
++  /* Check if SELinux denys or allows unknown object classes
++     and permissions.  It is 0 if they are allowed, 1 if they
++     are not allowed and -1 on error.  */
++  if ((avc_deny_unknown = security_deny_unknown ()) == -1)
++    dbg_log (_("Error querying policy for undefined object classes "
++             "or permissions."));
++
++  /* Get the security class for nscd.  If this fails we will likely be
++     unable to do anything unless avc_deny_unknown is 0.  */
++  sc_nscd = string_to_security_class ("nscd");
++  if (perm == 0 && avc_deny_unknown == 1)
++    dbg_log (_("Error getting security class for nscd."));
++
++  /* Convert permission to AVC bits.  */
++  perm = string_to_av_perm (sc_nscd, perms[req]);
++  if (perm == 0 && avc_deny_unknown == 1)
++      dbg_log (_("Error translating permission name "
++               "\"%s\" to access vector bit."), perms[req]);
++
++  /* If the nscd security class was not found or perms were not
++     found and AVC does not deny unknown values then allow it.  */
++  if ((sc_nscd == 0 || perm == 0) && avc_deny_unknown == 0)
++    return 0;
+   if (getpeercon (fd, &scon) < 0)
+     {
+@@ -372,15 +403,13 @@ nscd_request_avc_has_perm (int fd, request_type req)
+       goto out;
+     }
+-#ifndef NSCD__GETSERV
+-  if (perms[req] == 0)
+-    {
+-      dbg_log (_("compile-time support for database policy missing"));
+-      goto out;
+-    }
+-#endif
+-
+-  rc = avc_has_perm (ssid, tsid, SECCLASS_NSCD, perms[req], &aeref, NULL) < 0;
++  /* The SELinux API for avc_has_perm conflates access denied and error into
++     the return code -1, while nscd_request_avs_has_perm has distinct error
++     (-1) and denied (1) return codes. We map the avc_has_perm access denied or
++     error into an access denied at the nscd interface level (we do accurately
++     report error for the getpeercon, getcon, and avc_context_to_sid interfaces
++     used above).  */
++  rc = avc_has_perm (ssid, tsid, sc_nscd, perm, &aeref, NULL) < 0;
+ out:
+   if (scon)
diff --git a/src/patches/glibc/glibc-rh1028285.patch b/src/patches/glibc/glibc-rh1028285.patch
new file mode 100644 (file)
index 0000000..3bf8c4f
--- /dev/null
@@ -0,0 +1,149 @@
+From a5675717e35a02a3eba7e13701c6f9c0d7222e13 Mon Sep 17 00:00:00 2001
+From: Adhemerval Zanella <azanella@linux.vnet.ibm.com>
+Date: Fri, 7 Jun 2013 14:50:23 -0500
+Subject: [PATCH 2/2] PowerPC: gettimeofday optimization by using IFUNC
+
+Backport of ef26eece6331a1f6d959818e37c438cc7ce68e53 from master.
+---
+ sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h |   10 ++++
+ sysdeps/unix/sysv/linux/powerpc/gettimeofday.c   |   49 +++++++++++++++-------
+ 2 files changed, 44 insertions(+), 15 deletions(-)
+
+commit 76a9b9986141b1a7d9fd290c349d27fcee780c7a
+Author: Adhemerval Zanella <azanella@linux.vnet.ibm.com>
+Date:   Thu Nov 7 05:34:22 2013 -0600
+
+    PowerPC: Fix vDSO missing ODP entries
+    
+    This patch fixes the vDSO symbol used directed in IFUNC resolver where
+    they do not have an associated ODP entry leading to undefined behavior
+    in some cases. It adds an artificial OPD static entry to such cases
+    and set its TOC to non 0 to avoid triggering lazy resolutions.
+
+commit d98720e07f67fbeec00f9e1347840404240d3c48
+Author: Adhemerval Zanella <azanella@linux.vnet.ibm.com>
+Date:   Mon Jan 20 12:29:51 2014 -0600
+
+    PowerPC: Fix gettimeofday ifunc selection
+    
+    The IFUNC selector for gettimeofday runs before _libc_vdso_platform_setup where
+    __vdso_gettimeofday is set. The selector then sets __gettimeofday (the internal
+    version used within GLIBC) to use the system call version instead of the vDSO one.
+    This patch changes the check if vDSO is available to get its value directly
+    instead of rely on __vdso_gettimeofday.
+    
+    This patch changes it by getting the vDSO value directly.
+    
+    It fixes BZ#16431.
+
+diff -pruN a/sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h b/sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h
+--- a/sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h 2014-05-20 14:46:51.026871920 +0530
++++ b/sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h 2014-05-20 14:44:39.294877321 +0530
+@@ -33,6 +33,36 @@ extern void *__vdso_get_tbfreq;
+ extern void *__vdso_getcpu;
++#if defined(__PPC64__) || defined(__powerpc64__)
++/* The correct solution is for _dl_vdso_vsym to return the address of the OPD
++   for the kernel VDSO function.  That address would then be stored in the
++   __vdso_* variables and returned as the result of the IFUNC resolver function.
++   Yet, the kernel does not contain any OPD entries for the VDSO functions
++   (incomplete implementation).  However, PLT relocations for IFUNCs still expect
++   the address of an OPD to be returned from the IFUNC resolver function (since
++   PLT entries on PPC64 are just copies of OPDs).  The solution for now is to
++   create an artificial static OPD for each VDSO function returned by a resolver
++   function.  The TOC value is set to a non-zero value to avoid triggering lazy
++   symbol resolution via .glink0/.plt0 for a zero TOC (requires thread-safe PLT
++   sequences) when the dynamic linker isn't prepared for it e.g. RTLD_NOW.  None
++   of the kernel VDSO routines use the TOC or AUX values so any non-zero value
++   will work.  Note that function pointer comparisons will not use this artificial
++   static OPD since those are resolved via ADDR64 relocations and will point at
++   the non-IFUNC default OPD for the symbol.  Lastly, because the IFUNC relocations
++   are processed immediately at startup the resolver functions and this code need
++   not be thread-safe, but if the caller writes to a PLT slot it must do so in a
++   thread-safe manner with all the required barriers.  */
++#define VDSO_IFUNC_RET(value)                            \
++  ({                                                     \
++    static Elf64_FuncDesc vdso_opd = { .fd_toc = ~0x0 }; \
++    vdso_opd.fd_func = (Elf64_Addr)value;                \
++    &vdso_opd;                                           \
++  })
++
++#else
++#define VDSO_IFUNC_RET(value)  ((void *) (value))
++#endif
++
+ #endif
+ #endif /* _LIBC_VDSO_H */
+diff -pruN a/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c b/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c
+--- a/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c   2010-05-04 16:57:23.000000000 +0530
++++ b/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c   2014-05-20 14:44:39.298877321 +0530
+@@ -16,27 +16,51 @@
+    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+    02111-1307 USA.  */
+-#include <sysdep.h>
+-#include <bp-checks.h>
+-#include <stddef.h>
+ #include <sys/time.h>
+-#include <time.h>
+-#include <hp-timing.h>
+-#undef __gettimeofday
+-#include <bits/libc-vdso.h>
++#ifdef SHARED
+-/* Get the current time of day and timezone information,
+-   putting it into *TV and *TZ.  If TZ is NULL, *TZ is not filled.
+-   Returns 0 on success, -1 on errors.  */
+-
+-int
+-__gettimeofday (tv, tz)
+-     struct timeval *tv;
+-     struct timezone *tz;
++# include <dl-vdso.h>
++# include <bits/libc-vdso.h>
++# include <dl-machine.h>
++
++void *gettimeofday_ifunc (void) __asm__ ("__gettimeofday");
++
++static int
++__gettimeofday_syscall (struct timeval *tv, struct timezone *tz)
++{
++  return INLINE_SYSCALL (gettimeofday, 2, tv, tz);
++}
++
++void *
++gettimeofday_ifunc (void)
++{
++  PREPARE_VERSION (linux2615, "LINUX_2.6.15", 123718565);
++
++  /* If the vDSO is not available we fall back syscall.  */
++  void *vdso_gettimeofday = _dl_vdso_vsym ("__kernel_gettimeofday", &linux2615);
++  return (vdso_gettimeofday ? VDSO_IFUNC_RET (vdso_gettimeofday)
++        : (void*)__gettimeofday_syscall);
++}
++asm (".type __gettimeofday, %gnu_indirect_function");
++
++/* This is doing "libc_hidden_def (__gettimeofday)" but the compiler won't
++   let us do it in C because it doesn't know we're defining __gettimeofday
++   here in this file.  */
++asm (".globl __GI___gettimeofday\n"
++     "__GI___gettimeofday = __gettimeofday");
++
++#else
++
++# include <sysdep.h>
++# include <errno.h>
++
++int
++__gettimeofday (struct timeval *tv, struct timezone *tz)
+ {
+-  return INLINE_VSYSCALL (gettimeofday, 2, CHECK_1 (tv), CHECK_1 (tz));
++  return INLINE_SYSCALL (gettimeofday, 2, tv, tz);
+ }
++#endif
+ INTDEF (__gettimeofday)
+ weak_alias (__gettimeofday, gettimeofday)
diff --git a/src/patches/glibc/glibc-rh1039988.patch b/src/patches/glibc/glibc-rh1039988.patch
new file mode 100644 (file)
index 0000000..253b311
--- /dev/null
@@ -0,0 +1,141 @@
+commit 9a3c6a6ff602c88d7155139a7d7d0000b7b7e946
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date:   Thu Jan 2 10:05:27 2014 +0530
+
+    Fix return code from getent netgroup when the netgroup is not found (bz #16366)
+    
+    nscd incorrectly returns a success even when the netgroup in question
+    is not found and adds a positive result in the cache.  this patch
+    fixes this behaviour by adding a negative lookup entry to cache and
+    returning an error when the netgroup is not found.
+
+diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c
+index 50936ee..9fc1664 100644
+--- a/nscd/netgroupcache.c
++++ b/nscd/netgroupcache.c
+@@ -65,6 +65,55 @@ struct dataset
+   char strdata[0];
+ };
++/* Sends a notfound message and prepares a notfound dataset to write to the
++   cache.  Returns true if there was enough memory to allocate the dataset and
++   returns the dataset in DATASETP, total bytes to write in TOTALP and the
++   timeout in TIMEOUTP.  KEY_COPY is set to point to the copy of the key in the
++   dataset. */
++static bool
++do_notfound (struct database_dyn *db, int fd, request_header *req,
++             const char *key, struct dataset **datasetp, ssize_t *totalp,
++             time_t *timeoutp, char **key_copy)
++{
++  struct dataset *dataset;
++  ssize_t total;
++  time_t timeout;
++  bool cacheable = false;
++
++  total = sizeof (notfound);
++  timeout = time (NULL) + db->negtimeout;
++
++  if (fd != -1)
++    TEMP_FAILURE_RETRY (send (fd, &notfound, total, MSG_NOSIGNAL));
++
++  dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len, 1);
++  /* If we cannot permanently store the result, so be it.  */
++  if (dataset != NULL)
++    {
++      dataset->head.allocsize = sizeof (struct dataset) + req->key_len;
++      dataset->head.recsize = total;
++      dataset->head.notfound = true;
++      dataset->head.nreloads = 0;
++      dataset->head.usable = true;
++
++      /* Compute the timeout time.  */
++      timeout = dataset->head.timeout = time (NULL) + db->negtimeout;
++      dataset->head.ttl = db->negtimeout;
++
++      /* This is the reply.  */
++      memcpy (&dataset->resp, &notfound, total);
++
++      /* Copy the key data.  */
++      memcpy (dataset->strdata, key, req->key_len);
++      *key_copy = dataset->strdata;
++
++      cacheable = true;
++    }
++  *timeoutp = timeout;
++  *totalp = total;
++  *datasetp = dataset;
++  return cacheable;
++}
+ static time_t
+ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
+@@ -84,6 +133,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
+   struct dataset *dataset;
+   bool cacheable = false;
+   ssize_t total;
++  bool found = false;
+   char *key_copy = NULL;
+   struct __netgrent data;
+@@ -103,35 +153,8 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
+       && __nss_database_lookup ("netgroup", NULL, NULL, &netgroup_database))
+     {
+       /* No such service.  */
+-      total = sizeof (notfound);
+-      timeout = time (NULL) + db->negtimeout;
+-
+-      if (fd != -1)
+-      TEMP_FAILURE_RETRY (send (fd, &notfound, total, MSG_NOSIGNAL));
+-
+-      dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len, 1);
+-      /* If we cannot permanently store the result, so be it.  */
+-      if (dataset != NULL)
+-      {
+-        dataset->head.allocsize = sizeof (struct dataset) + req->key_len;
+-        dataset->head.recsize = total;
+-        dataset->head.notfound = true;
+-        dataset->head.nreloads = 0;
+-        dataset->head.usable = true;
+-
+-        /* Compute the timeout time.  */
+-        timeout = dataset->head.timeout = time (NULL) + db->negtimeout;
+-        dataset->head.ttl = db->negtimeout;
+-
+-        /* This is the reply.  */
+-        memcpy (&dataset->resp, &notfound, total);
+-
+-        /* Copy the key data.  */
+-        memcpy (dataset->strdata, key, req->key_len);
+-
+-        cacheable = true;
+-      }
+-
++      cacheable = do_notfound (db, fd, req, key, &dataset, &total, &timeout,
++                             &key_copy);
+       goto writeout;
+     }
+@@ -167,6 +190,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
+         if (status == NSS_STATUS_SUCCESS)
+           {
++            found = true;
+             union
+             {
+               enum nss_status (*f) (struct __netgrent *, char *, size_t,
+@@ -326,6 +350,15 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
+       }
+     }
++  /* No results.  Return a failure and write out a notfound record in the
++     cache.  */
++  if (!found)
++    {
++      cacheable = do_notfound (db, fd, req, key, &dataset, &total, &timeout,
++                             &key_copy);
++      goto writeout;
++    }
++
+   total = buffilled;
+   /* Fill in the dataset.  */
diff --git a/src/patches/glibc/glibc-rh1043557.patch b/src/patches/glibc/glibc-rh1043557.patch
new file mode 100644 (file)
index 0000000..affbe96
--- /dev/null
@@ -0,0 +1,145 @@
+commit af37a8a3496327a6e5617a2c76f17aa1e8db835e
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date:   Mon Jan 27 11:32:44 2014 +0530
+
+    Avoid undefined behaviour in netgroupcache
+    
+    Using a buffer after it has been reallocated is undefined behaviour,
+    so get offsets of the triplets in the old buffer before reallocating
+    it.
+
+commit 5d41dadf31bc8a2f9c34c40d52a442d3794e405c
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date:   Fri Jan 24 13:51:15 2014 +0530
+
+    Adjust pointers to triplets in netgroup query data (BZ #16474)
+    
+    The _nss_*_getnetgrent_r query populates the netgroup results in the
+    allocated buffer and then sets the result triplet to point to strings
+    in the buffer.  This is a problem when the buffer is reallocated since
+    the pointers to the triplet strings are no longer valid.  The pointers
+    need to be adjusted so that they now point to strings in the
+    reallocated buffer.
+
+commit 980cb5180e1b71224a57ca52b995c959b7148c09
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date:   Thu Jan 16 10:20:22 2014 +0530
+
+    Don't use alloca in addgetnetgrentX (BZ #16453)
+
+    addgetnetgrentX has a buffer which is grown as per the needs of the
+    requested size either by using alloca or by falling back to malloc if
+    the size is larger than 1K.  There are two problems with the alloca
+    bits: firstly, it doesn't really extend the buffer since it does not
+    use the return value of the extend_alloca macro, which is the location
+    of the reallocated buffer.  Due to this the buffer does not actually
+    extend itself and hence a subsequent write may overwrite stuff on the
+    stack.
+
+    The second problem is more subtle - the buffer growth on the stack is
+    discontinuous due to block scope local variables.  Combine that with
+    the fact that unlike realloc, extend_alloca does not copy over old
+    content and you have a situation where the buffer just has garbage in
+    the space where it should have had data.
+
+    This could have been fixed by adding code to copy over old data
+    whenever we call extend_alloca, but it seems unnecessarily
+    complicated.  This code is not exactly a performance hotspot (it's
+    called when there is a cache miss, so factors like network lookup or
+    file reads will dominate over memory allocation/reallocation), so this
+    premature optimization is unnecessary.
+    
+    Thanks Brad Hubbard <bhubbard@redhat.com> for his help with debugging
+    the problem.
+
+diff -pruN glibc-2.12-2-gc4ccff1/nscd/netgroupcache.c glibc-2.12-2-gc4ccff1.patched/nscd/netgroupcache.c
+--- glibc-2.12-2-gc4ccff1/nscd/netgroupcache.c 2014-04-09 12:13:58.618582111 +0530
++++ glibc-2.12-2-gc4ccff1.patched/nscd/netgroupcache.c 2014-04-09 12:07:21.486598665 +0530
+@@ -93,7 +93,6 @@ addgetnetgrentX (struct database_dyn *db
+   size_t buffilled = sizeof (*dataset);
+   char *buffer = NULL;
+   size_t nentries = 0;
+-  bool use_malloc = false;
+   size_t group_len = strlen (key) + 1;
+   union
+   {
+@@ -138,7 +137,7 @@ addgetnetgrentX (struct database_dyn *db
+     }
+   memset (&data, '\0', sizeof (data));
+-  buffer = alloca (buflen);
++  buffer = xmalloc (buflen);
+   first_needed.elem.next = &first_needed.elem;
+   memcpy (first_needed.elem.name, key, group_len);
+   data.needed_groups = &first_needed.elem;
+@@ -218,21 +217,24 @@ addgetnetgrentX (struct database_dyn *db
+                               if (buflen - req->key_len - bufused < needed)
+                                 {
+-                                  size_t newsize = MAX (2 * buflen,
+-                                                        buflen + 2 * needed);
+-                                  if (use_malloc || newsize > 1024 * 1024)
+-                                    {
+-                                      buflen = newsize;
+-                                      char *newbuf = xrealloc (use_malloc
+-                                                               ? buffer
+-                                                               : NULL,
+-                                                               buflen);
+-
+-                                      buffer = newbuf;
+-                                      use_malloc = true;
+-                                    }
+-                                  else
+-                                    extend_alloca (buffer, buflen, newsize);
++                                  buflen += MAX (buflen, 2 * needed);
++                                  /* Save offset in the old buffer.  We don't
++                                     bother with the NULL check here since
++                                     we'll do that later anyway.  */
++                                  size_t nhostdiff = nhost - buffer;
++                                  size_t nuserdiff = nuser - buffer;
++                                  size_t ndomaindiff = ndomain - buffer;
++
++                                  char *newbuf = xrealloc (buffer, buflen);
++                                  /* Fix up the triplet pointers into the new
++                                     buffer.  */
++                                  nhost = (nhost ? newbuf + nhostdiff
++                                           : NULL);
++                                  nuser = (nuser ? newbuf + nuserdiff
++                                           : NULL);
++                                  ndomain = (ndomain ? newbuf + ndomaindiff
++                                             : NULL);
++                                  buffer = newbuf;
+                                 }
+                               nhost = memcpy (buffer + bufused,
+@@ -299,18 +301,8 @@ addgetnetgrentX (struct database_dyn *db
+                     }
+                   else if (status == NSS_STATUS_UNAVAIL && e == ERANGE)
+                     {
+-                      size_t newsize = 2 * buflen;
+-                      if (use_malloc || newsize > 1024 * 1024)
+-                        {
+-                          buflen = newsize;
+-                          char *newbuf = xrealloc (use_malloc
+-                                                   ? buffer : NULL, buflen);
+-
+-                          buffer = newbuf;
+-                          use_malloc = true;
+-                        }
+-                      else
+-                        extend_alloca (buffer, buflen, newsize);
++                      buflen *= 2;
++                      buffer = xrealloc (buffer, buflen);
+                     }
+                 }
+@@ -446,8 +438,7 @@ addgetnetgrentX (struct database_dyn *db
+     }
+  out:
+-  if (use_malloc)
+-    free (buffer);
++  free (buffer);
+   *resultp = dataset;
diff --git a/src/patches/glibc/glibc-rh1053178.patch b/src/patches/glibc/glibc-rh1053178.patch
new file mode 100644 (file)
index 0000000..a662cfe
--- /dev/null
@@ -0,0 +1,214 @@
+#
+# Based on the commit:
+#
+# commit 6c82a2f8d7c8e21e39237225c819f182ae438db3
+# Author: Carlos O'Donell <carlos@redhat.com>
+# Date:   Fri Sep 6 01:02:30 2013 -0400
+#
+#    Coordinate IPv6 definitions for Linux and glibc
+#    
+#    This change synchronizes the glibc headers with the Linux kernel
+#    headers and arranges to coordinate the definition of structures
+#    already defined the Linux kernel UAPI headers.
+#    
+#    It is now safe to include glibc's netinet/in.h or Linux's linux/in6.h
+#    in any order in a userspace application and you will get the same
+#    ABI. The ABI is guaranteed by UAPI and glibc.
+#
+# 2013-09-05  Carlos O'Donell  <carlos@redhat.com>
+#          Cong Wang  <amwang@redhat.com>
+# 
+#      * sysdeps/unix/sysv/linux/bits/in.h
+#      [_UAPI_LINUX_IN6_H]: Define __USE_KERNEL_IPV6_DEFS.
+#      * inet/netinet/in.h: Move in_addr definition and bits/in.h inclusion
+#      before __USE_KERNEL_IPV6_DEFS uses.
+#      * inet/netinet/in.h [!__USE_KERNEL_IPV6_DEFS]: Define IPPROTO_MH, and
+#      IPPROTO_BEETPH.
+#      [__USE_KERNEL_IPV6_DEFS]: Don't define any of IPPROTO_*, in6_addr,
+#      sockaddr_in6, or ipv6_mreq.
+# 
+diff -urN glibc-2.12-2-gc4ccff1/inet/netinet/in.h glibc-2.12-2-gc4ccff1.mod/inet/netinet/in.h
+--- glibc-2.12-2-gc4ccff1/inet/netinet/in.h    2010-05-04 07:27:23.000000000 -0400
++++ glibc-2.12-2-gc4ccff1.mod/inet/netinet/in.h        2015-02-18 13:06:56.436802873 -0500
+@@ -28,13 +28,21 @@
+ __BEGIN_DECLS
++/* Internet address.  */
++typedef uint32_t in_addr_t;
++struct in_addr
++  {
++    in_addr_t s_addr;
++  };
++
++/* Get system-specific definitions.  */
++#include <bits/in.h>
++
+ /* Standard well-defined IP protocols.  */
+ enum
+   {
+     IPPROTO_IP = 0,      /* Dummy protocol for TCP.  */
+ #define IPPROTO_IP            IPPROTO_IP
+-    IPPROTO_HOPOPTS = 0,   /* IPv6 Hop-by-Hop options.  */
+-#define IPPROTO_HOPOPTS               IPPROTO_HOPOPTS
+     IPPROTO_ICMP = 1,    /* Internet Control Message Protocol.  */
+ #define IPPROTO_ICMP          IPPROTO_ICMP
+     IPPROTO_IGMP = 2,    /* Internet Group Management Protocol. */
+@@ -57,10 +65,6 @@
+ #define IPPROTO_DCCP          IPPROTO_DCCP
+     IPPROTO_IPV6 = 41,     /* IPv6 header.  */
+ #define IPPROTO_IPV6          IPPROTO_IPV6
+-    IPPROTO_ROUTING = 43,  /* IPv6 routing header.  */
+-#define IPPROTO_ROUTING               IPPROTO_ROUTING
+-    IPPROTO_FRAGMENT = 44, /* IPv6 fragmentation header.  */
+-#define IPPROTO_FRAGMENT      IPPROTO_FRAGMENT
+     IPPROTO_RSVP = 46,           /* Reservation Protocol.  */
+ #define IPPROTO_RSVP          IPPROTO_RSVP
+     IPPROTO_GRE = 47,    /* General Routing Encapsulation.  */
+@@ -69,14 +73,10 @@
+ #define IPPROTO_ESP           IPPROTO_ESP
+     IPPROTO_AH = 51,       /* authentication header.  */
+ #define IPPROTO_AH            IPPROTO_AH
+-    IPPROTO_ICMPV6 = 58,   /* ICMPv6.  */
+-#define IPPROTO_ICMPV6                IPPROTO_ICMPV6
+-    IPPROTO_NONE = 59,     /* IPv6 no next header.  */
+-#define IPPROTO_NONE          IPPROTO_NONE
+-    IPPROTO_DSTOPTS = 60,  /* IPv6 destination options.  */
+-#define IPPROTO_DSTOPTS               IPPROTO_DSTOPTS
+     IPPROTO_MTP = 92,    /* Multicast Transport Protocol.  */
+ #define IPPROTO_MTP           IPPROTO_MTP
++    IPPROTO_BEETPH = 94,   /* IP option pseudo header for BEET.  */
++#define IPPROTO_BEETPH                IPPROTO_BEETPH
+     IPPROTO_ENCAP = 98,          /* Encapsulation Header.  */
+ #define IPPROTO_ENCAP         IPPROTO_ENCAP
+     IPPROTO_PIM = 103,           /* Protocol Independent Multicast.  */
+@@ -92,6 +92,28 @@
+     IPPROTO_MAX
+   };
++/* If __USER_KERNEL_IPV6_DEFS is defined then the user has included the kernel
++   network headers first and we should use those ABI-identical definitions
++   instead of our own.  */
++#ifndef __USE_KERNEL_IPV6_DEFS
++enum
++  {
++    IPPROTO_HOPOPTS = 0,   /* IPv6 Hop-by-Hop options.  */
++#define IPPROTO_HOPOPTS               IPPROTO_HOPOPTS
++    IPPROTO_ROUTING = 43,  /* IPv6 routing header.  */
++#define IPPROTO_ROUTING               IPPROTO_ROUTING
++    IPPROTO_FRAGMENT = 44, /* IPv6 fragmentation header.  */
++#define IPPROTO_FRAGMENT      IPPROTO_FRAGMENT
++    IPPROTO_ICMPV6 = 58,   /* ICMPv6.  */
++#define IPPROTO_ICMPV6                IPPROTO_ICMPV6
++    IPPROTO_NONE = 59,     /* IPv6 no next header.  */
++#define IPPROTO_NONE          IPPROTO_NONE
++    IPPROTO_DSTOPTS = 60,  /* IPv6 destination options.  */
++#define IPPROTO_DSTOPTS               IPPROTO_DSTOPTS
++    IPPROTO_MH = 135,      /* IPv6 mobility header.  */
++#define IPPROTO_MH            IPPROTO_MH
++  };
++#endif /* !__USE_KERNEL_IPV6_DEFS */
+ /* Type to represent a port.  */
+ typedef uint16_t in_port_t;
+@@ -136,15 +158,6 @@
+     IPPORT_USERRESERVED = 5000
+   };
+-
+-/* Internet address.  */
+-typedef uint32_t in_addr_t;
+-struct in_addr
+-  {
+-    in_addr_t s_addr;
+-  };
+-
+-
+ /* Definitions of the bits in an Internet address integer.
+    On subnets, host and network parts are found according to
+@@ -193,7 +206,7 @@
+ #define INADDR_ALLRTRS_GROUP    ((in_addr_t) 0xe0000002) /* 224.0.0.2 */
+ #define INADDR_MAX_LOCAL_GROUP  ((in_addr_t) 0xe00000ff) /* 224.0.0.255 */
+-
++#ifndef __USE_KERNEL_IPV6_DEFS
+ /* IPv6 address */
+ struct in6_addr
+   {
+@@ -211,6 +224,7 @@
+ # define s6_addr32            __in6_u.__u6_addr32
+ #endif
+   };
++#endif /* !__USE_KERNEL_IPV6_DEFS */
+ extern const struct in6_addr in6addr_any;        /* :: */
+ extern const struct in6_addr in6addr_loopback;   /* ::1 */
+@@ -235,6 +249,7 @@
+                          sizeof (struct in_addr)];
+   };
++#ifndef __USE_KERNEL_IPV6_DEFS
+ /* Ditto, for IPv6.  */
+ struct sockaddr_in6
+   {
+@@ -244,7 +259,7 @@
+     struct in6_addr sin6_addr;        /* IPv6 address */
+     uint32_t sin6_scope_id;   /* IPv6 scope-id */
+   };
+-
++#endif /* !__USE_KERNEL_IPV6_DEFS */
+ #if defined __USE_MISC || defined __USE_GNU
+ /* IPv4 multicast request.  */
+@@ -270,7 +285,7 @@
+   };
+ #endif
+-
++#ifndef __USE_KERNEL_IPV6_DEFS
+ /* Likewise, for IPv6.  */
+ struct ipv6_mreq
+   {
+@@ -280,7 +295,7 @@
+     /* local interface */
+     unsigned int ipv6mr_interface;
+   };
+-
++#endif /* !__USE_KERNEL_IPV6_DEFS */
+ #if defined __USE_MISC || defined __USE_GNU
+ /* Multicast group request.  */
+@@ -351,10 +366,6 @@
+                                     * sizeof (struct sockaddr_storage)))
+ #endif
+-
+-/* Get system-specific definitions.  */
+-#include <bits/in.h>
+-
+ /* Functions to convert between host and network byte order.
+    Please note that these functions normally take `unsigned long int' or
+diff -urN glibc-2.12-2-gc4ccff1/sysdeps/unix/sysv/linux/bits/in.h glibc-2.12-2-gc4ccff1.mod/sysdeps/unix/sysv/linux/bits/in.h
+--- glibc-2.12-2-gc4ccff1/sysdeps/unix/sysv/linux/bits/in.h    2015-02-18 13:04:15.547734092 -0500
++++ glibc-2.12-2-gc4ccff1.mod/sysdeps/unix/sysv/linux/bits/in.h        2015-02-18 13:06:56.436802873 -0500
+@@ -22,6 +22,18 @@
+ # error "Never use <bits/in.h> directly; include <netinet/in.h> instead."
+ #endif
++/* If the application has already included linux/in6.h from a linux-based
++   kernel then we will not define the IPv6 IPPROTO_* defines, in6_addr (nor the
++   defines), sockaddr_in6, or ipv6_mreq.  The ABI used by the linux-kernel and
++   glibc match exactly.  Neither the linux kernel nor glibc should break this
++   ABI without coordination.  */
++#ifdef _UAPI_LINUX_IN6_H
++/* This is not quite the same API since the kernel always defines s6_addr16 and
++   s6_addr32. This is not a violation of POSIX since POSIX says "at least the
++   following member" and that holds true.  */
++# define __USE_KERNEL_IPV6_DEFS
++#endif
++
+ /* Options for use with `getsockopt' and `setsockopt' at the IP level.
+    The first word in the comment at the right is the data type used;
+    "bool" means a boolean value stored in an `int'.  */
diff --git a/src/patches/glibc/glibc-rh1054846.patch b/src/patches/glibc/glibc-rh1054846.patch
new file mode 100644 (file)
index 0000000..50b4109
--- /dev/null
@@ -0,0 +1,57 @@
+commit fbd6b5a4052316f7eb03c4617eebfaafc59dcc06
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date:   Thu Mar 27 07:15:22 2014 +0530
+
+    Fix nscd lookup for innetgr when netgroup has wildcards (BZ #16758)
+    
+    nscd works correctly when the request in innetgr is a wildcard,
+    i.e. when one or more of host, user or domain parameters is NULL.
+    However, it does not work when the the triplet in the netgroup
+    definition has a wildcard.  This is easy to reproduce for a triplet
+    defined as follows:
+    
+        foonet (,foo,)
+    
+    Here, an innetgr call that looks like this:
+    
+        innetgr ("foonet", "foohost", "foo", NULL);
+    
+    should succeed and so should:
+    
+        innetgr ("foonet", NULL, "foo", "foodomain");
+    
+    It does succeed with nscd disabled, but not with nscd enabled.  This
+    fix adds this additional check for all three parts of the triplet so
+    that it gives the correct result.
+    
+       [BZ #16758]
+       * nscd/netgroupcache.c (addinnetgrX): Succeed if triplet has
+       blank values.
+
+diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c
+index 5ba1e1f..5d15aa4 100644
+--- a/nscd/netgroupcache.c
++++ b/nscd/netgroupcache.c
+@@ -560,15 +560,19 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
+       {
+         bool success = true;
+-        if (host != NULL)
++        /* For the host, user and domain in each triplet, we assume success
++           if the value is blank because that is how the wildcard entry to
++           match anything is stored in the netgroup cache.  */
++        if (host != NULL && *triplets != '\0')
+           success = strcmp (host, triplets) == 0;
+         triplets = (const char *) rawmemchr (triplets, '\0') + 1;
+-        if (success && user != NULL)
++        if (success && user != NULL && *triplets != '\0')
+           success = strcmp (user, triplets) == 0;
+         triplets = (const char *) rawmemchr (triplets, '\0') + 1;
+-        if (success && (domain == NULL || strcmp (domain, triplets) == 0))
++        if (success && (domain == NULL || *triplets == '\0'
++                        || strcmp (domain, triplets) == 0))
+           {
+             dataset->resp.result = 1;
+             break;
diff --git a/src/patches/glibc/glibc-rh1066724.patch b/src/patches/glibc/glibc-rh1066724.patch
new file mode 100644 (file)
index 0000000..a03f1d1
--- /dev/null
@@ -0,0 +1,620 @@
+diff --git a/malloc/Makefile b/malloc/Makefile
+index e7ec1ab..5330a3b 100644
+--- a/malloc/Makefile
++++ b/malloc/Makefile
+@@ -27,7 +27,8 @@ all:
+ dist-headers := malloc.h
+ headers := $(dist-headers) obstack.h mcheck.h
+ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \
+-       tst-mallocstate tst-mcheck tst-mallocfork tst-trim1
++       tst-mallocstate tst-mcheck tst-mallocfork tst-trim1 \
++       tst-malloc-backtrace
+ test-srcs = tst-mtrace
+ distribute = thread-m.h mtrace.pl mcheck-init.c stackinfo.h memusage.h \
+@@ -49,6 +50,9 @@ extra-libs-others = $(extra-libs)
+ libmemusage-routines = memusage
+ libmemusage-inhibit-o = $(filter-out .os,$(object-suffixes))
++$(objpfx)tst-malloc-backtrace: $(common-objpfx)nptl/libpthread.so \
++                             $(common-objpfx)nptl/libpthread_nonshared.a
++
+ # These should be removed by `make clean'.
+ extra-objs = mcheck-init.o libmcheck.a
+diff --git a/malloc/arena.c b/malloc/arena.c
+index 18bea2b..5180516 100644
+--- a/malloc/arena.c
++++ b/malloc/arena.c
+@@ -123,7 +123,7 @@ int __malloc_initialized = -1;
+ #ifdef PER_THREAD
+ #define arena_lock(ptr, size) do { \
+-  if(ptr) \
++  if(ptr && !arena_is_corrupt (ptr)) \
+     (void)mutex_lock(&ptr->mutex); \
+   else \
+     ptr = arena_get2(ptr, (size), false); \
+@@ -1011,7 +1011,21 @@ reused_arena (bool retrying)
+   if (retrying && result == &main_arena)
+     result = result->next;
+-  /* No arena available.  Wait for the next in line.  */
++  /* Make sure that the arena we get is not corrupted.  */
++  mstate begin = result;
++  while (arena_is_corrupt (result))
++    {
++      result = result->next;
++      if (result == begin)
++       break;
++    }
++
++  /* We could not find any arena that was either not corrupted or not the one
++     we wanted to avoid.  */
++  if (result == begin)
++    return NULL;
++
++  /* No arena available without contention.  Wait for the next in line.  */
+   (void)mutex_lock(&result->mutex);
+  out:
+diff --git a/malloc/hooks.c b/malloc/hooks.c
+index cc83d21..38d2542 100644
+--- a/malloc/hooks.c
++++ b/malloc/hooks.c
+@@ -220,7 +220,8 @@ top_check()
+     return 0;
+   mutex_unlock(&main_arena);
+-  malloc_printerr (check_action, "malloc: top chunk is corrupt", t);
++  malloc_printerr (check_action, "malloc: top chunk is corrupt", t,
++                 &main_arena);
+   mutex_lock(&main_arena);
+   /* Try to set up a new top chunk. */
+@@ -283,7 +284,7 @@ free_check(mem, caller) Void_t* mem; const Void_t *caller;
+   if(!p) {
+     (void)mutex_unlock(&main_arena.mutex);
+-    malloc_printerr(check_action, "free(): invalid pointer", mem);
++    malloc_printerr(check_action, "free(): invalid pointer", mem, &main_arena);
+     return;
+   }
+ #if HAVE_MMAP
+@@ -329,7 +330,8 @@ realloc_check(oldmem, bytes, caller)
+   const mchunkptr oldp = mem2chunk_check(oldmem, &magic_p);
+   (void)mutex_unlock(&main_arena.mutex);
+   if(!oldp) {
+-    malloc_printerr(check_action, "realloc(): invalid pointer", oldmem);
++    malloc_printerr(check_action, "realloc(): invalid pointer", oldmem,
++                  &main_arena);
+     return malloc_check(bytes, NULL);
+   }
+   const INTERNAL_SIZE_T oldsize = chunksize(oldp);
+diff --git a/malloc/malloc.c b/malloc/malloc.c
+index 597c7b0..20ac534 100644
+--- a/malloc/malloc.c
++++ b/malloc/malloc.c
+@@ -1633,7 +1633,7 @@ static size_t   mUSABLe(Void_t*);
+ static void     mSTATs(void);
+ static int      mALLOPt(int, int);
+ static struct mallinfo mALLINFo(mstate);
+-static void malloc_printerr(int action, const char *str, void *ptr);
++static void malloc_printerr(int action, const char *str, void *ptr, mstate av);
+ static Void_t* internal_function mem2mem_check(Void_t *p, size_t sz);
+ static int internal_function top_check(void);
+@@ -2114,7 +2114,8 @@ typedef struct malloc_chunk* mbinptr;
+   BK = P->bk;                                                          \
+   if (__builtin_expect (FD->bk != P || BK->fd != P, 0)) {            \
+     mutex_unlock(&(AV)->mutex);                                              \
+-    malloc_printerr (check_action, "corrupted double-linked list", P); \
++    malloc_printerr (check_action, "corrupted double-linked list", P,  \
++                   AV);                                              \
+     mutex_lock(&(AV)->mutex);                                        \
+   } else {                                                           \
+     FD->bk = BK;                                                       \
+@@ -2344,6 +2345,15 @@ typedef struct malloc_chunk* mfastbinptr;
+ #define set_noncontiguous(M)   ((M)->flags |=  NONCONTIGUOUS_BIT)
+ #define set_contiguous(M)      ((M)->flags &= ~NONCONTIGUOUS_BIT)
++/* ARENA_CORRUPTION_BIT is set if a memory corruption was detected on the
++   arena.  Such an arena is no longer used to allocate chunks.  Chunks
++   allocated in that arena before detecting corruption are not freed.  */
++
++#define ARENA_CORRUPTION_BIT (4U)
++
++#define arena_is_corrupt(A)    (((A)->flags & ARENA_CORRUPTION_BIT))
++#define set_arena_corrupt(A)   ((A)->flags |= ARENA_CORRUPTION_BIT)
++
+ /*
+    Set value of max_fast.
+    Use impossibly small value if 0.
+@@ -3002,8 +3012,9 @@ static Void_t* sYSMALLOc(nb, av) INTERNAL_SIZE_T nb; mstate av;
+     rather than expanding top.
+   */
+-  if ((unsigned long)(nb) >= (unsigned long)(mp_.mmap_threshold) &&
+-      (mp_.n_mmaps < mp_.n_mmaps_max)) {
++  if (av == NULL
++      || ((unsigned long)(nb) >= (unsigned long)(mp_.mmap_threshold) &&
++        (mp_.n_mmaps < mp_.n_mmaps_max))) {
+     char* mm;             /* return value from mmap call*/
+@@ -3079,6 +3090,10 @@ static Void_t* sYSMALLOc(nb, av) INTERNAL_SIZE_T nb; mstate av;
+   }
+ #endif
++  /* There are no usable arenas and mmap also failed.  */
++  if (av == NULL)
++    return 0;
++
+   /* Record incoming configuration of top */
+   old_top  = av->top;
+@@ -3260,7 +3275,7 @@ static Void_t* sYSMALLOc(nb, av) INTERNAL_SIZE_T nb; mstate av;
+     else if (contiguous(av) && old_size && brk < old_end) {
+       /* Oops!  Someone else killed our space..  Can't touch anything.  */
+       mutex_unlock(&av->mutex);
+-      malloc_printerr (3, "break adjusted to free malloc space", brk);
++      malloc_printerr (3, "break adjusted to free malloc space", brk, av);
+       mutex_lock(&av->mutex);
+     }
+@@ -3542,7 +3557,7 @@ munmap_chunk(p) mchunkptr p;
+   if (__builtin_expect (((block | total_size) & (mp_.pagesize - 1)) != 0, 0))
+     {
+       malloc_printerr (check_action, "munmap_chunk(): invalid pointer",
+-                     chunk2mem (p));
++                     chunk2mem (p), NULL);
+       return;
+     }
+@@ -3625,65 +3640,31 @@ public_mALLOc(size_t bytes)
+   if (__builtin_expect (hook != NULL, 0))
+     return (*hook)(bytes, RETURN_ADDRESS (0));
+-  arena_lookup(ar_ptr);
+-#if 0
+-  // XXX We need double-word CAS and fastbins must be extended to also
+-  // XXX hold a generation counter for each entry.
+-  if (ar_ptr) {
+-    INTERNAL_SIZE_T nb;               /* normalized request size */
+-    checked_request2size(bytes, nb);
+-    if (nb <= get_max_fast ()) {
+-      long int idx = fastbin_index(nb);
+-      mfastbinptr* fb = &fastbin (ar_ptr, idx);
+-      mchunkptr pp = *fb;
+-      mchunkptr v;
+-      do
+-      {
+-        v = pp;
+-        if (v == NULL)
+-          break;
+-      }
+-      while ((pp = catomic_compare_and_exchange_val_acq (fb, v->fd, v)) != v);
+-      if (v != 0) {
+-      if (__builtin_expect (fastbin_index (chunksize (v)) != idx, 0))
+-        malloc_printerr (check_action, "malloc(): memory corruption (fast)",
+-                         chunk2mem (v));
+-      check_remalloced_chunk(ar_ptr, v, nb);
+-      void *p = chunk2mem(v);
+-      if (__builtin_expect (perturb_byte, 0))
+-        alloc_perturb (p, bytes);
+-      return p;
+-      }
+-    }
+-  }
+-#endif
++  arena_get(ar_ptr, bytes);
+-  arena_lock(ar_ptr, bytes);
+-  if(!ar_ptr)
+-    return 0;
+   victim = _int_malloc(ar_ptr, bytes);
+-  if(!victim) {
++  if(!victim && ar_ptr != NULL) {
+     /* Maybe the failure is due to running out of mmapped areas. */
+     if(ar_ptr != &main_arena) {
+       (void)mutex_unlock(&ar_ptr->mutex);
+       ar_ptr = &main_arena;
+       (void)mutex_lock(&ar_ptr->mutex);
+       victim = _int_malloc(ar_ptr, bytes);
+-      (void)mutex_unlock(&ar_ptr->mutex);
+     } else {
+ #if USE_ARENAS
+       /* ... or sbrk() has failed and there is still a chance to mmap() */
+       mstate prev = ar_ptr->next ? ar_ptr : 0;
+       (void)mutex_unlock(&ar_ptr->mutex);
+       ar_ptr = arena_get2(prev, bytes, true);
+-      if(ar_ptr) {
++      if(ar_ptr)
+       victim = _int_malloc(ar_ptr, bytes);
+-      (void)mutex_unlock(&ar_ptr->mutex);
+-      }
+ #endif
+     }
+-  } else
++  }
++
++  if (ar_ptr != NULL)
+     (void)mutex_unlock(&ar_ptr->mutex);
++
+   assert(!victim || chunk_is_mmapped(mem2chunk(victim)) ||
+        ar_ptr == arena_for_chunk(mem2chunk(victim)));
+   return victim;
+@@ -3773,6 +3754,11 @@ public_rEALLOc(Void_t* oldmem, size_t bytes)
+   /* its size */
+   const INTERNAL_SIZE_T oldsize = chunksize(oldp);
++  if (chunk_is_mmapped (oldp))
++    ar_ptr = NULL;
++  else
++    ar_ptr = arena_for_chunk (oldp);
++
+   /* Little security check which won't hurt performance: the
+      allocator never wrapps around at the end of the address space.
+      Therefore we can exclude some size values which might appear
+@@ -3780,7 +3766,8 @@ public_rEALLOc(Void_t* oldmem, size_t bytes)
+   if (__builtin_expect ((uintptr_t) oldp > (uintptr_t) -oldsize, 0)
+       || __builtin_expect (misaligned_chunk (oldp), 0))
+     {
+-      malloc_printerr (check_action, "realloc(): invalid pointer", oldmem);
++      malloc_printerr (check_action, "realloc(): invalid pointer", oldmem,
++                     ar_ptr);
+       return NULL;
+     }
+@@ -3806,7 +3793,6 @@ public_rEALLOc(Void_t* oldmem, size_t bytes)
+   }
+ #endif
+-  ar_ptr = arena_for_chunk(oldp);
+ #if THREAD_STATS
+   if(!mutex_trylock(&ar_ptr->mutex))
+     ++(ar_ptr->stat_lock_direct);
+@@ -3887,31 +3873,29 @@ public_mEMALIGn(size_t alignment, size_t bytes)
+     }
+   arena_get(ar_ptr, bytes + alignment + MINSIZE);
+-  if(!ar_ptr)
+-    return 0;
+   p = _int_memalign(ar_ptr, alignment, bytes);
+-  if(!p) {
++  if(!p && ar_ptr != NULL) {
+     /* Maybe the failure is due to running out of mmapped areas. */
+     if(ar_ptr != &main_arena) {
+       (void)mutex_unlock(&ar_ptr->mutex);
+       ar_ptr = &main_arena;
+       (void)mutex_lock(&ar_ptr->mutex);
+       p = _int_memalign(ar_ptr, alignment, bytes);
+-      (void)mutex_unlock(&ar_ptr->mutex);
+     } else {
+ #if USE_ARENAS
+       /* ... or sbrk() has failed and there is still a chance to mmap() */
+       mstate prev = ar_ptr->next ? ar_ptr : 0;
+       (void)mutex_unlock(&ar_ptr->mutex);
+       ar_ptr = arena_get2(prev, bytes, true);
+-      if(ar_ptr) {
++      if(ar_ptr)
+       p = _int_memalign(ar_ptr, alignment, bytes);
+-      (void)mutex_unlock(&ar_ptr->mutex);
+-      }
+ #endif
+     }
+-  } else
++  }
++  
++  if (ar_ptr != NULL)
+     (void)mutex_unlock(&ar_ptr->mutex);
++
+   assert(!p || chunk_is_mmapped(mem2chunk(p)) ||
+        ar_ptr == arena_for_chunk(mem2chunk(p)));
+   return p;
+@@ -3945,31 +3929,29 @@ public_vALLOc(size_t bytes)
+     return (*hook)(pagesz, bytes, RETURN_ADDRESS (0));
+   arena_get(ar_ptr, bytes + pagesz + MINSIZE);
+-  if(!ar_ptr)
+-    return 0;
+   p = _int_valloc(ar_ptr, bytes);
+-  if(!p) {
++  if(!p && ar_ptr != NULL) {
+     /* Maybe the failure is due to running out of mmapped areas. */
+     if(ar_ptr != &main_arena) {
+       (void)mutex_unlock(&ar_ptr->mutex);
+       ar_ptr = &main_arena;
+       (void)mutex_lock(&ar_ptr->mutex);
+       p = _int_memalign(ar_ptr, pagesz, bytes);
+-      (void)mutex_unlock(&ar_ptr->mutex);
+     } else {
+ #if USE_ARENAS
+       /* ... or sbrk() has failed and there is still a chance to mmap() */
+       mstate prev = ar_ptr->next ? ar_ptr : 0;
+       (void)mutex_unlock(&ar_ptr->mutex);
+       ar_ptr = arena_get2(prev, bytes, true);
+-      if(ar_ptr) {
++      if(ar_ptr)
+       p = _int_memalign(ar_ptr, pagesz, bytes);
+-      (void)mutex_unlock(&ar_ptr->mutex);
+-      }
+ #endif
+     }
+-  } else
++  }
++
++  if (ar_ptr != NULL)
+     (void)mutex_unlock(&ar_ptr->mutex);
++
+   assert(!p || chunk_is_mmapped(mem2chunk(p)) ||
+        ar_ptr == arena_for_chunk(mem2chunk(p)));
+@@ -4004,28 +3986,28 @@ public_pVALLOc(size_t bytes)
+   arena_get(ar_ptr, bytes + 2*pagesz + MINSIZE);
+   p = _int_pvalloc(ar_ptr, bytes);
+-  if(!p) {
++  if(!p && ar_ptr != NULL) {
+     /* Maybe the failure is due to running out of mmapped areas. */
+     if(ar_ptr != &main_arena) {
+       (void)mutex_unlock(&ar_ptr->mutex);
+       ar_ptr = &main_arena;
+       (void)mutex_lock(&ar_ptr->mutex);
+       p = _int_memalign(ar_ptr, pagesz, rounded_bytes);
+-      (void)mutex_unlock(&ar_ptr->mutex);
+     } else {
+ #if USE_ARENAS
+       /* ... or sbrk() has failed and there is still a chance to mmap() */
+       mstate prev = ar_ptr->next ? ar_ptr : 0;
+       (void)mutex_unlock(&ar_ptr->mutex);
+       ar_ptr = arena_get2(prev, bytes + 2*pagesz + MINSIZE, true);
+-      if(ar_ptr) {
++      if(ar_ptr)
+       p = _int_memalign(ar_ptr, pagesz, rounded_bytes);
+-      (void)mutex_unlock(&ar_ptr->mutex);
+-      }
+ #endif
+     }
+-  } else
++  }
++
++  if (ar_ptr != NULL)
+     (void)mutex_unlock(&ar_ptr->mutex);
++
+   assert(!p || chunk_is_mmapped(mem2chunk(p)) ||
+        ar_ptr == arena_for_chunk(mem2chunk(p)));
+@@ -4072,55 +4054,65 @@ public_cALLOc(size_t n, size_t elem_size)
+   sz = bytes;
+   arena_get(av, sz);
+-  if(!av)
+-    return 0;
+-  /* Check if we hand out the top chunk, in which case there may be no
+-     need to clear. */
++  if (av)
++    {
++      /* Check if we hand out the top chunk, in which case there may be no
++       need to clear. */
+ #if MORECORE_CLEARS
+-  oldtop = top(av);
+-  oldtopsize = chunksize(top(av));
++      oldtop = top(av);
++      oldtopsize = chunksize(top(av));
+ #if MORECORE_CLEARS < 2
+-  /* Only newly allocated memory is guaranteed to be cleared.  */
+-  if (av == &main_arena &&
+-      oldtopsize < mp_.sbrk_base + av->max_system_mem - (char *)oldtop)
+-    oldtopsize = (mp_.sbrk_base + av->max_system_mem - (char *)oldtop);
++      /* Only newly allocated memory is guaranteed to be cleared.  */
++      if (av == &main_arena &&
++        oldtopsize < mp_.sbrk_base + av->max_system_mem - (char *)oldtop)
++      oldtopsize = (mp_.sbrk_base + av->max_system_mem - (char *)oldtop);
+ #endif
+-  if (av != &main_arena)
++      if (av != &main_arena)
++      {
++        heap_info *heap = heap_for_ptr (oldtop);
++        if (oldtopsize < (char *) heap + heap->mprotect_size - (char *) oldtop)
++          oldtopsize = (char *) heap + heap->mprotect_size - (char *) oldtop;
++      }
++#endif
++    }
++  else
+     {
+-      heap_info *heap = heap_for_ptr (oldtop);
+-      if (oldtopsize < (char *) heap + heap->mprotect_size - (char *) oldtop)
+-      oldtopsize = (char *) heap + heap->mprotect_size - (char *) oldtop;
++      /* No usable arenas.  */
++      oldtop = 0;
++      oldtopsize = 0;
+     }
+-#endif
+   mem = _int_malloc(av, sz);
+-
+   assert(!mem || chunk_is_mmapped(mem2chunk(mem)) ||
+        av == arena_for_chunk(mem2chunk(mem)));
+-  if (mem == 0) {
++  if (mem == 0 && av != NULL) {
+     /* Maybe the failure is due to running out of mmapped areas. */
+     if(av != &main_arena) {
+       (void)mutex_unlock(&av->mutex);
+       (void)mutex_lock(&main_arena.mutex);
+       mem = _int_malloc(&main_arena, sz);
+-      (void)mutex_unlock(&main_arena.mutex);
+     } else {
+ #if USE_ARENAS
+       /* ... or sbrk() has failed and there is still a chance to mmap() */
+       mstate prev = av->next ? av : 0;
+       (void)mutex_unlock(&av->mutex);
+       av = arena_get2(prev, sz, true);
+-      if(av) {
++      if(av)
+       mem = _int_malloc(av, sz);
+-      (void)mutex_unlock(&av->mutex);
+-      }
+ #endif
+     }
+     if (mem == 0) return 0;
+-  } else
++  }
++
++  if (av != NULL)
+     (void)mutex_unlock(&av->mutex);
++
++  /* Allocation failed even after a retry.  */
++  if (mem == 0)
++    return 0;
++
+   p = mem2chunk(mem);
+   /* Two optional cases in which clearing not necessary */
+@@ -4175,6 +4167,8 @@ public_cALLOc(size_t n, size_t elem_size)
+ }
+ #ifndef _LIBC
++/* XXX These functions are not patched to detect arena corruption because they
++   are not built in glibc.  */
+ Void_t**
+ public_iCALLOc(size_t n, size_t elem_size, Void_t** chunks)
+@@ -4309,6 +4303,16 @@ _int_malloc(mstate av, size_t bytes)
+   checked_request2size(bytes, nb);
++  /* There are no usable arenas.  Fall back to sysmalloc to get a chunk from
++     mmap.  */
++  if (__glibc_unlikely (av == NULL))
++    {
++      void *p = sYSMALLOc (nb, av);
++      if (p != NULL)
++      alloc_perturb (p, bytes);
++      return p;
++    }
++
+   /*
+     If the size qualifies as a fastbin, first check corresponding bin.
+     This code is safe to execute even if av is not yet initialized, so we
+@@ -4337,7 +4341,7 @@ _int_malloc(mstate av, size_t bytes)
+         errstr = "malloc(): memory corruption (fast)";
+       errout:
+         mutex_unlock(&av->mutex);
+-        malloc_printerr (check_action, errstr, chunk2mem (victim));
++        malloc_printerr (check_action, errstr, chunk2mem (victim), av);
+         mutex_lock(&av->mutex);
+         return NULL;
+       }
+@@ -4429,7 +4433,7 @@ _int_malloc(mstate av, size_t bytes)
+       {
+         void *p = chunk2mem(victim);
+         mutex_unlock(&av->mutex);
+-        malloc_printerr (check_action, "malloc(): memory corruption", p);
++        malloc_printerr (check_action, "malloc(): memory corruption", p, av);
+         mutex_lock(&av->mutex);
+       }
+       size = chunksize(victim);
+@@ -4829,7 +4833,7 @@ _int_free(mstate av, mchunkptr p)
+       if (have_lock || locked)
+       (void)mutex_unlock(&av->mutex);
+ #endif
+-      malloc_printerr (check_action, errstr, chunk2mem(p));
++      malloc_printerr (check_action, errstr, chunk2mem(p), av);
+ #ifdef ATOMIC_FASTBINS
+       if (have_lock)
+       mutex_lock(&av->mutex);
+@@ -5281,7 +5285,7 @@ _int_realloc(mstate av, mchunkptr oldp, INTERNAL_SIZE_T oldsize,
+       errstr = "realloc(): invalid old size";
+     errout:
+       mutex_unlock(&av->mutex);
+-      malloc_printerr (check_action, errstr, chunk2mem(oldp));
++      malloc_printerr (check_action, errstr, chunk2mem(oldp), av);
+       mutex_lock(&av->mutex);
+       return NULL;
+     }
+@@ -5881,6 +5885,10 @@ static int mTRIm(mstate av, size_t pad)
+ static int mTRIm(av, pad) mstate av; size_t pad;
+ #endif
+ {
++  /* Don't touch corrupt arenas.  */
++  if (arena_is_corrupt (av))
++    return 0;
++
+   /* Ensure initialization/consolidation */
+   malloc_consolidate (av);
+@@ -6320,8 +6328,14 @@ int mALLOPt(param_number, value) int param_number; int value;
+ extern char **__libc_argv attribute_hidden;
+ static void
+-malloc_printerr(int action, const char *str, void *ptr)
++malloc_printerr(int action, const char *str, void *ptr, mstate ar_ptr)
+ {
++  /* Avoid using this arena in future.  We do not attempt to synchronize this
++     with anything else because we minimally want to ensure that __libc_message
++     gets its resources safely without stumbling on the current corruption.  */
++  if (ar_ptr)
++    set_arena_corrupt (ar_ptr);
++
+   if ((action & 5) == 5)
+     __libc_message (action & 2, "%s\n", str);
+   else if (action & 1)
+diff --git a/malloc/tst-malloc-backtrace.c b/malloc/tst-malloc-backtrace.c
+new file mode 100644
+index 0000000..796a42f
+--- /dev/null
++++ b/malloc/tst-malloc-backtrace.c
+@@ -0,0 +1,50 @@
++/* Verify that backtrace does not deadlock on itself on memory corruption.
++   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
++   <http://www.gnu.org/licenses/>.  */
++
++
++#include <stdlib.h>
++
++#define SIZE 4096
++
++/* Wrap free with a function to prevent gcc from optimizing it out.  */
++static void
++__attribute__((noinline))
++call_free (void *ptr)
++{
++  free (ptr);
++  *(size_t *)(ptr - sizeof (size_t)) = 1;
++}
++
++int
++do_test (void)
++{
++  void *ptr1 = malloc (SIZE);
++  void *ptr2 = malloc (SIZE);
++
++  call_free ((void *) ptr1);
++  ptr1 = malloc (SIZE);
++
++  /* Not reached.  The return statement is to put ptr2 into use so that gcc
++     doesn't optimize out that malloc call.  */
++  return (ptr1 == ptr2);
++}
++
++#define TEST_FUNCTION do_test ()
++#define EXPECTED_SIGNAL SIGABRT
++
++#include "../test-skeleton.c"
diff --git a/src/patches/glibc/glibc-rh1074342.patch b/src/patches/glibc/glibc-rh1074342.patch
new file mode 100644 (file)
index 0000000..121127e
--- /dev/null
@@ -0,0 +1,26 @@
+commit c44496df2f090a56d3bf75df930592dac6bba46f
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date:   Wed Mar 12 17:27:22 2014 +0530
+
+    Provide correct buffer length to netgroup queries in nscd (BZ #16695)
+    
+    The buffer to query netgroup entries is allocated sufficient space for
+    the netgroup entries and the key to be appended at the end, but it
+    sends in an incorrect available length to the NSS netgroup query
+    functions, resulting in overflow of the buffer in some special cases.
+    The fix here is to factor in the key length when sending the available
+    buffer and buffer length to the query functions.
+
+diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c
+index 426d3c5..5ba1e1f 100644
+--- a/nscd/netgroupcache.c
++++ b/nscd/netgroupcache.c
+@@ -202,7 +202,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
+                 {
+                   int e;
+                   status = getfct.f (&data, buffer + buffilled,
+-                                     buflen - buffilled, &e);
++                                     buflen - buffilled - req->key_len, &e);
+                   if (status == NSS_STATUS_RETURN
+                       || status == NSS_STATUS_NOTFOUND)
+                     /* This was either the last one for this group or the
diff --git a/src/patches/glibc/glibc-rh1074353.patch b/src/patches/glibc/glibc-rh1074353.patch
new file mode 100644 (file)
index 0000000..c8aa8b0
--- /dev/null
@@ -0,0 +1,398 @@
+commit bc8f194c8c29e46e8ee4034f06e46988dfff38f7
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date:   Wed Apr 30 12:00:39 2014 +0530
+
+    Initialize all of datahead structure in nscd (BZ #16791)
+    
+    The datahead structure has an unused padding field that remains
+    uninitialized.  Valgrind prints out a warning for it on querying a
+    netgroups entry.  This is harmless, but is a potential data leak since
+    it would result in writing out an uninitialized byte to the cache
+    file.  Besides, this happens only when there is a cache miss, so we're
+    not adding computation to any fast path.
+
+commit 1cdeb2372ddecac0dfe0c132a033e9590ffa07d2
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date:   Wed Apr 30 11:57:09 2014 +0530
+
+    Consolidate code to initialize nscd dataset header
+    
+    This patch consolidates the code to initialize the header of a dataset
+    into a single set of functions (one for positive and another for
+    negative datasets) primarily to reduce repetition of code.  The
+    secondary reason is to simplify Patch 2/2 which fixes the problem of
+    an uninitialized byte in the header by initializing an unused field in
+    the structure and hence preventing a possible data leak into the cache
+    file.
+
+diff --git a/nscd/aicache.c b/nscd/aicache.c
+index 98d40a1..d7966bd 100644
+--- a/nscd/aicache.c
++++ b/nscd/aicache.c
+@@ -383,17 +383,12 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
+         cp = family;
+       }
+-      /* Fill in the rest of the dataset.  */
+-      dataset->head.allocsize = total + req->key_len;
+-      dataset->head.recsize = total - offsetof (struct dataset, resp);
+-      dataset->head.notfound = false;
+-      dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
+-      dataset->head.usable = true;
+-
+-      /* Compute the timeout time.  */
+-      dataset->head.ttl = ttl == INT32_MAX ? db->postimeout : ttl;
+-      timeout = dataset->head.timeout = time (NULL) + dataset->head.ttl;
++      timeout = datahead_init_pos (&dataset->head, total + req->key_len,
++                                 total - offsetof (struct dataset, resp),
++                                 he == NULL ? 0 : dh->nreloads + 1,
++                                 ttl == INT32_MAX ? db->postimeout : ttl);
++      /* Fill in the rest of the dataset.  */
+       dataset->resp.version = NSCD_VERSION;
+       dataset->resp.found = 1;
+       dataset->resp.naddrs = naddrs;
+@@ -528,15 +523,9 @@ next_nip:
+       else if ((dataset = mempool_alloc (db, (sizeof (struct dataset)
+                                             + req->key_len), 1)) != NULL)
+       {
+-        dataset->head.allocsize = sizeof (struct dataset) + req->key_len;
+-        dataset->head.recsize = total;
+-        dataset->head.notfound = true;
+-        dataset->head.nreloads = 0;
+-        dataset->head.usable = true;
+-
+-        /* Compute the timeout time.  */
+-        timeout = dataset->head.timeout = time (NULL) + db->negtimeout;
+-        dataset->head.ttl = db->negtimeout;
++        timeout = datahead_init_neg (&dataset->head,
++                                     sizeof (struct dataset) + req->key_len,
++                                     total, db->negtimeout);
+         /* This is the reply.  */
+         memcpy (&dataset->resp, &notfound, total);
+diff --git a/nscd/grpcache.c b/nscd/grpcache.c
+index b5a33eb..df59fa7 100644
+--- a/nscd/grpcache.c
++++ b/nscd/grpcache.c
+@@ -128,14 +128,10 @@ cache_addgr (struct database_dyn *db, int fd, request_header *req,
+           }
+         else if ((dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len, 1)) != NULL)
+           {
+-            dataset->head.allocsize = sizeof (struct dataset) + req->key_len;
+-            dataset->head.recsize = total;
+-            dataset->head.notfound = true;
+-            dataset->head.nreloads = 0;
+-            dataset->head.usable = true;
+-
+-            /* Compute the timeout time.  */
+-            timeout = dataset->head.timeout = t + db->negtimeout;
++            timeout = datahead_init_neg (&dataset->head,
++                                         (sizeof (struct dataset)
++                                          + req->key_len), total,
++                                         db->negtimeout);
+             /* This is the reply.  */
+             memcpy (&dataset->resp, &notfound, total);
+@@ -232,14 +228,10 @@ cache_addgr (struct database_dyn *db, int fd, request_header *req,
+         dataset_temporary = true; 
+       }
+-      dataset->head.allocsize = total + n;
+-      dataset->head.recsize = total - offsetof (struct dataset, resp);
+-      dataset->head.notfound = false;
+-      dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
+-      dataset->head.usable = true;
+-
+-      /* Compute the timeout time.  */
+-      timeout = dataset->head.timeout = t + db->postimeout;
++      timeout = datahead_init_pos (&dataset->head, total + n,
++                                 total - offsetof (struct dataset, resp),
++                                 he == NULL ? 0 : dh->nreloads + 1,
++                                 db->postimeout);
+       dataset->resp.version = NSCD_VERSION;
+       dataset->resp.found = 1;
+diff --git a/nscd/hstcache.c b/nscd/hstcache.c
+index a79b67a..d4f1ad2 100644
+--- a/nscd/hstcache.c
++++ b/nscd/hstcache.c
+@@ -152,15 +152,11 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req,
+         else if ((dataset = mempool_alloc (db, (sizeof (struct dataset)
+                                                 + req->key_len), 1)) != NULL)
+           {
+-            dataset->head.allocsize = sizeof (struct dataset) + req->key_len;
+-            dataset->head.recsize = total;
+-            dataset->head.notfound = true;
+-            dataset->head.nreloads = 0;
+-            dataset->head.usable = true;
+-
+-            /* Compute the timeout time.  */
+-            dataset->head.ttl = ttl == INT32_MAX ? db->negtimeout : ttl;
+-            timeout = dataset->head.timeout = t + dataset->head.ttl;
++            timeout = datahead_init_neg (&dataset->head,
++                                         (sizeof (struct dataset)
++                                          + req->key_len), total,
++                                         (ttl == INT32_MAX
++                                          ? db->negtimeout : ttl));
+             /* This is the reply.  */
+             memcpy (&dataset->resp, resp, total);
+@@ -257,15 +253,10 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req,
+         alloca_used = true;
+       }
+-      dataset->head.allocsize = total + req->key_len;
+-      dataset->head.recsize = total - offsetof (struct dataset, resp);
+-      dataset->head.notfound = false;
+-      dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
+-      dataset->head.usable = true;
+-
+-      /* Compute the timeout time.  */
+-      dataset->head.ttl = ttl == INT32_MAX ? db->postimeout : ttl;
+-      timeout = dataset->head.timeout = t + dataset->head.ttl;
++      timeout = datahead_init_pos (&dataset->head, total + req->key_len,
++                                 total - offsetof (struct dataset, resp),
++                                 he == NULL ? 0 : dh->nreloads + 1,
++                                 ttl == INT32_MAX ? db->postimeout : ttl);
+       dataset->resp.version = NSCD_VERSION;
+       dataset->resp.found = 1;
+diff --git a/nscd/initgrcache.c b/nscd/initgrcache.c
+index 1bf9f0d..361319f 100644
+--- a/nscd/initgrcache.c
++++ b/nscd/initgrcache.c
+@@ -213,14 +213,10 @@ addinitgroupsX (struct database_dyn *db, int fd, request_header *req,
+         else if ((dataset = mempool_alloc (db, (sizeof (struct dataset)
+                                                 + req->key_len), 1)) != NULL)
+           {
+-            dataset->head.allocsize = sizeof (struct dataset) + req->key_len;
+-            dataset->head.recsize = total;
+-            dataset->head.notfound = true;
+-            dataset->head.nreloads = 0;
+-            dataset->head.usable = true;
+-
+-            /* Compute the timeout time.  */
+-            timeout = dataset->head.timeout = time (NULL) + db->negtimeout;
++            timeout = datahead_init_neg (&dataset->head,
++                                         (sizeof (struct dataset)
++                                          + req->key_len), total,
++                                         db->negtimeout);
+             /* This is the reply.  */
+             memcpy (&dataset->resp, &notfound, total);
+@@ -276,14 +272,10 @@ addinitgroupsX (struct database_dyn *db, int fd, request_header *req,
+         alloca_used = true;
+       }
+-      dataset->head.allocsize = total + req->key_len;
+-      dataset->head.recsize = total - offsetof (struct dataset, resp);
+-      dataset->head.notfound = false;
+-      dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
+-      dataset->head.usable = true;
+-
+-      /* Compute the timeout time.  */
+-      timeout = dataset->head.timeout = time (NULL) + db->postimeout;
++      timeout = datahead_init_pos (&dataset->head, total + req->key_len,
++                                 total - offsetof (struct dataset, resp),
++                                 he == NULL ? 0 : dh->nreloads + 1,
++                                 db->postimeout);
+       dataset->resp.version = NSCD_VERSION;
+       dataset->resp.found = 1;
+diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c
+index 820d823..b3d40e9 100644
+--- a/nscd/netgroupcache.c
++++ b/nscd/netgroupcache.c
+@@ -90,15 +90,9 @@ do_notfound (struct database_dyn *db, int fd, request_header *req,
+   /* If we cannot permanently store the result, so be it.  */
+   if (dataset != NULL)
+     {
+-      dataset->head.allocsize = sizeof (struct dataset) + req->key_len;
+-      dataset->head.recsize = total;
+-      dataset->head.notfound = true;
+-      dataset->head.nreloads = 0;
+-      dataset->head.usable = true;
+-
+-      /* Compute the timeout time.  */
+-      timeout = dataset->head.timeout = time (NULL) + db->negtimeout;
+-      dataset->head.ttl = db->negtimeout;
++      timeout = datahead_init_neg (&dataset->head,
++                                 sizeof (struct dataset) + req->key_len,
++                                 total, db->negtimeout);
+       /* This is the reply.  */
+       memcpy (&dataset->resp, &notfound, total);
+@@ -359,13 +353,10 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
+   /* Fill in the dataset.  */
+   dataset = (struct dataset *) buffer;
+-  dataset->head.allocsize = total + req->key_len;
+-  dataset->head.recsize = total - offsetof (struct dataset, resp);
+-  dataset->head.notfound = false;
+-  dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
+-  dataset->head.usable = true;
+-  dataset->head.ttl = db->postimeout;
+-  timeout = dataset->head.timeout = time (NULL) + dataset->head.ttl;
++  timeout = datahead_init_pos (&dataset->head, total + req->key_len,
++                             total - offsetof (struct dataset, resp),
++                             he == NULL ? 0 : dh->nreloads + 1,
++                             db->postimeout);
+   dataset->resp.version = NSCD_VERSION;
+   dataset->resp.found = 1;
+@@ -541,12 +532,12 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
+       dataset = &dataset_mem;
+     }
+-  dataset->head.allocsize = sizeof (*dataset) + req->key_len;
+-  dataset->head.recsize = sizeof (innetgroup_response_header);
++  datahead_init_pos (&dataset->head, sizeof (*dataset) + req->key_len,
++                   sizeof (innetgroup_response_header),
++                   he == NULL ? 0 : dh->nreloads + 1, result->head.ttl);
++  /* Set the notfound status and timeout based on the result from
++     getnetgrent.  */
+   dataset->head.notfound = result->head.notfound;
+-  dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
+-  dataset->head.usable = true;
+-  dataset->head.ttl = result->head.ttl;
+   dataset->head.timeout = timeout;
+   dataset->resp.version = NSCD_VERSION;
+diff --git a/nscd/nscd-client.h b/nscd/nscd-client.h
+index 98f77e7..ee16df6 100644
+--- a/nscd/nscd-client.h
++++ b/nscd/nscd-client.h
+@@ -236,6 +236,48 @@ struct datahead
+   } data[0];
+ };
++static inline time_t
++datahead_init_common (struct datahead *head, nscd_ssize_t allocsize,
++                    nscd_ssize_t recsize, uint32_t ttl)
++{
++  /* Initialize so that we don't write out junk in uninitialized data to the
++     cache.  */
++  memset (head, 0, sizeof (*head));
++
++  head->allocsize = allocsize;
++  head->recsize = recsize;
++  head->usable = true;
++
++  head->ttl = ttl;
++
++  /* Compute and return the timeout time.  */
++  return head->timeout = time (NULL) + ttl;
++}
++
++static inline time_t
++datahead_init_pos (struct datahead *head, nscd_ssize_t allocsize,
++                 nscd_ssize_t recsize, uint8_t nreloads, uint32_t ttl)
++{
++  time_t ret = datahead_init_common (head, allocsize, recsize, ttl);
++
++  head->notfound = false;
++  head->nreloads = nreloads;
++
++  return ret;
++}
++
++static inline time_t
++datahead_init_neg (struct datahead *head, nscd_ssize_t allocsize,
++                 nscd_ssize_t recsize, uint32_t ttl)
++{
++  time_t ret = datahead_init_common (head, allocsize, recsize, ttl);
++
++  /* We don't need to touch nreloads here since it is set to our desired value
++     (0) when we clear the structure.  */
++  head->notfound = true;
++
++  return ret;
++}
+ /* Structure for one hash table entry.  */
+ struct hashentry
+diff --git a/nscd/pwdcache.c b/nscd/pwdcache.c
+index fa355c3..41c245b 100644
+--- a/nscd/pwdcache.c
++++ b/nscd/pwdcache.c
+@@ -135,14 +135,10 @@ cache_addpw (struct database_dyn *db, int fd, request_header *req,
+         else if ((dataset = mempool_alloc (db, (sizeof (struct dataset)
+                                                 + req->key_len), 1)) != NULL)
+           {
+-            dataset->head.allocsize = sizeof (struct dataset) + req->key_len;
+-            dataset->head.recsize = total;
+-            dataset->head.notfound = true;
+-            dataset->head.nreloads = 0;
+-            dataset->head.usable = true;
+-
+-            /* Compute the timeout time.  */
+-            timeout = dataset->head.timeout = t + db->negtimeout;
++            timeout = datahead_init_neg (&dataset->head,
++                                         (sizeof (struct dataset)
++                                          + req->key_len), total,
++                                         db->negtimeout);
+             /* This is the reply.  */
+             memcpy (&dataset->resp, &notfound, total);
+@@ -215,14 +211,10 @@ cache_addpw (struct database_dyn *db, int fd, request_header *req,
+         alloca_used = true;
+       }
+-      dataset->head.allocsize = total + n;
+-      dataset->head.recsize = total - offsetof (struct dataset, resp);
+-      dataset->head.notfound = false;
+-      dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
+-      dataset->head.usable = true;
+-
+-      /* Compute the timeout time.  */
+-      timeout = dataset->head.timeout = t + db->postimeout;
++      timeout = datahead_init_pos (&dataset->head, total + n,
++                                 total - offsetof (struct dataset, resp),
++                                 he == NULL ? 0 : dh->nreloads + 1,
++                                 db->postimeout);
+       dataset->resp.version = NSCD_VERSION;
+       dataset->resp.found = 1;
+diff --git a/nscd/servicescache.c b/nscd/servicescache.c
+index 12ce9b2..95bdcfe 100644
+--- a/nscd/servicescache.c
++++ b/nscd/servicescache.c
+@@ -120,14 +120,10 @@ cache_addserv (struct database_dyn *db, int fd, request_header *req,
+         else if ((dataset = mempool_alloc (db, (sizeof (struct dataset)
+                                                 + req->key_len), 1)) != NULL)
+           {
+-            dataset->head.allocsize = sizeof (struct dataset) + req->key_len;
+-            dataset->head.recsize = total;
+-            dataset->head.notfound = true;
+-            dataset->head.nreloads = 0;
+-            dataset->head.usable = true;
+-
+-            /* Compute the timeout time.  */
+-            timeout = dataset->head.timeout = t + db->negtimeout;
++            timeout = datahead_init_neg (&dataset->head,
++                                         (sizeof (struct dataset)
++                                          + req->key_len), total,
++                                         db->negtimeout);
+             /* This is the reply.  */
+             memcpy (&dataset->resp, &notfound, total);
+@@ -207,14 +203,10 @@ cache_addserv (struct database_dyn *db, int fd, request_header *req,
+         alloca_used = true;
+       }
+-      dataset->head.allocsize = total + req->key_len;
+-      dataset->head.recsize = total - offsetof (struct dataset, resp);
+-      dataset->head.notfound = false;
+-      dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
+-      dataset->head.usable = true;
+-
+-      /* Compute the timeout time.  */
+-      timeout = dataset->head.timeout = t + db->postimeout;
++      timeout = datahead_init_pos (&dataset->head, total + req->key_len,
++                                 total - offsetof (struct dataset, resp),
++                                 he == NULL ? 0 : dh->nreloads + 1,
++                                 db->postimeout);
+       dataset->resp.version = NSCD_VERSION;
+       dataset->resp.found = 1;
diff --git a/src/patches/glibc/glibc-rh1082379.patch b/src/patches/glibc/glibc-rh1082379.patch
new file mode 100644 (file)
index 0000000..60a0ece
--- /dev/null
@@ -0,0 +1,63 @@
+commit ea7d8b95e2fcb81f68b04ed7787a3dbda023991a
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date:   Thu Mar 27 19:48:15 2014 +0530
+
+    Avoid overlapping addresses to stpcpy calls in nscd (BZ #16760)
+    
+    Calls to stpcpy from nscd netgroups code will have overlapping source
+    and destination when all three values in the returned triplet are
+    non-NULL and in the expected (host,user,domain) order.  This is seen
+    in valgrind as:
+    
+    ==3181== Source and destination overlap in stpcpy(0x19973b48, 0x19973b48)
+    ==3181==    at 0x4C2F30A: stpcpy (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
+    ==3181==    by 0x12567A: addgetnetgrentX (string3.h:111)
+    ==3181==    by 0x12722D: addgetnetgrent (netgroupcache.c:665)
+    ==3181==    by 0x11114C: nscd_run_worker (connections.c:1338)
+    ==3181==    by 0x4E3C102: start_thread (pthread_create.c:309)
+    ==3181==    by 0x59B81AC: clone (clone.S:111)
+    ==3181==
+    
+    Fix this by using memmove instead of stpcpy.
+
+diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c
+index 5d15aa4..820d823 100644
+--- a/nscd/netgroupcache.c
++++ b/nscd/netgroupcache.c
+@@ -216,6 +216,10 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
+                           const char *nuser = data.val.triple.user;
+                           const char *ndomain = data.val.triple.domain;
++                          size_t hostlen = strlen (nhost ?: "") + 1;
++                          size_t userlen = strlen (nuser ?: "") + 1;
++                          size_t domainlen = strlen (ndomain ?: "") + 1;
++
+                           if (nhost == NULL || nuser == NULL || ndomain == NULL
+                               || nhost > nuser || nuser > ndomain)
+                             {
+@@ -233,9 +237,6 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
+                                    : last + strlen (last) + 1 - buffer);
+                               /* We have to make temporary copies.  */
+-                              size_t hostlen = strlen (nhost ?: "") + 1;
+-                              size_t userlen = strlen (nuser ?: "") + 1;
+-                              size_t domainlen = strlen (ndomain ?: "") + 1;
+                               size_t needed = hostlen + userlen + domainlen;
+                               if (buflen - req->key_len - bufused < needed)
+@@ -269,9 +270,12 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
+                             }
+                           char *wp = buffer + buffilled;
+-                          wp = stpcpy (wp, nhost) + 1;
+-                          wp = stpcpy (wp, nuser) + 1;
+-                          wp = stpcpy (wp, ndomain) + 1;
++                          wp = memmove (wp, nhost ?: "", hostlen);
++                          wp += hostlen;
++                          wp = memmove (wp, nuser ?: "", userlen);
++                          wp += userlen;
++                          wp = memmove (wp, ndomain ?: "", domainlen);
++                          wp += domainlen;
+                           buffilled = wp - buffer;
+                           ++nentries;
+                         }
diff --git a/src/patches/glibc/glibc-rh1085273.patch b/src/patches/glibc/glibc-rh1085273.patch
new file mode 100644 (file)
index 0000000..ee0f289
--- /dev/null
@@ -0,0 +1,31 @@
+commit d41242129ba693cdbc8db85b846fcaccf9f0b7c4
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date:   Thu Jan 2 10:03:12 2014 +0530
+
+    Fix infinite loop in nscd when netgroup is empty (bz #16365)
+    
+    Currently, when a user looks up a netgroup that does not have any
+    members, nscd goes into an infinite loop trying to find members in the
+    group.  This is because it does not handle cases when getnetgrent
+    returns an NSS_STATUS_NOTFOUND (which is what it does on empty group).
+    Fixed to handle this in the same way as NSS_STATUS_RETURN, similar to
+    what getgrent does by itself.
+
+diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c
+index baebdd7..50936ee 100644
+--- a/nscd/netgroupcache.c
++++ b/nscd/netgroupcache.c
+@@ -180,9 +180,10 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
+                   int e;
+                   status = getfct.f (&data, buffer + buffilled,
+                                      buflen - buffilled, &e);
+-                  if (status == NSS_STATUS_RETURN)
+-                    /* This was the last one for this group.  Look
+-                       at next group if available.  */
++                  if (status == NSS_STATUS_RETURN
++                      || status == NSS_STATUS_NOTFOUND)
++                    /* This was either the last one for this group or the
++                       group was empty.  Look at next group if available.  */
+                     break;
+                   if (status == NSS_STATUS_SUCCESS)
+                     {
diff --git a/src/patches/glibc/glibc-rh1085289.patch b/src/patches/glibc/glibc-rh1085289.patch
new file mode 100644 (file)
index 0000000..9bd284e
--- /dev/null
@@ -0,0 +1,60 @@
+commit dd3022d75e6fb8957843d6d84257a5d8457822d5
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date:   Thu Mar 27 19:49:51 2014 +0530
+
+    Return NULL for wildcard values in getnetgrent from nscd (BZ #16759)
+    
+    getnetgrent is supposed to return NULL for values that are wildcards
+    in the (host, user, domain) triplet.  This works correctly with nscd
+    disabled, but with it enabled, it returns a blank ("") instead of a
+    NULL.  This is easily seen with the output of `getent netgroup foonet`
+    for a netgroup foonet defined as follows in /etc/netgroup:
+    
+        foonet (,foo,)
+    
+    The output with nscd disabled is:
+    
+        foonet ( ,foo,)
+    
+    while with nscd enabled, it is:
+    
+        foonet (,foo,)
+    
+    The extra space with nscd disabled is due to the fact that `getent
+    netgroup` adds it if the return value from getnetgrent is NULL for
+    either host or user.
+
+diff --git a/inet/getnetgrent_r.c b/inet/getnetgrent_r.c
+index 62cdfda..f6d064d 100644
+--- a/inet/getnetgrent_r.c
++++ b/inet/getnetgrent_r.c
+@@ -235,6 +235,14 @@ endnetgrent (void)
+ libc_hidden_proto (internal_getnetgrent_r)
++static const char *
++get_nonempty_val (const char *in)
++{
++  if (*in == '\0')
++    return NULL;
++  return in;
++}
++
+ static enum nss_status
+ nscd_getnetgrent (struct __netgrent *datap, char *buffer, size_t buflen,
+                 int *errnop)
+@@ -243,11 +251,11 @@ nscd_getnetgrent (struct __netgrent *datap, char *buffer, size_t buflen,
+     return NSS_STATUS_UNAVAIL;
+   datap->type = triple_val;
+-  datap->val.triple.host = datap->cursor;
++  datap->val.triple.host = get_nonempty_val (datap->cursor);
+   datap->cursor = (char *) __rawmemchr (datap->cursor, '\0') + 1;
+-  datap->val.triple.user = datap->cursor;
++  datap->val.triple.user = get_nonempty_val (datap->cursor);
+   datap->cursor = (char *) __rawmemchr (datap->cursor, '\0') + 1;
+-  datap->val.triple.domain = datap->cursor;
++  datap->val.triple.domain = get_nonempty_val (datap->cursor);
+   datap->cursor = (char *) __rawmemchr (datap->cursor, '\0') + 1;
+   return NSS_STATUS_SUCCESS;
diff --git a/src/patches/glibc/glibc-rh1085312.patch b/src/patches/glibc/glibc-rh1085312.patch
new file mode 100644 (file)
index 0000000..bafb303
--- /dev/null
@@ -0,0 +1,34 @@
+commit 58b930ae216bfa98cd60212b954b07b9963d6d04
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date:   Wed Sep 10 21:51:50 2014 +0530
+
+    Return failure in getnetgrent only when all netgroups have been searched (#17363)
+    
+    The netgroups lookup code fails when one of the groups in the search
+    tree is empty.  In such a case it only returns the leaves of the tree
+    after the blank netgroup.  This is because the line parser returns a
+    NOTFOUND status when the netgroup exists but is empty.  The
+    __getnetgrent_internal implementation needs to be fixed to try
+    remaining groups if the current group is entry.  This patch implements
+    this fix.  Tested on x86_64.
+    
+       [BZ #17363]
+       * inet/getnetgrent_r.c (__internal_getnetgrent_r): Try next
+       group if the current group is empty.
+
+diff --git a/inet/getnetgrent_r.c b/inet/getnetgrent_r.c
+index f6d064d..e101537 100644
+--- a/inet/getnetgrent_r.c
++++ b/inet/getnetgrent_r.c
+@@ -297,7 +297,10 @@ __internal_getnetgrent_r (char **hostp, char **userp, char **domainp,
+     {
+       status = (*fct) (datap, buffer, buflen, &errno);
+-      if (status == NSS_STATUS_RETURN)
++      if (status == NSS_STATUS_RETURN
++        /* The service returned a NOTFOUND, but there are more groups that we
++           need to resolve before we give up.  */
++        || (status == NSS_STATUS_NOTFOUND && datap->needed_groups != NULL))
+       {
+         /* This was the last one for this group.  Look at next group
+            if available.  */
diff --git a/src/patches/glibc/glibc-rh1087833.patch b/src/patches/glibc/glibc-rh1087833.patch
new file mode 100644 (file)
index 0000000..ca8f1f0
--- /dev/null
@@ -0,0 +1,65 @@
+commit c3ec475c5dd16499aa040908e11d382c3ded9692
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date:   Mon May 26 11:40:08 2014 +0530
+
+    Use NSS_STATUS_TRYAGAIN to indicate insufficient buffer (BZ #16878)
+    
+    The netgroups nss modules in the glibc tree use NSS_STATUS_UNAVAIL
+    (with errno as ERANGE) when the supplied buffer does not have
+    sufficient space for the result.  This is wrong, because the canonical
+    way to indicate insufficient buffer is to set the errno to ERANGE and
+    the status to NSS_STATUS_TRYAGAIN, as is used by all other modules.
+    
+    This fixes nscd behaviour when the nss_ldap module returns
+    NSS_STATUS_TRYAGAIN to indicate that a netgroup entry is too long to
+    fit into the supplied buffer.
+
+diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c
+index b3d40e9..edab174 100644
+--- a/nscd/netgroupcache.c
++++ b/nscd/netgroupcache.c
+@@ -197,11 +197,6 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
+                   int e;
+                   status = getfct.f (&data, buffer + buffilled,
+                                      buflen - buffilled - req->key_len, &e);
+-                  if (status == NSS_STATUS_RETURN
+-                      || status == NSS_STATUS_NOTFOUND)
+-                    /* This was either the last one for this group or the
+-                       group was empty.  Look at next group if available.  */
+-                    break;
+                   if (status == NSS_STATUS_SUCCESS)
+                     {
+                       if (data.type == triple_val)
+@@ -320,11 +315,18 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
+                             }
+                         }
+                     }
+-                  else if (status == NSS_STATUS_UNAVAIL && e == ERANGE)
++                  else if (status == NSS_STATUS_TRYAGAIN && e == ERANGE)
+                     {
+                       buflen *= 2;
+                       buffer = xrealloc (buffer, buflen);
+                     }
++                  else if (status == NSS_STATUS_RETURN
++                           || status == NSS_STATUS_NOTFOUND
++                           || status == NSS_STATUS_UNAVAIL)
++                    /* This was either the last one for this group or the
++                       group was empty or the NSS module had an internal
++                       failure.  Look at next group if available.  */
++                    break;
+                 }
+             enum nss_status (*endfct) (struct __netgrent *);
+diff --git a/nss/nss_files/files-netgrp.c b/nss/nss_files/files-netgrp.c
+index 34eae4c..bc0b367 100644
+--- a/nss/nss_files/files-netgrp.c
++++ b/nss/nss_files/files-netgrp.c
+@@ -252,7 +252,7 @@ _nss_netgroup_parseline (char **cursor, struct __netgrent *result,
+   if (cp - host > buflen)
+     {
+       *errnop = ERANGE;
+-      status = NSS_STATUS_UNAVAIL;
++      status = NSS_STATUS_TRYAGAIN;
+     }
+   else
+     {
diff --git a/src/patches/glibc/glibc-rh1088301.patch b/src/patches/glibc/glibc-rh1088301.patch
new file mode 100644 (file)
index 0000000..d26eb14
--- /dev/null
@@ -0,0 +1,142 @@
+diff --git a/resolv/arpa/nameser.h b/resolv/arpa/nameser.h
+index fb8513b..372d5cd 100644
+--- a/resolv/arpa/nameser.h
++++ b/resolv/arpa/nameser.h
+@@ -293,6 +293,9 @@ typedef enum __ns_type {
+       ns_t_sink = 40,         /*%< Kitchen sink (experimentatl) */
+       ns_t_opt = 41,          /*%< EDNS0 option (meta-RR) */
+       ns_t_apl = 42,          /*%< Address prefix list (RFC3123) */
++      ns_t_rrsig = 46,        /*%< DNSSEC RRset Signature (RFC4034) */
++      ns_t_nsec = 47,         /*%< DNSSEC Next-Secure Record (RFC4034)*/
++      ns_t_dnskey = 48,       /*%< DNSSEC key record (RFC4034) */
+       ns_t_tkey = 249,        /*%< Transaction key */
+       ns_t_tsig = 250,        /*%< Transaction signature. */
+       ns_t_ixfr = 251,        /*%< Incremental zone transfer. */
+diff --git a/resolv/arpa/nameser_compat.h b/resolv/arpa/nameser_compat.h
+index d59c9e4..284bff7 100644
+--- a/resolv/arpa/nameser_compat.h
++++ b/resolv/arpa/nameser_compat.h
+@@ -164,6 +164,9 @@ typedef struct {
+ #define T_NAPTR               ns_t_naptr
+ #define T_A6          ns_t_a6
+ #define T_DNAME               ns_t_dname
++#define T_RRSIG               ns_t_rrsig
++#define T_NSEC                ns_t_nsec
++#define T_DNSKEY      ns_t_dnskey
+ #define       T_TSIG          ns_t_tsig
+ #define       T_IXFR          ns_t_ixfr
+ #define T_AXFR                ns_t_axfr
+diff --git a/resolv/gethnamaddr.c b/resolv/gethnamaddr.c
+index a861a84..ae55fac 100644
+--- a/resolv/gethnamaddr.c
++++ b/resolv/gethnamaddr.c
+@@ -331,23 +331,36 @@ getanswer (const querybuf *answer, int anslen, const char *qname, int qtype)
+                       buflen -= n;
+                       continue;
+               }
+-              if ((type == T_SIG) || (type == T_KEY) || (type == T_NXT)) {
+-                      /* We don't support DNSSEC yet.  For now, ignore
+-                       * the record and send a low priority message
+-                       * to syslog.
+-                       */
+-                      syslog(LOG_DEBUG|LOG_AUTH,
++              if ((type == T_SIG) || (type == T_KEY) || (type == T_NXT)
++                  || (type == T_RRSIG) || (type == T_NSEC)
++                  || (type == T_DNSKEY)) {
++                      /* We don't support DNSSEC responses yet, but we do
++                       * allow setting the DO bit.  If the DNS server sent us
++                       * these records without us asking for it, ignore the
++                       * record and send a low priority message to syslog.
++                       */
++                      if ((_res.options & RES_USE_DNSSEC) == 0) {
++                              syslog(LOG_DEBUG|LOG_AUTH,
+              "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
+-                             qname, p_class(C_IN), p_type(qtype),
+-                             p_type(type));
++                                      qname, p_class(C_IN), p_type(qtype),
++                                      p_type(type));
++                      }
+                       cp += n;
+                       continue;
+               }
+               if (type != qtype) {
+-                      syslog(LOG_NOTICE|LOG_AUTH,
++                      /* Skip logging if we received a DNAME when we have set
++                       * the DO bit.  DNAME records are a convenient way to
++                       * set up DNSSEC records and such setups can make this
++                       * log message needlessly noisy.
++                       */
++                      if (!((_res.options & RES_USE_DNSSEC)
++                            && type == T_DNAME)) {
++                              syslog(LOG_NOTICE|LOG_AUTH,
+              "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
+-                             qname, p_class(C_IN), p_type(qtype),
+-                             p_type(type));
++                                      qname, p_class(C_IN), p_type(qtype),
++                                      p_type(type));
++                      }
+                       cp += n;
+                       continue;               /* XXX - had_error++ ? */
+               }
+diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c
+index f715ab0..510d388 100644
+--- a/resolv/nss_dns/dns-host.c
++++ b/resolv/nss_dns/dns-host.c
+@@ -822,13 +822,20 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
+       }
+       if (__builtin_expect (type == T_SIG, 0)
+         || __builtin_expect (type == T_KEY, 0)
+-        || __builtin_expect (type == T_NXT, 0))
++        || __builtin_expect (type == T_NXT, 0)
++        || __builtin_expect (type == T_RRSIG, 0)
++        || __builtin_expect (type == T_NSEC, 0)
++        || __builtin_expect (type == T_DNSKEY, 0))
+       {
+-        /* We don't support DNSSEC yet.  For now, ignore the record
+-           and send a low priority message to syslog.  */
+-        syslog (LOG_DEBUG | LOG_AUTH,
+-             "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
+-                qname, p_class (C_IN), p_type(qtype), p_type (type));
++        /* We don't support DNSSEC responses yet, but we do allow setting the
++           DO bit.  If the DNS server sent us these records without us asking
++           for it, ignore the record and send a low priority message to
++           syslog.  */
++        if ((_res.options & RES_USE_DNSSEC) == 0)
++          syslog (LOG_DEBUG | LOG_AUTH,
++                  "gethostby*.getanswer: asked for \"%s %s %s\", "
++                  "got type \"%s\"",
++                  qname, p_class (C_IN), p_type(qtype), p_type (type));
+         cp += n;
+         continue;
+       }
+@@ -837,9 +844,14 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
+       have_to_map = 1;
+       else if (__builtin_expect (type != qtype, 0))
+       {
+-        syslog (LOG_NOTICE | LOG_AUTH,
+-             "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
+-                qname, p_class (C_IN), p_type (qtype), p_type (type));
++        /* Skip logging if we received a DNAME when we have set the DO bit.
++           DNAME records are a convenient way to set up DNSSEC records and
++           such setups can make this log message needlessly noisy.  */
++        if (!((_res.options & RES_USE_DNSSEC) && type == T_DNAME))
++          syslog (LOG_NOTICE | LOG_AUTH,
++                  "gethostby*.getanswer: asked for \"%s %s %s\", "
++                  "got type \"%s\"",
++                  qname, p_class (C_IN), p_type (qtype), p_type (type));
+         cp += n;
+         continue;                     /* XXX - had_error++ ? */
+       }
+diff --git a/resolv/res_debug.c b/resolv/res_debug.c
+index 7843439..4a49629 100644
+--- a/resolv/res_debug.c
++++ b/resolv/res_debug.c
+@@ -450,6 +450,8 @@ const struct res_sym __p_type_syms[] = {
+       {ns_t_kx,       "KX",           "Key Exchange"},
+       {ns_t_cert,     "CERT",         "Certificate"},
+       {ns_t_any,      "ANY",          "\"any\""},
++      /* TODO Add RRSIG, NSEC and DNSKEY once we actually do something with
++         them.  */
+       {0,             NULL,           NULL}
+ };
+ libresolv_hidden_data_def (__p_type_syms)
diff --git a/src/patches/glibc/glibc-rh1091915.patch b/src/patches/glibc/glibc-rh1091915.patch
new file mode 100644 (file)
index 0000000..d1af874
--- /dev/null
@@ -0,0 +1,40 @@
+commit 3cb26316b45b23dc5cfecbafdc489b28c3a52029
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date:   Thu Jan 29 10:30:09 2015 +0530
+
+    Initialize nscd stats data [BZ #17892]
+    
+    The padding bytes in the statsdata struct are not initialized, due to
+    which valgrind throws a warning:
+    
+    ==11384== Memcheck, a memory error detector
+    ==11384== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
+    ==11384== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
+    ==11384== Command: nscd -d
+    ==11384==
+    Fri 25 Apr 2014 10:34:53 AM CEST - 11384: handle_request: request received (Version = 2) from PID 11396
+    Fri 25 Apr 2014 10:34:53 AM CEST - 11384:       GETSTAT
+    ==11384== Thread 6:
+    ==11384== Syscall param socketcall.sendto(msg) points to uninitialised byte(s)
+    ==11384==    at 0x4E4ACDC: send (in /lib64/libpthread-2.12.so)
+    ==11384==    by 0x11AF6B: send_stats (in /usr/sbin/nscd)
+    ==11384==    by 0x112F75: nscd_run_worker (in /usr/sbin/nscd)
+    ==11384==    by 0x4E439D0: start_thread (in /lib64/libpthread-2.12.so)
+    ==11384==    by 0x599AB6C: clone (in /lib64/libc-2.12.so)
+    ==11384==  Address 0x15708395 is on thread 6's stack
+    
+    Fix the warning by initializing the structure.
+
+diff --git a/nscd/nscd_stat.c b/nscd/nscd_stat.c
+index 0f1f3c0..7aaa21b 100644
+--- a/nscd/nscd_stat.c
++++ b/nscd/nscd_stat.c
+@@ -94,6 +94,8 @@ send_stats (int fd, struct database_dyn dbs[lastdb])
+   struct statdata data;
+   int cnt;
++  memset (&data, 0, sizeof (data));
++
+   memcpy (data.version, compilation, sizeof (compilation));
+   data.debug_level = debug_level;
+   data.runtime = time (NULL) - start_time;
diff --git a/src/patches/glibc/glibc-rh1099025-2.patch b/src/patches/glibc/glibc-rh1099025-2.patch
new file mode 100644 (file)
index 0000000..58fe121
--- /dev/null
@@ -0,0 +1,159 @@
+commit d6c33fda03457ca8ca87a562fa2681af16ca4ea5
+Author: Roland McGrath <roland@hack.frob.com>
+Date:   Thu May 24 11:37:30 2012 -0700
+
+    Switch gettimeofday from INTUSE to libc_hidden_proto.
+
+diff --git a/include/sys/time.h b/include/sys/time.h
+index d5de942..599e189 100644
+--- a/include/sys/time.h
++++ b/include/sys/time.h
+@@ -4,9 +4,8 @@
+ /* Now document the internal interfaces.  */
+ extern int __gettimeofday (struct timeval *__tv,
+                          struct timezone *__tz);
+-extern int __gettimeofday_internal (struct timeval *__tv,
+-                                  struct timezone *__tz)
+-      attribute_hidden;
++libc_hidden_proto (__gettimeofday)
++libc_hidden_proto (gettimeofday)
+ extern int __settimeofday (__const struct timeval *__tv,
+                          __const struct timezone *__tz)
+       attribute_hidden;
+@@ -22,8 +21,4 @@ extern int __utimes (const char *__file, const struct timeval __tvp[2])
+       attribute_hidden;
+ extern int __futimes (int fd, __const struct timeval tvp[2]) attribute_hidden;
+-#ifndef NOT_IN_libc
+-# define __gettimeofday(tv, tz) INTUSE(__gettimeofday) (tv, tz)
+-#endif
+-
+ #endif
+diff --git a/sysdeps/mach/gettimeofday.c b/sysdeps/mach/gettimeofday.c
+index 88dca8e..293a775 100644
+--- a/sysdeps/mach/gettimeofday.c
++++ b/sysdeps/mach/gettimeofday.c
+@@ -20,8 +20,6 @@
+ #include <sys/time.h>
+ #include <mach.h>
+-#undef __gettimeofday
+-
+ /* Get the current time of day and timezone information,
+    putting it into *TV and *TZ.  If TZ is NULL, *TZ is not filled.
+    Returns 0 on success, -1 on errors.  */
+@@ -42,6 +40,6 @@ __gettimeofday (tv, tz)
+     }
+   return 0;
+ }
+-
+-INTDEF(__gettimeofday)
++libc_hidden_def (__gettimeofday)
+ weak_alias (__gettimeofday, gettimeofday)
++libc_hidden_weak (gettimeofday)
+diff --git a/sysdeps/posix/gettimeofday.c b/sysdeps/posix/gettimeofday.c
+index 31b3dd3..1108ff0 100644
+--- a/sysdeps/posix/gettimeofday.c
++++ b/sysdeps/posix/gettimeofday.c
+@@ -19,8 +19,6 @@
+ #include <time.h>
+ #include <sys/time.h>
+-#undef __gettimeofday
+-
+ /* Get the current time of day and timezone information,
+    putting it into *TV and *TZ.  If TZ is NULL, *TZ is not filled.
+    Returns 0 on success, -1 on errors.  */
+@@ -66,6 +64,6 @@ __gettimeofday (tv, tz)
+   return 0;
+ }
+-
+-INTDEF(__gettimeofday)
++libc_hidden_def (__gettimeofday)
+ weak_alias (__gettimeofday, gettimeofday)
++libc_hidden_weak (gettimeofday)
+diff --git a/sysdeps/unix/syscalls.list b/sysdeps/unix/syscalls.list
+index 39c40ed..bd780f5 100644
+--- a/sysdeps/unix/common/syscalls.list
++++ b/sysdeps/unix/common/syscalls.list
+@@ -5,7 +5,7 @@ getpid         -       getpid          Ei:     __getpid        getpid
+ fchown                -       fchown          i:iii   __fchown        fchown
+ ftruncate     -       ftruncate       i:ii    __ftruncate     ftruncate
+ getrusage     -       getrusage       i:ip    __getrusage     getrusage
+-gettimeofday  -       gettimeofday    i:PP    __gettimeofday  gettimeofday __gettimeofday_internal
++gettimeofday  -       gettimeofday    i:pP    __gettimeofday  gettimeofday
+ settimeofday  -       settimeofday    i:PP    __settimeofday  settimeofday
+ setpgid               -       setpgrp         i:ii    __setpgid       setpgid
+ setregid      -       setregid        i:ii    __setregid      setregid
+diff --git a/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c b/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c
+index b2ef2da..7376135 100644
+--- a/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c
++++ b/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c
+@@ -35,5 +35,6 @@ __gettimeofday (tv, tz)
+ }
+-
+-#endif
+-INTDEF (__gettimeofday)
++libc_hidden_def (__gettimeofday)
++
++#endif
+ weak_alias (__gettimeofday, gettimeofday)
++libc_hidden_weak (gettimeofday)
+diff --git a/sysdeps/unix/sysv/linux/s390/gettimeofday.c b/sysdeps/unix/sysv/linux/s390/gettimeofday.c
+index 63faef8..efbf1e8 100644
+--- a/sysdeps/unix/sysv/linux/s390/gettimeofday.c
++++ b/sysdeps/unix/sysv/linux/s390/gettimeofday.c
+@@ -22,7 +22,6 @@
+ #include <time.h>
+ #include <hp-timing.h>
+-#undef __gettimeofday
+ #include <bits/libc-vdso.h>
+ /* Get the current time of day and timezone information,
+@@ -36,6 +35,6 @@ __gettimeofday (tv, tz)
+ {
+   return INLINE_VSYSCALL (gettimeofday, 2, CHECK_1 (tv), CHECK_1 (tz));
+ }
+-
+-INTDEF (__gettimeofday)
++libc_hidden_def (__gettimeofday)
+ weak_alias (__gettimeofday, gettimeofday)
++libc_hidden_weak (gettimeofday)
+diff --git a/time/gettimeofday.c b/time/gettimeofday.c
+index cfe6549..7eb770c 100644
+--- a/time/gettimeofday.c
++++ b/time/gettimeofday.c
+@@ -18,8 +18,6 @@
+ #include <errno.h>
+ #include <sys/time.h>
+-#undef __gettimeofday
+-
+ /* Get the current time of day and timezone information,
+    putting it into *TV and *TZ.  If TZ is NULL, *TZ is not filled.
+    Returns 0 on success, -1 on errors.  */
+@@ -31,8 +29,9 @@ __gettimeofday (tv, tz)
+   __set_errno (ENOSYS);
+   return -1;
+ }
+-stub_warning (gettimeofday)
+-
+-INTDEF(__gettimeofday)
++libc_hidden_def (__gettimeofday)
+ weak_alias (__gettimeofday, gettimeofday)
++libc_hidden_weak (gettimeofday)
++
++stub_warning (gettimeofday)
+ #include <stub-tag.h>
+--- a/sysdeps/unix/sysv/linux/x86_64/gettimeofday.S    2014-07-28 14:40:24.640144825 +0530
++++ b/sysdeps/unix/sysv/linux/x86_64/gettimeofday.S    2014-07-28 14:40:21.320120072 +0530
+@@ -45,5 +45,6 @@
+       ret
+ PSEUDO_END(__gettimeofday)
+-strong_alias (__gettimeofday, __gettimeofday_internal)
++libc_hidden_def (__gettimeofday)
+ weak_alias (__gettimeofday, gettimeofday)
++libc_hidden_weak (gettimeofday)
diff --git a/src/patches/glibc/glibc-rh1099025.patch b/src/patches/glibc/glibc-rh1099025.patch
new file mode 100644 (file)
index 0000000..d075be8
--- /dev/null
@@ -0,0 +1,47 @@
+commit 736c304a1ab4cee36a2f3343f1698bc0abae4608
+Author: Adhemerval Zanella <azanella@linux.vnet.ibm.com>
+Date:   Thu Jan 16 06:53:18 2014 -0600
+
+    PowerPC: Fix ftime gettimeofday internal call returning bogus data
+    
+    This patches fixes BZ#16430 by setting a different symbol for internal
+    GLIBC calls that points to ifunc resolvers. For PPC32, if the symbol
+    is defined as hidden (which is the case for gettimeofday and time) the
+    compiler will create local branches (symbol@local) and linker will not
+    create PLT calls (required for IFUNC). This will leads to internal symbol
+    calling the IFUNC resolver instead of the resolved symbol.
+    For PPC64 this behavior does not occur because a call to a function in
+    another translation unit might use a different toc pointer thus requiring
+    a PLT call.
+
+diff --git a/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c b/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c
+index 29a5e08..2085b68 100644
+--- a/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c
++++ b/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c
+@@ -44,8 +44,24 @@ asm (".type __gettimeofday, %gnu_indirect_function");
+ /* This is doing "libc_hidden_def (__gettimeofday)" but the compiler won't
+    let us do it in C because it doesn't know we're defining __gettimeofday
+    here in this file.  */
+-asm (".globl __GI___gettimeofday\n"
+-     "__GI___gettimeofday = __gettimeofday");
++asm (".globl __GI___gettimeofday");
++
++/* __GI___gettimeofday is defined as hidden and for ppc32 it enables the
++   compiler make a local call (symbol@local) for internal GLIBC usage. It
++   means the PLT won't be used and the ifunc resolver will be called directly.
++   For ppc64 a call to a function in another translation unit might use a
++   different toc pointer thus disallowing direct branchess and making internal
++   ifuncs calls safe.  */
++#ifdef __powerpc64__
++asm ("__GI___gettimeofday = __gettimeofday");
++#else
++int
++__gettimeofday_vsyscall (struct timeval *tv, struct timezone *tz)
++{
++  return INLINE_VSYSCALL (gettimeofday, 2, tv, tz);
++}
++asm ("__GI___gettimeofday = __gettimeofday_vsyscall");
++#endif
+ #else
diff --git a/src/patches/glibc/glibc-rh1116050-1.patch b/src/patches/glibc/glibc-rh1116050-1.patch
new file mode 100644 (file)
index 0000000..439cf6d
--- /dev/null
@@ -0,0 +1,57 @@
+#
+# In rhel-6.x the Makerules are not entirely as mature as they are
+# in glibc 2.21 (from which the example link-libc-args is taken from).
+# In rhel-6.x the applications are not built like their counterpart
+# real applications, and because of that compiling DSOs that use TLS
+# will fail with undefined references to __tls_get_addr which resides
+# in ld.so and is never included in the link. This patch enhances
+# only the build-module and build-module-asneeded targets to include
+# a more fully and correct link line as the compiler driver would use
+# when constructing an application or DSO. We do not adjust the link
+# lines used to build lib* targets.
+#
+diff -urN glibc-2.12-2-gc4ccff1.orig/Makerules glibc-2.12-2-gc4ccff1/Makerules
+--- glibc-2.12-2-gc4ccff1.orig/Makerules       2015-02-18 19:53:00.000000000 -0500
++++ glibc-2.12-2-gc4ccff1/Makerules    2015-02-18 20:08:33.299000028 -0500
+@@ -443,6 +443,25 @@
+ load-map-file = $(map-file:%=-Wl,--version-script=%)
+ endif
++# Compiler arguments to use to link a shared object with libc and
++# ld.so.  This is intended to be as similar as possible to a default
++# link with an installed libc.
++link-libc-args = -Wl,--start-group \
++                 $(libc-for-link) \
++                 $(common-objpfx)libc_nonshared.a \
++                 $(as-needed) $(elf-objpfx)ld.so $(no-as-needed) \
++                 -Wl,--end-group
++
++# The corresponding shared libc to use.  This may be modified for a
++# particular target.
++libc-for-link = $(common-objpfx)libc.so
++
++# The corresponding dependencies.  As these are used in dependencies,
++# not just commands, they cannot use target-specific variables so need
++# to name both possible libc.so objects.
++link-libc-deps = $(common-objpfx)libc.so $(common-objpfx)linkobj/libc.so \
++                 $(common-objpfx)libc_nonshared.a $(elf-objpfx)ld.so
++
+ # Pattern rule to build a shared object from an archive of PIC objects.
+ # This must come after the installation rules so Make doesn't try to
+ # build shared libraries in place from the installed *_pic.a files.
+@@ -557,12 +576,13 @@
+ # not for shared objects
+ define build-module
+ $(build-module-helper) -o $@ -T $(common-objpfx)shlib.lds \
+-        $(csu-objpfx)abi-note.o $(build-module-objlist)
++        $(csu-objpfx)abi-note.o $(build-module-objlist) $(link-libc-args)
+ endef
+ define build-module-asneeded
+ $(build-module-helper) -o $@ -T $(common-objpfx)shlib.lds \
+         $(csu-objpfx)abi-note.o \
+-        -Wl,--as-needed $(build-module-objlist) -Wl,--no-as-needed
++        -Wl,--as-needed $(build-module-objlist) -Wl,--no-as-needed \
++        $(link-libc-args)
+ endef
+ else
+ ifneq (,$(findstring aix,$(config-os)))
diff --git a/src/patches/glibc/glibc-rh1116050.patch b/src/patches/glibc/glibc-rh1116050.patch
new file mode 100644 (file)
index 0000000..7631312
--- /dev/null
@@ -0,0 +1,407 @@
+#
+# Based on this upstream commit:
+#
+# commit d8dd00805b8f3a011735d7a407097fb1c408d867
+# Author: H.J. Lu <hjl.tools@gmail.com>
+# Date:   Fri Nov 28 07:54:07 2014 -0800
+# 
+#     Resize DTV if the current DTV isn't big enough
+#     
+#     This patch changes _dl_allocate_tls_init to resize DTV if the current DTV
+#     isn't big enough.  Tested on X86-64, x32 and ia32.
+#     
+#         [BZ #13862]
+#         * elf/dl-tls.c: Include <atomic.h>.
+#         (oom): Remove #ifdef SHARED/#endif.
+#         (_dl_static_dtv, _dl_initial_dtv): Moved before ...
+#         (_dl_resize_dtv): This.  Extracted from _dl_update_slotinfo.
+#         (_dl_allocate_tls_init): Resize DTV if the current DTV isn't
+#         big enough.
+#         (_dl_update_slotinfo): Call _dl_resize_dtv to resize DTV.
+#         * nptl/Makefile (tests): Add tst-stack4.
+#         (modules-names): Add tst-stack4mod.
+#         ($(objpfx)tst-stack4): New.
+#         (tst-stack4mod.sos): Likewise.
+#         ($(objpfx)tst-stack4.out): Likewise.
+#         ($(tst-stack4mod.sos)): Likewise.
+#         (clean): Likewise.
+#         * nptl/tst-stack4.c: New file.
+#         * nptl/tst-stack4mod.c: Likewise.
+# 
+diff -urN glibc-2.12-2-gc4ccff1/elf/dl-tls.c glibc-2.12-2-gc4ccff1.mod/elf/dl-tls.c
+--- glibc-2.12-2-gc4ccff1/elf/dl-tls.c 2015-02-18 14:15:28.078461873 -0500
++++ glibc-2.12-2-gc4ccff1.mod/elf/dl-tls.c     2015-02-18 14:38:37.630374771 -0500
+@@ -24,6 +24,7 @@
+ #include <stdlib.h>
+ #include <unistd.h>
+ #include <sys/param.h>
++#include <atomic.h>
+ #include <tls.h>
+ #include <dl-tls.h>
+@@ -35,14 +36,12 @@
+ /* Out-of-memory handler.  */
+-#ifdef SHARED
+ static void
+ __attribute__ ((__noreturn__))
+ oom (void)
+ {
+   _dl_fatal_printf ("cannot allocate memory for thread-local data: ABORT\n");
+ }
+-#endif
+ size_t
+@@ -392,6 +391,52 @@
+   return result;
+ }
++static dtv_t *
++_dl_resize_dtv (dtv_t *dtv)
++{
++  /* Resize the dtv.  */
++  dtv_t *newp;
++  /* Load GL(dl_tls_max_dtv_idx) atomically since it may be written to by
++     other threads concurrently. -- We don't have the required atomic
++     infrastructure to load dl_tls_max_dtv_idx atomically, but on all the
++     architectures we care about it should load atomically. If this had
++     an atomic_load_acquire we would still be missing the releases for
++     the writes.  */
++  size_t newsize = GL(dl_tls_max_dtv_idx) + DTV_SURPLUS;
++  size_t oldsize = dtv[-1].counter;
++
++#if SHARED
++  if (dtv == GL(dl_initial_dtv))
++    {
++      /* This is the initial dtv that was either statically allocated in
++       __libc_setup_tls or allocated during rtld startup using the
++       dl-minimal.c malloc instead of the real malloc.  We can't free
++       it, we have to abandon the old storage.  */
++
++      newp = malloc ((2 + newsize) * sizeof (dtv_t));
++      if (newp == NULL)
++      oom ();
++      memcpy (newp, &dtv[-1], (2 + oldsize) * sizeof (dtv_t));
++    }
++  else
++#endif
++    {
++      newp = realloc (&dtv[-1],
++                    (2 + newsize) * sizeof (dtv_t));
++      if (newp == NULL)
++      oom ();
++    }
++
++  newp[0].counter = newsize;
++
++  /* Clear the newly allocated part.  */
++  memset (newp + 2 + oldsize, '\0',
++        (newsize - oldsize) * sizeof (dtv_t));
++
++  /* Return the generation counter.  */
++  return &newp[1];
++}
++
+ void *
+ internal_function
+@@ -406,6 +451,16 @@
+   size_t total = 0;
+   size_t maxgen = 0;
++  /* Check if the current dtv is big enough.   */
++  if (dtv[-1].counter < GL(dl_tls_max_dtv_idx))
++    {
++      /* Resize the dtv.  */
++      dtv = _dl_resize_dtv (dtv);
++
++      /* Install this new dtv in the thread data structures.  */
++      INSTALL_DTV (result, &dtv[-1]);
++    }
++
+   /* We have to prepare the dtv for all currently loaded modules using
+      TLS.  For those which are dynamically loaded we add the values
+      indicating deferred allocation.  */
+@@ -637,41 +692,10 @@
+             assert (total + cnt == modid);
+             if (dtv[-1].counter < modid)
+               {
+-                /* Reallocate the dtv.  */
+-                dtv_t *newp;
+-                size_t newsize = GL(dl_tls_max_dtv_idx) + DTV_SURPLUS;
+-                size_t oldsize = dtv[-1].counter;
+-
+-                assert (map->l_tls_modid <= newsize);
+-
+-                if (dtv == GL(dl_initial_dtv))
+-                  {
+-                    /* This is the initial dtv that was allocated
+-                       during rtld startup using the dl-minimal.c
+-                       malloc instead of the real malloc.  We can't
+-                       free it, we have to abandon the old storage.  */
+-
+-                    newp = malloc ((2 + newsize) * sizeof (dtv_t));
+-                    if (newp == NULL)
+-                      oom ();
+-                    memcpy (newp, &dtv[-1], (2 + oldsize) * sizeof (dtv_t));
+-                  }
+-                else
+-                  {
+-                    newp = realloc (&dtv[-1],
+-                                    (2 + newsize) * sizeof (dtv_t));
+-                    if (newp == NULL)
+-                      oom ();
+-                  }
+-
+-                newp[0].counter = newsize;
+-
+-                /* Clear the newly allocated part.  */
+-                memset (newp + 2 + oldsize, '\0',
+-                        (newsize - oldsize) * sizeof (dtv_t));
++                /* Resize the dtv.  */
++                dtv = _dl_resize_dtv (dtv);
+-                /* Point dtv to the generation counter.  */
+-                dtv = &newp[1];
++                assert (modid <= dtv[-1].counter);
+                 /* Install this new dtv in the thread data
+                    structures.  */
+diff -urN glibc-2.12-2-gc4ccff1/nptl/Makefile glibc-2.12-2-gc4ccff1.mod/nptl/Makefile
+--- glibc-2.12-2-gc4ccff1/nptl/Makefile        2015-02-18 14:15:28.073462028 -0500
++++ glibc-2.12-2-gc4ccff1.mod/nptl/Makefile    2015-02-18 14:15:49.817786667 -0500
+@@ -245,7 +245,7 @@
+       tst-exec1 tst-exec2 tst-exec3 tst-exec4 \
+       tst-exit1 tst-exit2 tst-exit3 \
+       tst-stdio1 tst-stdio2 \
+-      tst-stack1 tst-stack2 tst-stack3 \
++      tst-stack1 tst-stack2 tst-stack3 tst-stack4 \
+       tst-unload \
+       tst-dlsym1 \
+       tst-sysconf \
+@@ -304,7 +304,7 @@
+ modules-names = tst-atfork2mod tst-tls3mod tst-tls4moda tst-tls4modb \
+               tst-tls5mod tst-tls5moda tst-tls5modb tst-tls5modc \
+-              tst-tls5modd tst-tls5mode tst-tls5modf \
++              tst-tls5modd tst-tls5mode tst-tls5modf tst-stack4mod \
+               tst-_res1mod1 tst-_res1mod2 tst-execstack-mod tst-fini1mod
+ extra-test-objs += $(addsuffix .os,$(strip $(modules-names))) tst-cleanup4aux.o
+ test-extras += $(modules-names)
+@@ -459,6 +459,19 @@
+       $(common-objpfx)malloc/mtrace $(objpfx)tst-stack3.mtrace > $@
+ generated += tst-stack3-mem tst-stack3.mtrace
++$(objpfx)tst-stack4: $(libdl) $(shared-thread-library)
++tst-stack4mod.sos=$(shell for i in 0 1 2 3 4 5 6 7 8 9 10 \
++                                 11 12 13 14 15 16 17 18 19; do \
++                          for j in 0 1 2 3 4 5 6 7 8 9 10 \
++                                   11 12 13 14 15 16 17 18 19; do \
++                            echo $(objpfx)tst-stack4mod-$$i-$$j.so; \
++                          done; done)
++$(objpfx)tst-stack4.out: $(tst-stack4mod.sos)
++$(tst-stack4mod.sos): $(objpfx)tst-stack4mod.so
++      cp -f $< $@
++clean:
++      rm -f $(tst-stack4mod.sos)
++
+ $(objpfx)tst-cleanup4: $(objpfx)tst-cleanup4aux.o $(shared-thread-library)
+ $(objpfx)tst-cleanupx4: $(objpfx)tst-cleanup4aux.o $(shared-thread-library)
+diff -urN glibc-2.12-2-gc4ccff1/nptl/tst-stack4.c glibc-2.12-2-gc4ccff1.mod/nptl/tst-stack4.c
+--- glibc-2.12-2-gc4ccff1/nptl/tst-stack4.c    1969-12-31 19:00:00.000000000 -0500
++++ glibc-2.12-2-gc4ccff1.mod/nptl/tst-stack4.c        2015-02-18 14:15:49.817786667 -0500
+@@ -0,0 +1,159 @@
++/* Test DTV size oveflow when pthread_create reuses old DTV and TLS is
++   used by dlopened shared object.
++   Copyright (C) 2014 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
++   <http://www.gnu.org/licenses/>.  */
++
++#include <stdio.h>
++#include <stdint.h>
++#include <dlfcn.h>
++#include <assert.h>
++#include <pthread.h>
++
++/* The choices of thread count, and file counts are arbitary.
++   The point is simply to run enough threads that an exiting
++   thread has it's stack reused by another thread at the same
++   time as new libraries have been loaded.  */
++#define DSO_SHARED_FILES 20
++#define DSO_OPEN_THREADS 20
++#define DSO_EXEC_THREADS 2
++
++/* Used to make sure that only one thread is calling dlopen and dlclose
++   at a time.  */
++pthread_mutex_t g_lock;
++
++typedef void (*function) (void);
++
++void *
++dso_invoke(void *dso_fun)
++{
++  function *fun_vec = (function *) dso_fun;
++  int dso;
++
++  for (dso = 0; dso < DSO_SHARED_FILES; dso++)
++    (*fun_vec[dso]) ();
++
++  pthread_exit (NULL);
++}
++
++void *
++dso_process (void * p)
++{
++  void *handle[DSO_SHARED_FILES];
++  function fun_vec[DSO_SHARED_FILES];
++  char dso_path[DSO_SHARED_FILES][100];
++  int dso;
++  uintptr_t t = (uintptr_t) p;
++
++  /* Open DSOs and get a function.  */
++  for (dso = 0; dso < DSO_SHARED_FILES; dso++)
++    {
++      sprintf (dso_path[dso], "tst-stack4mod-%i-%i.so", t, dso);
++
++      pthread_mutex_lock (&g_lock);
++
++      handle[dso] = dlopen (dso_path[dso], RTLD_NOW);
++      assert (handle[dso]);
++
++      fun_vec[dso] = (function) dlsym (handle[dso], "function");
++      assert (fun_vec[dso]);
++
++      pthread_mutex_unlock (&g_lock);
++    }
++
++  /* Spawn workers.  */
++  pthread_t thread[DSO_EXEC_THREADS];
++  int i, ret;
++  uintptr_t result = 0;
++  for (i = 0; i < DSO_EXEC_THREADS; i++)
++    {
++      pthread_mutex_lock (&g_lock);
++      ret = pthread_create (&thread[i], NULL, dso_invoke, (void *) fun_vec);
++      if (ret != 0)
++      {
++        printf ("pthread_create failed: %d\n", ret);
++        result = 1;
++      }
++      pthread_mutex_unlock (&g_lock);
++    }
++
++  if (!result)
++    for (i = 0; i < DSO_EXEC_THREADS; i++)
++      {
++      ret = pthread_join (thread[i], NULL);
++      if (ret != 0)
++        {
++          printf ("pthread_join failed: %d\n", ret);
++          result = 1;
++        }
++      }
++
++  /* Close all DSOs.  */
++  for (dso = 0; dso < DSO_SHARED_FILES; dso++)
++    {
++      pthread_mutex_lock (&g_lock);
++      dlclose (handle[dso]);
++      pthread_mutex_unlock (&g_lock);
++    }
++
++  /* Exit.  */
++  pthread_exit ((void *) result);
++}
++
++static int
++do_test (void)
++{
++  pthread_t thread[DSO_OPEN_THREADS];
++  int i,j;
++  int ret;
++  int result = 0;
++
++  pthread_mutex_init (&g_lock, NULL);
++
++  /* 100 is arbitrary here and is known to trigger PR 13862.  */
++  for (j = 0; j < 100; j++)
++    {
++      for (i = 0; i < DSO_OPEN_THREADS; i++)
++      {
++        ret = pthread_create (&thread[i], NULL, dso_process,
++                              (void *) (uintptr_t) i);
++        if (ret != 0)
++          {
++            printf ("pthread_create failed: %d\n", ret);
++            result = 1;
++          }
++      }
++
++      if (result)
++      break;
++
++      for (i = 0; i < DSO_OPEN_THREADS; i++)
++      {
++        ret = pthread_join (thread[i], NULL);
++        if (ret != 0)
++          {
++            printf ("pthread_join failed: %d\n", ret);
++            result = 1;
++          }
++      }
++    }
++
++  return result;
++}
++
++#define TEST_FUNCTION do_test ()
++#define TIMEOUT 100
++#include "../test-skeleton.c"
+diff -urN glibc-2.12-2-gc4ccff1/nptl/tst-stack4mod.c glibc-2.12-2-gc4ccff1.mod/nptl/tst-stack4mod.c
+--- glibc-2.12-2-gc4ccff1/nptl/tst-stack4mod.c 1969-12-31 19:00:00.000000000 -0500
++++ glibc-2.12-2-gc4ccff1.mod/nptl/tst-stack4mod.c     2015-02-18 14:15:49.817786667 -0500
+@@ -0,0 +1,28 @@
++/* This tests DTV usage with TLS in dlopened shared object.
++   Copyright (C) 2014 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
++   <http://www.gnu.org/licenses/>.  */
++
++/* 256 is arbitrary here and is known to trigger PR 13862.  */
++__thread int var[256] attribute_hidden = {0};
++
++void
++function (void)
++{
++  int i;
++  for (i = 0; i < sizeof (var) / sizeof (int); i++)
++    var[i] = i;
++}
diff --git a/src/patches/glibc/glibc-rh1124204.patch b/src/patches/glibc/glibc-rh1124204.patch
new file mode 100644 (file)
index 0000000..f14c4cb
--- /dev/null
@@ -0,0 +1,47 @@
+#
+# Derived from this upstream commit:
+#
+# commit 58a1335e76a553e1cf4edeebc27f16fc9b53d6e6
+# Author: Petr Baudis <pasky@ucw.cz>
+# Date:   Thu Mar 14 01:16:53 2013 +0100
+#
+#    Fix __times() handling of EFAULT when buf is NULL
+#
+# 2013-03-14  Petr Baudis  <pasky@ucw.cz>
+#
+#      * sysdeps/unix/sysv/linux/times.c (__times): On EFAULT, test
+#      for non-NULL pointer before the memory validity test. Pointed
+#      out by Holger Brunck <holger.brunck@keymile.com>.
+#
+diff --git a/sysdeps/unix/sysv/linux/times.c b/sysdeps/unix/sysv/linux/times.c
+index f3b5f01..e59bb4e 100644
+--- a/sysdeps/unix/sysv/linux/times.c
++++ b/sysdeps/unix/sysv/linux/times.c
+@@ -26,13 +26,14 @@ __times (struct tms *buf)
+   INTERNAL_SYSCALL_DECL (err);
+   clock_t ret = INTERNAL_SYSCALL (times, err, 1, buf);
+   if (INTERNAL_SYSCALL_ERROR_P (ret, err)
+-      && __builtin_expect (INTERNAL_SYSCALL_ERRNO (ret, err) == EFAULT, 0))
++      && __builtin_expect (INTERNAL_SYSCALL_ERRNO (ret, err) == EFAULT, 0)
++      && buf)
+     {
+       /* This might be an error or not.  For architectures which have
+        no separate return value and error indicators we cannot
+        distinguish a return value of -1 from an error.  Do it the
+-       hard way.  We crash applications which pass in an invalid BUF
+-       pointer.  */
++       hard way.  We crash applications which pass in an invalid
++       non-NULL BUF pointer.  Linux allows BUF to be NULL. */
+ #define touch(v) \
+       do {                                                                  \
+       clock_t temp = v;                                                     \
+@@ -44,7 +45,8 @@ __times (struct tms *buf)
+       touch (buf->tms_cutime);
+       touch (buf->tms_cstime);
+-      /* If we come here the memory is valid and the kernel did not
++      /* If we come here the memory is valid (or BUF is NULL, which is
++       * a valid condition for the kernel syscall) and the kernel did not
+        return an EFAULT error.  Return the value given by the kernel.  */
+     }
diff --git a/src/patches/glibc/glibc-rh1125307.patch b/src/patches/glibc/glibc-rh1125307.patch
new file mode 100644 (file)
index 0000000..72ba01d
--- /dev/null
@@ -0,0 +1,19 @@
+commit a11892631d92f594c690d0d50a642b0d1aba58b8
+Author: Ondřej Bílka <neleai@seznam.cz>
+Date:   Wed May 7 14:08:57 2014 +0200
+
+    Fix typo in nscd/selinux.c
+
+diff --git a/nscd/selinux.c b/nscd/selinux.c
+index 9a8a5a8..eaed6dd 100644
+--- a/nscd/selinux.c
++++ b/nscd/selinux.c
+@@ -372,7 +372,7 @@ nscd_request_avc_has_perm (int fd, request_type req)
+   /* Get the security class for nscd.  If this fails we will likely be
+      unable to do anything unless avc_deny_unknown is 0.  */
+   sc_nscd = string_to_security_class ("nscd");
+-  if (perm == 0 && avc_deny_unknown == 1)
++  if (sc_nscd == 0 && avc_deny_unknown == 1)
+     dbg_log (_("Error getting security class for nscd."));
+   /* Convert permission to AVC bits.  */
diff --git a/src/patches/glibc/glibc-rh1138769.patch b/src/patches/glibc/glibc-rh1138769.patch
new file mode 100644 (file)
index 0000000..94a7d2a
--- /dev/null
@@ -0,0 +1,45 @@
+commit e35c53e397e7abbd41fedacdedcfa5af7b5c2c52
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date:   Tue Jul 8 16:40:24 2014 +0530
+
+    Check value at resplen2 if it is not NULL
+    
+    There was a typo in the previous patch due to which resplen2 was
+    checked for non-zero instead of the value at resplen2.  Fix that and
+    improve the condition by checking resplen2 for non-NULL (instead of
+    answerp2) and also adding the check in a third place.
+
+diff --git a/resolv/res_query.c b/resolv/res_query.c
+index 4e6612c..e4ee2a6 100644
+--- a/resolv/res_query.c
++++ b/resolv/res_query.c
+@@ -384,7 +384,7 @@ __libc_res_nsearch(res_state statp,
+                                             answerp2, nanswerp2, resplen2);
+               if (ret > 0 || trailing_dot
+                   /* If the second response is valid then we use that.  */
+-                  || (ret == 0 && answerp2 != NULL && resplen2 > 0))
++                  || (ret == 0 && resplen2 != NULL && *resplen2 > 0))
+                       return (ret);
+               saved_herrno = h_errno;
+               tried_as_is++;
+@@ -424,8 +424,8 @@ __libc_res_nsearch(res_state statp,
+                                                     answer, anslen, answerp,
+                                                     answerp2, nanswerp2,
+                                                     resplen2);
+-                      if (ret > 0 || (ret == 0 && answerp2 != NULL
+-                                      && resplen2 > 0))
++                      if (ret > 0 || (ret == 0 && resplen2 != NULL
++                                      && *resplen2 > 0))
+                               return (ret);
+                       if (answerp && *answerp != answer) {
+@@ -494,7 +494,8 @@ __libc_res_nsearch(res_state statp,
+               ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
+                                             answer, anslen, answerp,
+                                             answerp2, nanswerp2, resplen2);
+-              if (ret > 0)
++              if (ret > 0 || (ret == 0 && resplen2 != NULL
++                              && *resplen2 > 0))
+                       return (ret);
+       }
diff --git a/src/patches/glibc/glibc-rh1144132.patch b/src/patches/glibc/glibc-rh1144132.patch
new file mode 100644 (file)
index 0000000..4114b58
--- /dev/null
@@ -0,0 +1,58 @@
+#
+# Based on this commit:
+#
+# commit 62058ce612ed3459501b4c4332e268edfe977f59
+# Author: Carlos O'Donell <carlos@redhat.com>
+# Date:   Mon Sep 29 13:14:21 2014 -0400
+# 
+#     Correctly size profiling reloc table (bug 17411)
+#     
+#     During auditing or profiling modes the dynamic loader
+#     builds a cache of the relocated PLT entries in order
+#     to reuse them when called again through the same PLT
+#     entry. This way the PLT entry is never completed and
+#     the call into the resolver always results in profiling
+#     or auditing code running.
+#     
+#     The problem is that the PLT relocation cache size
+#     is not computed correctly. The size of the cache
+#     should be "Size of a relocation result structure"
+#     x "Number of PLT-related relocations". Instead the
+#     code erroneously computes "Size of a relocation
+#     result" x "Number of bytes worth of PLT-related
+#     relocations". I can only assume this was a mistake
+#     in the understanding of the value of DT_PLTRELSZ
+#     which is the number of bytes of PLT-related relocs.
+#     We do have a DT_RELACOUNT entry, which is a count
+#     for dynamic relative relocs, but we have no
+#     DT_PLTRELCOUNT and thus we need to compute it.
+#     
+#     This patch corrects the computation of the size of the
+#     relocation table used by the glibc profiling code.
+#     
+#     For more details see:
+#     https://sourceware.org/ml/libc-alpha/2014-09/msg00513.html
+#     
+#         [BZ #17411]
+#         * elf/dl-reloc.c (_dl_relocate_object): Allocate correct amount for
+#         l_reloc_result.
+# 
+diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
+index d2c6dac..97a7119 100644
+--- a/elf/dl-reloc.c
++++ b/elf/dl-reloc.c
+@@ -279,8 +279,12 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
+                             l->l_name);
+         }
+-      l->l_reloc_result = calloc (sizeof (l->l_reloc_result[0]),
+-                                  l->l_info[DT_PLTRELSZ]->d_un.d_val);
++      size_t sizeofrel = l->l_info[DT_PLTREL]->d_un.d_val == DT_RELA
++                         ? sizeof (ElfW(Rela))
++                         : sizeof (ElfW(Rel));
++      size_t relcount = l->l_info[DT_PLTRELSZ]->d_un.d_val / sizeofrel;
++      l->l_reloc_result = calloc (sizeof (l->l_reloc_result[0]), relcount);
++
+       if (l->l_reloc_result == NULL)
+         {
+           errstring = N_("\
diff --git a/src/patches/glibc/glibc-rh1159167.patch b/src/patches/glibc/glibc-rh1159167.patch
new file mode 100644 (file)
index 0000000..59f4a6f
--- /dev/null
@@ -0,0 +1,15 @@
+diff --git a/sunrpc/svc.c b/sunrpc/svc.c
+index ccf0902..30c3a93 100644
+--- a/sunrpc/svc.c
++++ b/sunrpc/svc.c
+@@ -97,8 +97,8 @@ xprt_register (SVCXPRT *xprt)
+   if (xports == NULL)
+     {
+-      xports = (SVCXPRT **) malloc (_rpc_dtablesize () * sizeof (SVCXPRT *));
+-      if (xports == NULL) /* Don´t add handle */
++      xports = (SVCXPRT **) calloc (_rpc_dtablesize (), sizeof (SVCXPRT *));
++      if (xports == NULL) /* Don't add handle */
+       return;
+     }
diff --git a/src/patches/glibc/glibc-rh1176907.patch b/src/patches/glibc/glibc-rh1176907.patch
new file mode 100644 (file)
index 0000000..29cdacf
--- /dev/null
@@ -0,0 +1,22 @@
+commit 7d81e8d6db95c112c297930a8f2f9617c305529a
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Tue Dec 23 16:16:32 2014 +0100
+
+    iconvdata/run-iconv-test.sh: Actually test iconv modules
+    
+    Arjun Shankar noticed that this test case was not testing anything
+    because iconv was invoked without the required arguments.
+
+diff --git a/iconvdata/run-iconv-test.sh b/iconvdata/run-iconv-test.sh
+index 5dfb69f..1d0bf52 100755
+--- a/iconvdata/run-iconv-test.sh
++++ b/iconvdata/run-iconv-test.sh
+@@ -189,7 +189,7 @@ printf '\016\377\377\377\377\377\377\377' > $temp1
+ for from in $iconv_modules ; do
+     echo $ac_n "test decoder $from $ac_c"
+     PROG=`eval echo $ICONV`
+-    if $PROG < $temp1 >/dev/null 2>&1 ; then
++    if $PROG -f $from -t UTF8 < $temp1 >/dev/null 2>&1 ; then
+       : # fall through
+     else
+       status=$?
similarity index 94%
rename from src/patches/glibc/glibc-rh1183533.patch
rename to src/patches/glibc/glibc-rh1183534.patch
index 9263cd5b687432a2d95b0942a7bc618c674acd63..eab7a3fa49a294f2b20e1bdefefff9fbcdf902d8 100644 (file)
@@ -4,6 +4,19 @@ Date:   Mon Jan 21 17:41:28 2013 +0100
 
     Fix parsing of numeric hosts in gethostbyname_r
 
+diff --git a/nss/Makefile b/nss/Makefile
+index 449a258..553eafa 100644
+--- a/nss/Makefile
++++ b/nss/Makefile
+@@ -37,7 +37,7 @@ install-bin             := getent makedb
+ others                  := getent
+ install-bin             := getent
+-tests                 = test-netdb tst-nss-test1
++tests                 = test-netdb tst-nss-test1 test-digits-dots
+ xtests                        = bug-erange
+ include ../Makeconfig
 diff --git a/nss/digits_dots.c b/nss/digits_dots.c
 index 2b86295..e007ef4 100644
 --- a/nss/digits_dots.c
diff --git a/src/patches/glibc/glibc-rh1195453-avx512.patch b/src/patches/glibc/glibc-rh1195453-avx512.patch
new file mode 100644 (file)
index 0000000..4c70e5e
--- /dev/null
@@ -0,0 +1,481 @@
+#
+# Based on AVX-512 support for glibc, but heavaily modified for rhel-6.7.
+# Without assembler support we drop all of the configure checks and simply
+# output using .byte directives the minimal AVX512 instructsion required
+# by the loader. Likewise testing is also impossible, so instead we use
+# the Intel emulator running in `-skx` (Skylake Xeon) emulation mode and
+# verify that a pre-built set of tests passes.
+#
+# commit 6986b98a18490e76b16911d1c6b1ba013598d40d
+# Author: Ulrich Drepper <drepper@gmail.com>
+# Date:   Wed Jul 20 14:20:00 2011 -0400
+#
+#    Force :a_x86_64_ymm to be 16-byte aligned
+#
+# commit aa4de9cea5c07d43caeaca9722c2d417e9a2919c
+# Author: H.J. Lu <hjl.tools@gmail.com>
+# Date:   Fri Mar 14 08:51:25 2014 -0700
+# 
+#     Check AVX-512 assembler support first
+# 
+#     It checks AVX-512 assembler support first and sets libc_cv_cc_avx512 to
+#     $libc_cv_asm_avx512, instead of yes.  GCC won't support AVX-512 if
+#     assembler doesn't support it.
+# 
+#         * sysdeps/x86_64/configure.ac: Check AVX-512 assembler support
+#         first.  Disable AVX-512 GCC support if assembler doesn't support
+#         it.
+#         * sysdeps/x86_64/configure: Regenerated.
+# 
+# commit 2d63a517e4084ec80403cd9f278690fa8b676cc4
+# Author: Igor Zamyatin <igor.zamyatin@intel.com>
+# Date:   Thu Mar 13 11:10:22 2014 -0700
+# 
+#     Save and restore AVX-512 zmm registers to x86-64 ld.so
+#     
+#     AVX-512 ISA adds 512-bit zmm registers.  This patch updates
+#     _dl_runtime_profile to pass zmm registers to run-time audit. It also
+#     changes _dl_x86_64_save_sse and _dl_x86_64_restore_sse to upport zmm
+#     registers, which are called when only when RTLD_PREPARE_FOREIGN_CALL
+#     is used.  Its performance impact is minimum.
+#     
+#         * config.h.in (HAVE_AVX512_SUPPORT): New #undef.
+#         (HAVE_AVX512_ASM_SUPPORT): Likewise.
+#         * sysdeps/x86_64/bits/link.h (La_x86_64_zmm): New.
+#         (La_x86_64_vector): Add zmm.
+#         * sysdeps/x86_64/Makefile (tests): Add tst-audit10.
+#         (modules-names): Add tst-auditmod10a and tst-auditmod10b.
+#         ($(objpfx)tst-audit10): New target.
+#         ($(objpfx)tst-audit10.out): Likewise.
+#         (tst-audit10-ENV): New.
+#         (AVX512-CFLAGS): Likewise.
+#         (CFLAGS-tst-audit10.c): Likewise.
+#         (CFLAGS-tst-auditmod10a.c): Likewise.
+#         (CFLAGS-tst-auditmod10b.c): Likewise.
+#         * sysdeps/x86_64/configure.ac: Set config-cflags-avx512,
+#         HAVE_AVX512_SUPPORT and HAVE_AVX512_ASM_SUPPORT.
+#         * sysdeps/x86_64/configure: Regenerated.
+#         * sysdeps/x86_64/dl-trampoline.S (_dl_runtime_profile): Add
+#         AVX-512 zmm register support.
+#         (_dl_x86_64_save_sse): Likewise.
+#         (_dl_x86_64_restore_sse): Likewise.
+#         * sysdeps/x86_64/dl-trampoline.h: Updated to support different
+#         size vector registers.
+#         * sysdeps/x86_64/link-defines.sym (YMM_SIZE): New.
+#         (ZMM_SIZE): Likewise. 
+#         * sysdeps/x86_64/tst-audit10.c: New file.
+#         * sysdeps/x86_64/tst-auditmod10a.c: Likewise.
+#         * sysdeps/x86_64/tst-auditmod10b.c: Likewise.
+# 
+# In addition adds:
+# https://sourceware.org/ml/libc-alpha/2014-09/msg00228.html
+# To extend zmm register checking.
+#
+diff -urN glibc-2.12-2-gc4ccff1/sysdeps/x86_64/bits/link.h glibc-2.12-2-gc4ccff1.mod/sysdeps/x86_64/bits/link.h
+--- glibc-2.12-2-gc4ccff1/sysdeps/x86_64/bits/link.h   2010-05-04 07:27:23.000000000 -0400
++++ glibc-2.12-2-gc4ccff1.mod/sysdeps/x86_64/bits/link.h       2015-03-03 23:03:25.041829238 -0500
+@@ -65,7 +65,10 @@
+ /* Registers for entry into PLT on x86-64.  */
+ # if __GNUC_PREREQ (4,0)
+ typedef float La_x86_64_xmm __attribute__ ((__vector_size__ (16)));
+-typedef float La_x86_64_ymm __attribute__ ((__vector_size__ (32)));
++typedef float La_x86_64_ymm __attribute__ ((__vector_size__ (32),
++                                          __aligned__ (16)));
++typedef double La_x86_64_zmm __attribute__ ((__vector_size__ (64),
++                                          __aligned__ (16)));
+ # else
+ typedef float La_x86_64_xmm __attribute__ ((__mode__ (__V4SF__)));
+ # endif
+@@ -74,9 +77,10 @@
+ {
+ # if __GNUC_PREREQ (4,0)
+   La_x86_64_ymm ymm[2];
++  La_x86_64_zmm zmm[1];
+ # endif
+   La_x86_64_xmm xmm[4];
+-} La_x86_64_vector __attribute__ ((aligned(16)));
++} La_x86_64_vector __attribute__ ((__aligned__(16)));
+ typedef struct La_x86_64_regs
+ {
+diff -urN glibc-2.12-2-gc4ccff1/sysdeps/x86_64/dl-trampoline.h glibc-2.12-2-gc4ccff1.mod/sysdeps/x86_64/dl-trampoline.h
+--- glibc-2.12-2-gc4ccff1/sysdeps/x86_64/dl-trampoline.h       2015-03-03 23:03:05.109457627 -0500
++++ glibc-2.12-2-gc4ccff1.mod/sysdeps/x86_64/dl-trampoline.h   2015-03-03 23:06:58.434101818 -0500
+@@ -20,14 +20,26 @@
+ #ifdef RESTORE_AVX
+       /* This is to support AVX audit modules.  */
+-      vmovdqu %ymm0,                (LR_VECTOR_OFFSET)(%rsp)
+-      vmovdqu %ymm1, (LR_VECTOR_OFFSET +   VECTOR_SIZE)(%rsp)
+-      vmovdqu %ymm2, (LR_VECTOR_OFFSET + VECTOR_SIZE*2)(%rsp)
+-      vmovdqu %ymm3, (LR_VECTOR_OFFSET + VECTOR_SIZE*3)(%rsp)
+-      vmovdqu %ymm4, (LR_VECTOR_OFFSET + VECTOR_SIZE*4)(%rsp)
+-      vmovdqu %ymm5, (LR_VECTOR_OFFSET + VECTOR_SIZE*5)(%rsp)
+-      vmovdqu %ymm6, (LR_VECTOR_OFFSET + VECTOR_SIZE*6)(%rsp)
+-      vmovdqu %ymm7, (LR_VECTOR_OFFSET + VECTOR_SIZE*7)(%rsp)
++# if HAVE_NO_AVX512_ASM_SUPPORT
++      /* Restore AVX-512 registers. Use .byte becaues we lack assembler support.  */
++      .byte 0x62,0xf1,0xfe,0x48,0x7f,0x44,0x24,0x03 # vmovdqu64 %zmm0,0xc0(%rsp)
++      .byte 0x62,0xf1,0xfe,0x48,0x7f,0x4c,0x24,0x04 # vmovdqu64 %zmm1,0x100(%rsp)
++      .byte 0x62,0xf1,0xfe,0x48,0x7f,0x54,0x24,0x05 # vmovdqu64 %zmm2,0x140(%rsp)
++      .byte 0x62,0xf1,0xfe,0x48,0x7f,0x5c,0x24,0x06 # vmovdqu64 %zmm3,0x180(%rsp)
++      .byte 0x62,0xf1,0xfe,0x48,0x7f,0x64,0x24,0x07 # vmovdqu64 %zmm4,0x1c0(%rsp)
++      .byte 0x62,0xf1,0xfe,0x48,0x7f,0x6c,0x24,0x08 # vmovdqu64 %zmm5,0x200(%rsp)
++      .byte 0x62,0xf1,0xfe,0x48,0x7f,0x74,0x24,0x09 # vmovdqu64 %zmm6,0x240(%rsp)
++      .byte 0x62,0xf1,0xfe,0x48,0x7f,0x7c,0x24,0x0a # vmovdqu64 %zmm7,0x280(%rsp)
++# else
++      VMOV %VEC(0),                 (LR_VECTOR_OFFSET)(%rsp)
++      VMOV %VEC(1), (LR_VECTOR_OFFSET +   VECTOR_SIZE)(%rsp)
++      VMOV %VEC(2), (LR_VECTOR_OFFSET + VECTOR_SIZE*2)(%rsp)
++      VMOV %VEC(3), (LR_VECTOR_OFFSET + VECTOR_SIZE*3)(%rsp)
++      VMOV %VEC(4), (LR_VECTOR_OFFSET + VECTOR_SIZE*4)(%rsp)
++      VMOV %VEC(5), (LR_VECTOR_OFFSET + VECTOR_SIZE*5)(%rsp)
++      VMOV %VEC(6), (LR_VECTOR_OFFSET + VECTOR_SIZE*6)(%rsp)
++      VMOV %VEC(7), (LR_VECTOR_OFFSET + VECTOR_SIZE*7)(%rsp)
++# endif
+       /* Save xmm0-xmm7 registers to detect if any of them are
+          changed by audit module.  */
+@@ -73,7 +85,11 @@
+       je 2f
+       vmovdqa %xmm0, (LR_VECTOR_OFFSET)(%rsp)
+       jmp 1f
+-2:    vmovdqu (LR_VECTOR_OFFSET)(%rsp), %ymm0
++# if HAVE_NO_AVX512_ASM_SUPPORT
++2:    .byte 0x62,0xf1,0xfe,0x48,0x6f,0x44,0x24,0x03 # vmovdqu64 0xc0(%rsp),%zmm0
++# else
++2:    VMOV (LR_VECTOR_OFFSET)(%rsp), %VEC(0)
++# endif
+       vmovdqa %xmm0, (LR_XMM_OFFSET)(%rsp)
+ 1:    vpcmpeqq (LR_SIZE + XMM_SIZE)(%rsp), %xmm1, %xmm8
+@@ -82,7 +98,11 @@
+       je 2f
+       vmovdqa %xmm1, (LR_VECTOR_OFFSET + VECTOR_SIZE)(%rsp)
+       jmp 1f
+-2:    vmovdqu (LR_VECTOR_OFFSET + VECTOR_SIZE)(%rsp), %ymm1
++# if HAVE_NO_AVX512_ASM_SUPPORT
++2:    .byte 0x62,0xf1,0xfe,0x48,0x6f,0x4c,0x24,0x04 # vmovdqu64 0x100(%rsp),%zmm1
++# else
++2:    VMOV (LR_VECTOR_OFFSET + VECTOR_SIZE)(%rsp), %VEC(1)
++# endif
+       vmovdqa %xmm1, (LR_XMM_OFFSET + XMM_SIZE)(%rsp)
+ 1:    vpcmpeqq (LR_SIZE + XMM_SIZE*2)(%rsp), %xmm2, %xmm8
+@@ -91,7 +111,11 @@
+       je 2f
+       vmovdqa %xmm2, (LR_VECTOR_OFFSET + VECTOR_SIZE*2)(%rsp)
+       jmp 1f
+-2:    vmovdqu (LR_VECTOR_OFFSET + VECTOR_SIZE*2)(%rsp), %ymm2
++# if HAVE_NO_AVX512_ASM_SUPPORT
++2:    .byte 0x62,0xf1,0xfe,0x48,0x6f,0x54,0x24,0x05 # vmovdqu64 0x140(%rsp),%zmm2
++# else
++2:    VMOV (LR_VECTOR_OFFSET + VECTOR_SIZE*2)(%rsp), %VEC(2)
++# endif
+       vmovdqa %xmm2, (LR_XMM_OFFSET + XMM_SIZE*2)(%rsp)
+ 1:    vpcmpeqq (LR_SIZE + XMM_SIZE*3)(%rsp), %xmm3, %xmm8
+@@ -100,7 +124,11 @@
+       je 2f
+       vmovdqa %xmm3, (LR_VECTOR_OFFSET + VECTOR_SIZE*3)(%rsp)
+       jmp 1f
+-2:    vmovdqu (LR_VECTOR_OFFSET + VECTOR_SIZE*3)(%rsp), %ymm3
++# if HAVE_NO_AVX512_ASM_SUPPORT
++2:    .byte 0x62,0xf1,0xfe,0x48,0x6f,0x5c,0x24,0x06 # vmovdqu64 0x180(%rsp),%zmm3
++# else
++2:    VMOV (LR_VECTOR_OFFSET + VECTOR_SIZE*3)(%rsp), %VEC(3)
++# endif
+       vmovdqa %xmm3, (LR_XMM_OFFSET + XMM_SIZE*3)(%rsp)
+ 1:    vpcmpeqq (LR_SIZE + XMM_SIZE*4)(%rsp), %xmm4, %xmm8
+@@ -109,7 +137,11 @@
+       je 2f
+       vmovdqa %xmm4, (LR_VECTOR_OFFSET + VECTOR_SIZE*4)(%rsp)
+       jmp 1f
+-2:    vmovdqu (LR_VECTOR_OFFSET + VECTOR_SIZE*4)(%rsp), %ymm4
++# if HAVE_NO_AVX512_ASM_SUPPORT
++2:    .byte 0x62,0xf1,0xfe,0x48,0x6f,0x64,0x24,0x07 # vmovdqu64 0x1c0(%rsp),%zmm4
++# else
++2:    VMOV (LR_VECTOR_OFFSET + VECTOR_SIZE*4)(%rsp), %VEC(4)
++# endif
+       vmovdqa %xmm4, (LR_XMM_OFFSET + XMM_SIZE*4)(%rsp)
+ 1:    vpcmpeqq (LR_SIZE + XMM_SIZE*5)(%rsp), %xmm5, %xmm8
+@@ -118,7 +150,11 @@
+       je 2f
+       vmovdqa %xmm5, (LR_VECTOR_OFFSET + VECTOR_SIZE*5)(%rsp)
+       jmp 1f
+-2:    vmovdqu (LR_VECTOR_OFFSET + VECTOR_SIZE*5)(%rsp), %ymm5
++# if HAVE_NO_AVX512_ASM_SUPPORT
++2:    .byte 0x62,0xf1,0xfe,0x48,0x6f,0x6c,0x24,0x08 # vmovdqu64 0x200(%rsp),%zmm5
++# else
++2:    VMOV (LR_VECTOR_OFFSET + VECTOR_SIZE*5)(%rsp), %VEC(5)
++# endif
+       vmovdqa %xmm5, (LR_XMM_OFFSET + XMM_SIZE*5)(%rsp)
+ 1:    vpcmpeqq (LR_SIZE + XMM_SIZE*6)(%rsp), %xmm6, %xmm8
+@@ -127,7 +163,11 @@
+       je 2f
+       vmovdqa %xmm6, (LR_VECTOR_OFFSET + VECTOR_SIZE*6)(%rsp)
+       jmp 1f
+-2:    vmovdqu (LR_VECTOR_OFFSET + VECTOR_SIZE*6)(%rsp), %ymm6
++# if HAVE_NO_AVX512_ASM_SUPPORT
++2:    .byte 0x62,0xf1,0xfe,0x48,0x6f,0x74,0x24,0x09 # vmovdqu64 0x240(%rsp),%zmm6
++# else
++2:    VMOV (LR_VECTOR_OFFSET + VECTOR_SIZE*6)(%rsp), %VEC(6)
++# endif
+       vmovdqa %xmm6, (LR_XMM_OFFSET + XMM_SIZE*6)(%rsp)
+ 1:    vpcmpeqq (LR_SIZE + XMM_SIZE*7)(%rsp), %xmm7, %xmm8
+@@ -136,7 +176,11 @@
+       je 2f
+       vmovdqa %xmm7, (LR_VECTOR_OFFSET + VECTOR_SIZE*7)(%rsp)
+       jmp 1f
+-2:    vmovdqu (LR_VECTOR_OFFSET + VECTOR_SIZE*7)(%rsp), %ymm7
++# if HAVE_NO_AVX512_ASM_SUPPORT
++2:    .byte 0x62,0xf1,0xfe,0x48,0x6f,0x7c,0x24,0x0a # vmovdqu64 0x280(%rsp),%zmm7
++# else
++2:    VMOV (LR_VECTOR_OFFSET + VECTOR_SIZE*7)(%rsp), %VEC(7)
++# endif
+       vmovdqa %xmm7, (LR_XMM_OFFSET + XMM_SIZE*7)(%rsp)
+ 1:
+@@ -214,8 +258,13 @@
+ #ifdef RESTORE_AVX
+       /* This is to support AVX audit modules.  */
+-      vmovdqu %ymm0, LRV_VECTOR0_OFFSET(%rcx)
+-      vmovdqu %ymm1, LRV_VECTOR1_OFFSET(%rcx)
++# if HAVE_NO_AVX512_ASM_SUPPORT
++      .byte 0x62,0xf1,0xfe,0x48,0x7f,0x81,0x50,0x00,0x00,0x00 # vmovdqu64 %zmm0,0x50(%rcx)
++      .byte 0x62,0xf1,0xfe,0x48,0x7f,0x89,0x90,0x00,0x00,0x00 # vmovdqu64 %zmm1,0x90(%rcx)
++# else
++      VMOV %VEC(0), LRV_VECTOR0_OFFSET(%rcx)
++      VMOV %VEC(1), LRV_VECTOR1_OFFSET(%rcx)
++# endif
+       /* Save xmm0/xmm1 registers to detect if they are changed
+          by audit module.  */
+@@ -244,13 +293,21 @@
+       vpmovmskb %xmm2, %esi
+       cmpl $0xffff, %esi
+       jne 1f
+-      vmovdqu LRV_VECTOR0_OFFSET(%rsp), %ymm0
++# if HAVE_NO_AVX512_ASM_SUPPORT
++      .byte 0x62,0xf1,0xfe,0x48,0x6f,0x84,0x24,0x50,0x00,0x00,0x00 # vmovdqu64 0x50(%rsp),%zmm0
++# else
++      VMOV LRV_VECTOR0_OFFSET(%rsp), %VEC(0)
++# endif
+ 1:    vpcmpeqq (LRV_SIZE + XMM_SIZE)(%rsp), %xmm1, %xmm2
+       vpmovmskb %xmm2, %esi
+       cmpl $0xffff, %esi
+       jne 1f
+-      vmovdqu LRV_VECTOR1_OFFSET(%rsp), %ymm1
++# if HAVE_NO_AVX512_ASM_SUPPORT
++      .byte 0x62,0xf1,0xfe,0x48,0x6f,0x8c,0x24,0x90,0x00,0x00,0x00 # vmovdqu64 0x90(%rsp),%zmm1
++# else
++      VMOV LRV_VECTOR1_OFFSET(%rsp), %VEC(1)
++# endif
+ 1:
+ #endif
+diff -urN glibc-2.12-2-gc4ccff1/sysdeps/x86_64/dl-trampoline.S glibc-2.12-2-gc4ccff1.mod/sysdeps/x86_64/dl-trampoline.S
+--- glibc-2.12-2-gc4ccff1/sysdeps/x86_64/dl-trampoline.S       2015-03-03 23:03:05.108457659 -0500
++++ glibc-2.12-2-gc4ccff1.mod/sysdeps/x86_64/dl-trampoline.S   2015-03-03 23:07:31.799049953 -0500
+@@ -134,7 +134,7 @@
+       .previous
+       cmpl    $0, L(have_avx)(%rip)
+-      jne     1f
++      jne     L(defined)
+       movq    %rbx, %r11              # Save rbx
+       movl    $1, %eax
+       cpuid
+@@ -143,18 +143,51 @@
+       // AVX and XSAVE supported?
+       andl    $((1 << 28) | (1 << 27)), %ecx
+       cmpl    $((1 << 28) | (1 << 27)), %ecx
+-      jne     2f
++      jne     10f
++      // AVX512 supported in processor?
++      movq    %rbx, %r11              # Save rbx
++      xorl    %ecx, %ecx
++      mov     $0x7, %eax
++      cpuid
++      andl    $(1 << 16), %ebx
+       xorl    %ecx, %ecx
+       // Get XFEATURE_ENABLED_MASK
+       xgetbv
+-      andl    $0x6, %eax
+-2:    subl    $0x5, %eax
++      test    %ebx, %ebx
++      movq    %r11, %rbx              # Restore rbx
++      je      20f
++      // Verify that XCR0[7:5] = '111b' and
++      // XCR0[2:1] = '11b' which means
++      // that zmm state is enabled
++      andl    $0xe6, %eax
++      cmpl    $0xe6, %eax
++      jne     20f
++      movl    %eax, L(have_avx)(%rip)
++L(avx512):
++#   define RESTORE_AVX
++#   define HAVE_NO_AVX512_ASM_SUPPORT 1
++#   define VMOV    vmovdqu64
++#   define VEC(i)  zmm##i
++#   define MORE_CODE
++#   include "dl-trampoline.h"
++#   undef VMOV
++#   undef VEC
++#   undef RESTORE_AVX
++#   undef HAVE_NO_AVX512_ASM_SUPPORT
++20:   andl    $0x6, %eax
++10:   subl    $0x5, %eax
+       movl    %eax, L(have_avx)(%rip)
+       cmpl    $0, %eax
+-1:    js      L(no_avx)
++L(defined):
++      js      L(no_avx)
++      cmpl    $0xe6, L(have_avx)(%rip)
++      je      L(avx512)
++
+ #  define RESTORE_AVX
++#  define VMOV    vmovdqu
++#  define VEC(i)  ymm##i
+ #  define MORE_CODE
+ #  include "dl-trampoline.h"
+@@ -178,7 +211,7 @@
+ _dl_x86_64_save_sse:
+ # ifdef HAVE_AVX_SUPPORT
+       cmpl    $0, L(have_avx)(%rip)
+-      jne     1f
++      jne     L(defined_5)
+       movq    %rbx, %r11              # Save rbx
+       movl    $1, %eax
+       cpuid
+@@ -187,21 +220,37 @@
+       // AVX and XSAVE supported?
+       andl    $((1 << 28) | (1 << 27)), %ecx
+       cmpl    $((1 << 28) | (1 << 27)), %ecx
+-      jne     2f
++      jne     1f
++      // AVX512 supported in a processor?
++      movq    %rbx, %r11              # Save rbx
++      xorl    %ecx,%ecx
++      mov     $0x7,%eax
++      cpuid
++      andl    $(1 << 16), %ebx
+       xorl    %ecx, %ecx
+       // Get XFEATURE_ENABLED_MASK
+       xgetbv
+-      andl    $0x6, %eax
+-      cmpl    $0x6, %eax
+-      // Nonzero if SSE and AVX state saving is enabled.
+-      sete    %al
+-2:    leal    -1(%eax,%eax), %eax
++      test    %ebx, %ebx
++      movq    %r11, %rbx              # Restore rbx
++      je      2f
++      // Verify that XCR0[7:5] = '111b' and
++      // XCR0[2:1] = '11b' which means
++      // that zmm state is enabled
++      andl    $0xe6, %eax
+       movl    %eax, L(have_avx)(%rip)
+-      cmpl    $0, %eax
++      cmpl    $0xe6, %eax
++      je      L(avx512_5)
+-1:    js      L(no_avx5)
++2:    andl    $0x6, %eax
++1:    subl    $0x5, %eax
++      movl    %eax, L(have_avx)(%rip)
++      cmpl    $0, %eax
+-#  define YMM_SIZE 32
++L(defined_5):
++      js      L(no_avx5)
++      cmpl    $0xe6, L(have_avx)(%rip)
++      je      L(avx512_5)
++ 
+       vmovdqa %ymm0, %fs:RTLD_SAVESPACE_SSE+0*YMM_SIZE
+       vmovdqa %ymm1, %fs:RTLD_SAVESPACE_SSE+1*YMM_SIZE
+       vmovdqa %ymm2, %fs:RTLD_SAVESPACE_SSE+2*YMM_SIZE
+@@ -211,6 +260,26 @@
+       vmovdqa %ymm6, %fs:RTLD_SAVESPACE_SSE+6*YMM_SIZE
+       vmovdqa %ymm7, %fs:RTLD_SAVESPACE_SSE+7*YMM_SIZE
+       ret
++L(avx512_5):
++# Original instructions:
++#     vmovdqu64 %zmm0, %fs:RTLD_SAVESPACE_SSE+0*ZMM_SIZE
++#     vmovdqu64 %zmm1, %fs:RTLD_SAVESPACE_SSE+1*ZMM_SIZE
++#     vmovdqu64 %zmm2, %fs:RTLD_SAVESPACE_SSE+2*ZMM_SIZE
++#     vmovdqu64 %zmm3, %fs:RTLD_SAVESPACE_SSE+3*ZMM_SIZE
++#     vmovdqu64 %zmm4, %fs:RTLD_SAVESPACE_SSE+4*ZMM_SIZE
++#     vmovdqu64 %zmm5, %fs:RTLD_SAVESPACE_SSE+5*ZMM_SIZE
++#     vmovdqu64 %zmm6, %fs:RTLD_SAVESPACE_SSE+6*ZMM_SIZE
++#     vmovdqu64 %zmm7, %fs:RTLD_SAVESPACE_SSE+7*ZMM_SIZE
++# Assembled instructions:
++      .byte 0x64,0x62,0xf1,0xfe,0x48,0x7f,0x04,0x25,0x80,0x00,0x00,0x00 # vmovdqu64 %zmm0,%fs:0x80
++      .byte 0x64,0x62,0xf1,0xfe,0x48,0x7f,0x0c,0x25,0xc0,0x00,0x00,0x00 # vmovdqu64 %zmm1,%fs:0xc0
++      .byte 0x64,0x62,0xf1,0xfe,0x48,0x7f,0x14,0x25,0x00,0x01,0x00,0x00 # vmovdqu64 %zmm2,%fs:0x100
++      .byte 0x64,0x62,0xf1,0xfe,0x48,0x7f,0x1c,0x25,0x40,0x01,0x00,0x00 # vmovdqu64 %zmm3,%fs:0x140
++      .byte 0x64,0x62,0xf1,0xfe,0x48,0x7f,0x24,0x25,0x80,0x01,0x00,0x00 # vmovdqu64 %zmm4,%fs:0x180
++      .byte 0x64,0x62,0xf1,0xfe,0x48,0x7f,0x2c,0x25,0xc0,0x01,0x00,0x00 # vmovdqu64 %zmm5,%fs:0x1c0
++      .byte 0x64,0x62,0xf1,0xfe,0x48,0x7f,0x34,0x25,0x00,0x02,0x00,0x00 # vmovdqu64 %zmm6,%fs:0x200
++      .byte 0x64,0x62,0xf1,0xfe,0x48,0x7f,0x3c,0x25,0x40,0x02,0x00,0x00 # vmovdqu64 %zmm7,%fs:0x240
++      ret
+ L(no_avx5):
+ # endif
+       movdqa  %xmm0, %fs:RTLD_SAVESPACE_SSE+0*XMM_SIZE
+@@ -234,6 +303,8 @@
+ # ifdef HAVE_AVX_SUPPORT
+       cmpl    $0, L(have_avx)(%rip)
+       js      L(no_avx6)
++      cmpl    $0xe6, L(have_avx)(%rip)
++      je      L(avx512_6)
+       vmovdqa %fs:RTLD_SAVESPACE_SSE+0*YMM_SIZE, %ymm0
+       vmovdqa %fs:RTLD_SAVESPACE_SSE+1*YMM_SIZE, %ymm1
+@@ -244,6 +315,26 @@
+       vmovdqa %fs:RTLD_SAVESPACE_SSE+6*YMM_SIZE, %ymm6
+       vmovdqa %fs:RTLD_SAVESPACE_SSE+7*YMM_SIZE, %ymm7
+       ret
++L(avx512_6):
++# Original instructions:
++#     vmovdqu64 %fs:RTLD_SAVESPACE_SSE+0*ZMM_SIZE, %zmm0
++#     vmovdqu64 %fs:RTLD_SAVESPACE_SSE+1*ZMM_SIZE, %zmm1
++#     vmovdqu64 %fs:RTLD_SAVESPACE_SSE+2*ZMM_SIZE, %zmm2
++#     vmovdqu64 %fs:RTLD_SAVESPACE_SSE+3*ZMM_SIZE, %zmm3
++#     vmovdqu64 %fs:RTLD_SAVESPACE_SSE+4*ZMM_SIZE, %zmm4
++#     vmovdqu64 %fs:RTLD_SAVESPACE_SSE+5*ZMM_SIZE, %zmm5
++#     vmovdqu64 %fs:RTLD_SAVESPACE_SSE+6*ZMM_SIZE, %zmm6
++#     vmovdqu64 %fs:RTLD_SAVESPACE_SSE+7*ZMM_SIZE, %zmm7
++# Assembled instructions:
++      .byte 0x64,0x62,0xf1,0xfe,0x48,0x6f,0x04,0x25,0x80,0x00,0x00,0x00 # vmovdqu64 %fs:0x80,%zmm0
++      .byte 0x64,0x62,0xf1,0xfe,0x48,0x6f,0x0c,0x25,0xc0,0x00,0x00,0x00 # vmovdqu64 %fs:0xc0,%zmm1
++      .byte 0x64,0x62,0xf1,0xfe,0x48,0x6f,0x14,0x25,0x00,0x01,0x00,0x00 # vmovdqu64 %fs:0x100,%zmm2
++      .byte 0x64,0x62,0xf1,0xfe,0x48,0x6f,0x1c,0x25,0x40,0x01,0x00,0x00 # vmovdqu64 %fs:0x140,%zmm3
++      .byte 0x64,0x62,0xf1,0xfe,0x48,0x6f,0x24,0x25,0x80,0x01,0x00,0x00 # vmovdqu64 %fs:0x180,%zmm4
++      .byte 0x64,0x62,0xf1,0xfe,0x48,0x6f,0x2c,0x25,0xc0,0x01,0x00,0x00 # vmovdqu64 %fs:0x1c0,%zmm5
++      .byte 0x64,0x62,0xf1,0xfe,0x48,0x6f,0x34,0x25,0x00,0x02,0x00,0x00 # vmovdqu64 %fs:0x200,%zmm6
++      .byte 0x64,0x62,0xf1,0xfe,0x48,0x6f,0x3c,0x25,0x40,0x02,0x00,0x00 # vmovdqu64 %fs:0x240,%zmm7
++      ret
+ L(no_avx6):
+ # endif
+       movdqa  %fs:RTLD_SAVESPACE_SSE+0*XMM_SIZE, %xmm0
+diff -urN glibc-2.12-2-gc4ccff1/sysdeps/x86_64/link-defines.sym glibc-2.12-2-gc4ccff1.mod/sysdeps/x86_64/link-defines.sym
+--- glibc-2.12-2-gc4ccff1/sysdeps/x86_64/link-defines.sym      2010-05-04 07:27:23.000000000 -0400
++++ glibc-2.12-2-gc4ccff1.mod/sysdeps/x86_64/link-defines.sym  2015-03-03 23:03:25.042829206 -0500
+@@ -4,6 +4,8 @@
+ --
+ VECTOR_SIZE           sizeof (La_x86_64_vector)
+ XMM_SIZE              sizeof (La_x86_64_xmm)
++YMM_SIZE              sizeof (La_x86_64_ymm)
++ZMM_SIZE              sizeof (La_x86_64_zmm)
+ LR_SIZE                       sizeof (struct La_x86_64_regs)
+ LR_RDX_OFFSET         offsetof (struct La_x86_64_regs, lr_rdx)
diff --git a/src/patches/glibc/glibc-rh1207236.patch b/src/patches/glibc/glibc-rh1207236.patch
new file mode 100644 (file)
index 0000000..5671fd8
--- /dev/null
@@ -0,0 +1,12 @@
+diff -pruN glibc-2.12-2-gc4ccff1/malloc/malloc.c glibc-2.12-2-gc4ccff1.new/malloc/malloc.c
+--- glibc-2.12-2-gc4ccff1/malloc/malloc.c      2015-04-10 12:02:54.011106386 +0530
++++ glibc-2.12-2-gc4ccff1.new/malloc/malloc.c  2015-04-10 12:02:35.867958292 +0530
+@@ -5850,7 +5850,7 @@ _int_valloc(av, bytes) mstate av; size_t
+ #endif
+ {
+   /* Ensure initialization/consolidation */
+-  if (have_fastchunks(av)) malloc_consolidate(av);
++  if (av && have_fastchunks(av)) malloc_consolidate(av);
+   return _int_memalign(av, mp_.pagesize, bytes);
+ }
diff --git a/src/patches/glibc/glibc-rh1256812-2.patch b/src/patches/glibc/glibc-rh1256812-2.patch
new file mode 100644 (file)
index 0000000..5596de7
--- /dev/null
@@ -0,0 +1,15 @@
+diff -pruN glibc-2.12-2-gc4ccff1/malloc/malloc.c glibc-2.12-2-gc4ccff1.new/malloc/malloc.c
+--- glibc-2.12-2-gc4ccff1/malloc/malloc.c      2015-07-28 22:28:22.517107147 +0530
++++ glibc-2.12-2-gc4ccff1.new/malloc/malloc.c  2015-07-28 22:24:59.541394493 +0530
+@@ -4087,8 +4087,9 @@ public_cALLOc(size_t n, size_t elem_size
+     /* Maybe the failure is due to running out of mmapped areas. */
+     if(av != &main_arena) {
+       (void)mutex_unlock(&av->mutex);
+-      (void)mutex_lock(&main_arena.mutex);
+-      mem = _int_malloc(&main_arena, sz);
++      av = &main_arena;
++      (void)mutex_lock(&av->mutex);
++      mem = _int_malloc(av, sz);
+     } else {
+ #if USE_ARENAS
+       /* ... or sbrk() has failed and there is still a chance to mmap() */
diff --git a/src/patches/glibc/glibc-rh1256812-3.patch b/src/patches/glibc/glibc-rh1256812-3.patch
new file mode 100644 (file)
index 0000000..e8fbb1b
--- /dev/null
@@ -0,0 +1,138 @@
+commit fdc0f374bcd2d0513569aa8d600f960e43e8af1d
+Author: Ulrich Drepper <drepper@redhat.com>
+Date:   Sun Oct 24 22:37:00 2010 -0400
+
+    Fix perturbing in malloc on free.
+
+commit e8349efd466cfedc0aa98be61d88ca8795c9e565
+Author: Ondřej Bílka <neleai@seznam.cz>
+Date:   Mon Dec 9 17:25:19 2013 +0100
+
+    Simplify perturb_byte logic.
+
+diff --git a/malloc/malloc.c b/malloc/malloc.c
+index 4821deb..ac8c3f6 100644
+--- a/malloc/malloc.c
++++ b/malloc/malloc.c
+@@ -1870,8 +1870,20 @@ static int check_action = DEFAULT_CHECK_ACTION;
+ static int perturb_byte;
+-#define alloc_perturb(p, n) memset (p, (perturb_byte ^ 0xff) & 0xff, n)
+-#define free_perturb(p, n) memset (p, perturb_byte & 0xff, n)
++static inline void
++alloc_perturb (char *p, size_t n)
++{
++  if (__glibc_unlikely (perturb_byte))
++    memset (p, perturb_byte ^ 0xff, n);
++}
++
++static inline void
++free_perturb (char *p, size_t n)
++{
++  if (__glibc_unlikely (perturb_byte))
++    memset (p, perturb_byte, n);
++}
++
+ /* ------------------- Support for multiple arenas -------------------- */
+@@ -3287,8 +3299,7 @@ _int_malloc(mstate av, size_t bytes)
+ #endif
+       check_remalloced_chunk(av, victim, nb);
+       void *p = chunk2mem(victim);
+-      if (__builtin_expect (perturb_byte, 0))
+-      alloc_perturb (p, bytes);
++      alloc_perturb (p, bytes);
+       return p;
+     }
+   }
+@@ -3323,8 +3334,7 @@ _int_malloc(mstate av, size_t bytes)
+         victim->size |= NON_MAIN_ARENA;
+       check_malloced_chunk(av, victim, nb);
+       void *p = chunk2mem(victim);
+-      if (__builtin_expect (perturb_byte, 0))
+-        alloc_perturb (p, bytes);
++      alloc_perturb (p, bytes);
+       return p;
+       }
+     }
+@@ -3403,8 +3413,7 @@ _int_malloc(mstate av, size_t bytes)
+       check_malloced_chunk(av, victim, nb);
+       void *p = chunk2mem(victim);
+-      if (__builtin_expect (perturb_byte, 0))
+-        alloc_perturb (p, bytes);
++      alloc_perturb (p, bytes);
+       return p;
+       }
+@@ -3420,8 +3429,7 @@ _int_malloc(mstate av, size_t bytes)
+         victim->size |= NON_MAIN_ARENA;
+       check_malloced_chunk(av, victim, nb);
+       void *p = chunk2mem(victim);
+-      if (__builtin_expect (perturb_byte, 0))
+-        alloc_perturb (p, bytes);
++      alloc_perturb (p, bytes);
+       return p;
+       }
+@@ -3545,8 +3553,7 @@ _int_malloc(mstate av, size_t bytes)
+       }
+       check_malloced_chunk(av, victim, nb);
+       void *p = chunk2mem(victim);
+-      if (__builtin_expect (perturb_byte, 0))
+-        alloc_perturb (p, bytes);
++      alloc_perturb (p, bytes);
+       return p;
+       }
+     }
+@@ -3649,8 +3656,7 @@ _int_malloc(mstate av, size_t bytes)
+       }
+       check_malloced_chunk(av, victim, nb);
+       void *p = chunk2mem(victim);
+-      if (__builtin_expect (perturb_byte, 0))
+-        alloc_perturb (p, bytes);
++      alloc_perturb (p, bytes);
+       return p;
+       }
+     }
+@@ -3684,8 +3690,7 @@ _int_malloc(mstate av, size_t bytes)
+       check_malloced_chunk(av, victim, nb);
+       void *p = chunk2mem(victim);
+-      if (__builtin_expect (perturb_byte, 0))
+-      alloc_perturb (p, bytes);
++      alloc_perturb (p, bytes);
+       return p;
+     }
+@@ -3705,7 +3710,7 @@ _int_malloc(mstate av, size_t bytes)
+     */
+     else {
+       void *p = sYSMALLOc(nb, av);
+-      if (p != NULL && __builtin_expect (perturb_byte, 0))
++      if (p != NULL)
+       alloc_perturb (p, bytes);
+       return p;
+     }
+@@ -3798,8 +3803,7 @@ _int_free(mstate av, mchunkptr p, int have_lock)
+ #endif
+       }
+-    if (__builtin_expect (perturb_byte, 0))
+-      free_perturb (chunk2mem(p), size - SIZE_SZ);
++    free_perturb (chunk2mem(p), size - 2 * SIZE_SZ);
+     set_fastchunks(av);
+     unsigned int idx = fastbin_index(size);
+@@ -3881,8 +3885,7 @@ _int_free(mstate av, mchunkptr p, int have_lock)
+       goto errout;
+       }
+-    if (__builtin_expect (perturb_byte, 0))
+-      free_perturb (chunk2mem(p), size - SIZE_SZ);
++    free_perturb (chunk2mem(p), size - 2 * SIZE_SZ);
+     /* consolidate backward */
+     if (!prev_inuse(p)) {
diff --git a/src/patches/glibc/glibc-rh1256812-4.patch b/src/patches/glibc/glibc-rh1256812-4.patch
new file mode 100644 (file)
index 0000000..1e497f3
--- /dev/null
@@ -0,0 +1,45 @@
+commit 55765a349a96482207fbf927d3666a51878f973b
+Author: Josef Bacik <josef@toxicpanda.com>
+Date:   Wed Aug 19 14:06:56 2015 +0530
+
+    Don't fall back to mmap if the original arena is not corrupt
+    
+    The new logic to find an uncontended non-corrupt arena misses a case
+    where the current arena is contended, but is not corrupt.  In the
+    degenerate case, this is the only arena.  In both cases, the logic
+    falls back to using mmap despite there being an available arena.
+    
+    Attached patch by Josef Bacik makes sure that all arenas are indeed
+    corrupt before falling back to malloc.  Verified on x86_64.
+    
+       * malloc/arena.c (reused_arena): return NULL only if all
+       arenas are corrupt.
+
+diff --git a/malloc/arena.c b/malloc/arena.c
+index 21ecc5a1..0424273 100644
+--- a/malloc/arena.c
++++ b/malloc/arena.c
+@@ -823,16 +823,21 @@ reused_arena (mstate avoid_arena)
+   /* Make sure that the arena we get is not corrupted.  */
+   mstate begin = result;
++  bool looped = false;
++
+   while (arena_is_corrupt (result))
+     {
+       result = result->next;
+       if (result == begin)
+-       break;
++      {
++        looped = true;
++        break;
++      }
+     }
+   /* We could not find any arena that was either not corrupted or not the one
+      we wanted to avoid.  */
+-  if (result == begin)
++  if (looped)
+     return NULL;
+   /* No arena available without contention.  Wait for the next in line.  */
diff --git a/src/patches/glibc/glibc-rh1256812.patch b/src/patches/glibc/glibc-rh1256812.patch
new file mode 100644 (file)
index 0000000..1eafcc1
--- /dev/null
@@ -0,0 +1,56 @@
+diff -pruN glibc-2.12-2-gc4ccff1/malloc/malloc.c glibc-2.12-2-gc4ccff1.v2/malloc/malloc.c
+--- glibc-2.12-2-gc4ccff1/malloc/malloc.c      2015-07-24 19:29:37.679907396 +0530
++++ glibc-2.12-2-gc4ccff1.v2/malloc/malloc.c   2015-07-24 18:59:59.928055174 +0530
+@@ -3737,8 +3737,7 @@ public_mALLOc(size_t bytes)
+       mstate prev = ar_ptr->next ? ar_ptr : 0;
+       (void)mutex_unlock(&ar_ptr->mutex);
+       ar_ptr = arena_get2(prev, bytes, true);
+-      if(ar_ptr)
+-      victim = _int_malloc(ar_ptr, bytes);
++      victim = _int_malloc(ar_ptr, bytes);
+ #endif
+     }
+   }
+@@ -3968,8 +3967,7 @@ public_mEMALIGn(size_t alignment, size_t
+       mstate prev = ar_ptr->next ? ar_ptr : 0;
+       (void)mutex_unlock(&ar_ptr->mutex);
+       ar_ptr = arena_get2(prev, bytes, true);
+-      if(ar_ptr)
+-      p = _int_memalign(ar_ptr, alignment, bytes);
++      p = _int_memalign(ar_ptr, alignment, bytes);
+ #endif
+     }
+   }
+@@ -4024,8 +4022,7 @@ public_vALLOc(size_t bytes)
+       mstate prev = ar_ptr->next ? ar_ptr : 0;
+       (void)mutex_unlock(&ar_ptr->mutex);
+       ar_ptr = arena_get2(prev, bytes, true);
+-      if(ar_ptr)
+-      p = _int_memalign(ar_ptr, pagesz, bytes);
++      p = _int_memalign(ar_ptr, pagesz, bytes);
+ #endif
+     }
+   }
+@@ -4080,8 +4077,7 @@ public_pVALLOc(size_t bytes)
+       mstate prev = ar_ptr->next ? ar_ptr : 0;
+       (void)mutex_unlock(&ar_ptr->mutex);
+       ar_ptr = arena_get2(prev, bytes + 2*pagesz + MINSIZE, true);
+-      if(ar_ptr)
+-      p = _int_memalign(ar_ptr, pagesz, rounded_bytes);
++      p = _int_memalign(ar_ptr, pagesz, rounded_bytes);
+ #endif
+     }
+   }
+@@ -4180,11 +4176,9 @@ public_cALLOc(size_t n, size_t elem_size
+       mstate prev = av->next ? av : 0;
+       (void)mutex_unlock(&av->mutex);
+       av = arena_get2(prev, sz, true);
+-      if(av)
+-      mem = _int_malloc(av, sz);
++      mem = _int_malloc(av, sz);
+ #endif
+     }
+-    if (mem == 0) return 0;
+   }
+   if (av != NULL)
diff --git a/src/patches/glibc/glibc-rh1256890.patch b/src/patches/glibc/glibc-rh1256890.patch
new file mode 100644 (file)
index 0000000..4683dc4
--- /dev/null
@@ -0,0 +1,12 @@
+diff -pruN glibc-2.12-2-gc4ccff1/malloc/malloc.c glibc-2.12-2-gc4ccff1.new/malloc/malloc.c
+--- glibc-2.12-2-gc4ccff1/malloc/malloc.c      2015-08-19 23:13:52.826205930 +0530
++++ glibc-2.12-2-gc4ccff1.new/malloc/malloc.c  2015-08-19 23:13:40.021049289 +0530
+@@ -5867,7 +5867,7 @@ _int_pvalloc(av, bytes) mstate av, size_
+   size_t pagesz;
+   /* Ensure initialization/consolidation */
+-  if (have_fastchunks(av)) malloc_consolidate(av);
++  if (av && have_fastchunks(av)) malloc_consolidate(av);
+   pagesz = mp_.pagesize;
+   return _int_memalign(av, pagesz, (bytes + pagesz - 1) & ~(pagesz - 1));
+ }
diff --git a/src/patches/glibc/glibc-rh1256891.patch b/src/patches/glibc/glibc-rh1256891.patch
new file mode 100644 (file)
index 0000000..5364dba
--- /dev/null
@@ -0,0 +1,26 @@
+commit 5c44738353ecaa1c81efca063ee8b55e092d7a43
+Author: Alexandre Oliva <aoliva@redhat.com>
+Date:   Wed Sep 5 15:43:04 2012 -0300
+
+    Don't change no_dyn_threshold on mallopt failure
+    
+       * malloc/malloc.c (__libc_mallopt) <M_MMAP_THRESHOLD>: Do not
+       change internal state upon failure.
+
+diff --git a/malloc/malloc.c b/malloc/malloc.c
+index bd562df..c69e281 100644
+--- a/malloc/malloc.c
++++ b/malloc/malloc.c
+@@ -4769,8 +4769,10 @@ int __libc_mallopt(int param_number, int value)
+       res = 0;
+     else
+ #endif
+-      mp_.mmap_threshold = value;
+-      mp_.no_dyn_threshold = 1;
++      {
++      mp_.mmap_threshold = value;
++      mp_.no_dyn_threshold = 1;
++      }
+     break;
+   case M_MMAP_MAX:
diff --git a/src/patches/glibc/glibc-rh1291270.patch b/src/patches/glibc/glibc-rh1291270.patch
new file mode 100644 (file)
index 0000000..8d12d95
--- /dev/null
@@ -0,0 +1,41 @@
+Description: Allow loading more libraries with static TLS.
+Author: Carlos O'Donell <codonell@redhat.com>
+Origin: PATCH
+Bug-RHEL: #1291270 (rhel-6.7.z), #1198802 (rhel-6.8), #1202952 (rhel-7.2)
+Bug-Fedora: #1124987 (F21)
+Bug-Upstream: #17090, #17620, #17621, #17628 (2.22)
+Upstream status: not-needed
+#
+# The correct fix for this is already upstream and involves
+# changing the heuristics for DTV slot increases. In RHEL6
+# we take the conservative approach and provide a larger
+# slot surplus. This matches what was done in Fedora 21 before
+# we had the upstream fix: f8aeae347377f3dfa8cbadde057adf1827fb1d44.
+# In RHEL7 we have the upstream fix. This is fixed upstream as of
+# glibc 2.22.
+#
+Index: glibc-2.12-2-gc4ccff1/sysdeps/generic/ldsodefs.h
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/sysdeps/generic/ldsodefs.h
++++ glibc-2.12-2-gc4ccff1/sysdeps/generic/ldsodefs.h
+@@ -496,8 +496,18 @@ struct rtld_global
+    have to iterate beyond the first element in the slotinfo list.  */
+ #define TLS_SLOTINFO_SURPLUS (62)
+-/* Number of additional slots in the dtv allocated.  */
+-#define DTV_SURPLUS   (14)
++/* Number of additional allocated dtv slots.  This was initially
++   14, but problems with python, MESA, and X11's uses of static TLS meant
++   that most distributions were very close to this limit when they loaded
++   dynamically interpreted languages that used graphics. The simplest
++   solution was to roughly double the number of slots. The actual static
++   image space usage was relatively small, for example in MESA you
++   had only two dispatch pointers for a total of 16 bytes.  If we hit up
++   against this limit again we should start a campaign with the
++   distributions to coordinate the usage of static TLS.  Any user of this
++   resource is effectively coordinating a global resource since this
++   surplus is allocated for each thread at startup.  */
++#define DTV_SURPLUS   (32)
+   /* Initial dtv of the main thread, not allocated with normal malloc.  */
+   EXTERN void *_dl_initial_dtv;
diff --git a/src/patches/glibc/glibc-rh1296031-0.patch b/src/patches/glibc/glibc-rh1296031-0.patch
new file mode 100644 (file)
index 0000000..d44e491
--- /dev/null
@@ -0,0 +1,465 @@
+Sourceware bug 16574
+
+commit d668061994a7486a3ba9c7d5e7882d85a2883707
+Author: Andreas Schwab <schwab@suse.de>
+Date:   Thu Feb 13 11:01:57 2014 +0100
+
+    Fix memory leak in _nss_dns_gethostbyname4_r with big DNS answer
+
+commit ab7ac0f2cf8731fe4c3f3aea6088a7c0127b5725
+Author: Ondřej Bílka <neleai@seznam.cz>
+Date:   Sun Feb 16 12:59:23 2014 +0100
+
+    Deduplicate resolv/nss_dns/dns-host.c
+    
+    In resolv/nss_dns/dns-host.c one of code path duplicated code after
+    that. We merge these paths.
+
+commit ab09bf616ad527b249aca5f2a4956fd526f0712f
+Author: Andreas Schwab <schwab@suse.de>
+Date:   Tue Feb 18 10:57:25 2014 +0100
+
+    Properly fix memory leak in _nss_dns_gethostbyname4_r with big DNS answer
+    
+    Instead of trying to guess whether the second buffer needs to be freed
+    set a flag at the place it is allocated
+
+Index: glibc-2.12-2-gc4ccff1/include/resolv.h
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/include/resolv.h
++++ glibc-2.12-2-gc4ccff1/include/resolv.h
+@@ -58,11 +58,11 @@ libc_hidden_proto (__res_randomid)
+ libc_hidden_proto (__res_state)
+ int __libc_res_nquery (res_state, const char *, int, int, u_char *, int,
+-                     u_char **, u_char **, int *, int *);
++                     u_char **, u_char **, int *, int *, int *);
+ int __libc_res_nsearch (res_state, const char *, int, int, u_char *, int,
+-                      u_char **, u_char **, int *, int *);
++                      u_char **, u_char **, int *, int *, int *);
+ int __libc_res_nsend (res_state, const u_char *, int, const u_char *, int,
+-                    u_char *, int, u_char **, u_char **, int *, int *)
++                    u_char *, int, u_char **, u_char **, int *, int *, int *)
+   attribute_hidden;
+ libresolv_hidden_proto (_sethtent)
+Index: glibc-2.12-2-gc4ccff1/resolv/gethnamaddr.c
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/resolv/gethnamaddr.c
++++ glibc-2.12-2-gc4ccff1/resolv/gethnamaddr.c
+@@ -634,7 +634,7 @@ gethostbyname2(name, af)
+       buf.buf = origbuf = (querybuf *) alloca (1024);
+       if ((n = __libc_res_nsearch(&_res, name, C_IN, type, buf.buf->buf, 1024,
+-                                  &buf.ptr, NULL, NULL, NULL)) < 0) {
++                                  &buf.ptr, NULL, NULL, NULL, NULL)) < 0) {
+               if (buf.buf != origbuf)
+                       free (buf.buf);
+               Dprintf("res_nsearch failed (%d)\n", n);
+@@ -729,12 +729,12 @@ gethostbyaddr(addr, len, af)
+       buf.buf = orig_buf = (querybuf *) alloca (1024);
+       n = __libc_res_nquery(&_res, qbuf, C_IN, T_PTR, buf.buf->buf, 1024,
+-                            &buf.ptr, NULL, NULL, NULL);
++                            &buf.ptr, NULL, NULL, NULL, NULL);
+       if (n < 0 && af == AF_INET6 && (_res.options & RES_NOIP6DOTINT) == 0) {
+               strcpy(qp, "ip6.int");
+               n = __libc_res_nquery(&_res, qbuf, C_IN, T_PTR, buf.buf->buf,
+                                     buf.buf != orig_buf ? MAXPACKET : 1024,
+-                                    &buf.ptr, NULL, NULL, NULL);
++                                    &buf.ptr, NULL, NULL, NULL, NULL);
+       }
+       if (n < 0) {
+               if (buf.buf != orig_buf)
+Index: glibc-2.12-2-gc4ccff1/resolv/nss_dns/dns-canon.c
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/resolv/nss_dns/dns-canon.c
++++ glibc-2.12-2-gc4ccff1/resolv/nss_dns/dns-canon.c
+@@ -62,7 +62,7 @@ _nss_dns_getcanonname_r (const char *nam
+     {
+       int r = __libc_res_nquery (&_res, name, ns_c_in, qtypes[i],
+                                buf, sizeof (buf), &ansp.ptr, NULL, NULL,
+-                               NULL);
++                               NULL, NULL);
+       if (r > 0)
+       {
+         /* We need to decode the response.  Just one question record.
+Index: glibc-2.12-2-gc4ccff1/resolv/nss_dns/dns-host.c
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/resolv/nss_dns/dns-host.c
++++ glibc-2.12-2-gc4ccff1/resolv/nss_dns/dns-host.c
+@@ -191,7 +191,7 @@ _nss_dns_gethostbyname3_r (const char *n
+   host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024);
+   n = __libc_res_nsearch (&_res, name, C_IN, type, host_buffer.buf->buf,
+-                        1024, &host_buffer.ptr, NULL, NULL, NULL);
++                        1024, &host_buffer.ptr, NULL, NULL, NULL, NULL);
+   if (n < 0)
+     {
+       switch (errno)
+@@ -221,7 +221,7 @@ _nss_dns_gethostbyname3_r (const char *n
+       n = __libc_res_nsearch (&_res, name, C_IN, T_A, host_buffer.buf->buf,
+                               host_buffer.buf != orig_host_buffer
+                               ? MAXPACKET : 1024, &host_buffer.ptr,
+-                              NULL, NULL, NULL);
++                              NULL, NULL, NULL, NULL);
+       if (n < 0)
+       {
+@@ -304,13 +304,20 @@ _nss_dns_gethostbyname4_r (const char *n
+   u_char *ans2p = NULL;
+   int nans2p = 0;
+   int resplen2 = 0;
++  int ans2p_malloced = 0;
+   int olderr = errno;
+   enum nss_status status;
+   int n = __libc_res_nsearch (&_res, name, C_IN, T_UNSPEC,
+                             host_buffer.buf->buf, 2048, &host_buffer.ptr,
+-                            &ans2p, &nans2p, &resplen2);
+-  if (n < 0)
++                            &ans2p, &nans2p, &resplen2, &ans2p_malloced);
++  if (n >= 0)
++    {
++      status = gaih_getanswer (host_buffer.buf, n, (const querybuf *) ans2p,
++                             resplen2, name, pat, buffer, buflen,
++                             errnop, herrnop, ttlp);
++    }
++  else
+     {
+       if (errno == ESRCH)
+       {
+@@ -325,16 +332,11 @@ _nss_dns_gethostbyname4_r (const char *n
+       *errnop = EAGAIN;
+       else
+       __set_errno (olderr);
+-
+-      if (host_buffer.buf != orig_host_buffer)
+-      free (host_buffer.buf);
+-
+-      return status;
+     }
+-  status = gaih_getanswer(host_buffer.buf, n, (const querybuf *) ans2p,
+-                        resplen2, name, pat, buffer, buflen,
+-                        errnop, herrnop, ttlp);
++  /* Check whether ans2p was separately allocated.  */
++  if (ans2p_malloced)
++    free (ans2p);
+   if (host_buffer.buf != orig_host_buffer)
+     free (host_buffer.buf);
+@@ -444,7 +446,7 @@ _nss_dns_gethostbyaddr2_r (const void *a
+         strcpy (qp, "].ip6.arpa");
+         n = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR,
+                                host_buffer.buf->buf, 1024, &host_buffer.ptr,
+-                               NULL, NULL, NULL);
++                               NULL, NULL, NULL, NULL);
+         if (n >= 0)
+           goto got_it_already;
+       }
+@@ -465,14 +467,14 @@ _nss_dns_gethostbyaddr2_r (const void *a
+     }
+   n = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR, host_buffer.buf->buf,
+-                       1024, &host_buffer.ptr, NULL, NULL, NULL);
++                       1024, &host_buffer.ptr, NULL, NULL, NULL, NULL);
+   if (n < 0 && af == AF_INET6 && (_res.options & RES_NOIP6DOTINT) == 0)
+     {
+       strcpy (qp, "ip6.int");
+       n = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR, host_buffer.buf->buf,
+                            host_buffer.buf != orig_host_buffer
+                            ? MAXPACKET : 1024, &host_buffer.ptr,
+-                           NULL, NULL, NULL);
++                           NULL, NULL, NULL, NULL);
+     }
+   if (n < 0)
+     {
+Index: glibc-2.12-2-gc4ccff1/resolv/nss_dns/dns-network.c
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/resolv/nss_dns/dns-network.c
++++ glibc-2.12-2-gc4ccff1/resolv/nss_dns/dns-network.c
+@@ -130,7 +130,7 @@ _nss_dns_getnetbyname_r (const char *nam
+   net_buffer.buf = orig_net_buffer = (querybuf *) alloca (1024);
+   anslen = __libc_res_nsearch (&_res, qbuf, C_IN, T_PTR, net_buffer.buf->buf,
+-                             1024, &net_buffer.ptr, NULL, NULL, NULL);
++                             1024, &net_buffer.ptr, NULL, NULL, NULL, NULL);
+   if (anslen < 0)
+     {
+       /* Nothing found.  */
+@@ -206,7 +206,7 @@ _nss_dns_getnetbyaddr_r (uint32_t net, i
+   net_buffer.buf = orig_net_buffer = (querybuf *) alloca (1024);
+   anslen = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR, net_buffer.buf->buf,
+-                            1024, &net_buffer.ptr, NULL, NULL, NULL);
++                            1024, &net_buffer.ptr, NULL, NULL, NULL, NULL);
+   if (anslen < 0)
+     {
+       /* Nothing found.  */
+Index: glibc-2.12-2-gc4ccff1/resolv/res_query.c
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/resolv/res_query.c
++++ glibc-2.12-2-gc4ccff1/resolv/res_query.c
+@@ -98,7 +98,7 @@ static int
+ __libc_res_nquerydomain(res_state statp, const char *name, const char *domain,
+                       int class, int type, u_char *answer, int anslen,
+                       u_char **answerp, u_char **answerp2, int *nanswerp2,
+-                      int *resplen2);
++                      int *resplen2, int *answerp2_malloced);
+ /*
+  * Formulate a normal query, send, and await answer.
+@@ -119,7 +119,8 @@ __libc_res_nquery(res_state statp,
+                 u_char **answerp,     /* if buffer needs to be enlarged */
+                 u_char **answerp2,
+                 int *nanswerp2,
+-                int *resplen2)
++                int *resplen2,
++                int *answerp2_malloced)
+ {
+       HEADER *hp = (HEADER *) answer;
+       HEADER *hp2;
+@@ -224,7 +225,8 @@ __libc_res_nquery(res_state statp,
+       }
+       assert (answerp == NULL || (void *) *answerp == (void *) answer);
+       n = __libc_res_nsend(statp, query1, nquery1, query2, nquery2, answer,
+-                           anslen, answerp, answerp2, nanswerp2, resplen2);
++                           anslen, answerp, answerp2, nanswerp2, resplen2,
++                           answerp2_malloced);
+       if (use_malloc)
+               free (buf);
+       if (n < 0) {
+@@ -316,7 +318,7 @@ res_nquery(res_state statp,
+          int anslen)          /* size of answer buffer */
+ {
+       return __libc_res_nquery(statp, name, class, type, answer, anslen,
+-                               NULL, NULL, NULL, NULL);
++                               NULL, NULL, NULL, NULL, NULL);
+ }
+ libresolv_hidden_def (res_nquery)
+@@ -335,7 +337,8 @@ __libc_res_nsearch(res_state statp,
+                  u_char **answerp,
+                  u_char **answerp2,
+                  int *nanswerp2,
+-                 int *resplen2)
++                 int *resplen2,
++                 int *answerp2_malloced)
+ {
+       const char *cp, * const *domain;
+       HEADER *hp = (HEADER *) answer;
+@@ -359,7 +362,7 @@ __libc_res_nsearch(res_state statp,
+       if (!dots && (cp = res_hostalias(statp, name, tmp, sizeof tmp))!= NULL)
+               return (__libc_res_nquery(statp, cp, class, type, answer,
+                                         anslen, answerp, answerp2,
+-                                        nanswerp2, resplen2));
++                                        nanswerp2, resplen2, answerp2_malloced));
+ #ifdef DEBUG
+       if (statp->options & RES_DEBUG)
+@@ -376,7 +379,8 @@ __libc_res_nsearch(res_state statp,
+       if (dots >= statp->ndots || trailing_dot) {
+               ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
+                                             answer, anslen, answerp,
+-                                            answerp2, nanswerp2, resplen2);
++                                            answerp2, nanswerp2, resplen2,
++                                            answerp2_malloced);
+               if (ret > 0 || trailing_dot
+                   /* If the second response is valid then we use that.  */
+                   || (ret == 0 && resplen2 != NULL && *resplen2 > 0))
+@@ -387,12 +391,12 @@ __libc_res_nsearch(res_state statp,
+                       answer = *answerp;
+                       anslen = MAXPACKET;
+               }
+-              if (answerp2
+-                  && (*answerp2 < answer || *answerp2 >= answer + anslen))
++              if (answerp2 && *answerp2_malloced)
+                 {
+                   free (*answerp2);
+                   *nanswerp2 = 0;
+                   *answerp2 = NULL;
++                  *answerp2_malloced = 0;
+                 }
+       }
+@@ -418,7 +422,7 @@ __libc_res_nsearch(res_state statp,
+                                                     class, type,
+                                                     answer, anslen, answerp,
+                                                     answerp2, nanswerp2,
+-                                                    resplen2);
++                                                    resplen2, answerp2_malloced);
+                       if (ret > 0 || (ret == 0 && resplen2 != NULL
+                                       && *resplen2 > 0))
+                               return (ret);
+@@ -427,13 +431,12 @@ __libc_res_nsearch(res_state statp,
+                               answer = *answerp;
+                               anslen = MAXPACKET;
+                       }
+-                      if (answerp2
+-                          && (*answerp2 < answer
+-                              || *answerp2 >= answer + anslen))
++                      if (answerp2 && *answerp2_malloced)
+                         {
+                           free (*answerp2);
+                           *nanswerp2 = 0;
+                           *answerp2 = NULL;
++                          *answerp2_malloced = 0;
+                         }
+                       /*
+@@ -489,7 +492,8 @@ __libc_res_nsearch(res_state statp,
+       if (dots && !(tried_as_is || root_on_list)) {
+               ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
+                                             answer, anslen, answerp,
+-                                            answerp2, nanswerp2, resplen2);
++                                            answerp2, nanswerp2, resplen2,
++                                            answerp2_malloced);
+               if (ret > 0 || (ret == 0 && resplen2 != NULL
+                               && *resplen2 > 0))
+                       return (ret);
+@@ -502,11 +506,12 @@ __libc_res_nsearch(res_state statp,
+        * else send back meaningless H_ERRNO, that being the one from
+        * the last DNSRCH we did.
+        */
+-      if (answerp2 && (*answerp2 < answer || *answerp2 >= answer + anslen))
++      if (answerp2 && *answerp2_malloced)
+         {
+           free (*answerp2);
+-          *nanswerp2 = NULL;
++          *nanswerp2 = 0;
+           *answerp2 = NULL;
++          *answerp2_malloced = 0;
+         }
+       if (saved_herrno != -1)
+               RES_SET_H_ERRNO(statp, saved_herrno);
+@@ -526,7 +531,7 @@ res_nsearch(res_state statp,
+           int anslen)         /* size of answer */
+ {
+       return __libc_res_nsearch(statp, name, class, type, answer,
+-                                anslen, NULL, NULL, NULL, NULL);
++                                anslen, NULL, NULL, NULL, NULL, NULL);
+ }
+ libresolv_hidden_def (res_nsearch)
+@@ -544,7 +549,8 @@ __libc_res_nquerydomain(res_state statp,
+                       u_char **answerp,
+                       u_char **answerp2,
+                       int *nanswerp2,
+-                      int *resplen2)
++                      int *resplen2,
++                      int *answerp2_malloced)
+ {
+       char nbuf[MAXDNAME];
+       const char *longname = nbuf;
+@@ -582,7 +588,7 @@ __libc_res_nquerydomain(res_state statp,
+       }
+       return (__libc_res_nquery(statp, longname, class, type, answer,
+                                 anslen, answerp, answerp2, nanswerp2,
+-                                resplen2));
++                                resplen2, answerp2_malloced));
+ }
+ int
+@@ -594,7 +600,8 @@ res_nquerydomain(res_state statp,
+           int anslen)         /* size of answer */
+ {
+       return __libc_res_nquerydomain(statp, name, domain, class, type,
+-                                     answer, anslen, NULL, NULL, NULL, NULL);
++                                     answer, anslen, NULL, NULL, NULL, NULL,
++                                     NULL);
+ }
+ libresolv_hidden_def (res_nquerydomain)
+Index: glibc-2.12-2-gc4ccff1/resolv/res_send.c
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/resolv/res_send.c
++++ glibc-2.12-2-gc4ccff1/resolv/res_send.c
+@@ -203,12 +203,12 @@ evNowTime(struct timespec *res) {
+ static int            send_vc(res_state, const u_char *, int,
+                               const u_char *, int,
+                               u_char **, int *, int *, int, u_char **,
+-                              u_char **, int *, int *);
++                              u_char **, int *, int *, int *);
+ static int            send_dg(res_state, const u_char *, int,
+                               const u_char *, int,
+                               u_char **, int *, int *, int,
+                               int *, int *, u_char **,
+-                              u_char **, int *, int *);
++                              u_char **, int *, int *, int *);
+ #ifdef DEBUG
+ static void           Aerror(const res_state, FILE *, const char *, int,
+                              const struct sockaddr *);
+@@ -360,7 +360,7 @@ int
+ __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
+                const u_char *buf2, int buflen2,
+                u_char *ans, int anssiz, u_char **ansp, u_char **ansp2,
+-               int *nansp2, int *resplen2)
++               int *nansp2, int *resplen2, int *ansp2_malloced)
+ {
+   int gotsomewhere, terrno, try, v_circuit, resplen, ns, n;
+@@ -565,7 +565,8 @@ __libc_res_nsend(res_state statp, const
+                       try = statp->retry;
+                       n = send_vc(statp, buf, buflen, buf2, buflen2,
+                                   &ans, &anssiz, &terrno,
+-                                  ns, ansp, ansp2, nansp2, resplen2);
++                                  ns, ansp, ansp2, nansp2, resplen2,
++                                  ansp2_malloced);
+                       if (n < 0)
+                               return (-1);
+                       if (n == 0 && (buf2 == NULL || *resplen2 == 0))
+@@ -575,7 +576,7 @@ __libc_res_nsend(res_state statp, const
+                       n = send_dg(statp, buf, buflen, buf2, buflen2,
+                                   &ans, &anssiz, &terrno,
+                                   ns, &v_circuit, &gotsomewhere, ansp,
+-                                  ansp2, nansp2, resplen2);
++                                  ansp2, nansp2, resplen2, ansp2_malloced);
+                       if (n < 0)
+                               return (-1);
+                       if (n == 0 && (buf2 == NULL || *resplen2 == 0))
+@@ -665,7 +666,7 @@ res_nsend(res_state statp,
+         const u_char *buf, int buflen, u_char *ans, int anssiz)
+ {
+   return __libc_res_nsend(statp, buf, buflen, NULL, 0, ans, anssiz,
+-                        NULL, NULL, NULL, NULL);
++                        NULL, NULL, NULL, NULL, NULL);
+ }
+ libresolv_hidden_def (res_nsend)
+@@ -747,7 +748,7 @@ send_vc(res_state statp,
+       const u_char *buf, int buflen, const u_char *buf2, int buflen2,
+       u_char **ansp, int *anssizp,
+       int *terrno, int ns, u_char **anscp, u_char **ansp2, int *anssizp2,
+-      int *resplen2)
++      int *resplen2, int *ansp2_malloced)
+ {
+       const HEADER *hp = (HEADER *) buf;
+       const HEADER *hp2 = (HEADER *) buf2;
+@@ -896,6 +897,8 @@ send_vc(res_state statp,
+                       }
+                       *thisanssizp = MAXPACKET;
+                       *thisansp = newp;
++                      if (thisansp == ansp2)
++                        *ansp2_malloced = 1;
+                       anhp = (HEADER *) newp;
+                       /* A uint16_t can't be larger than MAXPACKET
+                          thus it's safe to allocate MAXPACKET but
+@@ -1128,7 +1131,7 @@ send_dg(res_state statp,
+       const u_char *buf, int buflen, const u_char *buf2, int buflen2,
+       u_char **ansp, int *anssizp,
+       int *terrno, int ns, int *v_circuit, int *gotsomewhere, u_char **anscp,
+-      u_char **ansp2, int *anssizp2, int *resplen2)
++      u_char **ansp2, int *anssizp2, int *resplen2, int *ansp2_malloced)
+ {
+       const HEADER *hp = (HEADER *) buf;
+       const HEADER *hp2 = (HEADER *) buf2;
+@@ -1289,6 +1292,8 @@ send_dg(res_state statp,
+                       if (newp != NULL) {
+                               *thisanssizp = MAXPACKET;
+                               *thisansp = newp;
++                              if (thisansp == ansp2)
++                                *ansp2_malloced = 1;
+                       }
+               }
+               /* We could end up with truncation if anscp was NULL
diff --git a/src/patches/glibc/glibc-rh1296031.patch b/src/patches/glibc/glibc-rh1296031.patch
new file mode 100644 (file)
index 0000000..c430abb
--- /dev/null
@@ -0,0 +1,544 @@
+Index: glibc-2.12-2-gc4ccff1/resolv/nss_dns/dns-host.c
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/resolv/nss_dns/dns-host.c
++++ glibc-2.12-2-gc4ccff1/resolv/nss_dns/dns-host.c
+@@ -1043,7 +1043,10 @@ gaih_getanswer_slice (const querybuf *an
+   int h_namelen = 0;
+   if (ancount == 0)
+-    return NSS_STATUS_NOTFOUND;
++    {
++      *h_errnop = HOST_NOT_FOUND;
++      return NSS_STATUS_NOTFOUND;
++    }
+   while (ancount-- > 0 && cp < end_of_message && had_error == 0)
+     {
+@@ -1217,7 +1220,14 @@ gaih_getanswer_slice (const querybuf *an
+   /* Special case here: if the resolver sent a result but it only
+      contains a CNAME while we are looking for a T_A or T_AAAA record,
+      we fail with NOTFOUND instead of TRYAGAIN.  */
+-  return canon == NULL ? NSS_STATUS_TRYAGAIN : NSS_STATUS_NOTFOUND;
++  if (canon != NULL)
++    {
++      *h_errnop = HOST_NOT_FOUND;
++      return NSS_STATUS_NOTFOUND;
++    }
++
++  *h_errnop = NETDB_INTERNAL;
++  return NSS_STATUS_TRYAGAIN;
+ }
+@@ -1231,11 +1241,101 @@ gaih_getanswer (const querybuf *answer1,
+   enum nss_status status = NSS_STATUS_NOTFOUND;
++  /* Combining the NSS status of two distinct queries requires some
++     compromise and attention to symmetry (A or AAAA queries can be
++     returned in any order).  What follows is a breakdown of how this
++     code is expected to work and why. We discuss only SUCCESS,
++     TRYAGAIN, NOTFOUND and UNAVAIL, since they are the only returns
++     that apply (though RETURN and MERGE exist).  We make a distinction
++     between TRYAGAIN (recoverable) and TRYAGAIN' (not-recoverable).
++     A recoverable TRYAGAIN is almost always due to buffer size issues
++     and returns ERANGE in errno and the caller is expected to retry
++     with a larger buffer.
++
++     Lastly, you may be tempted to make significant changes to the
++     conditions in this code to bring about symmetry between responses.
++     Please don't change anything without due consideration for
++     expected application behaviour.  Some of the synthesized responses
++     aren't very well thought out and sometimes appear to imply that
++     IPv4 responses are always answer 1, and IPv6 responses are always
++     answer 2, but that's not true (see the implemetnation of send_dg
++     and send_vc to see response can arrive in any order, particlarly
++     for UDP). However, we expect it holds roughly enough of the time
++     that this code works, but certainly needs to be fixed to make this
++     a more robust implementation.
++
++     ----------------------------------------------
++     | Answer 1 Status /   | Synthesized | Reason |
++     | Answer 2 Status     | Status      |        |
++     |--------------------------------------------|
++     | SUCCESS/SUCCESS     | SUCCESS     | [1]    |
++     | SUCCESS/TRYAGAIN    | TRYAGAIN    | [5]    |
++     | SUCCESS/TRYAGAIN'   | SUCCESS     | [1]    |
++     | SUCCESS/NOTFOUND    | SUCCESS     | [1]    |
++     | SUCCESS/UNAVAIL     | SUCCESS     | [1]    |
++     | TRYAGAIN/SUCCESS    | TRYAGAIN    | [2]    |
++     | TRYAGAIN/TRYAGAIN   | TRYAGAIN    | [2]    |
++     | TRYAGAIN/TRYAGAIN'  | TRYAGAIN    | [2]    |
++     | TRYAGAIN/NOTFOUND   | TRYAGAIN    | [2]    |
++     | TRYAGAIN/UNAVAIL    | TRYAGAIN    | [2]    |
++     | TRYAGAIN'/SUCCESS   | SUCCESS     | [3]    |
++     | TRYAGAIN'/TRYAGAIN  | TRYAGAIN    | [3]    |
++     | TRYAGAIN'/TRYAGAIN' | TRYAGAIN'   | [3]    |
++     | TRYAGAIN'/NOTFOUND  | TRYAGAIN'   | [3]    |
++     | TRYAGAIN'/UNAVAIL   | UNAVAIL     | [3]    |
++     | NOTFOUND/SUCCESS    | SUCCESS     | [3]    |
++     | NOTFOUND/TRYAGAIN   | TRYAGAIN    | [3]    |
++     | NOTFOUND/TRYAGAIN'  | TRYAGAIN'   | [3]    |
++     | NOTFOUND/NOTFOUND   | NOTFOUND    | [3]    |
++     | NOTFOUND/UNAVAIL    | UNAVAIL     | [3]    |
++     | UNAVAIL/SUCCESS     | UNAVAIL     | [4]    |
++     | UNAVAIL/TRYAGAIN    | UNAVAIL     | [4]    |
++     | UNAVAIL/TRYAGAIN'   | UNAVAIL     | [4]    |
++     | UNAVAIL/NOTFOUND    | UNAVAIL     | [4]    |
++     | UNAVAIL/UNAVAIL     | UNAVAIL     | [4]    |
++     ----------------------------------------------
++
++     [1] If the first response is a success we return success.
++         This ignores the state of the second answer and in fact
++         incorrectly sets errno and h_errno to that of the second
++       answer.  However because the response is a success we ignore
++       *errnop and *h_errnop (though that means you touched errno on
++         success).  We are being conservative here and returning the
++         likely IPv4 response in the first answer as a success.
++
++     [2] If the first response is a recoverable TRYAGAIN we return
++       that instead of looking at the second response.  The
++       expectation here is that we have failed to get an IPv4 response
++       and should retry both queries.
++
++     [3] If the first response was not a SUCCESS and the second
++       response is not NOTFOUND (had a SUCCESS, need to TRYAGAIN,
++       or failed entirely e.g. TRYAGAIN' and UNAVAIL) then use the
++       result from the second response, otherwise the first responses
++       status is used.  Again we have some odd side-effects when the
++       second response is NOTFOUND because we overwrite *errnop and
++       *h_errnop that means that a first answer of NOTFOUND might see
++       its *errnop and *h_errnop values altered.  Whether it matters
++       in practice that a first response NOTFOUND has the wrong
++       *errnop and *h_errnop is undecided.
++
++     [4] If the first response is UNAVAIL we return that instead of
++       looking at the second response.  The expectation here is that
++       it will have failed similarly e.g. configuration failure.
++
++     [5] Testing this code is complicated by the fact that truncated
++       second response buffers might be returned as SUCCESS if the
++       first answer is a SUCCESS.  To fix this we add symmetry to
++       TRYAGAIN with the second response.  If the second response
++       is a recoverable error we now return TRYAGIN even if the first
++       response was SUCCESS.  */
++
+   if (anslen1 > 0)
+     status = gaih_getanswer_slice(answer1, anslen1, qname,
+                                 &pat, &buffer, &buflen,
+                                 errnop, h_errnop, ttlp,
+                                 &first);
++
+   if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND
+        || (status == NSS_STATUS_TRYAGAIN
+          && (*errnop != ERANGE || *h_errnop == NO_RECOVERY)))
+@@ -1245,8 +1345,15 @@ gaih_getanswer (const querybuf *answer1,
+                                                    &pat, &buffer, &buflen,
+                                                    errnop, h_errnop, ttlp,
+                                                    &first);
++      /* Use the second response status in some cases.  */
+       if (status != NSS_STATUS_SUCCESS && status2 != NSS_STATUS_NOTFOUND)
+       status = status2;
++      /* Do not return a truncated second response (unless it was
++         unavoidable e.g. unrecoverable TRYAGAIN).  */
++      if (status == NSS_STATUS_SUCCESS
++        && (status2 == NSS_STATUS_TRYAGAIN
++            && *errnop == ERANGE && *h_errnop != NO_RECOVERY))
++      status = NSS_STATUS_TRYAGAIN;
+     }
+   return status;
+Index: glibc-2.12-2-gc4ccff1/resolv/res_send.c
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/resolv/res_send.c
++++ glibc-2.12-2-gc4ccff1/resolv/res_send.c
+@@ -1,3 +1,20 @@
++/* Copyright (C) 2016 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
++   <http://www.gnu.org/licenses/>.  */
++
+ /*
+  * Copyright (c) 1985, 1989, 1993
+  *    The Regents of the University of California.  All rights reserved.
+@@ -360,6 +377,8 @@ __libc_res_nsend(res_state statp, const
+ #ifdef USE_HOOKS
+       if (__builtin_expect (statp->qhook || statp->rhook, 0)) {
+               if (anssiz < MAXPACKET && ansp) {
++                      /* Always allocate MAXPACKET, callers expect
++                         this specific size.  */
+                       u_char *buf = malloc (MAXPACKET);
+                       if (buf == NULL)
+                               return (-1);
+@@ -652,6 +671,77 @@ libresolv_hidden_def (res_nsend)
+ /* Private */
++/* 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
++   IPv6 queries at the same serially on the same socket.
++
++   Please note that for TCP there is no way to disable sending both
++   queries, unlike UDP, which honours RES_SNGLKUP and RES_SNGLKUPREOP
++   and sends the queries serially and waits for the result after each
++   sent query.  This implemetnation should be corrected to honour these
++   options.
++
++   Please also note that for TCP we send both queries over the same
++   socket one after another.  This technically violates best practice
++   since the server is allowed to read the first query, respond, and
++   then close the socket (to service another client).  If the server
++   does this, then the remaining second query in the socket data buffer
++   will cause the server to send the client an RST which will arrive
++   asynchronously and the client's OS will likely tear down the socket
++   receive buffer resulting in a potentially short read and lost
++   response data.  This will force the client to retry the query again,
++   and this process may repeat until all servers and connection resets
++   are exhausted and then the query will fail.  It's not known if this
++   happens with any frequency in real DNS server implementations.  This
++   implementation should be corrected to use two sockets by default for
++   parallel queries.
++
++   The query stored in BUF of BUFLEN length is sent first followed by
++   the query stored in BUF2 of BUFLEN2 length.  Queries are sent
++   serially on the same socket.
++
++   Answers to the query are stored firstly in *ANSP up to a max of
++   *ANSSIZP bytes.  If more than *ANSSIZP bytes are needed and ANSCP
++   is non-NULL (to indicate that modifying the answer buffer is allowed)
++   then malloc is used to allocate a new response buffer and ANSCP and
++   ANSP will both point to the new buffer.  If more than *ANSSIZP bytes
++   are needed but ANSCP is NULL, then as much of the response as
++   possible is read into the buffer, but the results will be truncated.
++   When truncation happens because of a small answer buffer the DNS
++   packets header feild TC will bet set to 1, indicating a truncated
++   message and the rest of the socket data will be read and discarded.
++
++   Answers to the query are stored secondly in *ANSP2 up to a max of
++   *ANSSIZP2 bytes, with the actual response length stored in
++   *RESPLEN2.  If more than *ANSSIZP bytes are needed and ANSP2
++   is non-NULL (required for a second query) then malloc is used to
++   allocate a new response buffer, *ANSSIZP2 is set to the new buffer
++   size and *ANSP2_MALLOCED is set to 1.
++
++   The ANSP2_MALLOCED argument will eventually be removed as the
++   change in buffer pointer can be used to detect the buffer has
++   changed and that the caller should use free on the new buffer.
++
++   Note that the answers may arrive in any order from the server and
++   therefore the first and second answer buffers may not correspond to
++   the first and second queries.
++
++   It is not supported to call this function with a non-NULL ANSP2
++   but a NULL ANSCP.  Put another way, you can call send_vc with a
++   single unmodifiable buffer or two modifiable buffers, but no other
++   combination is supported.
++
++   It is the caller's responsibility to free the malloc allocated
++   buffers by detecting that the pointers have changed from their
++   original values i.e. *ANSCP or *ANSP2 has changed.
++
++   If errors are encountered then *TERRNO is set to an appropriate
++   errno value and a zero result is returned for a recoverable error,
++   and a less-than zero result is returned for a non-recoverable error.
++
++   If no errors are encountered then *TERRNO is left unmodified and
++   a the length of the first response in bytes is returned.  */
+ static int
+ send_vc(res_state statp,
+       const u_char *buf, int buflen, const u_char *buf2, int buflen2,
+@@ -661,11 +751,7 @@ send_vc(res_state statp,
+ {
+       const HEADER *hp = (HEADER *) buf;
+       const HEADER *hp2 = (HEADER *) buf2;
+-      u_char *ans = *ansp;
+-      int orig_anssizp = *anssizp;
+-      // XXX REMOVE
+-      // int anssiz = *anssizp;
+-      HEADER *anhp = (HEADER *) ans;
++      HEADER *anhp = (HEADER *) *ansp;
+       struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns];
+       int truncating, connreset, resplen, n;
+       struct iovec iov[4];
+@@ -741,6 +827,8 @@ send_vc(res_state statp,
+        * Receive length & response
+        */
+       int recvresp1 = 0;
++      /* Skip the second response if there is no second query.
++           To do that we mark the second response as received.  */
+       int recvresp2 = buf2 == NULL;
+       uint16_t rlen16;
+  read_len:
+@@ -777,33 +865,14 @@ send_vc(res_state statp,
+       u_char **thisansp;
+       int *thisresplenp;
+       if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) {
++              /* We have not received any responses
++                 yet or we only have one response to
++                 receive.  */
+               thisanssizp = anssizp;
+               thisansp = anscp ?: ansp;
+               assert (anscp != NULL || ansp2 == NULL);
+               thisresplenp = &resplen;
+       } else {
+-              if (*anssizp != MAXPACKET) {
+-                      /* No buffer allocated for the first
+-                         reply.  We can try to use the rest
+-                         of the user-provided buffer.  */
+-#ifdef _STRING_ARCH_unaligned
+-                      *anssizp2 = orig_anssizp - resplen;
+-                      *ansp2 = *ansp + resplen;
+-#else
+-                      int aligned_resplen
+-                        = ((resplen + __alignof__ (HEADER) - 1)
+-                           & ~(__alignof__ (HEADER) - 1));
+-                      *anssizp2 = orig_anssizp - aligned_resplen;
+-                      *ansp2 = *ansp + aligned_resplen;
+-#endif
+-              } else {
+-                      /* The first reply did not fit into the
+-                         user-provided buffer.  Maybe the second
+-                         answer will.  */
+-                      *anssizp2 = orig_anssizp;
+-                      *ansp2 = *ansp;
+-              }
+-
+               thisanssizp = anssizp2;
+               thisansp = ansp2;
+               thisresplenp = resplen2;
+@@ -811,10 +880,14 @@ send_vc(res_state statp,
+       anhp = (HEADER *) *thisansp;
+       *thisresplenp = rlen;
+-      if (rlen > *thisanssizp) {
+-              /* Yes, we test ANSCP here.  If we have two buffers
+-                 both will be allocatable.  */
+-              if (__builtin_expect (anscp != NULL, 1)) {
++      /* Is the answer buffer too small?  */
++      if (*thisanssizp < rlen) {
++              /* If the current buffer is non-NULL and it's not
++                 pointing at the static user-supplied buffer then
++                 we can reallocate it.  */
++              if (thisansp != NULL && thisansp != ansp) {
++                      /* Always allocate MAXPACKET, callers expect
++                         this specific size.  */
+                       u_char *newp = malloc (MAXPACKET);
+                       if (newp == NULL) {
+                               *terrno = ENOMEM;
+@@ -824,6 +897,9 @@ send_vc(res_state statp,
+                       *thisanssizp = MAXPACKET;
+                       *thisansp = newp;
+                       anhp = (HEADER *) newp;
++                      /* A uint16_t can't be larger than MAXPACKET
++                         thus it's safe to allocate MAXPACKET but
++                         read RLEN bytes instead.  */
+                       len = rlen;
+               } else {
+                       Dprint(statp->options & RES_DEBUG,
+@@ -987,6 +1063,66 @@ reopen (res_state statp, int *terrno, in
+       return 1;
+ }
++/* The send_dg function is responsible for sending a DNS query over UDP
++   to the nameserver numbered NS from the res_state STATP i.e.
++   EXT(statp).nssocks[ns].  The function supports IPv4 and IPv6 queries
++   along with the ability to send the query in parallel for both stacks
++   (default) or serially (RES_SINGLKUP).  It also supports serial lookup
++   with a close and reopen of the socket used to talk to the server
++   (RES_SNGLKUPREOP) to work around broken name servers.
++
++   The query stored in BUF of BUFLEN length is sent first followed by
++   the query stored in BUF2 of BUFLEN2 length.  Queries are sent
++   in parallel (default) or serially (RES_SINGLKUP or RES_SNGLKUPREOP).
++
++   Answers to the query are stored firstly in *ANSP up to a max of
++   *ANSSIZP bytes.  If more than *ANSSIZP bytes are needed and ANSCP
++   is non-NULL (to indicate that modifying the answer buffer is allowed)
++   then malloc is used to allocate a new response buffer and ANSCP and
++   ANSP will both point to the new buffer.  If more than *ANSSIZP bytes
++   are needed but ANSCP is NULL, then as much of the response as
++   possible is read into the buffer, but the results will be truncated.
++   When truncation happens because of a small answer buffer the DNS
++   packets header feild TC will bet set to 1, indicating a truncated
++   message, while the rest of the UDP packet is discarded.
++
++   Answers to the query are stored secondly in *ANSP2 up to a max of
++   *ANSSIZP2 bytes, with the actual response length stored in
++   *RESPLEN2.  If more than *ANSSIZP bytes are needed and ANSP2
++   is non-NULL (required for a second query) then malloc is used to
++   allocate a new response buffer, *ANSSIZP2 is set to the new buffer
++   size and *ANSP2_MALLOCED is set to 1.
++
++   The ANSP2_MALLOCED argument will eventually be removed as the
++   change in buffer pointer can be used to detect the buffer has
++   changed and that the caller should use free on the new buffer.
++
++   Note that the answers may arrive in any order from the server and
++   therefore the first and second answer buffers may not correspond to
++   the first and second queries.
++
++   It is not supported to call this function with a non-NULL ANSP2
++   but a NULL ANSCP.  Put another way, you can call send_vc with a
++   single unmodifiable buffer or two modifiable buffers, but no other
++   combination is supported.
++
++   It is the caller's responsibility to free the malloc allocated
++   buffers by detecting that the pointers have changed from their
++   original values i.e. *ANSCP or *ANSP2 has changed.
++
++   If an answer is truncated because of UDP datagram DNS limits then
++   *V_CIRCUIT is set to 1 and the return value non-zero to indicate to
++   the caller to retry with TCP.  The value *GOTSOMEWHERE is set to 1
++   if any progress was made reading a response from the nameserver and
++   is used by the caller to distinguish between ECONNREFUSED and
++   ETIMEDOUT (the latter if *GOTSOMEWHERE is 1).
++
++   If errors are encountered then *TERRNO is set to an appropriate
++   errno value and a zero result is returned for a recoverable error,
++   and a less-than zero result is returned for a non-recoverable error.
++
++   If no errors are encountered then *TERRNO is left unmodified and
++   a the length of the first response in bytes is returned.  */
+ static int
+ send_dg(res_state statp,
+       const u_char *buf, int buflen, const u_char *buf2, int buflen2,
+@@ -996,8 +1132,6 @@ send_dg(res_state statp,
+ {
+       const HEADER *hp = (HEADER *) buf;
+       const HEADER *hp2 = (HEADER *) buf2;
+-      u_char *ans = *ansp;
+-      int orig_anssizp = *anssizp;
+       struct timespec now, timeout, finish;
+       struct pollfd pfd[1];
+       int ptimeout;
+@@ -1029,6 +1163,8 @@ send_dg(res_state statp,
+       int need_recompute = 0;
+       int nwritten = 0;
+       int recvresp1 = 0;
++      /* Skip the second response if there is no second query.
++           To do that we mark the second response as received.  */
+       int recvresp2 = buf2 == NULL;
+       pfd[0].fd = EXT(statp).nssocks[ns];
+       pfd[0].events = POLLOUT;
+@@ -1125,50 +1261,52 @@ send_dg(res_state statp,
+               int *thisresplenp;
+               if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) {
++                      /* We have not received any responses
++                         yet or we only have one response to
++                         receive.  */
+                       thisanssizp = anssizp;
+                       thisansp = anscp ?: ansp;
+                       assert (anscp != NULL || ansp2 == NULL);
+                       thisresplenp = &resplen;
+               } else {
+-                      if (*anssizp != MAXPACKET) {
+-                              /* No buffer allocated for the first
+-                                 reply.  We can try to use the rest
+-                                 of the user-provided buffer.  */
+-#ifdef _STRING_ARCH_unaligned
+-                              *anssizp2 = orig_anssizp - resplen;
+-                              *ansp2 = *ansp + resplen;
+-#else
+-                              int aligned_resplen
+-                                = ((resplen + __alignof__ (HEADER) - 1)
+-                                   & ~(__alignof__ (HEADER) - 1));
+-                              *anssizp2 = orig_anssizp - aligned_resplen;
+-                              *ansp2 = *ansp + aligned_resplen;
+-#endif
+-                      } else {
+-                              /* The first reply did not fit into the
+-                                 user-provided buffer.  Maybe the second
+-                                 answer will.  */
+-                              *anssizp2 = orig_anssizp;
+-                              *ansp2 = *ansp;
+-                      }
+-
+                       thisanssizp = anssizp2;
+                       thisansp = ansp2;
+                       thisresplenp = resplen2;
+               }
+               if (*thisanssizp < MAXPACKET
+-                  /* Yes, we test ANSCP here.  If we have two buffers
+-                     both will be allocatable.  */
+-                  && anscp
++                  /* If the current buffer is non-NULL and it's not
++                     pointing at the static user-supplied buffer then
++                     we can reallocate it.  */
++                  && (thisansp != NULL && thisansp != ansp)
++                  /* Is the size too small?  */
+                   && (ioctl (pfd[0].fd, FIONREAD, thisresplenp) < 0
+-                      || *thisanssizp < *thisresplenp)) {
++                      || *thisanssizp < *thisresplenp)
++                  ) {
++                      /* Always allocate MAXPACKET, callers expect
++                         this specific size.  */
+                       u_char *newp = malloc (MAXPACKET);
+                       if (newp != NULL) {
+-                              *anssizp = MAXPACKET;
+-                              *thisansp = ans = newp;
++                              *thisanssizp = MAXPACKET;
++                              *thisansp = newp;
+                       }
+               }
++              /* We could end up with truncation if anscp was NULL
++                 (not allowed to change caller's buffer) and the
++                 response buffer size is too small.  This isn't a
++                 reliable way to detect truncation because the ioctl
++                 may be an inaccurate report of the UDP message size.
++                 Therefore we use this only to issue debug output.
++                 To do truncation accurately with UDP we need
++                 MSG_TRUNC which is only available on Linux.  We
++                 can abstract out the Linux-specific feature in the
++                 future to detect truncation.  */
++              if (__glibc_unlikely (*thisanssizp < *thisresplenp)) {
++                      Dprint(statp->options & RES_DEBUG,
++                             (stdout, ";; response may be truncated (UDP)\n")
++                      );
++              }
++
+               HEADER *anhp = (HEADER *) *thisansp;
+               socklen_t fromlen = sizeof(struct sockaddr_in6);
+               assert (sizeof(from) <= fromlen);
+Index: glibc-2.12-2-gc4ccff1/resolv/res_query.c
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/resolv/res_query.c
++++ glibc-2.12-2-gc4ccff1/resolv/res_query.c
+@@ -391,6 +391,7 @@ __libc_res_nsearch(res_state statp,
+                   && (*answerp2 < answer || *answerp2 >= answer + anslen))
+                 {
+                   free (*answerp2);
++                  *nanswerp2 = 0;
+                   *answerp2 = NULL;
+                 }
+       }
+@@ -431,6 +432,7 @@ __libc_res_nsearch(res_state statp,
+                               || *answerp2 >= answer + anslen))
+                         {
+                           free (*answerp2);
++                          *nanswerp2 = 0;
+                           *answerp2 = NULL;
+                         }
+@@ -503,6 +505,7 @@ __libc_res_nsearch(res_state statp,
+       if (answerp2 && (*answerp2 < answer || *answerp2 >= answer + anslen))
+         {
+           free (*answerp2);
++          *nanswerp2 = NULL;
+           *answerp2 = NULL;
+         }
+       if (saved_herrno != -1)
diff --git a/src/patches/glibc/glibc-rh1299319-0.patch b/src/patches/glibc/glibc-rh1299319-0.patch
new file mode 100644 (file)
index 0000000..f27eccd
--- /dev/null
@@ -0,0 +1,61 @@
+commit 2c1094bd700e63a8d7f547b3f5495bedb55c0a08
+Author: Ulrich Drepper <drepper@gmail.com>
+Date:   Thu Dec 22 22:43:39 2011 -0500
+
+    Create internal threads with sufficient stack size
+
+Index: glibc-2.12-2-gc4ccff1/nptl/Versions
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/nptl/Versions
++++ glibc-2.12-2-gc4ccff1/nptl/Versions
+@@ -255,6 +255,6 @@ libpthread {
+   GLIBC_PRIVATE {
+     __pthread_initialize_minimal;
+     __pthread_clock_gettime; __pthread_clock_settime;
+-    __pthread_unwind;
++    __pthread_unwind; __pthread_get_minstack;
+   }
+ }
+Index: glibc-2.12-2-gc4ccff1/nptl/nptl-init.c
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/nptl/nptl-init.c
++++ glibc-2.12-2-gc4ccff1/nptl/nptl-init.c
+@@ -507,3 +507,13 @@ __pthread_initialize_minimal_internal (i
+ }
+ strong_alias (__pthread_initialize_minimal_internal,
+             __pthread_initialize_minimal)
++
++
++size_t
++__pthread_get_minstack (const pthread_attr_t *attr)
++{
++  struct pthread_attr *iattr = (struct pthread_attr *) attr;
++
++  return (GLRO(dl_pagesize) + __static_tls_size + PTHREAD_STACK_MIN
++        + iattr->guardsize);
++}
+Index: glibc-2.12-2-gc4ccff1/nptl/pthreadP.h
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/nptl/pthreadP.h
++++ glibc-2.12-2-gc4ccff1/nptl/pthreadP.h
+@@ -397,6 +397,7 @@ weak_function;
+ extern void __pthread_init_static_tls (struct link_map *) attribute_hidden;
++extern size_t __pthread_get_minstack (const pthread_attr_t *attr);
+ /* Namespace save aliases.  */
+ extern int __pthread_getschedparam (pthread_t thread_id, int *policy,
+Index: glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/timer_routines.c
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/nptl/sysdeps/unix/sysv/linux/timer_routines.c
++++ glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/timer_routines.c
+@@ -165,7 +165,7 @@ __start_helper_thread (void)
+      and should go away automatically when canceled.  */
+   pthread_attr_t attr;
+   (void) pthread_attr_init (&attr);
+-  (void) pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN);
++  (void) pthread_attr_setstacksize (&attr, __pthread_get_minstack (&attr));
+   /* Block all signals in the helper thread but SIGSETXID.  To do this
+      thoroughly we temporarily have to block all signals here.  The
diff --git a/src/patches/glibc/glibc-rh1299319-1.patch b/src/patches/glibc/glibc-rh1299319-1.patch
new file mode 100644 (file)
index 0000000..e6288a2
--- /dev/null
@@ -0,0 +1,19 @@
+commit 232872379ee82cd040a52a48cbbae65a249b5765
+Author: Adhemerval Zanella <azanella@linux.vnet.ibm.com>
+Date:   Sun Jan 8 19:56:52 2012 -0500
+
+    Use __pthread_get_minstack for AIO helper thread
+
+diff --git a/nptl/sysdeps/unix/sysv/linux/aio_misc.h b/nptl/sysdeps/unix/sysv/linux/aio_misc.h
+index 406d96e..8011c3e 100644
+--- a/nptl/sysdeps/unix/sysv/linux/aio_misc.h
++++ b/nptl/sysdeps/unix/sysv/linux/aio_misc.h
+@@ -47,7 +47,7 @@ __aio_create_helper_thread (pthread_t *threadp, void *(*tf) (void *),
+   pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
+   /* The helper thread needs only very little resources.  */
+-  (void) pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN);
++  (void) pthread_attr_setstacksize (&attr, __pthread_get_minstack (&attr));
+   /* Block all signals in the helper thread.  To do this thoroughly we
+      temporarily have to block all signals here.  */
diff --git a/src/patches/glibc/glibc-rh552960.patch b/src/patches/glibc/glibc-rh552960.patch
new file mode 100644 (file)
index 0000000..41eccb7
--- /dev/null
@@ -0,0 +1,1213 @@
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/Makefile glibc-2.12-2-gc4ccff1.fixed/nptl/Makefile
+--- glibc-2.12-2-gc4ccff1/nptl/Makefile        2013-07-09 10:18:22.267421846 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/Makefile  2013-07-09 10:16:22.043427519 +0530
+@@ -207,7 +207,8 @@ tests = tst-typesizes \
+       tst-cond1 tst-cond2 tst-cond3 tst-cond4 tst-cond5 tst-cond6 tst-cond7 \
+       tst-cond8 tst-cond9 tst-cond10 tst-cond11 tst-cond12 tst-cond13 \
+       tst-cond14 tst-cond15 tst-cond16 tst-cond17 tst-cond18 tst-cond19 \
+-      tst-cond20 tst-cond21 tst-cond22 tst-cond23 \
++      tst-cond20 tst-cond21 tst-cond22 tst-cond23 tst-cond24 tst-cond25 \
++      tst-cond-except \
+       tst-robust1 tst-robust2 tst-robust3 tst-robust4 tst-robust5 \
+       tst-robust6 tst-robust7 tst-robust8 tst-robust9 \
+       tst-robustpi1 tst-robustpi2 tst-robustpi3 tst-robustpi4 tst-robustpi5 \
+@@ -275,6 +276,8 @@ gen-as-const-headers = pthread-errnos.sy
+ LDFLAGS-pthread.so = -Wl,--enable-new-dtags,-z,nodelete,-z,initfirst
++LDFLAGS-tst-cond24 = -lrt
++LDFLAGS-tst-cond25 = -lrt
+ include ../Makeconfig
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S glibc-2.12-2-gc4ccff1.fixed/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S
+--- glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S      2010-05-04 16:57:23.000000000 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S        2013-07-09 10:16:22.044427519 +0530
+@@ -203,9 +203,11 @@ __pthread_cond_timedwait:
+ 42:   leal    (%ebp), %esi
+       movl    28(%esp), %edx
+       addl    $cond_futex, %ebx
++.Ladd_cond_futex_pi:
+       movl    $SYS_futex, %eax
+       ENTER_KERNEL
+       subl    $cond_futex, %ebx
++.Lsub_cond_futex_pi:
+       movl    %eax, %esi
+       /* Set the pi-requeued flag only if the kernel has returned 0. The
+          kernel does not hold the mutex on ETIMEDOUT or any other error.  */
+@@ -213,8 +215,23 @@ __pthread_cond_timedwait:
+       sete    24(%esp)
+       je      41f
+-      /* Normal and PI futexes dont mix. Use normal futex functions only
+-         if the kernel does not support the PI futex functions.  */
++      /* When a futex syscall with FUTEX_WAIT_REQUEUE_PI returns
++         successfully, it has already locked the mutex for us and the
++         pi_flag (24(%esp)) is set to denote that fact.  However, if another
++         thread changed the futex value before we entered the wait, the
++         syscall may return an EAGAIN and the mutex is not locked.  We go
++         ahead with a success anyway since later we look at the pi_flag to
++         decide if we got the mutex or not.  The sequence numbers then make
++         sure that only one of the threads actually wake up.  We retry using
++         normal FUTEX_WAIT only if the kernel returned ENOSYS, since normal
++         and PI futexes don't mix.
++
++         Note that we don't check for EAGAIN specifically; we assume that the
++         only other error the futex function could return is EAGAIN (barring
++         the ETIMEOUT of course, for the timeout case in futex) since
++         anything else would mean an error in our function.  It is too
++         expensive to do that check for every call (which is  quite common in
++         case of a large number of threads), so it has been skipped.  */
+       cmpl    $-ENOSYS, %eax
+       jne     41f
+       xorl    %ecx, %ecx
+@@ -274,9 +291,24 @@ __pthread_cond_timedwait:
+       jne     9f
+ 15:   cmpl    $-ETIMEDOUT, %esi
+-      jne     8b
++      je      28f
+-      addl    $1, wakeup_seq(%ebx)
++      /* We need to go back to futex_wait.  If we're using requeue_pi, then
++         release the mutex we had acquired and go back.  */
++      movl    24(%esp), %edx
++      test    %edx, %edx
++      jz      8b
++
++      /* Adjust the mutex values first and then unlock it.  The unlock
++         should always succeed or else the kernel did not lock the mutex
++         correctly.  */
++      movl    dep_mutex(%ebx), %eax
++      call    __pthread_mutex_cond_lock_adjust
++      xorl    %edx, %edx
++      call    __pthread_mutex_unlock_usercnt
++      jmp     8b
++
++28:   addl    $1, wakeup_seq(%ebx)
+       adcl    $0, wakeup_seq+4(%ebx)
+       addl    $1, cond_futex(%ebx)
+       movl    $ETIMEDOUT, %esi
+@@ -644,10 +676,27 @@ __condvar_tw_cleanup:
+       movl    $0x7fffffff, %edx
+       ENTER_KERNEL
++      /* Lock the mutex only if we don't own it already.  This only happens
++         in case of PI mutexes, if we got cancelled after a successful
++         return of the futex syscall and before disabling async
++         cancellation.  */
+ 5:    movl    24+FRAME_SIZE(%esp), %eax
+-      call    __pthread_mutex_cond_lock
++      movl    MUTEX_KIND(%eax), %ebx
++      andl    $(ROBUST_BIT|PI_BIT), %ebx
++      cmpl    $PI_BIT, %ebx
++      jne     8f
++
++      movl    (%eax), %ebx
++      andl    $TID_MASK, %ebx
++      cmpl    %ebx, %gs:TID
++      jne     8f
++      /* We managed to get the lock.  Fix it up before returning.  */
++      call    __pthread_mutex_cond_lock_adjust
++      jmp     9f
++
++8:    call    __pthread_mutex_cond_lock
+-      movl    %esi, (%esp)
++9:    movl    %esi, (%esp)
+ .LcallUR:
+       call    _Unwind_Resume
+       hlt
+@@ -665,7 +714,15 @@ __condvar_tw_cleanup:
+       .uleb128 .Lcstend-.Lcstbegin
+ .Lcstbegin:
+       .long   .LcleanupSTART-.LSTARTCODE
+-      .long   .Ladd_cond_futex-.LcleanupSTART
++      .long   .Ladd_cond_futex_pi-.LcleanupSTART
++      .long   __condvar_tw_cleanup-.LSTARTCODE
++      .uleb128  0
++      .long   .Ladd_cond_futex_pi-.LSTARTCODE
++      .long   .Lsub_cond_futex_pi-.Ladd_cond_futex_pi
++      .long   __condvar_tw_cleanup2-.LSTARTCODE
++      .uleb128  0
++      .long   .Lsub_cond_futex_pi-.LSTARTCODE
++      .long   .Ladd_cond_futex-.Lsub_cond_futex_pi
+       .long   __condvar_tw_cleanup-.LSTARTCODE
+       .uleb128  0
+       .long   .Ladd_cond_futex-.LSTARTCODE
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S glibc-2.12-2-gc4ccff1.fixed/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S
+--- glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S   2010-05-04 16:57:23.000000000 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S     2013-07-09 10:16:22.046427519 +0530
+@@ -138,17 +138,33 @@ __pthread_cond_wait:
+       movl    %ebp, %edx
+       xorl    %esi, %esi
+       addl    $cond_futex, %ebx
++.Ladd_cond_futex_pi:
+       movl    $SYS_futex, %eax
+       ENTER_KERNEL
+       subl    $cond_futex, %ebx
++.Lsub_cond_futex_pi:
+       /* Set the pi-requeued flag only if the kernel has returned 0. The
+          kernel does not hold the mutex on error.  */
+       cmpl    $0, %eax
+       sete    16(%esp)
+       je      19f
+-      /* Normal and PI futexes dont mix. Use normal futex functions only
+-         if the kernel does not support the PI futex functions.  */
++      /* When a futex syscall with FUTEX_WAIT_REQUEUE_PI returns
++         successfully, it has already locked the mutex for us and the
++         pi_flag (16(%esp)) is set to denote that fact.  However, if another
++         thread changed the futex value before we entered the wait, the
++         syscall may return an EAGAIN and the mutex is not locked.  We go
++         ahead with a success anyway since later we look at the pi_flag to
++         decide if we got the mutex or not.  The sequence numbers then make
++         sure that only one of the threads actually wake up.  We retry using
++         normal FUTEX_WAIT only if the kernel returned ENOSYS, since normal
++         and PI futexes don't mix.
++
++         Note that we don't check for EAGAIN specifically; we assume that the
++         only other error the futex function could return is EAGAIN since
++         anything else would mean an error in our function.  It is too
++         expensive to do that check for every call (which is  quite common in
++         case of a large number of threads), so it has been skipped.  */
+       cmpl    $-ENOSYS, %eax
+       jne     19f
+       xorl    %ecx, %ecx
+@@ -198,12 +214,12 @@ __pthread_cond_wait:
+       cmpl    8(%esp), %edx
+       jne     7f
+       cmpl    4(%esp), %edi
+-      je      8b
++      je      22f
+ 7:    cmpl    %ecx, %edx
+       jne     9f
+       cmp     %eax, %edi
+-      je      8b
++      je      22f
+ 9:    addl    $1, woken_seq(%ebx)
+       adcl    $0, woken_seq+4(%ebx)
+@@ -279,6 +295,22 @@ __pthread_cond_wait:
+       jmp     20b
+       cfi_adjust_cfa_offset(-FRAME_SIZE);
++
++      /* We need to go back to futex_wait.  If we're using requeue_pi, then
++         release the mutex we had acquired and go back.  */
++22:   movl    16(%esp), %edx
++      test    %edx, %edx
++      jz      8b
++
++      /* Adjust the mutex values first and then unlock it.  The unlock
++         should always succeed or else the kernel did not lock the mutex
++         correctly.  */
++      movl    dep_mutex(%ebx), %eax
++      call    __pthread_mutex_cond_lock_adjust
++      xorl    %edx, %edx
++      call    __pthread_mutex_unlock_usercnt
++      jmp     8b
++
+       /* Initial locking failed.  */
+ 1:
+ #if cond_lock == 0
+@@ -391,6 +423,7 @@ __pthread_cond_wait:
+ #endif
+       call    __lll_unlock_wake
+       jmp     11b
++
+       .size   __pthread_cond_wait, .-__pthread_cond_wait
+ versioned_symbol (libpthread, __pthread_cond_wait, pthread_cond_wait,
+                 GLIBC_2_3_2)
+@@ -531,10 +564,27 @@ __condvar_w_cleanup:
+       movl    $0x7fffffff, %edx
+       ENTER_KERNEL
++      /* Lock the mutex only if we don't own it already.  This only happens
++         in case of PI mutexes, if we got cancelled after a successful
++         return of the futex syscall and before disabling async
++         cancellation.  */
+ 5:    movl    24+FRAME_SIZE(%esp), %eax
+-      call    __pthread_mutex_cond_lock
++      movl    MUTEX_KIND(%eax), %ebx
++      andl    $(ROBUST_BIT|PI_BIT), %ebx
++      cmpl    $PI_BIT, %ebx
++      jne     8f
++
++      movl    (%eax), %ebx
++      andl    $TID_MASK, %ebx
++      cmpl    %ebx, %gs:TID
++      jne     8f
++      /* We managed to get the lock.  Fix it up before returning.  */
++      call    __pthread_mutex_cond_lock_adjust
++      jmp     9f
+-      movl    %esi, (%esp)
++8:    call    __pthread_mutex_cond_lock
++
++9:    movl    %esi, (%esp)
+ .LcallUR:
+       call    _Unwind_Resume
+       hlt
+@@ -552,7 +602,15 @@ __condvar_w_cleanup:
+       .uleb128 .Lcstend-.Lcstbegin
+ .Lcstbegin:
+       .long   .LcleanupSTART-.LSTARTCODE
+-      .long   .Ladd_cond_futex-.LcleanupSTART
++      .long   .Ladd_cond_futex_pi-.LcleanupSTART
++      .long   __condvar_w_cleanup-.LSTARTCODE
++      .uleb128  0
++      .long   .Ladd_cond_futex_pi-.LSTARTCODE
++      .long   .Lsub_cond_futex_pi-.Ladd_cond_futex_pi
++      .long   __condvar_w_cleanup2-.LSTARTCODE
++      .uleb128  0
++      .long   .Lsub_cond_futex_pi-.LSTARTCODE
++      .long   .Ladd_cond_futex-.Lsub_cond_futex_pi
+       .long   __condvar_w_cleanup-.LSTARTCODE
+       .uleb128  0
+       .long   .Ladd_cond_futex-.LSTARTCODE
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/pthread-pi-defines.sym glibc-2.12-2-gc4ccff1.fixed/nptl/sysdeps/unix/sysv/linux/pthread-pi-defines.sym
+--- glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/pthread-pi-defines.sym  2010-05-04 16:57:23.000000000 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/sysdeps/unix/sysv/linux/pthread-pi-defines.sym    2013-07-09 10:16:22.047427519 +0530
+@@ -6,3 +6,4 @@ MUTEX_KIND     offsetof (pthread_mutex_t, __
+ ROBUST_BIT    PTHREAD_MUTEX_ROBUST_NORMAL_NP
+ PI_BIT                PTHREAD_MUTEX_PRIO_INHERIT_NP
+ PS_BIT                PTHREAD_MUTEX_PSHARED_BIT
++TID_MASK      FUTEX_TID_MASK
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S glibc-2.12-2-gc4ccff1.fixed/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S
+--- glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S 2013-07-09 10:18:22.506421835 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S   2013-07-09 10:16:22.048427519 +0530
+@@ -104,6 +104,8 @@ __pthread_cond_timedwait:
+       movq    %rsi, dep_mutex(%rdi)
+ 22:
++      xorb    %r15b, %r15b
++
+ #ifndef __ASSUME_FUTEX_CLOCK_REALTIME
+ #  ifdef PIC
+       cmpl    $0, __have_futex_clock_realtime(%rip)
+@@ -189,18 +191,39 @@ __pthread_cond_timedwait:
+       movl    $SYS_futex, %eax
+       syscall
+-      movl    $1, %r15d
++      cmpl    $0, %eax
++      sete    %r15b
++
+ #ifdef __ASSUME_REQUEUE_PI
+       jmp     62f
+ #else
+-      cmpq    $-4095, %rax
+-      jnae    62f
++      je      62f
++
++      /* When a futex syscall with FUTEX_WAIT_REQUEUE_PI returns
++         successfully, it has already locked the mutex for us and the
++         pi_flag (%r15b) is set to denote that fact.  However, if another
++         thread changed the futex value before we entered the wait, the
++         syscall may return an EAGAIN and the mutex is not locked.  We go
++         ahead with a success anyway since later we look at the pi_flag to
++         decide if we got the mutex or not.  The sequence numbers then make
++         sure that only one of the threads actually wake up.  We retry using
++         normal FUTEX_WAIT only if the kernel returned ENOSYS, since normal
++         and PI futexes don't mix.
++
++         Note that we don't check for EAGAIN specifically; we assume that the
++         only other error the futex function could return is EAGAIN (barring
++         the ETIMEOUT of course, for the timeout case in futex) since
++         anything else would mean an error in our function.  It is too
++         expensive to do that check for every call (which is  quite common in
++         case of a large number of threads), so it has been skipped.  */
++      cmpl    $-ENOSYS, %eax
++      jne     62f
+       subq    $cond_futex, %rdi
+ #endif
+ 61:   movl    $(FUTEX_WAIT_BITSET|FUTEX_PRIVATE_FLAG), %esi
+-60:   xorl    %r15d, %r15d
++60:   xorb    %r15b, %r15b
+       xorl    %eax, %eax
+       /* The following only works like this because we only support
+          two clocks, represented using a single bit.  */
+@@ -247,7 +270,23 @@ __pthread_cond_timedwait:
+       ja      39f
+ 45:   cmpq    $-ETIMEDOUT, %r14
+-      jne     38b
++      je      99f
++
++      /* We need to go back to futex_wait.  If we're using requeue_pi, then
++         release the mutex we had acquired and go back.  */
++      test    %r15b, %r15b
++      jz      38b
++
++      /* Adjust the mutex values first and then unlock it.  The unlock
++         should always succeed or else the kernel did not lock the
++         mutex correctly.  */
++      movq    %r8, %rdi
++      callq   __pthread_mutex_cond_lock_adjust
++      xorl    %esi, %esi
++      callq   __pthread_mutex_unlock_usercnt
++      /* Reload cond_var.  */
++      movq    8(%rsp), %rdi
++      jmp     38b
+ 99:   incq    wakeup_seq(%rdi)
+       incl    cond_futex(%rdi)
+@@ -297,7 +336,7 @@ __pthread_cond_timedwait:
+       /* If requeue_pi is used the kernel performs the locking of the
+          mutex. */
+ 41:   movq    16(%rsp), %rdi
+-      testl   %r15d, %r15d
++      testb   %r15b, %r15b
+       jnz     64f
+       callq   __pthread_mutex_cond_lock
+@@ -405,8 +444,6 @@ __pthread_cond_timedwait:
+ #ifndef __ASSUME_FUTEX_CLOCK_REALTIME
+ .Lreltmo:
+-      xorl    %r15d, %r15d
+-
+       /* Get internal lock.  */
+       movl    $1, %esi
+       xorl    %eax, %eax
+@@ -765,10 +802,27 @@ __condvar_cleanup2:
+       movl    $SYS_futex, %eax
+       syscall
++      /* Lock the mutex only if we don't own it already.  This only happens
++         in case of PI mutexes, if we got cancelled after a successful
++         return of the futex syscall and before disabling async
++         cancellation.  */
+ 5:    movq    16(%rsp), %rdi
+-      callq   __pthread_mutex_cond_lock
++      movl    MUTEX_KIND(%rdi), %eax
++      andl    $(ROBUST_BIT|PI_BIT), %eax
++      cmpl    $PI_BIT, %eax
++      jne     7f
++
++      movl    (%rdi), %eax
++      andl    $TID_MASK, %eax
++      cmpl    %eax, %fs:TID
++      jne     7f
++      /* We managed to get the lock.  Fix it up before returning.  */
++      callq   __pthread_mutex_cond_lock_adjust
++      jmp     8f
++
++7:    callq   __pthread_mutex_cond_lock
+-      movq    24(%rsp), %rdi
++8:    movq    24(%rsp), %rdi
+       movq    FRAME_SIZE(%rsp), %r15
+       movq    FRAME_SIZE+8(%rsp), %r14
+       movq    FRAME_SIZE+16(%rsp), %r13
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S glibc-2.12-2-gc4ccff1.fixed/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S
+--- glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S      2013-07-09 10:18:22.507421834 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S        2013-07-09 10:16:22.048427519 +0530
+@@ -23,6 +23,7 @@
+ #include <lowlevelcond.h>
+ #include <tcb-offsets.h>
+ #include <pthread-pi-defines.h>
++#include <pthread-errnos.h>
+ #include <kernel-features.h>
+@@ -137,12 +138,32 @@ __pthread_cond_wait:
+       movl    $SYS_futex, %eax
+       syscall
+-      movl    $1, %r8d
++      cmpl    $0, %eax
++      sete    %r8b
++
+ #ifdef __ASSUME_REQUEUE_PI
+       jmp     62f
+ #else
+-      cmpq    $-4095, %rax
+-      jnae    62f
++      je      62f
++
++      /* When a futex syscall with FUTEX_WAIT_REQUEUE_PI returns
++         successfully, it has already locked the mutex for us and the
++         pi_flag (%r8b) is set to denote that fact.  However, if another
++         thread changed the futex value before we entered the wait, the
++         syscall may return an EAGAIN and the mutex is not locked.  We go
++         ahead with a success anyway since later we look at the pi_flag to
++         decide if we got the mutex or not.  The sequence numbers then make
++         sure that only one of the threads actually wake up.  We retry using
++         normal FUTEX_WAIT only if the kernel returned ENOSYS, since normal
++         and PI futexes don't mix.
++
++         Note that we don't check for EAGAIN specifically; we assume that the
++         only other error the futex function could return is EAGAIN since
++         anything else would mean an error in our function.  It is too
++         expensive to do that check for every call (which is  quite common in
++         case of a large number of threads), so it has been skipped.  */
++      cmpl    $-ENOSYS, %eax
++      jne     62f
+ # ifndef __ASSUME_PRIVATE_FUTEX
+       movl    $FUTEX_WAIT, %esi
+@@ -155,7 +176,7 @@ __pthread_cond_wait:
+ #else
+       orl     %fs:PRIVATE_FUTEX, %esi
+ #endif
+-60:   xorl    %r8d, %r8d
++60:   xorb    %r8b, %r8b
+       movl    $SYS_futex, %eax
+       syscall
+@@ -185,10 +206,10 @@ __pthread_cond_wait:
+       jne     16f
+       cmpq    24(%rsp), %r9
+-      jbe     8b
++      jbe     19f
+       cmpq    %rax, %r9
+-      jna     8b
++      jna     19f
+       incq    woken_seq(%rdi)
+@@ -230,7 +251,7 @@ __pthread_cond_wait:
+       /* If requeue_pi is used the kernel performs the locking of the
+          mutex. */
+ 11:   movq    16(%rsp), %rdi
+-      testl   %r8d, %r8d
++      testb   %r8b, %r8b
+       jnz     18f
+       callq   __pthread_mutex_cond_lock
+@@ -247,6 +268,23 @@ __pthread_cond_wait:
+       xorl    %eax, %eax
+       jmp     14b
++      /* We need to go back to futex_wait.  If we're using requeue_pi, then
++         release the mutex we had acquired and go back.  */
++19:   testb   %r8b, %r8b
++      jz      8b
++
++      /* Adjust the mutex values first and then unlock it.  The unlock
++         should always succeed or else the kernel did not lock the mutex
++         correctly.  */
++      movq    16(%rsp), %rdi
++      callq   __pthread_mutex_cond_lock_adjust
++      movq    %rdi, %r8
++      xorl    %esi, %esi
++      callq   __pthread_mutex_unlock_usercnt
++      /* Reload cond_var.  */
++      movq    8(%rsp), %rdi
++      jmp     8b
++
+       /* Initial locking failed.  */
+ 1:
+ #if cond_lock != 0
+@@ -324,6 +362,7 @@ __pthread_cond_wait:
+ 13:   movq    %r10, %rax
+       jmp     14b
++
+       .size   __pthread_cond_wait, .-__pthread_cond_wait
+ versioned_symbol (libpthread, __pthread_cond_wait, pthread_cond_wait,
+                 GLIBC_2_3_2)
+@@ -454,10 +493,28 @@ __condvar_cleanup1:
+       movl    $SYS_futex, %eax
+       syscall
++      /* Lock the mutex only if we don't own it already.  This only happens
++         in case of PI mutexes, if we got cancelled after a successful
++         return of the futex syscall and before disabling async
++         cancellation.  */
+ 5:    movq    16(%rsp), %rdi
+-      callq   __pthread_mutex_cond_lock
++      movl    MUTEX_KIND(%rdi), %eax
++      andl    $(ROBUST_BIT|PI_BIT), %eax
++      cmpl    $PI_BIT, %eax
++      jne     7f
++
++      movl    (%rdi), %eax
++      andl    $TID_MASK, %eax
++      cmpl    %eax, %fs:TID
++      jne     7f
++      /* We managed to get the lock.  Fix it up before returning.  */
++      callq   __pthread_mutex_cond_lock_adjust
++      jmp     8f
++
+-      movq    24(%rsp), %rdi
++7:    callq   __pthread_mutex_cond_lock
++
++8:    movq    24(%rsp), %rdi
+ .LcallUR:
+       call    _Unwind_Resume@PLT
+       hlt
+@@ -476,11 +533,11 @@ __condvar_cleanup1:
+       .uleb128 .LcleanupSTART-.LSTARTCODE
+       .uleb128 .LcleanupEND-.LcleanupSTART
+       .uleb128 __condvar_cleanup1-.LSTARTCODE
+-      .uleb128  0
++      .uleb128 0
+       .uleb128 .LcallUR-.LSTARTCODE
+       .uleb128 .LENDCODE-.LcallUR
+       .uleb128 0
+-      .uleb128  0
++      .uleb128 0
+ .Lcstend:
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/tst-cond24.c glibc-2.12-2-gc4ccff1.fixed/nptl/tst-cond24.c
+--- glibc-2.12-2-gc4ccff1/nptl/tst-cond24.c    1970-01-01 05:30:00.000000000 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/tst-cond24.c      2013-07-09 10:19:10.008419593 +0530
+@@ -0,0 +1,249 @@
++/* Verify that condition variables synchronized by PI mutexes don't hang.
++   Copyright (C) 2012-2013 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
++   <http://www.gnu.org/licenses/>.  */
++
++#include <pthread.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <errno.h>
++#include <sys/types.h>
++#include <sys/syscall.h>
++#include <unistd.h>
++#include <sys/time.h>
++#include <time.h>
++
++#define THREADS_NUM 5
++#define MAXITER 50000
++
++static pthread_mutex_t mutex;
++static pthread_mutexattr_t mutex_attr;
++static pthread_cond_t cond;
++static pthread_t threads[THREADS_NUM];
++static int pending = 0;
++
++typedef void * (*threadfunc) (void *);
++
++void *
++thread_fun_timed (void *arg)
++{
++  int *ret = arg;
++  int rv, i;
++
++  printf ("Started thread_fun_timed[%d]\n", *ret);
++
++  for (i = 0; i < MAXITER / THREADS_NUM; i++)
++    {
++      rv = pthread_mutex_lock (&mutex);
++      if (rv)
++        {
++        printf ("pthread_mutex_lock: %s(%d)\n", strerror (rv), rv);
++        *ret = 1;
++        goto out;
++      }
++
++      while (!pending)
++      {
++        struct timespec ts;
++        clock_gettime(CLOCK_REALTIME, &ts);
++        ts.tv_sec += 20;
++        rv = pthread_cond_timedwait (&cond, &mutex, &ts);
++
++        /* There should be no timeout either.  */
++        if (rv)
++            {
++            printf ("pthread_cond_wait: %s(%d)\n", strerror (rv), rv);
++            *ret = 1;
++            goto out;
++          }
++      }
++
++      pending--;
++
++      rv = pthread_mutex_unlock (&mutex);
++      if (rv)
++        {
++        printf ("pthread_mutex_unlock: %s(%d)\n", strerror (rv), rv);
++        *ret = 1;
++        goto out;
++      }
++    }
++
++  *ret = 0;
++
++out:
++  return ret;
++}
++
++void *
++thread_fun (void *arg)
++{
++  int *ret = arg;
++  int rv, i;
++
++  printf ("Started thread_fun[%d]\n", *ret);
++
++  for (i = 0; i < MAXITER / THREADS_NUM; i++)
++    {
++      rv = pthread_mutex_lock (&mutex);
++      if (rv)
++        {
++        printf ("pthread_mutex_lock: %s(%d)\n", strerror (rv), rv);
++        *ret = 1;
++        goto out;
++      }
++
++      while (!pending)
++      {
++        rv = pthread_cond_wait (&cond, &mutex);
++
++        if (rv)
++            {
++            printf ("pthread_cond_wait: %s(%d)\n", strerror (rv), rv);
++            *ret = 1;
++            goto out;
++          }
++      }
++
++      pending--;
++
++      rv = pthread_mutex_unlock (&mutex);
++      if (rv)
++        {
++        printf ("pthread_mutex_unlock: %s(%d)\n", strerror (rv), rv);
++        *ret = 1;
++        goto out;
++      }
++    }
++
++  *ret = 0;
++
++out:
++  return ret;
++}
++
++static int
++do_test_wait (threadfunc f)
++{
++  int i;
++  int rv;
++  int counter = 0;
++  int retval[THREADS_NUM];
++
++  puts ("Starting test");
++
++  rv = pthread_mutexattr_init (&mutex_attr);
++  if (rv)
++    {
++      printf ("pthread_mutexattr_init: %s(%d)\n", strerror (rv), rv);
++      return 1;
++    }
++
++  rv = pthread_mutexattr_setprotocol (&mutex_attr, PTHREAD_PRIO_INHERIT);
++  if (rv)
++    {
++      printf ("pthread_mutexattr_setprotocol: %s(%d)\n", strerror (rv), rv);
++      return 1;
++    }
++
++  rv = pthread_mutex_init (&mutex, &mutex_attr);
++  if (rv)
++    {
++      printf ("pthread_mutex_init: %s(%d)\n", strerror (rv), rv);
++      return 1;
++    }
++
++  rv = pthread_cond_init (&cond, NULL);
++  if (rv)
++    {
++      printf ("pthread_cond_init: %s(%d)\n", strerror (rv), rv);
++      return 1;
++    }
++
++  for (i = 0; i < THREADS_NUM; i++)
++    {
++      retval[i] = i;
++      rv = pthread_create (&threads[i], NULL, f, &retval[i]);
++      if (rv)
++        {
++          printf ("pthread_create: %s(%d)\n", strerror (rv), rv);
++          return 1;
++        }
++    }
++
++  for (; counter < MAXITER; counter++)
++    {
++      rv = pthread_mutex_lock (&mutex);
++      if (rv)
++        {
++          printf ("pthread_mutex_lock: %s(%d)\n", strerror (rv), rv);
++          return 1;
++        }
++
++      if (!(counter % 100))
++      printf ("counter: %d\n", counter);
++      pending += 1;
++
++      rv = pthread_cond_signal (&cond);
++      if (rv)
++        {
++          printf ("pthread_cond_signal: %s(%d)\n", strerror (rv), rv);
++          return 1;
++        }
++
++      rv = pthread_mutex_unlock (&mutex);
++      if (rv)
++        {
++          printf ("pthread_mutex_unlock: %s(%d)\n", strerror (rv), rv);
++          return 1;
++        }
++    }
++
++  for (i = 0; i < THREADS_NUM; i++)
++    {
++      void *ret;
++      rv = pthread_join (threads[i], &ret);
++      if (rv)
++        {
++          printf ("pthread_join: %s(%d)\n", strerror (rv), rv);
++          return 1;
++        }
++      if (ret && *(int *)ret)
++        {
++        printf ("Thread %d returned with an error\n", i);
++        return 1;
++      }
++    }
++
++  return 0;
++}
++
++static int
++do_test (void)
++{
++  puts ("Testing pthread_cond_wait");
++  int ret = do_test_wait (thread_fun);
++  if (ret)
++    return ret;
++
++  puts ("Testing pthread_cond_timedwait");
++  return do_test_wait (thread_fun_timed);
++}
++
++#define TIMEOUT 20
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/tst-cond25.c glibc-2.12-2-gc4ccff1.fixed/nptl/tst-cond25.c
+--- glibc-2.12-2-gc4ccff1/nptl/tst-cond25.c    1970-01-01 05:30:00.000000000 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/tst-cond25.c      2013-07-09 10:19:15.472419335 +0530
+@@ -0,0 +1,281 @@
++/* Verify that condition variables synchronized by PI mutexes don't hang on
++   on cancellation.
++   Copyright (C) 2012-2013 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
++   <http://www.gnu.org/licenses/>.  */
++
++#include <pthread.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <stdint.h>
++#include <string.h>
++#include <errno.h>
++#include <sys/types.h>
++#include <sys/syscall.h>
++#include <unistd.h>
++#include <sys/time.h>
++#include <time.h>
++
++#define NUM 5
++#define ITERS 10000
++#define COUNT 100
++
++typedef void *(*thr_func) (void *);
++
++pthread_mutex_t mutex;
++pthread_cond_t cond;
++
++void cleanup (void *u)
++{
++  /* pthread_cond_wait should always return with the mutex locked.  */
++  if (pthread_mutex_unlock (&mutex))
++    abort ();
++}
++
++void *
++signaller (void *u)
++{
++  int i, ret = 0;
++  void *tret = NULL;
++
++  for (i = 0; i < ITERS; i++)
++    {
++      if ((ret = pthread_mutex_lock (&mutex)) != 0)
++        {
++        tret = (void *)1;
++        printf ("signaller:mutex_lock failed: %s\n", strerror (ret));
++        goto out;
++      }
++      if ((ret = pthread_cond_signal (&cond)) != 0)
++        {
++        tret = (void *)1;
++        printf ("signaller:signal failed: %s\n", strerror (ret));
++        goto unlock_out;
++      }
++      if ((ret = pthread_mutex_unlock (&mutex)) != 0)
++        {
++        tret = (void *)1;
++        printf ("signaller:mutex_unlock failed: %s\n", strerror (ret));
++        goto out;
++      }
++      pthread_testcancel ();
++    }
++
++out:
++  return tret;
++
++unlock_out:
++  if ((ret = pthread_mutex_unlock (&mutex)) != 0)
++    printf ("signaller:mutex_unlock[2] failed: %s\n", strerror (ret));
++  goto out;
++}
++
++void *
++waiter (void *u)
++{
++  int i, ret = 0;
++  void *tret = NULL;
++  int seq = (uintptr_t) u;
++
++  for (i = 0; i < ITERS / NUM; i++)
++    {
++      if ((ret = pthread_mutex_lock (&mutex)) != 0)
++        {
++        tret = (void *) (uintptr_t) 1;
++        printf ("waiter[%u]:mutex_lock failed: %s\n", seq, strerror (ret));
++        goto out;
++      }
++      pthread_cleanup_push (cleanup, NULL);
++
++      if ((ret = pthread_cond_wait (&cond, &mutex)) != 0)
++        {
++        tret = (void *) (uintptr_t) 1;
++        printf ("waiter[%u]:wait failed: %s\n", seq, strerror (ret));
++        goto unlock_out;
++      }
++
++      if ((ret = pthread_mutex_unlock (&mutex)) != 0)
++        {
++        tret = (void *) (uintptr_t) 1;
++        printf ("waiter[%u]:mutex_unlock failed: %s\n", seq, strerror (ret));
++        goto out;
++      }
++      pthread_cleanup_pop (0);
++    }
++
++out:
++  puts ("waiter tests done");
++  return tret;
++
++unlock_out:
++  if ((ret = pthread_mutex_unlock (&mutex)) != 0)
++    printf ("waiter:mutex_unlock[2] failed: %s\n", strerror (ret));
++  goto out;
++}
++
++void *
++timed_waiter (void *u)
++{
++  int i, ret;
++  void *tret = NULL;
++  int seq = (uintptr_t) u;
++
++  for (i = 0; i < ITERS / NUM; i++)
++    {
++      struct timespec ts;
++
++      if ((ret = clock_gettime(CLOCK_REALTIME, &ts)) != 0)
++        {
++        tret = (void *) (uintptr_t) 1;
++        printf ("%u:clock_gettime failed: %s\n", seq, strerror (errno));
++        goto out;
++      }
++      ts.tv_sec += 20;
++
++      if ((ret = pthread_mutex_lock (&mutex)) != 0)
++        {
++        tret = (void *) (uintptr_t) 1;
++        printf ("waiter[%u]:mutex_lock failed: %s\n", seq, strerror (ret));
++        goto out;
++      }
++      pthread_cleanup_push (cleanup, NULL);
++
++      /* We should not time out either.  */
++      if ((ret = pthread_cond_timedwait (&cond, &mutex, &ts)) != 0)
++        {
++        tret = (void *) (uintptr_t) 1;
++        printf ("waiter[%u]:timedwait failed: %s\n", seq, strerror (ret));
++        goto unlock_out;
++      }
++      if ((ret = pthread_mutex_unlock (&mutex)) != 0)
++        {
++        tret = (void *) (uintptr_t) 1;
++        printf ("waiter[%u]:mutex_unlock failed: %s\n", seq, strerror (ret));
++        goto out;
++      }
++      pthread_cleanup_pop (0);
++    }
++
++out:
++  puts ("timed_waiter tests done");
++  return tret;
++
++unlock_out:
++  if ((ret = pthread_mutex_unlock (&mutex)) != 0)
++    printf ("waiter[%u]:mutex_unlock[2] failed: %s\n", seq, strerror (ret));
++  goto out;
++}
++
++int
++do_test_wait (thr_func f)
++{
++  pthread_t w[NUM];
++  pthread_t s;
++  pthread_mutexattr_t attr;
++  int i, j, ret = 0;
++  void *thr_ret;
++
++  for (i = 0; i < COUNT; i++)
++    {
++      if ((ret = pthread_mutexattr_init (&attr)) != 0)
++        {
++        printf ("mutexattr_init failed: %s\n", strerror (ret));
++        goto out;
++      }
++
++      if ((ret = pthread_mutexattr_setprotocol (&attr,
++                                                PTHREAD_PRIO_INHERIT)) != 0)
++        {
++        printf ("mutexattr_setprotocol failed: %s\n", strerror (ret));
++        goto out;
++      }
++
++      if ((ret = pthread_cond_init (&cond, NULL)) != 0)
++        {
++        printf ("cond_init failed: %s\n", strerror (ret));
++        goto out;
++      }
++
++      if ((ret = pthread_mutex_init (&mutex, &attr)) != 0)
++        {
++        printf ("mutex_init failed: %s\n", strerror (ret));
++        goto out;
++      }
++
++      for (j = 0; j < NUM; j++)
++        if ((ret = pthread_create (&w[j], NULL,
++                                   f, (void *) (uintptr_t) j)) != 0)
++        {
++          printf ("waiter[%d]: create failed: %s\n", j, strerror (ret));
++          goto out;
++        }
++
++      if ((ret = pthread_create (&s, NULL, signaller, NULL)) != 0)
++        {
++        printf ("signaller: create failed: %s\n", strerror (ret));
++        goto out;
++      }
++
++      for (j = 0; j < NUM; j++)
++        {
++          pthread_cancel (w[j]);
++
++          if ((ret = pthread_join (w[j], &thr_ret)) != 0)
++          {
++            printf ("waiter[%d]: join failed: %s\n", j, strerror (ret));
++            goto out;
++          }
++
++          if (thr_ret != NULL && thr_ret != PTHREAD_CANCELED)
++          {
++            ret = 1;
++            goto out;
++          }
++        }
++
++      /* The signalling thread could have ended before it was cancelled.  */
++      pthread_cancel (s);
++
++      if ((ret = pthread_join (s, &thr_ret)) != 0)
++        {
++        printf ("signaller: join failed: %s\n", strerror (ret));
++        goto out;
++      }
++
++      if (thr_ret != NULL && thr_ret != PTHREAD_CANCELED)
++        {
++          ret = 1;
++          goto out;
++        }
++    }
++
++out:
++  return ret;
++}
++
++int
++do_test (int argc, char **argv)
++{
++  int ret = do_test_wait (waiter);
++
++  if (ret)
++    return ret;
++
++  return do_test_wait (timed_waiter);
++}
++
++#define TIMEOUT 5
++#include "../test-skeleton.c"
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/tst-cond-except.c glibc-2.12-2-gc4ccff1.fixed/nptl/tst-cond-except.c
+--- glibc-2.12-2-gc4ccff1/nptl/tst-cond-except.c       1970-01-01 05:30:00.000000000 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/tst-cond-except.c 2013-07-09 10:19:01.334420002 +0530
+@@ -0,0 +1,110 @@
++/* Verify that exception table for pthread_cond_wait is correct.
++   Copyright (C) 2012-2013 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
++   <http://www.gnu.org/licenses/>.  */
++
++#include <pthread.h>
++#include <stdio.h>
++#include <stdint.h>
++#include <string.h>
++#include <unistd.h>
++
++pthread_mutex_t mutex;
++pthread_cond_t cond;
++
++#define CHECK_RETURN_VAL_OR_FAIL(ret,str) \
++  ({ if ((ret) != 0) \
++       { \
++         printf ("%s failed: %s\n", (str), strerror (ret)); \
++         ret = 1; \
++         goto out; \
++       } \
++  })
++
++
++void
++clean (void *arg)
++{
++  puts ("clean: Unlocking mutex...");
++  pthread_mutex_unlock ((pthread_mutex_t *) arg);
++  puts ("clean: Mutex unlocked...");
++}
++
++void *
++thr (void *arg)
++{
++  int ret = 0;
++  pthread_mutexattr_t mutexAttr;
++  ret = pthread_mutexattr_init (&mutexAttr);
++  CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_mutexattr_init");
++
++  ret = pthread_mutexattr_setprotocol (&mutexAttr, PTHREAD_PRIO_INHERIT);
++  CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_mutexattr_setprotocol");
++
++  ret = pthread_mutex_init (&mutex, &mutexAttr);
++  CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_mutex_init");
++
++  ret = pthread_cond_init (&cond, 0);
++  CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_cond_init");
++
++  puts ("th: Init done, entering wait...");
++
++  pthread_cleanup_push (clean, (void *) &mutex);
++  ret = pthread_mutex_lock (&mutex);
++  CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_mutex_lock");
++  while (1)
++    {
++      ret = pthread_cond_wait (&cond, &mutex);
++      CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_cond_wait");
++    }
++  pthread_cleanup_pop (1);
++
++out:
++  return (void *) (uintptr_t) ret;
++}
++
++int
++do_test (void)
++{
++  pthread_t thread;
++  int ret = 0;
++  void *thr_ret = 0;
++  ret = pthread_create (&thread, 0, thr, &thr_ret);
++  CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_create");
++
++  puts ("main: Thread created, waiting a bit...");
++  sleep (2);
++
++  puts ("main: Cancelling thread...");
++  ret = pthread_cancel (thread);
++  CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_cancel");
++
++  puts ("main: Joining th...");
++  ret = pthread_join (thread, NULL);
++  CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_join");
++
++  if (thr_ret != NULL)
++    return 1;
++
++  puts ("main: Joined thread, done!");
++
++out:
++  return ret;
++}
++
++#define TEST_FUNCTION do_test ()
++#define TIMEOUT 5
++#include "../test-skeleton.c"
diff --git a/src/patches/glibc/glibc-rh629823-2.patch b/src/patches/glibc/glibc-rh629823-2.patch
new file mode 100644 (file)
index 0000000..d3e4f45
--- /dev/null
@@ -0,0 +1,95 @@
+commit 50fd745b4dec07e8e213cf2703b5cabcfa128225
+Author: Andreas Schwab <schwab@suse.de>
+Date:   Mon Jun 10 14:39:09 2013 +0200
+
+    Fix handling of netgroup cache in nscd
+
+diff --git a/nscd/connections.c b/nscd/connections.c
+index 7099215..69e3e7d 100644
+--- a/nscd/connections.c
++++ b/nscd/connections.c
+@@ -1779,7 +1779,7 @@ nscd_run_worker (void *p)
+       else
+       {
+         /* Get the key.  */
+-        char keybuf[MAXKEYLEN];
++        char keybuf[MAXKEYLEN + 1];
+         if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd, keybuf,
+                                                         req.key_len))
+@@ -1791,6 +1791,7 @@ nscd_run_worker (void *p)
+                        strerror_r (errno, buf, sizeof (buf)));
+             goto close_and_out;
+           }
++        keybuf[req.key_len] = '\0';
+         if (__builtin_expect (debug_level, 0) > 0)
+           {
+diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c
+index 2d6c5aa..dd06ce4 100644
+--- a/nscd/netgroupcache.c
++++ b/nscd/netgroupcache.c
+@@ -192,18 +192,26 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
+                           const char *nuser = data.val.triple.user;
+                           const char *ndomain = data.val.triple.domain;
+-                          if (data.val.triple.host > data.val.triple.user
+-                              || data.val.triple.user > data.val.triple.domain)
++                          if (nhost == NULL || nuser == NULL || ndomain == NULL
++                              || nhost > nuser || nuser > ndomain)
+                             {
+-                              const char *last = MAX (nhost,
+-                                                      MAX (nuser, ndomain));
+-                              size_t bufused = (last + strlen (last) + 1
+-                                                - buffer);
++                              const char *last = nhost;
++                              if (last == NULL
++                                  || (nuser != NULL && nuser > last))
++                                last = nuser;
++                              if (last == NULL
++                                  || (ndomain != NULL && ndomain > last))
++                                last = ndomain;
++
++                              size_t bufused
++                                = (last == NULL
++                                   ? buffilled
++                                   : last + strlen (last) + 1 - buffer);
+                               /* We have to make temporary copies.  */
+-                              size_t hostlen = strlen (nhost) + 1;
+-                              size_t userlen = strlen (nuser) + 1;
+-                              size_t domainlen = strlen (ndomain) + 1;
++                              size_t hostlen = strlen (nhost ?: "") + 1;
++                              size_t userlen = strlen (nuser ?: "") + 1;
++                              size_t domainlen = strlen (ndomain ?: "") + 1;
+                               size_t needed = hostlen + userlen + domainlen;
+                               if (buflen - req->key_len - bufused < needed)
+@@ -226,11 +234,11 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
+                                 }
+                               nhost = memcpy (buffer + bufused,
+-                                              nhost, hostlen);
++                                              nhost ?: "", hostlen);
+                               nuser = memcpy ((char *) nhost + hostlen,
+-                                              nuser, userlen);
++                                              nuser ?: "", userlen);
+                               ndomain = memcpy ((char *) nuser + userlen,
+-                                                ndomain, domainlen);
++                                                ndomain ?: "", domainlen);
+                             }
+                           char *wp = buffer + buffilled;
+diff --git a/nscd/nscd_netgroup.c b/nscd/nscd_netgroup.c
+index cac4ebf..acb2c81 100644
+--- a/nscd/nscd_netgroup.c
++++ b/nscd/nscd_netgroup.c
+@@ -48,7 +48,7 @@ __nscd_setnetgrent (const char *group, struct __netgrent *datap)
+ {
+   int gc_cycle;
+   int nretries = 0;
+-  size_t group_len = strlen (group);
++  size_t group_len = strlen (group) + 1;
+   /* If the mapping is available, try to search there instead of
+      communicating with the nscd.  */
diff --git a/src/patches/glibc/glibc-rh629823.patch b/src/patches/glibc/glibc-rh629823.patch
new file mode 100644 (file)
index 0000000..6315246
--- /dev/null
@@ -0,0 +1,1954 @@
+diff -Nrup a/grp/initgroups.c b/grp/initgroups.c
+--- a/grp/initgroups.c 2012-08-06 15:07:48.935060494 -0600
++++ b/grp/initgroups.c 2012-08-23 14:19:49.370442142 -0600
+@@ -1,4 +1,4 @@
+-/* Copyright (C) 1989,91,93,1996-2005,2006,2008 Free Software Foundation, Inc.
++/* Copyright (C) 1989,91,93,1996-2006,2008,2010 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
+@@ -58,7 +58,8 @@ internal_getgrouplist (const char *user,
+   if (__nss_not_use_nscd_group > 0
+       && ++__nss_not_use_nscd_group > NSS_NSCD_RETRY)
+     __nss_not_use_nscd_group = 0;
+-  if (!__nss_not_use_nscd_group)
++  if (!__nss_not_use_nscd_group
++      && !__nss_database_custom[NSS_DBSIDX_group])
+     {
+       int n = __nscd_getgrouplist (user, group, size, groupsp, limit);
+       if (n >= 0)
+diff -Nrup a/inet/getnetgrent_r.c b/inet/getnetgrent_r.c
+--- a/inet/getnetgrent_r.c     2010-05-04 05:27:23.000000000 -0600
++++ b/inet/getnetgrent_r.c     2012-08-06 15:10:05.865520055 -0600
+@@ -28,6 +28,7 @@
+ #include "netgroup.h"
+ #include "nsswitch.h"
+ #include <sysdep.h>
++#include <nscd/nscd_proto.h>
+ /* Protect above variable against multiple uses at the same time.  */
+@@ -101,7 +102,7 @@ endnetgrent_hook (struct __netgrent *dat
+ {
+   enum nss_status (*endfct) (struct __netgrent *);
+-  if (datap->nip == NULL)
++  if (datap->nip == NULL || datap->nip == (service_user *) -1l)
+     return;
+   endfct = __nss_lookup_function (datap->nip, "endnetgrent");
+@@ -189,8 +190,21 @@ setnetgrent (const char *group)
+   __libc_lock_lock (lock);
++  if (__nss_not_use_nscd_netgroup > 0
++      && ++__nss_not_use_nscd_netgroup > NSS_NSCD_RETRY)
++    __nss_not_use_nscd_netgroup = 0;
++
++  if (!__nss_not_use_nscd_netgroup
++      && !__nss_database_custom[NSS_DBSIDX_netgroup])
++    {
++      result = __nscd_setnetgrent (group, &dataset);
++      if (result >= 0)
++      goto out;
++    }
++
+   result = internal_setnetgrent (group, &dataset);
++ out:
+   __libc_lock_unlock (lock);
+   return result;
+@@ -226,6 +240,26 @@ int internal_getnetgrent_r (char **hostp
+                           char *buffer, size_t buflen, int *errnop);
+ libc_hidden_proto (internal_getnetgrent_r)
++
++static enum nss_status
++nscd_getnetgrent (struct __netgrent *datap, char *buffer, size_t buflen,
++                int *errnop)
++{
++  if (datap->cursor >= datap->data + datap->data_size)
++    return NSS_STATUS_UNAVAIL;
++
++  datap->type = triple_val;
++  datap->val.triple.host = datap->cursor;
++  datap->cursor = (char *) __rawmemchr (datap->cursor, '\0') + 1;
++  datap->val.triple.user = datap->cursor;
++  datap->cursor = (char *) __rawmemchr (datap->cursor, '\0') + 1;
++  datap->val.triple.domain = datap->cursor;
++  datap->cursor = (char *) __rawmemchr (datap->cursor, '\0') + 1;
++
++  return NSS_STATUS_SUCCESS;
++}
++
++
+ int
+ internal_getnetgrent_r (char **hostp, char **userp, char **domainp,
+                         struct __netgrent *datap,
+@@ -239,9 +273,18 @@ internal_getnetgrent_r (char **hostp, ch
+   /* Run through available functions, starting with the same function last
+      run.  We will repeat each function as long as it succeeds, and then go
+      on to the next service action.  */
+-  int no_more = (datap->nip == NULL
+-               || (fct = __nss_lookup_function (datap->nip, "getnetgrent_r"))
+-                  == NULL);
++  int no_more = datap->nip == NULL;
++  if (! no_more)
++    {
++      if (datap->nip == (service_user *) -1l)
++      fct = nscd_getnetgrent;
++      else
++      {
++        fct = __nss_lookup_function (datap->nip, "getnetgrent_r");
++        no_more = fct == NULL;
++      }
++    }
++
+   while (! no_more)
+     {
+       status = (*fct) (datap, buffer, buflen, &errno);
+@@ -337,6 +380,18 @@ int
+ innetgr (const char *netgroup, const char *host, const char *user,
+        const char *domain)
+ {
++  if (__nss_not_use_nscd_netgroup > 0
++      && ++__nss_not_use_nscd_netgroup > NSS_NSCD_RETRY)
++    __nss_not_use_nscd_netgroup = 0;
++
++  if (!__nss_not_use_nscd_netgroup
++      && !__nss_database_custom[NSS_DBSIDX_netgroup])
++    {
++      int result = __nscd_innetgr (netgroup, host, user, domain);
++      if (result >= 0)
++      return result;
++    }
++
+   union
+   {
+     int (*f) (const char *, struct __netgrent *);
+@@ -444,7 +499,7 @@ innetgr (const char *netgroup, const cha
+         entry.needed_groups = tmp->next;
+         tmp->next = entry.known_groups;
+         entry.known_groups = tmp;
+-        current_group = entry.known_groups->name;
++        current_group = tmp->name;
+         continue;
+       }
+diff -Nrup a/nscd/Makefile b/nscd/Makefile
+--- a/nscd/Makefile    2010-05-04 05:27:23.000000000 -0600
++++ b/nscd/Makefile    2012-08-06 15:08:19.045941627 -0600
+@@ -22,7 +22,7 @@
+ subdir        := nscd
+ routines := nscd_getpw_r nscd_getgr_r nscd_gethst_r nscd_getai \
+-          nscd_initgroups nscd_getserv_r
++          nscd_initgroups nscd_getserv_r nscd_netgroup
+ aux   := nscd_helper
+ include ../Makeconfig
+@@ -34,7 +34,8 @@ nscd-modules := nscd connections pwdcach
+               getgrnam_r getgrgid_r hstcache gethstbyad_r gethstbynm3_r \
+               getsrvbynm_r getsrvbypt_r servicescache \
+               dbg_log nscd_conf nscd_stat cache mem nscd_setup_thread \
+-              xmalloc xstrdup aicache initgrcache gai res_hconf
++              xmalloc xstrdup aicache initgrcache gai res_hconf \
++              netgroupcache
+ ifeq ($(have-thread-library),yes)
+@@ -122,6 +123,7 @@ CFLAGS-servicescache.c += $(nscd-cflags)
+ CFLAGS-getsrvbynm_r.c += $(nscd-cflags)
+ CFLAGS-getsrvbypt_r.c += $(nscd-cflags)
+ CFLAGS-res_hconf.c += $(nscd-cflags)
++CFLAGS-netgroupcache.c += $(nscd-cflags)
+ ifeq (yesyes,$(have-fpie)$(build-shared))
+ relro-LDFLAGS += -Wl,-z,now
+diff -Nrup a/nscd/cache.c b/nscd/cache.c
+--- a/nscd/cache.c     2012-08-06 15:07:48.973060344 -0600
++++ b/nscd/cache.c     2012-08-06 15:08:19.046941626 -0600
+@@ -60,7 +60,9 @@ static time_t (*const readdfcts[LASTREQ]
+   [GETAI] = readdhstai,
+   [INITGROUPS] = readdinitgroups,
+   [GETSERVBYNAME] = readdservbyname,
+-  [GETSERVBYPORT] = readdservbyport
++  [GETSERVBYPORT] = readdservbyport,
++  [GETNETGRENT] = readdgetnetgrent,
++  [INNETGR] = readdinnetgr
+ };
+@@ -70,7 +72,7 @@ static time_t (*const readdfcts[LASTREQ]
+    This function must be called with the read-lock held.  */
+ struct datahead *
+-cache_search (request_type type, void *key, size_t len,
++cache_search (request_type type, const void *key, size_t len,
+             struct database_dyn *table, uid_t owner)
+ {
+   unsigned long int hash = __nis_hash (key, len) % table->head->module;
+diff -Nrup a/nscd/connections.c b/nscd/connections.c
+--- a/nscd/connections.c       2012-08-06 15:07:49.076059937 -0600
++++ b/nscd/connections.c       2012-08-21 21:36:10.210358578 -0600
+@@ -57,11 +57,6 @@
+ #endif
+-/* Wrapper functions with error checking for standard functions.  */
+-extern void *xmalloc (size_t n);
+-extern void *xcalloc (size_t n, size_t s);
+-extern void *xrealloc (void *o, size_t n);
+-
+ /* Support to run nscd as an unprivileged user */
+ const char *server_user;
+ static uid_t server_uid;
+@@ -100,7 +95,10 @@ const char *const serv2str[LASTREQ] =
+   [INITGROUPS] = "INITGROUPS",
+   [GETSERVBYNAME] = "GETSERVBYNAME",
+   [GETSERVBYPORT] = "GETSERVBYPORT",
+-  [GETFDSERV] = "GETFDSERV"
++  [GETFDSERV] = "GETFDSERV",
++  [GETNETGRENT] = "GETNETGRENT",
++  [INNETGR] = "INNETGR",
++  [GETFDNETGR] = "GETFDNETGR"
+ };
+ /* The control data structures for the services.  */
+@@ -189,6 +187,27 @@ struct database_dyn dbs[lastdb] =
+     .wr_fd = -1,
+     .ro_fd = -1,
+     .mmap_used = false
++  },
++  [netgrdb] = {
++    .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
++    .prune_lock = PTHREAD_MUTEX_INITIALIZER,
++    .prune_run_lock = PTHREAD_MUTEX_INITIALIZER,
++    .enabled = 0,
++    .check_file = 1,
++    .persistent = 0,
++    .propagate = 0,           /* Not used.  */
++    .shared = 0,
++    .max_db_size = DEFAULT_MAX_DB_SIZE,
++    .suggested_module = DEFAULT_SUGGESTED_MODULE,
++    .reset_res = 0,
++    .filename = "/etc/netgroup",
++    .db_filename = _PATH_NSCD_NETGROUP_DB,
++    .disabled_iov = &netgroup_iov_disabled,
++    .postimeout = 28800,
++    .negtimeout = 20,
++    .wr_fd = -1,
++    .ro_fd = -1,
++    .mmap_used = false
+   }
+ };
+@@ -218,7 +237,10 @@ static struct
+   [INITGROUPS] = { true, &dbs[grpdb] },
+   [GETSERVBYNAME] = { true, &dbs[servdb] },
+   [GETSERVBYPORT] = { true, &dbs[servdb] },
+-  [GETFDSERV] = { false, &dbs[servdb] }
++  [GETFDSERV] = { false, &dbs[servdb] },
++  [GETNETGRENT] = { true, &dbs[netgrdb] },
++  [INNETGR] = { true, &dbs[netgrdb] },
++  [GETFDNETGR] = { false, &dbs[netgrdb] }
+ };
+@@ -366,7 +388,8 @@ check_use (const char *data, nscd_ssize_
+ static int
+ verify_persistent_db (void *mem, struct database_pers_head *readhead, int dbnr)
+ {
+-  assert (dbnr == pwddb || dbnr == grpdb || dbnr == hstdb || dbnr == servdb);
++  assert (dbnr == pwddb || dbnr == grpdb || dbnr == hstdb || dbnr == servdb
++        || dbnr == netgrdb);
+   time_t now = time (NULL);
+@@ -1241,6 +1264,14 @@ request from '%s' [%ld] not handled due
+       addservbyport (db, fd, req, key, uid);
+       break;
++    case GETNETGRENT:
++      addgetnetgrent (db, fd, req, key, uid);
++      break;
++
++    case INNETGR:
++      addinnetgr (db, fd, req, key, uid);
++      break;
++
+     case GETSTAT:
+     case SHUTDOWN:
+     case INVALIDATE:
+@@ -1287,6 +1318,7 @@ request from '%s' [%ld] not handled due
+     case GETFDGR:
+     case GETFDHST:
+     case GETFDSERV:
++    case GETFDNETGR:
+ #ifdef SCM_RIGHTS
+       send_ro_fd (reqinfo[req->type].db, key, fd);
+ #endif
+diff -Nrup a/nscd/netgroupcache.c b/nscd/netgroupcache.c
+--- a/nscd/netgroupcache.c     1969-12-31 17:00:00.000000000 -0700
++++ b/nscd/netgroupcache.c     2012-08-24 11:38:05.118254176 -0600
+@@ -0,0 +1,667 @@
++/* Cache handling for netgroup lookup.
++   Copyright (C) 2011 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++   Contributed by Ulrich Drepper <drepper@gmail.com>, 2011.
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published
++   by the Free Software Foundation; version 2 of the License, or
++   (at your option) any later version.
++
++   This program 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 General Public License for more details.
++
++   You should have received a copy of the GNU General Public License
++   along with this program; if not, write to the Free Software Foundation,
++   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
++
++#include <alloca.h>
++#include <assert.h>
++#include <errno.h>
++#include <libintl.h>
++#include <stdbool.h>
++#include <unistd.h>
++#include <sys/mman.h>
++
++#include "../inet/netgroup.h"
++#include "nscd.h"
++#include "dbg_log.h"
++#ifdef HAVE_SENDFILE
++# include <kernel-features.h>
++#endif
++
++
++/* This is the standard reply in case the service is disabled.  */
++static const netgroup_response_header disabled =
++{
++  .version = NSCD_VERSION,
++  .found = -1,
++  .nresults = 0,
++  .result_len = 0
++};
++
++/* This is the struct describing how to write this record.  */
++const struct iovec netgroup_iov_disabled =
++{
++  .iov_base = (void *) &disabled,
++  .iov_len = sizeof (disabled)
++};
++
++
++/* This is the standard reply in case we haven't found the dataset.  */
++static const netgroup_response_header notfound =
++{
++  .version = NSCD_VERSION,
++  .found = 0,
++  .nresults = 0,
++  .result_len = 0
++};
++
++
++struct dataset
++{
++  struct datahead head;
++  netgroup_response_header resp;
++  char strdata[0];
++};
++
++
++static time_t
++addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
++               const char *key, uid_t uid, struct hashentry *he,
++               struct datahead *dh, struct dataset **resultp)
++{
++  if (__builtin_expect (debug_level > 0, 0))
++    {
++      if (he == NULL)
++      dbg_log (_("Haven't found \"%s\" in netgroup cache!"), key);
++      else
++      dbg_log (_("Reloading \"%s\" in netgroup cache!"), key);
++    }
++
++  static service_user *netgroup_database;
++  time_t timeout;
++  struct dataset *dataset;
++  bool cacheable = false;
++  ssize_t total;
++
++  char *key_copy = NULL;
++  struct __netgrent data;
++  size_t buflen = MAX (1024, sizeof (*dataset) + req->key_len);
++  size_t buffilled = sizeof (*dataset);
++  char *buffer = NULL;
++  size_t nentries = 0;
++  bool use_malloc = false;
++  size_t group_len = strlen (key) + 1;
++  union
++  {
++    struct name_list elem;
++    char mem[sizeof (struct name_list) + group_len];
++  } first_needed;
++
++  if (netgroup_database == NULL
++      && __nss_database_lookup ("netgroup", NULL, NULL, &netgroup_database))
++    {
++      /* No such service.  */
++      total = sizeof (notfound);
++      timeout = time (NULL) + db->negtimeout;
++
++      if (fd != -1)
++      TEMP_FAILURE_RETRY (send (fd, &notfound, total, MSG_NOSIGNAL));
++
++      dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len, 1);
++      /* If we cannot permanently store the result, so be it.  */
++      if (dataset != NULL)
++      {
++        dataset->head.allocsize = sizeof (struct dataset) + req->key_len;
++        dataset->head.recsize = total;
++        dataset->head.notfound = true;
++        dataset->head.nreloads = 0;
++        dataset->head.usable = true;
++
++        /* Compute the timeout time.  */
++        timeout = dataset->head.timeout = time (NULL) + db->negtimeout;
++        dataset->head.ttl = db->negtimeout;
++
++        /* This is the reply.  */
++        memcpy (&dataset->resp, &notfound, total);
++
++        /* Copy the key data.  */
++        memcpy (dataset->strdata, key, req->key_len);
++
++        cacheable = true;
++      }
++
++      goto writeout;
++    }
++
++  memset (&data, '\0', sizeof (data));
++  buffer = alloca (buflen);
++  first_needed.elem.next = &first_needed.elem;
++  memcpy (first_needed.elem.name, key, group_len);
++  data.needed_groups = &first_needed.elem;
++
++  while (data.needed_groups != NULL)
++    {
++      /* Add the next group to the list of those which are known.  */
++      struct name_list *this_group = data.needed_groups->next;
++      if (this_group == data.needed_groups)
++      data.needed_groups = NULL;
++      else
++      data.needed_groups->next = this_group->next;
++      this_group->next = data.known_groups;
++      data.known_groups = this_group;
++
++      union
++      {
++      enum nss_status (*f) (const char *, struct __netgrent *);
++      void *ptr;
++      } setfct;
++
++      service_user *nip = netgroup_database;
++      int no_more = __nss_lookup (&nip, "setnetgrent", NULL, &setfct.ptr);
++      while (!no_more)
++      {
++        enum nss_status status
++          = DL_CALL_FCT (*setfct.f, (data.known_groups->name, &data));
++
++        if (status == NSS_STATUS_SUCCESS)
++          {
++            union
++            {
++              enum nss_status (*f) (struct __netgrent *, char *, size_t,
++                                    int *);
++              void *ptr;
++            } getfct;
++            getfct.ptr = __nss_lookup_function (nip, "getnetgrent_r");
++            if (getfct.f != NULL)
++              while (1)
++                {
++                  int e;
++                  status = getfct.f (&data, buffer + buffilled,
++                                     buflen - buffilled, &e);
++                  if (status == NSS_STATUS_RETURN)
++                    /* This was the last one for this group.  Look
++                       at next group if available.  */
++                    break;
++                  if (status == NSS_STATUS_SUCCESS)
++                    {
++                      if (data.type == triple_val)
++                        {
++                          const char *nhost = data.val.triple.host;
++                          const char *nuser = data.val.triple.user;
++                          const char *ndomain = data.val.triple.domain;
++
++                          if (data.val.triple.host > data.val.triple.user
++                              || data.val.triple.user > data.val.triple.domain)
++                            {
++                              const char *last = MAX (nhost,
++                                                      MAX (nuser, ndomain));
++                              size_t bufused = (last + strlen (last) + 1
++                                                - buffer);
++
++                              /* We have to make temporary copies.  */
++                              size_t hostlen = strlen (nhost) + 1;
++                              size_t userlen = strlen (nuser) + 1;
++                              size_t domainlen = strlen (ndomain) + 1;
++                              size_t needed = hostlen + userlen + domainlen;
++
++                              if (buflen - req->key_len - bufused < needed)
++                                {
++                                  size_t newsize = MAX (2 * buflen,
++                                                        buflen + 2 * needed);
++                                  if (use_malloc || newsize > 1024 * 1024)
++                                    {
++                                      buflen = newsize;
++                                      char *newbuf = xrealloc (use_malloc
++                                                               ? buffer
++                                                               : NULL,
++                                                               buflen);
++
++                                      buffer = newbuf;
++                                      use_malloc = true;
++                                    }
++                                  else
++                                    extend_alloca (buffer, buflen, newsize);
++                                }
++
++                              nhost = memcpy (buffer + bufused,
++                                              nhost, hostlen);
++                              nuser = memcpy ((char *) nhost + hostlen,
++                                              nuser, userlen);
++                              ndomain = memcpy ((char *) nuser + userlen,
++                                                ndomain, domainlen);
++                            }
++
++                          char *wp = buffer + buffilled;
++                          wp = stpcpy (wp, nhost) + 1;
++                          wp = stpcpy (wp, nuser) + 1;
++                          wp = stpcpy (wp, ndomain) + 1;
++                          buffilled = wp - buffer;
++                          ++nentries;
++                        }
++                      else
++                        {
++                          /* Check that the group has not been
++                             requested before.  */
++                          struct name_list *runp = data.needed_groups;
++                          if (runp != NULL)
++                            while (1)
++                              {
++                                if (strcmp (runp->name, data.val.group) == 0)
++                                  break;
++
++                                runp = runp->next;
++                                if (runp == data.needed_groups)
++                                  {
++                                    runp = NULL;
++                                    break;
++                                  }
++                              }
++
++                          if (runp == NULL)
++                            {
++                              runp = data.known_groups;
++                              while (runp != NULL)
++                                if (strcmp (runp->name, data.val.group) == 0)
++                                  break;
++                                else
++                                  runp = runp->next;
++                              }
++
++                          if (runp == NULL)
++                            {
++                              /* A new group is requested.  */
++                              size_t namelen = strlen (data.val.group) + 1;
++                              struct name_list *newg = alloca (sizeof (*newg)
++                                                               + namelen);
++                              memcpy (newg->name, data.val.group, namelen);
++                              if (data.needed_groups == NULL)
++                                data.needed_groups = newg->next = newg;
++                              else
++                                {
++                                  newg->next = data.needed_groups->next;
++                                  data.needed_groups->next = newg;
++                                  data.needed_groups = newg;
++                                }
++                            }
++                        }
++                    }
++                  else if (status == NSS_STATUS_UNAVAIL && e == ERANGE)
++                    {
++                      size_t newsize = 2 * buflen;
++                      if (use_malloc || newsize > 1024 * 1024)
++                        {
++                          buflen = newsize;
++                          char *newbuf = xrealloc (use_malloc
++                                                   ? buffer : NULL, buflen);
++
++                          buffer = newbuf;
++                          use_malloc = true;
++                        }
++                      else
++                        extend_alloca (buffer, buflen, newsize);
++                    }
++                }
++
++            enum nss_status (*endfct) (struct __netgrent *);
++            endfct = __nss_lookup_function (nip, "endnetgrent");
++            if (endfct != NULL)
++              (void) DL_CALL_FCT (*endfct, (&data));
++
++            break;
++          }
++
++        no_more = __nss_next2 (&nip, "setnetgrent", NULL, &setfct.ptr,
++                               status, 0);
++      }
++    }
++
++  total = buffilled;
++
++  /* Fill in the dataset.  */
++  dataset = (struct dataset *) buffer;
++  dataset->head.allocsize = total + req->key_len;
++  dataset->head.recsize = total - offsetof (struct dataset, resp);
++  dataset->head.notfound = false;
++  dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
++  dataset->head.usable = true;
++  dataset->head.ttl = db->postimeout;
++  timeout = dataset->head.timeout = time (NULL) + dataset->head.ttl;
++
++  dataset->resp.version = NSCD_VERSION;
++  dataset->resp.found = 1;
++  dataset->resp.nresults = nentries;
++  dataset->resp.result_len = buffilled - sizeof (*dataset);
++
++  assert (buflen - buffilled >= req->key_len);
++  key_copy = memcpy (buffer + buffilled, key, req->key_len);
++  buffilled += req->key_len;
++
++  /* Now we can determine whether on refill we have to create a new
++     record or not.  */
++  if (he != NULL)
++    {
++      assert (fd == -1);
++
++      if (dataset->head.allocsize == dh->allocsize
++        && dataset->head.recsize == dh->recsize
++        && memcmp (&dataset->resp, dh->data,
++                   dh->allocsize - offsetof (struct dataset, resp)) == 0)
++      {
++        /* The data has not changed.  We will just bump the timeout
++           value.  Note that the new record has been allocated on
++           the stack and need not be freed.  */
++        dh->timeout = dataset->head.timeout;
++        dh->ttl = dataset->head.ttl;
++        ++dh->nreloads;
++        dataset = (struct dataset *) dh;
++
++        goto out;
++      }
++    }
++
++  {
++    struct dataset *newp
++      = (struct dataset *) mempool_alloc (db, total + req->key_len, 1);
++    if (__builtin_expect (newp != NULL, 1))
++      {
++      /* Adjust pointer into the memory block.  */
++      key_copy = (char *) newp + (key_copy - buffer);
++
++      dataset = memcpy (newp, dataset, total + req->key_len);
++      cacheable = true;
++
++      if (he != NULL)
++        /* Mark the old record as obsolete.  */
++        dh->usable = false;
++      }
++  }
++
++  if (he == NULL && fd != -1)
++    {
++      /* We write the dataset before inserting it to the database
++       since while inserting this thread might block and so would
++       unnecessarily let the receiver wait.  */
++    writeout:
++#ifdef HAVE_SENDFILE
++      if (__builtin_expect (db->mmap_used, 1) && cacheable)
++      {
++        assert (db->wr_fd != -1);
++        assert ((char *) &dataset->resp > (char *) db->data);
++        assert ((char *) dataset - (char *) db->head + total
++                <= (sizeof (struct database_pers_head)
++                    + db->head->module * sizeof (ref_t)
++                    + db->head->data_size));
++# ifndef __ASSUME_SENDFILE
++        ssize_t written =
++# endif
++          sendfileall (fd, db->wr_fd, (char *) &dataset->resp
++                       - (char *) db->head, dataset->head.recsize);
++# ifndef __ASSUME_SENDFILE
++        if (written == -1 && errno == ENOSYS)
++          goto use_write;
++# endif
++      }
++      else
++#endif
++      {
++#if defined HAVE_SENDFILE && !defined __ASSUME_SENDFILE
++      use_write:
++#endif
++        writeall (fd, &dataset->resp, dataset->head.recsize);
++      }
++    }
++
++  if (cacheable)
++    {
++      /* If necessary, we also propagate the data to disk.  */
++      if (db->persistent)
++      {
++        // XXX async OK?
++        uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
++        msync ((void *) pval,
++               ((uintptr_t) dataset & pagesize_m1) + total + req->key_len,
++               MS_ASYNC);
++      }
++
++      (void) cache_add (req->type, key_copy, req->key_len, &dataset->head,
++                      true, db, uid, he == NULL);
++
++      pthread_rwlock_unlock (&db->lock);
++
++      /* Mark the old entry as obsolete.  */
++      if (dh != NULL)
++      dh->usable = false;
++    }
++
++ out:
++  if (use_malloc)
++    free (buffer);
++
++  *resultp = dataset;
++
++  return timeout;
++}
++
++
++static time_t
++addinnetgrX (struct database_dyn *db, int fd, request_header *req,
++           char *key, uid_t uid, struct hashentry *he,
++           struct datahead *dh)
++{
++  const char *group = key;
++  key = (char *) rawmemchr (key, '\0') + 1;
++  size_t group_len = key - group - 1;
++  const char *host = *key++ ? key : NULL;
++  if (host != NULL)
++    key = (char *) rawmemchr (key, '\0') + 1;
++  const char *user = *key++ ? key : NULL;
++  if (user != NULL)
++    key = (char *) rawmemchr (key, '\0') + 1;
++  const char *domain = *key++ ? key : NULL;
++
++  if (__builtin_expect (debug_level > 0, 0))
++    {
++      if (he == NULL)
++      dbg_log (_("Haven't found \"%s (%s,%s,%s)\" in netgroup cache!"),
++               group, host ?: "", user ?: "", domain ?: "");
++      else
++      dbg_log (_("Reloading \"%s (%s,%s,%s)\" in netgroup cache!"),
++               group, host ?: "", user ?: "", domain ?: "");
++    }
++
++  struct dataset *result = (struct dataset *) cache_search (GETNETGRENT,
++                                                          group, group_len,
++                                                          db, uid);
++  time_t timeout;
++  if (result != NULL)
++    timeout = result->head.timeout;
++  else
++    {
++      request_header req_get =
++      {
++        .type = GETNETGRENT,
++        .key_len = group_len
++      };
++      timeout = addgetnetgrentX (db, -1, &req_get, group, uid, NULL, NULL,
++                               &result);
++    }
++
++  struct indataset
++  {
++    struct datahead head;
++    innetgroup_response_header resp;
++  } *dataset
++      = (struct indataset *) mempool_alloc (db,
++                                          sizeof (*dataset) + req->key_len,
++                                          1);
++  struct indataset dataset_mem;
++  bool cacheable = true;
++  if (__builtin_expect (dataset == NULL, 0))
++    {
++      cacheable = false;
++      dataset = &dataset_mem;
++    }
++
++  dataset->head.allocsize = sizeof (*dataset) + req->key_len;
++  dataset->head.recsize = sizeof (innetgroup_response_header);
++  dataset->head.notfound = result->head.notfound;
++  dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
++  dataset->head.usable = true;
++  dataset->head.ttl = result->head.ttl;
++  dataset->head.timeout = timeout;
++
++  dataset->resp.version = NSCD_VERSION;
++  dataset->resp.found = result->resp.found;
++  /* Until we find a matching entry the result is 0.  */
++  dataset->resp.result = 0;
++
++  char *key_copy = memcpy ((char *) (dataset + 1), group, req->key_len);
++
++  if (dataset->resp.found)
++    {
++      const char *triplets = (const char *) (&result->resp + 1);
++
++      for (nscd_ssize_t i = result->resp.nresults; i > 0; --i)
++      {
++        bool success = true;
++
++        if (host != NULL)
++          success = strcmp (host, triplets) == 0;
++        triplets = (const char *) rawmemchr (triplets, '\0') + 1;
++
++        if (success && user != NULL)
++          success = strcmp (user, triplets) == 0;
++        triplets = (const char *) rawmemchr (triplets, '\0') + 1;
++
++        if (success && (domain == NULL || strcmp (domain, triplets) == 0))
++          {
++            dataset->resp.result = 1;
++            break;
++          }
++        triplets = (const char *) rawmemchr (triplets, '\0') + 1;
++      }
++    }
++
++  if (he != NULL && dh->data[0].innetgroupdata.result == dataset->resp.result)
++    {
++      /* The data has not changed.  We will just bump the timeout
++       value.  Note that the new record has been allocated on
++       the stack and need not be freed.  */
++      dh->timeout = timeout;
++      dh->ttl = dataset->head.ttl;
++      ++dh->nreloads;
++      return timeout;
++    }
++
++  if (he == NULL)
++    {
++      /* We write the dataset before inserting it to the database
++       since while inserting this thread might block and so would
++       unnecessarily let the receiver wait.  */
++       assert (fd != -1);
++
++#ifdef HAVE_SENDFILE
++      if (__builtin_expect (db->mmap_used, 1) && cacheable)
++      {
++        assert (db->wr_fd != -1);
++        assert ((char *) &dataset->resp > (char *) db->data);
++        assert ((char *) dataset - (char *) db->head + sizeof (*dataset)
++                <= (sizeof (struct database_pers_head)
++                    + db->head->module * sizeof (ref_t)
++                    + db->head->data_size));
++# ifndef __ASSUME_SENDFILE
++        ssize_t written =
++# endif
++          sendfileall (fd, db->wr_fd,
++                       (char *) &dataset->resp - (char *) db->head,
++                       sizeof (innetgroup_response_header));
++# ifndef __ASSUME_SENDFILE
++        if (written == -1 && errno == ENOSYS)
++          goto use_write;
++# endif
++      }
++      else
++# ifndef __ASSUME_SENDFILE
++      use_write:
++# endif
++#endif
++        writeall (fd, &dataset->resp, sizeof (innetgroup_response_header));
++    }
++
++  if (cacheable)
++    {
++      /* If necessary, we also propagate the data to disk.  */
++      if (db->persistent)
++      {
++        // XXX async OK?
++        uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
++        msync ((void *) pval,
++               ((uintptr_t) dataset & pagesize_m1) + sizeof (*dataset)
++               + req->key_len,
++               MS_ASYNC);
++      }
++
++      (void) cache_add (req->type, key_copy, req->key_len, &dataset->head,
++                      true, db, uid, he == NULL);
++
++      pthread_rwlock_unlock (&db->lock);
++
++      /* Mark the old entry as obsolete.  */
++      if (dh != NULL)
++      dh->usable = false;
++    }
++
++  return timeout;
++}
++
++
++void
++addgetnetgrent (struct database_dyn *db, int fd, request_header *req,
++              void *key, uid_t uid)
++{
++  struct dataset *ignore;
++
++  addgetnetgrentX (db, fd, req, key, uid, NULL, NULL, &ignore);
++}
++
++
++time_t
++readdgetnetgrent (struct database_dyn *db, struct hashentry *he,
++                struct datahead *dh)
++{
++  request_header req =
++    {
++      .type = GETNETGRENT,
++      .key_len = he->len
++    };
++  struct dataset *ignore;
++
++  return addgetnetgrentX (db, -1, &req, db->data + he->key, he->owner, he, dh,
++                        &ignore);
++}
++
++
++void
++addinnetgr (struct database_dyn *db, int fd, request_header *req,
++          void *key, uid_t uid)
++{
++  addinnetgrX (db, fd, req, key, uid, NULL, NULL);
++}
++
++
++time_t
++readdinnetgr (struct database_dyn *db, struct hashentry *he,
++            struct datahead *dh)
++{
++  request_header req =
++    {
++      .type = INNETGR,
++      .key_len = he->len
++    };
++
++  return addinnetgrX (db, -1, &req, db->data + he->key, he->owner, he, dh);
++}
+diff -Nrup a/nscd/nscd-client.h b/nscd/nscd-client.h
+--- a/nscd/nscd-client.h       2012-08-06 15:07:49.082059915 -0600
++++ b/nscd/nscd-client.h       2012-08-06 15:08:19.090941456 -0600
+@@ -70,6 +70,9 @@ typedef enum
+   GETSERVBYNAME,
+   GETSERVBYPORT,
+   GETFDSERV,
++  GETNETGRENT,
++  INNETGR,
++  GETFDNETGR,
+   LASTREQ
+ } request_type;
+@@ -171,6 +174,24 @@ typedef struct
+ } serv_response_header;
++/* Structure send in reply to netgroup query.  Note that this struct is
++   sent also if the service is disabled or there is no record found.  */
++typedef struct
++{
++  int32_t version;
++  int32_t found;
++  nscd_ssize_t nresults;
++  nscd_ssize_t result_len;
++} netgroup_response_header;
++
++typedef struct
++{
++  int32_t version;
++  int32_t found;
++  int32_t result;
++} innetgroup_response_header;
++
++
+ /* Type for offsets in data part of database.  */
+ typedef uint32_t ref_t;
+ /* Value for invalid/no reference.  */
+@@ -210,6 +231,8 @@ struct datahead
+     ai_response_header aidata;
+     initgr_response_header initgrdata;
+     serv_response_header servdata;
++    netgroup_response_header netgroupdata;
++    innetgroup_response_header innetgroupdata;
+     nscd_ssize_t align1;
+     nscd_time_t align2;
+   } data[0];
+diff -Nrup a/nscd/nscd.conf b/nscd/nscd.conf
+--- a/nscd/nscd.conf   2012-08-06 15:07:48.553062002 -0600
++++ b/nscd/nscd.conf   2012-08-06 15:08:19.091941452 -0600
+@@ -77,3 +77,12 @@
+       persistent              services        yes
+       shared                  services        yes
+       max-db-size             services        33554432
++
++      enable-cache            netgroup        yes
++      positive-time-to-live   netgroup        28800
++      negative-time-to-live   netgroup        20
++      suggested-size          netgroup        211
++      check-files             netgroup        yes
++      persistent              netgroup        yes
++      shared                  netgroup        yes
++      max-db-size             netgroup        33554432
+diff -Nrup a/nscd/nscd.h b/nscd/nscd.h
+--- a/nscd/nscd.h      2012-08-06 15:07:49.085059903 -0600
++++ b/nscd/nscd.h      2012-08-06 15:08:19.093941443 -0600
+@@ -38,6 +38,7 @@ typedef enum
+   grpdb,
+   hstdb,
+   servdb,
++  netgrdb,
+   lastdb
+ } dbtype;
+@@ -107,6 +108,7 @@ struct database_dyn
+ #define _PATH_NSCD_GROUP_DB   "/var/db/nscd/group"
+ #define _PATH_NSCD_HOSTS_DB   "/var/db/nscd/hosts"
+ #define _PATH_NSCD_SERVICES_DB        "/var/db/nscd/services"
++#define _PATH_NSCD_NETGROUP_DB        "/var/db/nscd/netgroup"
+ /* Path used when not using persistent storage.  */
+ #define _PATH_NSCD_XYZ_DB_TMP "/var/run/nscd/dbXXXXXX"
+@@ -140,6 +142,7 @@ extern const struct iovec pwd_iov_disabl
+ extern const struct iovec grp_iov_disabled;
+ extern const struct iovec hst_iov_disabled;
+ extern const struct iovec serv_iov_disabled;
++extern const struct iovec netgroup_iov_disabled;
+ /* Initial number of threads to run.  */
+@@ -185,6 +188,11 @@ extern gid_t old_gid;
+ /* Prototypes for global functions.  */
++/* Wrapper functions with error checking for standard functions.  */
++extern void *xmalloc (size_t n);
++extern void *xcalloc (size_t n, size_t s);
++extern void *xrealloc (void *o, size_t n);
++
+ /* nscd.c */
+ extern void termination_handler (int signum) __attribute__ ((__noreturn__));
+ extern int nscd_open_socket (void);
+@@ -203,8 +211,8 @@ extern void send_stats (int fd, struct d
+ extern int receive_print_stats (void) __attribute__ ((__noreturn__));
+ /* cache.c */
+-extern struct datahead *cache_search (request_type, void *key, size_t len,
+-                                    struct database_dyn *table,
++extern struct datahead *cache_search (request_type, const void *key,
++                                    size_t len, struct database_dyn *table,
+                                     uid_t owner);
+ extern int cache_add (int type, const void *key, size_t len,
+                     struct datahead *packet, bool first,
+@@ -273,6 +281,16 @@ extern void addservbyport (struct databa
+ extern time_t readdservbyport (struct database_dyn *db, struct hashentry *he,
+                              struct datahead *dh);
++/* netgroupcache.c */
++extern void addinnetgr (struct database_dyn *db, int fd, request_header *req,
++                      void *key, uid_t uid);
++extern time_t readdinnetgr (struct database_dyn *db, struct hashentry *he,
++                          struct datahead *dh);
++extern void addgetnetgrent (struct database_dyn *db, int fd,
++                          request_header *req, void *key, uid_t uid);
++extern time_t readdgetnetgrent (struct database_dyn *db, struct hashentry *he,
++                              struct datahead *dh);
++
+ /* mem.c */
+ extern void *mempool_alloc (struct database_dyn *db, size_t len,
+                           int data_alloc);
+diff -Nrup a/nscd/nscd_conf.c b/nscd/nscd_conf.c
+--- a/nscd/nscd_conf.c 2010-05-04 05:27:23.000000000 -0600
++++ b/nscd/nscd_conf.c 2012-08-06 15:08:19.093941443 -0600
+@@ -43,7 +43,8 @@ const char *const dbnames[lastdb] =
+   [pwddb] = "passwd",
+   [grpdb] = "group",
+   [hstdb] = "hosts",
+-  [servdb] = "services"
++  [servdb] = "services",
++  [netgrdb] = "netgroup"
+ };
+diff -Nrup a/nscd/nscd_netgroup.c b/nscd/nscd_netgroup.c
+--- a/nscd/nscd_netgroup.c     1969-12-31 17:00:00.000000000 -0700
++++ b/nscd/nscd_netgroup.c     2012-08-06 15:08:19.094941439 -0600
+@@ -0,0 +1,290 @@
++/* Copyright (C) 2011 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++   Contributed by Ulrich Drepper <drepper@gmail.com>, 2011.
++
++   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, write to the Free
++   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++   02111-1307 USA.  */
++
++#include <alloca.h>
++#include <errno.h>
++#include <stdlib.h>
++#include <string.h>
++#include <not-cancel.h>
++
++#include "nscd-client.h"
++#include "nscd_proto.h"
++
++int __nss_not_use_nscd_netgroup;
++
++
++libc_locked_map_ptr (static, map_handle);
++/* Note that we only free the structure if necessary.  The memory
++   mapping is not removed since it is not visible to the malloc
++   handling.  */
++libc_freeres_fn (pw_map_free)
++{
++  if (map_handle.mapped != NO_MAPPING)
++    {
++      void *p = map_handle.mapped;
++      map_handle.mapped = NO_MAPPING;
++      free (p);
++    }
++}
++
++
++int
++__nscd_setnetgrent (const char *group, struct __netgrent *datap)
++{
++  int gc_cycle;
++  int nretries = 0;
++  size_t group_len = strlen (group);
++
++  /* If the mapping is available, try to search there instead of
++     communicating with the nscd.  */
++  struct mapped_database *mapped;
++  mapped = __nscd_get_map_ref (GETFDNETGR, "netgroup", &map_handle, &gc_cycle);
++
++ retry:;
++  char *respdata = NULL;
++  int retval = -1;
++  netgroup_response_header netgroup_resp;
++
++  if (mapped != NO_MAPPING)
++    {
++      struct datahead *found = __nscd_cache_search (GETNETGRENT, group,
++                                                  group_len, mapped,
++                                                  sizeof netgroup_resp);
++      if (found != NULL)
++      {
++        respdata = (char *) (&found->data[0].netgroupdata + 1);
++        netgroup_resp = found->data[0].netgroupdata;
++        /* Now check if we can trust pw_resp fields.  If GC is
++           in progress, it can contain anything.  */
++        if (mapped->head->gc_cycle != gc_cycle)
++          {
++            retval = -2;
++            goto out;
++          }
++      }
++    }
++
++  int sock = -1;
++  if (respdata == NULL)
++    {
++      sock = __nscd_open_socket (group, group_len, GETNETGRENT,
++                               &netgroup_resp, sizeof (netgroup_resp));
++      if (sock == -1)
++      {
++        /* nscd not running or wrong version.  */
++        __nss_not_use_nscd_netgroup = 1;
++        goto out;
++      }
++    }
++
++  if (netgroup_resp.found == 1)
++    {
++      size_t datalen = netgroup_resp.result_len;
++
++      /* If we do not have to read the data here it comes from the
++       mapped data and does not have to be freed.  */
++      if (respdata == NULL)
++      {
++        /* The data will come via the socket.  */
++        respdata = malloc (datalen);
++        if (respdata == NULL)
++          goto out_close;
++
++        if ((size_t) __readall (sock, respdata, datalen) != datalen)
++          {
++            free (respdata);
++            goto out_close;
++          }
++      }
++
++      datap->data = respdata;
++      datap->data_size = datalen;
++      datap->cursor = respdata;
++      datap->first = 1;
++      datap->nip = (service_user *) -1l;
++      datap->known_groups = NULL;
++      datap->needed_groups = NULL;
++
++      retval = 1;
++    }
++  else
++    {
++      if (__builtin_expect (netgroup_resp.found == -1, 0))
++      {
++        /* The daemon does not cache this database.  */
++        __nss_not_use_nscd_netgroup = 1;
++        goto out_close;
++      }
++
++      /* Set errno to 0 to indicate no error, just no found record.  */
++      __set_errno (0);
++      /* Even though we have not found anything, the result is zero.  */
++      retval = 0;
++    }
++
++ out_close:
++  if (sock != -1)
++    close_not_cancel_no_status (sock);
++ out:
++  if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
++    {
++      /* When we come here this means there has been a GC cycle while we
++       were looking for the data.  This means the data might have been
++       inconsistent.  Retry if possible.  */
++      if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
++      {
++        /* nscd is just running gc now.  Disable using the mapping.  */
++        if (atomic_decrement_val (&mapped->counter) == 0)
++          __nscd_unmap (mapped);
++        mapped = NO_MAPPING;
++      }
++
++      if (retval != -1)
++      goto retry;
++    }
++
++  return retval;
++}
++
++
++int
++__nscd_innetgr (const char *netgroup, const char *host, const char *user,
++              const char *domain)
++{
++  size_t key_len = (strlen (netgroup) + strlen (host ?: "")
++                  + strlen (user ?: "") + strlen (domain ?: "") + 7);
++  char *key;
++  bool use_alloca = __libc_use_alloca (key_len);
++  if (use_alloca)
++    key = alloca (key_len);
++  else
++    {
++      key = malloc (key_len);
++      if (key == NULL)
++      return -1;
++    }
++  char *wp = stpcpy (key, netgroup) + 1;
++  if (host != NULL)
++    {
++      *wp++ = '\1';
++      wp = stpcpy (wp, host) + 1;
++    }
++  else
++    *wp++ = '\0';
++  if (user != NULL)
++    {
++      *wp++ = '\1';
++      wp = stpcpy (wp, user) + 1;
++    }
++  else
++    *wp++ = '\0';
++  if (domain != NULL)
++    {
++      *wp++ = '\1';
++      wp = stpcpy (wp, domain) + 1;
++    }
++  else
++    *wp++ = '\0';
++  key_len = wp - key;
++
++  /* If the mapping is available, try to search there instead of
++     communicating with the nscd.  */
++  int gc_cycle;
++  int nretries = 0;
++  struct mapped_database *mapped;
++  mapped = __nscd_get_map_ref (GETFDNETGR, "netgroup", &map_handle, &gc_cycle);
++
++ retry:;
++  int retval = -1;
++  innetgroup_response_header innetgroup_resp;
++  int sock = -1;
++
++  if (mapped != NO_MAPPING)
++    {
++      struct datahead *found = __nscd_cache_search (INNETGR, key,
++                                                  key_len, mapped,
++                                                  sizeof innetgroup_resp);
++      if (found != NULL)
++      {
++        innetgroup_resp = found->data[0].innetgroupdata;
++        /* Now check if we can trust pw_resp fields.  If GC is
++           in progress, it can contain anything.  */
++        if (mapped->head->gc_cycle != gc_cycle)
++          {
++            retval = -2;
++            goto out;
++          }
++
++        goto found_entry;
++      }
++    }
++
++  sock = __nscd_open_socket (key, key_len, INNETGR,
++                           &innetgroup_resp, sizeof (innetgroup_resp));
++  if (sock == -1)
++    {
++      /* nscd not running or wrong version.  */
++      __nss_not_use_nscd_netgroup = 1;
++      goto out;
++    }
++
++ found_entry:
++  if (innetgroup_resp.found == 1)
++    retval = innetgroup_resp.result;
++  else
++    {
++      if (__builtin_expect (innetgroup_resp.found == -1, 0))
++      {
++        /* The daemon does not cache this database.  */
++        __nss_not_use_nscd_netgroup = 1;
++        goto out_close;
++      }
++
++      /* Set errno to 0 to indicate no error, just no found record.  */
++      __set_errno (0);
++      /* Even though we have not found anything, the result is zero.  */
++      retval = 0;
++    }
++
++ out_close:
++  if (sock != -1)
++    close_not_cancel_no_status (sock);
++ out:
++  if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
++    {
++      /* When we come here this means there has been a GC cycle while we
++       were looking for the data.  This means the data might have been
++       inconsistent.  Retry if possible.  */
++      if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
++      {
++        /* nscd is just running gc now.  Disable using the mapping.  */
++        if (atomic_decrement_val (&mapped->counter) == 0)
++          __nscd_unmap (mapped);
++        mapped = NO_MAPPING;
++      }
++
++      if (retval != -1)
++      goto retry;
++    }
++
++  if (! use_alloca)
++    free (key);
++
++  return retval;
++}
+diff -Nrup a/nscd/nscd_proto.h b/nscd/nscd_proto.h
+--- a/nscd/nscd_proto.h        2010-05-04 05:27:23.000000000 -0600
++++ b/nscd/nscd_proto.h        2012-08-06 15:14:24.446648305 -0600
+@@ -1,4 +1,4 @@
+-/* Copyright (C) 1998-2000, 2002, 2004, 2007 Free Software Foundation, Inc.
++/* Copyright (C) 1998-2000,2002,2004,2007,2011 Free Software Foundation, Inc.
+    This file is part of the GNU C Library.
+    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
+@@ -36,6 +36,7 @@ extern int __nss_not_use_nscd_passwd att
+ extern int __nss_not_use_nscd_group attribute_hidden;
+ extern int __nss_not_use_nscd_hosts attribute_hidden;
+ extern int __nss_not_use_nscd_services attribute_hidden;
++extern int __nss_not_use_nscd_netgroup attribute_hidden;
+ extern int __nscd_getpwnam_r (const char *name, struct passwd *resultbuf,
+                             char *buffer, size_t buflen,
+@@ -71,5 +72,9 @@ extern int __nscd_getservbyname_r (const
+ extern int __nscd_getservbyport_r (int port, const char *proto,
+                                  struct servent *result_buf, char *buf,
+                                  size_t buflen, struct servent **result);
++extern int __nscd_innetgr (const char *netgroup, const char *host,
++                         const char *user, const char *domain);
++extern int __nscd_setnetgrent (const char *group, struct __netgrent *datap);
++
+ #endif /* _NSCD_PROTO_H */
+diff -Nrup a/nscd/selinux.c b/nscd/selinux.c
+--- a/nscd/selinux.c   2010-05-04 05:27:23.000000000 -0600
++++ b/nscd/selinux.c   2012-08-06 15:08:19.096941431 -0600
+@@ -1,5 +1,5 @@
+ /* SELinux access controls for nscd.
+-   Copyright (C) 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
++   Copyright (C) 2004,2005,2006,2007,2009,2011 Free Software Foundation, Inc.
+    This file is part of the GNU C Library.
+    Contributed by Matthew Rickard <mjricka@epoch.ncsc.mil>, 2004.
+@@ -46,7 +46,7 @@
+ int selinux_enabled;
+ /* Define mappings of access vector permissions to request types.  */
+-static const int perms[LASTREQ] =
++static const access_vector_t perms[LASTREQ] =
+ {
+   [GETPWBYNAME] = NSCD__GETPWD,
+   [GETPWBYUID] = NSCD__GETPWD,
+@@ -69,6 +69,11 @@ static const int perms[LASTREQ] =
+   [GETSERVBYPORT] = NSCD__GETSERV,
+   [GETFDSERV] = NSCD__SHMEMSERV,
+ #endif
++#ifdef NSCD__GETNETGRP
++  [GETNETGRENT] = NSCD__GETNETGRP,
++  [INNETGR] = NSCD__GETNETGRP,
++  [GETFDNETGR] = NSCD__SHMEMNETGRP,
++#endif
+ };
+ /* Store an entry ref to speed AVC decisions.  */
+diff -Nrup a/nss/Makefile b/nss/Makefile
+--- a/nss/Makefile     2012-08-06 15:07:48.938060482 -0600
++++ b/nss/Makefile     2012-08-23 14:19:49.382442094 -0600
+@@ -1,4 +1,5 @@
+-# Copyright (C) 1996-1998,2000-2002,2007,2009 Free Software Foundation, Inc.
++# Copyright (C) 1996-1998,2000-2002,2007,2009,2010
++# 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
+@@ -39,7 +40,7 @@ databases            = proto service hosts network
+ others                  := getent
+ install-bin             := getent
+-tests                 = test-netdb
++tests                 = test-netdb tst-nss-test1
+ xtests                        = bug-erange
+ include ../Makeconfig
+@@ -85,3 +86,14 @@ endif
+ # a statically-linked program that hasn't already loaded it.
+ $(services:%=$(objpfx)libnss_%.so): $(common-objpfx)libc.so \
+                                   $(common-objpfx)libc_nonshared.a
++
++
++distribute            += nss_test1.c
++
++CFLAGS-nss_test1.c = -DNOT_IN_libc=1
++$(objpfx)/libnss_test1.so: $(objpfx)nss_test1.os $(common-objpfx)libc.so \
++                         $(common-objpfx)libc_nonshared.a
++      $(build-module)
++$(objpfx)/libnss_test1.so$(libnss_test1.so-version): $(objpfx)/libnss_test1.so
++      $(make-link)
++$(objpfx)tst-nss-test1.out: $(objpfx)/libnss_test1.so$(libnss_test1.so-version)
+diff -Nrup a/nss/Versions b/nss/Versions
+--- a/nss/Versions     2012-08-06 15:07:48.939060479 -0600
++++ b/nss/Versions     2012-08-06 15:08:19.096941431 -0600
+@@ -12,7 +12,7 @@ libc {
+     __nss_disable_nscd; __nss_lookup_function; _nss_files_parse_sgent;
+     __nss_passwd_lookup2; __nss_group_lookup2; __nss_hosts_lookup2;
+-    __nss_services_lookup2; __nss_next2;
++    __nss_services_lookup2; __nss_next2; __nss_lookup;
+   }
+ }
+diff -Nrup a/nss/getXXbyYY_r.c b/nss/getXXbyYY_r.c
+--- a/nss/getXXbyYY_r.c        2010-05-04 05:27:23.000000000 -0600
++++ b/nss/getXXbyYY_r.c        2012-08-23 14:19:49.403442011 -0600
+@@ -1,4 +1,4 @@
+-/* Copyright (C) 1996-2004, 2006, 2007, 2009 Free Software Foundation, Inc.
++/* Copyright (C) 1996-2004,2006,2007,2009,2010 Free Software Foundation, Inc.
+    This file is part of the GNU C Library.
+    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+@@ -87,6 +87,8 @@
+ # define NOT_USENSCD_NAME ADD_NOT_NSCDUSE (DATABASE_NAME)
+ # define ADD_NOT_NSCDUSE(name) ADD_NOT_NSCDUSE1 (name)
+ # define ADD_NOT_NSCDUSE1(name) __nss_not_use_nscd_##name
++# define CONCAT2(arg1, arg2) CONCAT2_2 (arg1, arg2)
++# define CONCAT2_2(arg1, arg2) arg1##arg2
+ #endif
+ #define FUNCTION_NAME_STRING STRINGIZE (FUNCTION_NAME)
+@@ -186,7 +188,8 @@ INTERNAL (REENTRANT_NAME) (ADD_PARAMS, L
+   if (NOT_USENSCD_NAME > 0 && ++NOT_USENSCD_NAME > NSS_NSCD_RETRY)
+     NOT_USENSCD_NAME = 0;
+-  if (!NOT_USENSCD_NAME)
++  if (!NOT_USENSCD_NAME
++      && !__nss_database_custom[CONCAT2 (NSS_DBSIDX_, DATABASE_NAME)])
+     {
+       nscd_status = NSCD_NAME (ADD_VARIABLES, resbuf, buffer, buflen, result
+                              H_ERRNO_VAR);
+diff -Nrup a/nss/getent.c b/nss/getent.c
+--- a/nss/getent.c     2010-05-04 05:27:23.000000000 -0600
++++ b/nss/getent.c     2012-08-06 15:15:06.479427609 -0600
+@@ -466,7 +466,6 @@ static int
+ netgroup_keys (int number, char *key[])
+ {
+   int result = 0;
+-  int i;
+   if (number == 0)
+     {
+@@ -474,18 +473,28 @@ netgroup_keys (int number, char *key[])
+       return 3;
+     }
+-  for (i = 0; i < number; ++i)
++  if (number == 4)
+     {
+-      if (!setnetgrent (key[i]))
++      char *host = strcmp (key[1], "*") == 0 ? NULL : key[1];
++      char *user = strcmp (key[2], "*") == 0 ? NULL : key[2];
++      char *domain = strcmp (key[3], "*") == 0 ? NULL : key[3];
++
++      printf ("%-21s (%s,%s,%s) = %d\n",
++            key[0], host ?: "", user ?: "", domain ?: "",
++            innetgr (key[0], host, user, domain));
++    }
++  else if (number == 1)
++    {
++      if (!setnetgrent (key[0]))
+       result = 2;
+       else
+       {
+         char *p[3];
+-        printf ("%-21s", key[i]);
++        printf ("%-21s", key[0]);
+         while (getnetgrent (p, p + 1, p + 2))
+-          printf (" (%s, %s, %s)", p[0] ?: " ", p[1] ?: "", p[2] ?: "");
++          printf (" (%s,%s,%s)", p[0] ?: " ", p[1] ?: "", p[2] ?: "");
+         putchar_unlocked ('\n');
+       }
+     }
+diff -Nrup a/nss/nss_files/files-parse.c b/nss/nss_files/files-parse.c
+--- a/nss/nss_files/files-parse.c      2010-05-04 05:27:23.000000000 -0600
++++ b/nss/nss_files/files-parse.c      2012-08-23 14:19:49.418441951 -0600
+@@ -1,5 +1,5 @@
+ /* Common code for file-based database parsers in nss_files module.
+-   Copyright (C) 1996-2000, 2003, 2004, 2009 Free Software Foundation, Inc.
++   Copyright (C) 1996-2000,2003,2004,2009,2010 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
+@@ -29,7 +29,7 @@
+    DATABASE -- string of the database file's name ("hosts", "passwd").
+    ENTDATA -- if defined, `struct ENTDATA' is used by the parser to store
+-              things pointed to by the resultant `struct STRUCTURE'.
++            things pointed to by the resultant `struct STRUCTURE'.
+    NEED_H_ERRNO - defined iff an arg `int *herrnop' is used.
+@@ -229,7 +229,7 @@ strtou32 (const char *nptr, char **endpt
+   char **list = parse_list (&line, buf_start, buf_end, '\0', errnop);       \
+   if (list)                                                                 \
+     result->TRAILING_LIST_MEMBER = list;                                    \
+-  else                                                                              \
++  else                                                                              \
+     return -1;                /* -1 indicates we ran out of space.  */              \
+ }
+diff -Nrup a/nss/nss_test1.c b/nss/nss_test1.c
+--- a/nss/nss_test1.c  1969-12-31 17:00:00.000000000 -0700
++++ b/nss/nss_test1.c  2012-08-23 14:19:49.418441951 -0600
+@@ -0,0 +1,154 @@
++#include <errno.h>
++#include <nss.h>
++#include <pthread.h>
++#include <string.h>
++
++
++#define COPY_IF_ROOM(s) \
++  ({ size_t len_ = strlen (s) + 1;            \
++     char *start_ = cp;                               \
++     buflen - (cp - buffer) < len_            \
++     ? NULL                                   \
++     : (cp = mempcpy (cp, s, len_), start_); })
++
++
++/* Password handling.  */
++#include <pwd.h>
++
++static struct passwd pwd_data[] =
++  {
++#define PWD(u) \
++    { .pw_name = (char *) "name" #u, .pw_passwd = (char *) "*", .pw_uid = u,  \
++      .pw_gid = 100, .pw_gecos = (char *) "*", .pw_dir = (char *) "*",              \
++      .pw_shell = (char *) "*" }
++    PWD (100),
++    PWD (30),
++    PWD (200),
++    PWD (60),
++    PWD (20000)
++  };
++#define npwd_data (sizeof (pwd_data) / sizeof (pwd_data[0]))
++
++static size_t pwd_iter;
++#define CURPWD pwd_data[pwd_iter]
++
++static pthread_mutex_t pwd_lock = PTHREAD_MUTEX_INITIALIZER;
++
++
++enum nss_status
++_nss_test1_setpwent (int stayopen)
++{
++  pwd_iter = 0;
++  return NSS_STATUS_SUCCESS;
++}
++
++
++enum nss_status
++_nss_test1_endpwent (void)
++{
++  return NSS_STATUS_SUCCESS;
++}
++
++
++enum nss_status
++_nss_test1_getpwent_r (struct passwd *result, char *buffer, size_t buflen,
++                     int *errnop)
++{
++  char *cp = buffer;
++  int res = NSS_STATUS_SUCCESS;
++
++  pthread_mutex_lock (&pwd_lock);
++
++  if (pwd_iter >= npwd_data)
++    res = NSS_STATUS_NOTFOUND;
++  else
++    {
++      result->pw_name = COPY_IF_ROOM (CURPWD.pw_name);
++      result->pw_passwd = COPY_IF_ROOM (CURPWD.pw_passwd);
++      result->pw_uid = CURPWD.pw_uid;
++      result->pw_gid = CURPWD.pw_gid;
++      result->pw_gecos = COPY_IF_ROOM (CURPWD.pw_gecos);
++      result->pw_dir = COPY_IF_ROOM (CURPWD.pw_dir);
++      result->pw_shell = COPY_IF_ROOM (CURPWD.pw_shell);
++
++      if (result->pw_name == NULL || result->pw_passwd == NULL
++        || result->pw_gecos == NULL || result->pw_dir == NULL
++        || result->pw_shell == NULL)
++      {
++        *errnop = ERANGE;
++        res = NSS_STATUS_TRYAGAIN;
++      }
++
++      ++pwd_iter;
++    }
++
++  pthread_mutex_unlock (&pwd_lock);
++
++  return res;
++}
++
++
++enum nss_status
++_nss_test1_getpwuid_r (uid_t uid, struct passwd *result, char *buffer,
++                     size_t buflen, int *errnop)
++{
++  for (size_t idx = 0; idx < npwd_data; ++idx)
++    if (pwd_data[idx].pw_uid == uid)
++      {
++      char *cp = buffer;
++      int res = NSS_STATUS_SUCCESS;
++
++      result->pw_name = COPY_IF_ROOM (pwd_data[idx].pw_name);
++      result->pw_passwd = COPY_IF_ROOM (pwd_data[idx].pw_passwd);
++      result->pw_uid = pwd_data[idx].pw_uid;
++      result->pw_gid = pwd_data[idx].pw_gid;
++      result->pw_gecos = COPY_IF_ROOM (pwd_data[idx].pw_gecos);
++      result->pw_dir = COPY_IF_ROOM (pwd_data[idx].pw_dir);
++      result->pw_shell = COPY_IF_ROOM (pwd_data[idx].pw_shell);
++
++      if (result->pw_name == NULL || result->pw_passwd == NULL
++          || result->pw_gecos == NULL || result->pw_dir == NULL
++          || result->pw_shell == NULL)
++        {
++          *errnop = ERANGE;
++          res = NSS_STATUS_TRYAGAIN;
++        }
++
++      return res;
++      }
++
++  return NSS_STATUS_NOTFOUND;
++}
++
++
++enum nss_status
++_nss_test1_getpwnam_r (const char *name, struct passwd *result, char *buffer,
++                     size_t buflen, int *errnop)
++{
++  for (size_t idx = 0; idx < npwd_data; ++idx)
++    if (strcmp (pwd_data[idx].pw_name, name) == 0)
++      {
++      char *cp = buffer;
++      int res = NSS_STATUS_SUCCESS;
++
++      result->pw_name = COPY_IF_ROOM (pwd_data[idx].pw_name);
++      result->pw_passwd = COPY_IF_ROOM (pwd_data[idx].pw_passwd);
++      result->pw_uid = pwd_data[idx].pw_uid;
++      result->pw_gid = pwd_data[idx].pw_gid;
++      result->pw_gecos = COPY_IF_ROOM (pwd_data[idx].pw_gecos);
++      result->pw_dir = COPY_IF_ROOM (pwd_data[idx].pw_dir);
++      result->pw_shell = COPY_IF_ROOM (pwd_data[idx].pw_shell);
++
++      if (result->pw_name == NULL || result->pw_passwd == NULL
++          || result->pw_gecos == NULL || result->pw_dir == NULL
++          || result->pw_shell == NULL)
++        {
++          *errnop = ERANGE;
++          res = NSS_STATUS_TRYAGAIN;
++        }
++
++      return res;
++      }
++
++  return NSS_STATUS_NOTFOUND;
++}
+diff -Nrup a/nss/nsswitch.c b/nss/nsswitch.c
+--- a/nss/nsswitch.c   2010-05-04 05:27:23.000000000 -0600
++++ b/nss/nsswitch.c   2012-08-23 14:19:49.430441903 -0600
+@@ -1,4 +1,4 @@
+-/* Copyright (C) 1996-1999, 2001-2007, 2009 Free Software Foundation, Inc.
++/* Copyright (C) 1996-1999,2001-2007,2009,2010 Free Software Foundation, Inc.
+    This file is part of the GNU C Library.
+    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+@@ -71,6 +71,9 @@ static const struct
+ };
+ #define ndatabases (sizeof (databases) / sizeof (databases[0]))
++/* Flags whether custom rules for database is set.  */
++bool __nss_database_custom[NSS_DBSIDX_max];
++
+ __libc_lock_define_initialized (static, lock)
+@@ -165,6 +168,7 @@ __nss_lookup (service_user **ni, const c
+   return *fctp != NULL ? 0 : (*ni)->next == NULL ? 1 : -1;
+ }
++libc_hidden_def (__nss_lookup)
+ /* -1 == not found
+@@ -265,6 +269,7 @@ __nss_configure_lookup (const char *dbna
+   /* Install new rules.  */
+   *databases[cnt].dbp = new_db;
++  __nss_database_custom[cnt] = true;
+   __libc_lock_unlock (lock);
+@@ -729,6 +734,7 @@ __nss_disable_nscd (void)
+   __nss_not_use_nscd_group = -1;
+   __nss_not_use_nscd_hosts = -1;
+   __nss_not_use_nscd_services = -1;
++  __nss_not_use_nscd_netgroup = -1;
+ }
+diff -Nrup a/nss/nsswitch.h b/nss/nsswitch.h
+--- a/nss/nsswitch.h   2010-05-04 05:27:23.000000000 -0600
++++ b/nss/nsswitch.h   2012-08-23 14:19:49.431441899 -0600
+@@ -1,4 +1,4 @@
+-/* Copyright (C) 1996-1999,2001,2002,2003,2004,2007
++/* Copyright (C) 1996-1999,2001,2002,2003,2004,2007,2010
+    Free Software Foundation, Inc.
+    This file is part of the GNU C Library.
+@@ -28,6 +28,7 @@
+ #include <resolv.h>
+ #include <search.h>
+ #include <dlfcn.h>
++#include <stdbool.h>
+ /* Actions performed after lookup finished.  */
+ typedef enum
+@@ -96,6 +97,19 @@ typedef struct name_database
+ } name_database;
++/* Indices into DATABASES in nsswitch.c and __NSS_DATABASE_CUSTOM.  */
++enum
++  {
++#define DEFINE_DATABASE(arg) NSS_DBSIDX_##arg,
++#include "databases.def"
++#undef DEFINE_DATABASE
++    NSS_DBSIDX_max
++  };
++
++/* Flags whether custom rules for database is set.  */
++extern bool __nss_database_custom[NSS_DBSIDX_max];
++
++
+ /* Interface functions for NSS.  */
+ /* Get the data structure representing the specified database.
+@@ -111,7 +125,8 @@ libc_hidden_proto (__nss_database_lookup
+    position is remembered in NI.  The function returns a value < 0 if
+    an error occurred or no such function exists.  */
+ extern int __nss_lookup (service_user **ni, const char *fct_name,
+-                       const char *fct2_name, void **fctp) attribute_hidden;
++                       const char *fct2_name, void **fctp);
++libc_hidden_proto (__nss_lookup)
+ /* Determine the next step in the lookup process according to the
+    result STATUS of the call to the last function returned by
+diff -Nrup a/nss/tst-nss-test1.c b/nss/tst-nss-test1.c
+--- a/nss/tst-nss-test1.c      1969-12-31 17:00:00.000000000 -0700
++++ b/nss/tst-nss-test1.c      2012-08-23 14:19:49.432441895 -0600
+@@ -0,0 +1,72 @@
++#include <nss.h>
++#include <pwd.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++
++
++static int
++do_test (void)
++{
++  int retval = 0;
++
++  __nss_configure_lookup ("passwd", "test1");
++
++  static const unsigned int pwdids[] = { 100, 30, 200, 60, 20000 };
++#define npwdids (sizeof (pwdids) / sizeof (pwdids[0]))
++  setpwent ();
++
++  const unsigned int *np = pwdids;
++  for (struct passwd *p = getpwent (); p != NULL; ++np, p = getpwent ())
++    if (p->pw_uid != *np || strncmp (p->pw_name, "name", 4) != 0
++      || atol (p->pw_name + 4) != *np)
++      {
++      printf ("passwd entry %ju wrong (%s, %u)\n",
++              np - pwdids, p->pw_name, p->pw_uid);
++      retval = 1;
++      break;
++      }
++
++  endpwent ();
++
++  for (int i = npwdids - 1; i >= 0; --i)
++    {
++      char buf[30];
++      snprintf (buf, sizeof (buf), "name%u", pwdids[i]);
++
++      struct passwd *p = getpwnam (buf);
++      if (p == NULL || p->pw_uid != pwdids[i] || strcmp (buf, p->pw_name) != 0)
++      {
++        printf ("passwd entry \"%s\" wrong\n", buf);
++        retval = 1;
++      }
++
++      p = getpwuid (pwdids[i]);
++      if (p == NULL || p->pw_uid != pwdids[i] || strcmp (buf, p->pw_name) != 0)
++      {
++        printf ("passwd entry %u wrong\n", pwdids[i]);
++        retval = 1;
++      }
++
++      snprintf (buf, sizeof (buf), "name%u", pwdids[i] + 1);
++
++      p = getpwnam (buf);
++      if (p != NULL)
++      {
++        printf ("passwd entry \"%s\" wrong\n", buf);
++        retval = 1;
++      }
++
++      p = getpwuid (pwdids[i] + 1);
++      if (p != NULL)
++      {
++        printf ("passwd entry %u wrong\n", pwdids[i] + 1);
++        retval = 1;
++      }
++    }
++
++  return retval;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
+diff -Nrup a/shlib-versions b/shlib-versions
+--- a/shlib-versions   2010-05-04 05:27:23.000000000 -0600
++++ b/shlib-versions   2012-08-23 14:19:49.473441732 -0600
+@@ -114,6 +114,10 @@ alpha.*-.*-linux.*        libresolv=2.1
+ .*-.*-.*              libnss_ldap=2
+ .*-.*-.*              libnss_hesiod=2
++# Tests for NSS.  They must have the same NSS_SHLIB_REVISION number as
++# the rest.
++.*-.*-.*              libnss_test1=2
++
+ # Version for libnsl with YP and NIS+ functions.
+ alpha.*-.*-linux.*    libnsl=1.1
+ .*-.*-.*              libnsl=1
+diff -Nrup a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
+--- a/sysdeps/posix/getaddrinfo.c      2012-08-06 15:07:49.571057983 -0600
++++ b/sysdeps/posix/getaddrinfo.c      2012-08-23 14:19:49.541441461 -0600
+@@ -669,7 +669,8 @@ gaih_inet (const char *name, const struc
+             && ++__nss_not_use_nscd_hosts > NSS_NSCD_RETRY)
+           __nss_not_use_nscd_hosts = 0;
+-        if (!__nss_not_use_nscd_hosts)
++        if (!__nss_not_use_nscd_hosts
++            && !__nss_database_custom[NSS_DBSIDX_hosts])
+           {
+             /* Try to use nscd.  */
+             struct nscd_ai_result *air = NULL;
diff --git a/src/patches/glibc/glibc-rh663641-2.patch b/src/patches/glibc/glibc-rh663641-2.patch
new file mode 100644 (file)
index 0000000..13c1bee
--- /dev/null
@@ -0,0 +1,279 @@
+diff -pruN glibc-2.12-2-gc4ccff1/csu/libc-start.c glibc-2.12-2-gc4ccff1.fixed/csu/libc-start.c
+--- glibc-2.12-2-gc4ccff1/csu/libc-start.c     2010-05-04 16:57:23.000000000 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/csu/libc-start.c       2013-07-09 23:34:59.596859295 +0530
+@@ -33,7 +33,7 @@ extern int __libc_multiple_libcs;
+ #include <tls.h>
+ #ifndef SHARED
+ # include <dl-osinfo.h>
+-extern void __pthread_initialize_minimal (void);
++extern void __pthread_initialize_minimal (int, char **, char **);
+ # ifndef THREAD_SET_STACK_GUARD
+ /* Only exported for architectures that don't store the stack guard canary
+    in thread local area.  */
+@@ -143,7 +143,7 @@ LIBC_START_MAIN (int (*main) (int, char
+   /* Initialize the thread library at least a bit since the libgcc
+      functions are using thread functions if these are available and
+      we need to setup errno.  */
+-  __pthread_initialize_minimal ();
++  __pthread_initialize_minimal (argc, argv, __environ);
+   /* Set up the stack checker's canary.  */
+   uintptr_t stack_chk_guard = _dl_setup_stack_chk_guard (_dl_random);
+diff -pruN glibc-2.12-2-gc4ccff1/csu/libc-tls.c glibc-2.12-2-gc4ccff1.fixed/csu/libc-tls.c
+--- glibc-2.12-2-gc4ccff1/csu/libc-tls.c       2010-05-04 16:57:23.000000000 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/csu/libc-tls.c 2013-07-09 23:34:59.596859295 +0530
+@@ -244,7 +244,7 @@ _dl_tls_setup (void)
+    not used.  */
+ void
+ __attribute__ ((weak))
+-__pthread_initialize_minimal (void)
++__pthread_initialize_minimal (int argc, char **argv, char **envp)
+ {
+   __libc_setup_tls (TLS_INIT_TCB_SIZE, TLS_INIT_TCB_ALIGN);
+ }
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/Makefile glibc-2.12-2-gc4ccff1.fixed/nptl/Makefile
+--- glibc-2.12-2-gc4ccff1/nptl/Makefile        2013-07-09 23:35:21.692858252 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/Makefile  2013-07-09 23:34:59.597859295 +0530
+@@ -197,7 +197,7 @@ CFLAGS-pt-system.c = -fexceptions
+ tests = tst-typesizes \
+-      tst-attr1 tst-attr2 tst-attr3 \
++      tst-attr1 tst-attr2 tst-attr3 tst-default-attr \
+       tst-mutex1 tst-mutex2 tst-mutex3 tst-mutex4 tst-mutex5 tst-mutex6 \
+       tst-mutex7 tst-mutex8 tst-mutex9 tst-mutex5a tst-mutex7a \
+       tst-mutexpi1 tst-mutexpi2 tst-mutexpi3 tst-mutexpi4 tst-mutexpi5 \
+@@ -279,6 +279,13 @@ LDFLAGS-pthread.so = -Wl,--enable-new-dt
+ LDFLAGS-tst-cond24 = -lrt
+ LDFLAGS-tst-cond25 = -lrt
++# The size is 1MB + 4KB.  The extra 4KB has been added to prevent allocatestack
++# from resizing the input size to avoid the 64K aliasing conflict on Intel
++# processors.
++DEFAULT_STACKSIZE=1052672
++CFLAGS-tst-default-attr.c = -DDEFAULT_STACKSIZE=$(DEFAULT_STACKSIZE)
++tst-default-attr-ENV = GLIBC_PTHREAD_STACKSIZE=$(DEFAULT_STACKSIZE)
++
+ include ../Makeconfig
+ ifeq ($(have-forced-unwind),yes)
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/nptl-init.c glibc-2.12-2-gc4ccff1.fixed/nptl/nptl-init.c
+--- glibc-2.12-2-gc4ccff1/nptl/nptl-init.c     2013-07-09 23:35:21.723858250 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/nptl-init.c       2013-07-09 23:36:35.070854789 +0530
+@@ -36,6 +36,7 @@
+ #include <smp.h>
+ #include <lowlevellock.h>
+ #include <kernel-features.h>
++#include <libc-internal.h>
+ /* Size and alignment of static TLS block.  */
+@@ -288,8 +289,28 @@ extern void **__libc_dl_error_tsd (void)
+ /* This can be set by the debugger before initialization is complete.  */
+ static bool __nptl_initial_report_events __attribute_used__;
++/* Validate and set the default stacksize.  */
++static void
++set_default_stacksize (size_t stacksize)
++{
++  if (stacksize < PTHREAD_STACK_MIN)
++    stacksize = PTHREAD_STACK_MIN;
++
++  /* Make sure it meets the minimum size that allocate_stack
++     (allocatestack.c) will demand, which depends on the page size.  */
++  const uintptr_t pagesz = GLRO(dl_pagesize);
++  const size_t minstack = pagesz + __static_tls_size + MINIMAL_REST_STACK;
++
++  if (stacksize < minstack)
++    stacksize = minstack;
++
++  /* Round the resource limit up to page size.  */
++  stacksize = ALIGN_UP (stacksize, pagesz);
++  __default_pthread_attr.stacksize = stacksize;
++}
++
+ void
+-__pthread_initialize_minimal_internal (void)
++__pthread_initialize_minimal_internal (int argc, char **argv, char **envp)
+ {
+ #ifndef SHARED
+   /* Unlike in the dynamically linked case the dynamic linker has not
+@@ -413,29 +434,44 @@ __pthread_initialize_minimal_internal (v
+   __static_tls_size = roundup (__static_tls_size, static_tls_align);
+-  /* Determine the default allowed stack size.  This is the size used
+-     in case the user does not specify one.  */
+-  struct rlimit limit;
+-  if (getrlimit (RLIMIT_STACK, &limit) != 0
+-      || limit.rlim_cur == RLIM_INFINITY)
+-    /* The system limit is not usable.  Use an architecture-specific
+-       default.  */
+-    limit.rlim_cur = ARCH_STACK_DEFAULT_SIZE;
+-  else if (limit.rlim_cur < PTHREAD_STACK_MIN)
+-    /* The system limit is unusably small.
+-       Use the minimal size acceptable.  */
+-    limit.rlim_cur = PTHREAD_STACK_MIN;
++  /* Initialize the environment.  libc.so gets initialized after us due to a
++     circular dependency and hence __environ is not available otherwise.  */
++  __environ = envp; 
+-  /* Make sure it meets the minimum size that allocate_stack
+-     (allocatestack.c) will demand, which depends on the page size.  */
+-  const uintptr_t pagesz = __sysconf (_SC_PAGESIZE);
+-  const size_t minstack = pagesz + __static_tls_size + MINIMAL_REST_STACK;
+-  if (limit.rlim_cur < minstack)
+-    limit.rlim_cur = minstack;
++#ifndef SHARED
++  __libc_init_secure ();
++#endif
+-  /* Round the resource limit up to page size.  */
+-  limit.rlim_cur = (limit.rlim_cur + pagesz - 1) & -pagesz;
+-  __default_pthread_attr.stacksize = limit.rlim_cur;
++  /* Get the default stack size from the environment variable if it is set and
++     is valid.  */
++  size_t stacksize = 0;
++  char *envval = __secure_getenv ("GLIBC_PTHREAD_STACKSIZE");
++
++  if (__builtin_expect (envval != NULL && envval[0] != '\0', 0))
++    {
++      char *env_conv = envval;
++      size_t ret = strtoul (envval, &env_conv, 0);
++
++      if (*env_conv == '\0' && env_conv != envval)
++      stacksize = ret;
++    }
++
++  if (stacksize == 0)
++    {
++      /* Determine the default allowed stack size.  */
++      struct rlimit limit;
++      if (getrlimit (RLIMIT_STACK, &limit) != 0
++        || limit.rlim_cur == RLIM_INFINITY)
++      /* The system limit is not usable.  Use an architecture-specific
++         default.  */
++      stacksize = ARCH_STACK_DEFAULT_SIZE;
++      else
++      stacksize = limit.rlim_cur;
++    }
++
++  /* Finally, set the default stack size.  This size is used when the user does
++     not specify a stack size during thread creation.  */
++  set_default_stacksize (stacksize);
+   __default_pthread_attr.guardsize = GLRO (dl_pagesize);
+ #ifdef SHARED
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/tst-default-attr.c glibc-2.12-2-gc4ccff1.fixed/nptl/tst-default-attr.c
+--- glibc-2.12-2-gc4ccff1/nptl/tst-default-attr.c      1970-01-01 05:30:00.000000000 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/tst-default-attr.c        2013-07-09 23:34:59.598859295 +0530
+@@ -0,0 +1,109 @@
++/* Verify that default stack size gets set correctly from the environment
++   variable.
++
++   Copyright (C) 2013 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
++   <http://www.gnu.org/licenses/>.  */
++
++#include <pthread.h>
++#include <stdio.h>
++#include <stdint.h>
++#include <string.h>
++#include <unistd.h>
++#include <errno.h>
++
++#define RETURN_IF_FAIL(f, ...) \
++  ({                                                                        \
++    int ret = f (__VA_ARGS__);                                                      \
++    if (ret != 0)                                                           \
++      {                                                                             \
++      printf ("%s:%d: %s returned %d (errno = %d)\n", __FILE__, __LINE__,   \
++              #f, ret, errno);                                              \
++      return ret;                                                           \
++      }                                                                             \
++  })
++
++/* DEFAULT_STACKSIZE macro is defined in the Makefile.  */
++static size_t stacksize = DEFAULT_STACKSIZE;
++
++static int
++verify_stacksize_result (pthread_attr_t *attr)
++{
++  size_t stack;
++
++  RETURN_IF_FAIL (pthread_attr_getstacksize, attr, &stack);
++
++  if (stacksize != stack)
++    {
++      printf ("failed to set default stacksize (%zu, %zu)\n", stacksize, stack);
++      return 1;
++    }
++
++  return 0;
++}
++
++static void *
++thr (void *unused __attribute__ ((unused)))
++{
++  pthread_attr_t attr;
++  int ret;
++
++  memset (&attr, 0xab, sizeof attr);
++  /* To verify that the attributes actually got applied.  */
++  if ((ret = pthread_getattr_np (pthread_self (), &attr)) != 0)
++    {
++      printf ("pthread_getattr_np failed: %s\n", strerror (ret));
++      goto out;
++    }
++
++  ret = verify_stacksize_result (&attr);
++
++out:
++  return (void *) (uintptr_t) ret;
++}
++
++static int
++run_threads (void)
++{
++  pthread_t t;
++  void *tret = NULL;
++
++  /* Run twice to ensure that the attributes do not get overwritten in the
++     first run somehow.  */
++  for (int i = 0; i < 2; i++)
++    {
++      RETURN_IF_FAIL (pthread_create, &t, NULL, thr, NULL);
++      RETURN_IF_FAIL (pthread_join, t, &tret);
++
++      if (tret != NULL)
++      {
++        puts ("Thread failed");
++        return 1;
++      }
++    }
++
++  return 0;
++}
++
++static int
++do_test (void)
++{
++  RETURN_IF_FAIL (run_threads);
++  return 0;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
diff --git a/src/patches/glibc/glibc-rh663641-3.patch b/src/patches/glibc/glibc-rh663641-3.patch
new file mode 100644 (file)
index 0000000..182fe99
--- /dev/null
@@ -0,0 +1,31 @@
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/sysdeps/pthread/pt-initfini.c glibc-2.12-2-gc4ccff1.fixed/nptl/sysdeps/pthread/pt-initfini.c
+--- glibc-2.12-2-gc4ccff1/nptl/sysdeps/pthread/pt-initfini.c   2010-05-04 16:57:23.000000000 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/sysdeps/pthread/pt-initfini.c     2013-07-22 21:52:03.519184065 +0530
+@@ -63,21 +63,21 @@ asm ("\n/*@TESTS_END*/");
+ asm ("\n/*@_init_PROLOG_BEGINS*/");
+ static void
+-call_initialize_minimal (void)
++call_initialize_minimal (int argc, char **argv, char **envp)
+ {
+-  extern void __pthread_initialize_minimal_internal (void)
++  extern void __pthread_initialize_minimal_internal (int, char **, char **)
+     __attribute ((visibility ("hidden")));
+-  __pthread_initialize_minimal_internal ();
++  __pthread_initialize_minimal_internal (argc, argv, envp);
+ }
+ SECTION (".init");
+-extern void __attribute__ ((section (".init"))) _init (void);
++extern void __attribute__ ((section (".init"))) _init (int, char **, char **);
+ void
+-_init (void)
++_init (int argc, char **argv, char **envp)
+ {
+   /* The very first thing we must do is to set up the registers.  */
+-  call_initialize_minimal ();
++  call_initialize_minimal (argc, argv, envp);
+   asm ("ALIGN");
+   asm("END_INIT");
diff --git a/src/patches/glibc/glibc-rh663641.patch b/src/patches/glibc/glibc-rh663641.patch
new file mode 100644 (file)
index 0000000..e1ca4f1
--- /dev/null
@@ -0,0 +1,191 @@
+diff -pruN glibc-2.12-2-gc4ccff1/include/libc-internal.h glibc-2.12-2-gc4ccff1.fixed/include/libc-internal.h
+--- glibc-2.12-2-gc4ccff1/include/libc-internal.h      2010-05-04 16:57:23.000000000 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/include/libc-internal.h        2013-07-09 23:44:00.272833779 +0530
+@@ -34,4 +34,24 @@ extern void __libc_thread_freeres (void)
+ /* Define and initialize `__progname' et. al.  */
+ extern void __init_misc (int, char **, char **);
++/* Align a value by rounding down to closest size.
++   e.g. Using size of 4096, we get this behavior:
++      {4095, 4096, 4097} = {0, 4096, 4096}.  */
++#define ALIGN_DOWN(base, size)        ((base) & -((__typeof__ (base)) (size)))
++
++/* Align a value by rounding up to closest size.
++   e.g. Using size of 4096, we get this behavior:
++      {4095, 4096, 4097} = {4096, 4096, 8192}.
++
++  Note: The size argument has side effects (expanded multiple times).  */
++#define ALIGN_UP(base, size)  ALIGN_DOWN ((base) + (size) - 1, (size))
++
++/* Same as ALIGN_DOWN(), but automatically casts when base is a pointer.  */
++#define PTR_ALIGN_DOWN(base, size) \
++  ((__typeof__ (base)) ALIGN_DOWN ((uintptr_t) (base), (size)))
++
++/* Same as ALIGN_UP(), but automatically casts when base is a pointer.  */
++#define PTR_ALIGN_UP(base, size) \
++  ((__typeof__ (base)) ALIGN_UP ((uintptr_t) (base), (size)))
++
+ #endif /* _LIBC_INTERNAL  */
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/allocatestack.c glibc-2.12-2-gc4ccff1.fixed/nptl/allocatestack.c
+--- glibc-2.12-2-gc4ccff1/nptl/allocatestack.c 2013-07-09 23:43:09.427836179 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/allocatestack.c   2013-07-09 23:43:52.727834136 +0530
+@@ -351,7 +351,7 @@ allocate_stack (const struct pthread_att
+   /* Get the stack size from the attribute if it is set.  Otherwise we
+      use the default we determined at start time.  */
+-  size = attr->stacksize ?: __default_stacksize;
++  size = attr->stacksize ?: __default_pthread_attr.stacksize;
+   /* Get memory for the stack.  */
+   if (__builtin_expect (attr->flags & ATTR_FLAG_STACKADDR, 0))
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/nptl-init.c glibc-2.12-2-gc4ccff1.fixed/nptl/nptl-init.c
+--- glibc-2.12-2-gc4ccff1/nptl/nptl-init.c     2013-07-09 23:43:09.553836173 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/nptl-init.c       2013-07-09 23:43:52.728834135 +0530
+@@ -435,7 +435,8 @@ __pthread_initialize_minimal_internal (v
+   /* Round the resource limit up to page size.  */
+   limit.rlim_cur = (limit.rlim_cur + pagesz - 1) & -pagesz;
+-  __default_stacksize = limit.rlim_cur;
++  __default_pthread_attr.stacksize = limit.rlim_cur;
++  __default_pthread_attr.guardsize = GLRO (dl_pagesize);
+ #ifdef SHARED
+   /* Transfer the old value from the dynamic linker's internal location.  */
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/pthread_attr_getstacksize.c glibc-2.12-2-gc4ccff1.fixed/nptl/pthread_attr_getstacksize.c
+--- glibc-2.12-2-gc4ccff1/nptl/pthread_attr_getstacksize.c     2010-05-04 16:57:23.000000000 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/pthread_attr_getstacksize.c       2013-07-09 23:43:52.817834131 +0530
+@@ -33,7 +33,7 @@ __pthread_attr_getstacksize (attr, stack
+   /* If the user has not set a stack size we return what the system
+      will use as the default.  */
+-  *stacksize = iattr->stacksize ?: __default_stacksize;
++  *stacksize = iattr->stacksize ?: __default_pthread_attr.stacksize;
+   return 0;
+ }
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/pthread_barrier_init.c glibc-2.12-2-gc4ccff1.fixed/nptl/pthread_barrier_init.c
+--- glibc-2.12-2-gc4ccff1/nptl/pthread_barrier_init.c  2010-05-04 16:57:23.000000000 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/pthread_barrier_init.c    2013-07-09 23:43:52.821834131 +0530
+@@ -23,7 +23,7 @@
+ #include <kernel-features.h>
+-static const struct pthread_barrierattr default_attr =
++static const struct pthread_barrierattr default_barrierattr =
+   {
+     .pshared = PTHREAD_PROCESS_PRIVATE
+   };
+@@ -43,7 +43,7 @@ pthread_barrier_init (barrier, attr, cou
+   const struct pthread_barrierattr *iattr
+     = (attr != NULL
+        ? iattr = (struct pthread_barrierattr *) attr
+-       : &default_attr);
++       : &default_barrierattr);
+   if (iattr->pshared != PTHREAD_PROCESS_PRIVATE
+       && __builtin_expect (iattr->pshared != PTHREAD_PROCESS_SHARED, 0))
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/pthread_create.c glibc-2.12-2-gc4ccff1.fixed/nptl/pthread_create.c
+--- glibc-2.12-2-gc4ccff1/nptl/pthread_create.c        2013-07-09 23:43:09.542836173 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/pthread_create.c  2013-07-09 23:43:52.822834131 +0530
+@@ -425,15 +425,6 @@ start_thread (void *arg)
+ }
+-/* Default thread attributes for the case when the user does not
+-   provide any.  */
+-static const struct pthread_attr default_attr =
+-  {
+-    /* Just some value > 0 which gets rounded to the nearest page size.  */
+-    .guardsize = 1,
+-  };
+-
+-
+ int
+ __pthread_create_2_1 (newthread, attr, start_routine, arg)
+      pthread_t *newthread;
+@@ -447,7 +438,7 @@ __pthread_create_2_1 (newthread, attr, s
+   if (iattr == NULL)
+     /* Is this the best idea?  On NUMA machines this could mean
+        accessing far-away memory.  */
+-    iattr = &default_attr;
++    iattr = &__default_pthread_attr;
+   struct pthread *pd = NULL;
+   int err = ALLOCATE_STACK (iattr, &pd);
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/pthread_mutex_init.c glibc-2.12-2-gc4ccff1.fixed/nptl/pthread_mutex_init.c
+--- glibc-2.12-2-gc4ccff1/nptl/pthread_mutex_init.c    2010-05-04 16:57:23.000000000 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/pthread_mutex_init.c      2013-07-09 23:43:52.822834131 +0530
+@@ -24,7 +24,7 @@
+ #include <kernel-features.h>
+ #include "pthreadP.h"
+-static const struct pthread_mutexattr default_attr =
++static const struct pthread_mutexattr default_mutexattr =
+   {
+     /* Default is a normal mutex, not shared between processes.  */
+     .mutexkind = PTHREAD_MUTEX_NORMAL
+@@ -45,7 +45,8 @@ __pthread_mutex_init (mutex, mutexattr)
+   assert (sizeof (pthread_mutex_t) <= __SIZEOF_PTHREAD_MUTEX_T);
+-  imutexattr = (const struct pthread_mutexattr *) mutexattr ?: &default_attr;
++  imutexattr = ((const struct pthread_mutexattr *) mutexattr
++              ?: &default_mutexattr);
+   /* Sanity checks.  */
+   switch (__builtin_expect (imutexattr->mutexkind
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/pthreadP.h glibc-2.12-2-gc4ccff1.fixed/nptl/pthreadP.h
+--- glibc-2.12-2-gc4ccff1/nptl/pthreadP.h      2013-07-09 23:43:09.553836173 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/pthreadP.h        2013-07-09 23:43:52.823834131 +0530
+@@ -148,8 +148,8 @@ enum
+ /* Internal variables.  */
+-/* Default stack size.  */
+-extern size_t __default_stacksize attribute_hidden;
++/* Default pthread attributes.  */
++extern struct pthread_attr __default_pthread_attr attribute_hidden;
+ /* Size and alignment of static TLS block.  */
+ extern size_t __static_tls_size attribute_hidden;
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/pthread_rwlock_init.c glibc-2.12-2-gc4ccff1.fixed/nptl/pthread_rwlock_init.c
+--- glibc-2.12-2-gc4ccff1/nptl/pthread_rwlock_init.c   2010-05-04 16:57:23.000000000 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/pthread_rwlock_init.c     2013-07-09 23:43:52.823834131 +0530
+@@ -21,7 +21,7 @@
+ #include <kernel-features.h>
+-static const struct pthread_rwlockattr default_attr =
++static const struct pthread_rwlockattr default_rwlockattr =
+   {
+     .lockkind = PTHREAD_RWLOCK_DEFAULT_NP,
+     .pshared = PTHREAD_PROCESS_PRIVATE
+@@ -35,7 +35,7 @@ __pthread_rwlock_init (rwlock, attr)
+ {
+   const struct pthread_rwlockattr *iattr;
+-  iattr = ((const struct pthread_rwlockattr *) attr) ?: &default_attr;
++  iattr = ((const struct pthread_rwlockattr *) attr) ?: &default_rwlockattr;
+   memset (rwlock, '\0', sizeof (*rwlock));
+diff -pruN glibc-2.12-2-gc4ccff1/nptl/vars.c glibc-2.12-2-gc4ccff1.fixed/nptl/vars.c
+--- glibc-2.12-2-gc4ccff1/nptl/vars.c  2010-05-04 16:57:23.000000000 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/nptl/vars.c    2013-07-09 23:43:52.824834131 +0530
+@@ -21,13 +21,9 @@
+ #include <tls.h>
+ #include <unistd.h>
+-/* Default stack size.  */
+-size_t __default_stacksize attribute_hidden
+-#ifdef SHARED
+-;
+-#else
+-  = PTHREAD_STACK_MIN;
+-#endif
++/* Default thread attributes for the case when the user does not
++   provide any.  */
++struct pthread_attr __default_pthread_attr attribute_hidden;
+ /* Flag whether the machine is SMP or not.  */
+ int __is_smp attribute_hidden;
index 1064640af53914cb3ca7ab0555d3d6d4626de92b..1147af6860b7019b92ae7f85a7621e7e291676b5 100644 (file)
-diff -rcp a/nscd/grpcache.c b/nscd/grpcache.c
-*** a/nscd/grpcache.c  Wed Apr 11 12:50:07 2012
---- b/nscd/grpcache.c  Wed Apr 11 21:45:58 2012
-*************** cache_addgr (struct database_dyn *db, in
-*** 178,184 ****
-        char *cp;
-        const size_t key_len = strlen (key);
-        const size_t buf_len = 3 * sizeof (grp->gr_gid) + key_len + 1;
-!       char *buf = alloca (buf_len);
-        ssize_t n;
-        size_t cnt;
-  
---- 178,185 ----
-        char *cp;
-        const size_t key_len = strlen (key);
-        const size_t buf_len = 3 * sizeof (grp->gr_gid) + key_len + 1;
-!       size_t alloca_used = 0;
-!       char *buf = alloca_account (buf_len, alloca_used);
-        ssize_t n;
-        size_t cnt;
-  
-*************** cache_addgr (struct database_dyn *db, in
-*** 190,196 ****
-        /* Determine the length of all members.  */
-        while (grp->gr_mem[gr_mem_cnt])
-       ++gr_mem_cnt;
-!       gr_mem_len = (uint32_t *) alloca (gr_mem_cnt * sizeof (uint32_t));
-        for (gr_mem_cnt = 0; grp->gr_mem[gr_mem_cnt]; ++gr_mem_cnt)
-       {
-         gr_mem_len[gr_mem_cnt] = strlen (grp->gr_mem[gr_mem_cnt]) + 1;
---- 191,198 ----
-        /* Determine the length of all members.  */
-        while (grp->gr_mem[gr_mem_cnt])
-       ++gr_mem_cnt;
-!       gr_mem_len = (uint32_t *) alloca_account (gr_mem_cnt * sizeof (uint32_t),
-!                                              alloca_used);
-        for (gr_mem_cnt = 0; grp->gr_mem[gr_mem_cnt]; ++gr_mem_cnt)
-       {
-         gr_mem_len[gr_mem_cnt] = strlen (grp->gr_mem[gr_mem_cnt]) + 1;
-*************** cache_addgr (struct database_dyn *db, in
-*** 205,214 ****
-        change.  Allocate memory on the cache since it is likely
-        discarded anyway.  If it turns out to be necessary to have a
-        new record we can still allocate real memory.  */
-!       bool alloca_used = false;
-        dataset = NULL;
-  
-!       if (he == NULL)
-       dataset = (struct dataset *) mempool_alloc (db, total + n, 1);
-  
-        if (dataset == NULL)
---- 207,216 ----
-        change.  Allocate memory on the cache since it is likely
-        discarded anyway.  If it turns out to be necessary to have a
-        new record we can still allocate real memory.  */
-!       bool dataset_in_stack_or_freed = false;
-        dataset = NULL;
-  
-!       if (he == NULL || ! __libc_use_alloca (alloca_used + total + n))
-       dataset = (struct dataset *) mempool_alloc (db, total + n, 1);
-  
-        if (dataset == NULL)
-*************** cache_addgr (struct database_dyn *db, in
-*** 216,225 ****
-         /* We cannot permanently add the result in the moment.  But
-            we can provide the result as is.  Store the data in some
-            temporary memory.  */
-!        dataset = (struct dataset *) alloca (total + n);
-  
-         /* We cannot add this record to the permanent database.  */
-!        alloca_used = true;
-       }
-  
-        dataset->head.allocsize = total + n;
---- 218,227 ----
-         /* We cannot permanently add the result in the moment.  But
-            we can provide the result as is.  Store the data in some
-            temporary memory.  */
-!        dataset = (struct dataset *) alloca_account (total + n, alloca_used);
-  
-         /* We cannot add this record to the permanent database.  */
-!        dataset_in_stack_or_freed = true;
-       }
-  
-        dataset->head.allocsize = total + n;
-*************** cache_addgr (struct database_dyn *db, in
-*** 273,278 ****
---- 275,288 ----
-                allocated on the stack and need not be freed.  */
-             dh->timeout = dataset->head.timeout;
-             ++dh->nreloads;
-+ 
-+            /* If the new record was not allocated on the stack, then it must
-+               be freed.  Note that it can no longer be used.  */
-+            if (! dataset_in_stack_or_freed)
-+              {
-+                free (dataset);
-+                dataset_in_stack_or_freed = true;
-+              }
-           }
-         else
-           {
-*************** cache_addgr (struct database_dyn *db, in
-*** 288,294 ****
-                 key_copy = (char *) newp + (key_copy - (char *) dataset);
-  
-                 dataset = memcpy (newp, dataset, total + n);
-!                alloca_used = false;
-               }
-  
-             /* Mark the old record as obsolete.  */
---- 298,304 ----
-                 key_copy = (char *) newp + (key_copy - (char *) dataset);
-  
-                 dataset = memcpy (newp, dataset, total + n);
-!                dataset_in_stack_or_freed = false;
-               }
-  
-             /* Mark the old record as obsolete.  */
-*************** cache_addgr (struct database_dyn *db, in
-*** 303,309 ****
-         assert (fd != -1);
-  
-  #ifdef HAVE_SENDFILE
-!        if (__builtin_expect (db->mmap_used, 1) && !alloca_used)
-           {
-             assert (db->wr_fd != -1);
-             assert ((char *) &dataset->resp > (char *) db->data);
---- 313,319 ----
-         assert (fd != -1);
-  
-  #ifdef HAVE_SENDFILE
-!        if (__builtin_expect (db->mmap_used, 1) && !dataset_in_stack_or_freed)
-           {
-             assert (db->wr_fd != -1);
-             assert ((char *) &dataset->resp > (char *) db->data);
-*************** cache_addgr (struct database_dyn *db, in
-*** 330,336 ****
-  
-        /* Add the record to the database.  But only if it has not been
-        stored on the stack.  */
-!       if (! alloca_used)
-       {
-         /* If necessary, we also propagate the data to disk.  */
-         if (db->persistent)
---- 340,346 ----
-  
-        /* Add the record to the database.  But only if it has not been
-        stored on the stack.  */
-!       if (! dataset_in_stack_or_freed)
-       {
-         /* If necessary, we also propagate the data to disk.  */
-         if (db->persistent)
+Index: glibc-2.12-2-gc4ccff1/nscd/grpcache.c
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/nscd/grpcache.c
++++ glibc-2.12-2-gc4ccff1/nscd/grpcache.c
+@@ -178,7 +178,8 @@ cache_addgr (struct database_dyn *db, in
+       char *cp;
+       const size_t key_len = strlen (key);
+       const size_t buf_len = 3 * sizeof (grp->gr_gid) + key_len + 1;
+-      char *buf = alloca (buf_len);
++      size_t alloca_used = 0;
++      char *buf = alloca_account (buf_len, alloca_used);
+       ssize_t n;
+       size_t cnt;
+@@ -190,7 +191,8 @@ cache_addgr (struct database_dyn *db, in
+       /* Determine the length of all members.  */
+       while (grp->gr_mem[gr_mem_cnt])
+       ++gr_mem_cnt;
+-      gr_mem_len = (uint32_t *) alloca (gr_mem_cnt * sizeof (uint32_t));
++      gr_mem_len = (uint32_t *) alloca_account (gr_mem_cnt * sizeof (uint32_t),
++                                              alloca_used);
+       for (gr_mem_cnt = 0; grp->gr_mem[gr_mem_cnt]; ++gr_mem_cnt)
+       {
+         gr_mem_len[gr_mem_cnt] = strlen (grp->gr_mem[gr_mem_cnt]) + 1;
+@@ -205,10 +207,10 @@ cache_addgr (struct database_dyn *db, in
+        change.  Allocate memory on the cache since it is likely
+        discarded anyway.  If it turns out to be necessary to have a
+        new record we can still allocate real memory.  */
+-      bool alloca_used = false;
++      bool dataset_in_stack_or_freed = false;
+       dataset = NULL;
+-      if (he == NULL)
++      if (he == NULL || ! __libc_use_alloca (alloca_used + total + n))
+       dataset = (struct dataset *) mempool_alloc (db, total + n, 1);
+       if (dataset == NULL)
+@@ -216,10 +218,10 @@ cache_addgr (struct database_dyn *db, in
+         /* We cannot permanently add the result in the moment.  But
+            we can provide the result as is.  Store the data in some
+            temporary memory.  */
+-        dataset = (struct dataset *) alloca (total + n);
++        dataset = (struct dataset *) alloca_account (total + n, alloca_used);
+         /* We cannot add this record to the permanent database.  */
+-        alloca_used = true;
++        dataset_in_stack_or_freed = true;
+       }
+       dataset->head.allocsize = total + n;
+@@ -273,6 +275,14 @@ cache_addgr (struct database_dyn *db, in
+                allocated on the stack and need not be freed.  */
+             dh->timeout = dataset->head.timeout;
+             ++dh->nreloads;
++
++            /* If the new record was not allocated on the stack, then it must
++               be freed.  Note that it can no longer be used.  */
++            if (! dataset_in_stack_or_freed)
++              {
++                free (dataset);
++                dataset_in_stack_or_freed = true;
++              }
+           }
+         else
+           {
+@@ -288,7 +298,7 @@ cache_addgr (struct database_dyn *db, in
+                 key_copy = (char *) newp + (key_copy - (char *) dataset);
+                 dataset = memcpy (newp, dataset, total + n);
+-                alloca_used = false;
++                dataset_in_stack_or_freed = false;
+               }
+             /* Mark the old record as obsolete.  */
+@@ -303,7 +313,7 @@ cache_addgr (struct database_dyn *db, in
+         assert (fd != -1);
+ #ifdef HAVE_SENDFILE
+-        if (__builtin_expect (db->mmap_used, 1) && !alloca_used)
++        if (__builtin_expect (db->mmap_used, 1) && !dataset_in_stack_or_freed)
+           {
+             assert (db->wr_fd != -1);
+             assert ((char *) &dataset->resp > (char *) db->data);
+@@ -330,7 +340,7 @@ cache_addgr (struct database_dyn *db, in
+       /* Add the record to the database.  But only if it has not been
+        stored on the stack.  */
+-      if (! alloca_used)
++      if (! dataset_in_stack_or_freed)
+       {
+         /* If necessary, we also propagate the data to disk.  */
+         if (db->persistent)
diff --git a/src/patches/glibc/glibc-rh845218.patch b/src/patches/glibc/glibc-rh845218.patch
new file mode 100644 (file)
index 0000000..47f909c
--- /dev/null
@@ -0,0 +1,218 @@
+commit 16b293a7a6f65d8ff348a603d19e8fd4372fa3a9
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date:   Wed Apr 30 11:48:43 2014 +0530
+
+    Do not fail if one of the two responses to AF_UNSPEC fails (BZ #14308)
+    
+    [Fixes BZ #14308, #12994, #13651]
+    
+    AF_UNSPEC results in sending two queries in parallel, one for the A
+    record and the other for the AAAA record.  If one of these is a
+    referral, then the query fails, which is wrong.  It should return at
+    least the one successful response.
+    
+    The fix has two parts.  The first part makes the referral fall back to
+    the SERVFAIL path, which results in using the successful response.
+    There is a bug in that path however, due to which the second part is
+    necessary.  The bug here is that if the first response is a failure
+    and the second succeeds, __libc_res_nsearch does not detect that and
+    assumes a failure.  The case where the first response is a success and
+    the second fails, works correctly.
+    
+    This condition is produced by buggy routers, so here's a crude
+    interposable library that can simulate such a condition.  The library
+    overrides the recvfrom syscall and modifies the header of the packet
+    received to reproduce this scenario.  It has two key variables:
+    mod_packet and first_error.
+    
+    The mod_packet variable when set to 0, results in odd packets being
+    modified to be a referral.  When set to 1, even packets are modified
+    to be a referral.
+    
+    The first_error causes the first response to be a failure so that a
+    domain-appended search is performed to test the second part of the
+    __libc_nsearch fix.
+    
+    The driver for this fix is a simple getaddrinfo program that does an
+    AF_UNSPEC query.  I have omitted this since it should be easy to
+    implement.
+    
+    I have tested this on x86_64.
+    
+    The interceptor library source:
+    
+    /* Override recvfrom and modify the header of the first DNS response to make it
+       a referral and reproduce bz #845218.  We have to resort to this ugly hack
+       because we cannot make bind return the buggy response of a referral for the
+       AAAA record and an authoritative response for the A record.  */
+     #define _GNU_SOURCE
+     #include <sys/types.h>
+     #include <sys/socket.h>
+     #include <netinet/in.h>
+     #include <arpa/inet.h>
+     #include <stdio.h>
+     #include <stdbool.h>
+     #include <endian.h>
+     #include <dlfcn.h>
+     #include <stdlib.h>
+    
+    /* Lifted from resolv/arpa/nameser_compat.h.  */
+    typedef struct {
+        unsigned        id :16;         /*%< query identification number */
+     #if BYTE_ORDER == BIG_ENDIAN
+        /* fields in third byte */
+        unsigned        qr: 1;          /*%< response flag */
+        unsigned        opcode: 4;      /*%< purpose of message */
+        unsigned        aa: 1;          /*%< authoritive answer */
+        unsigned        tc: 1;          /*%< truncated message */
+        unsigned        rd: 1;          /*%< recursion desired */
+        /* fields
+         * in
+         * fourth
+         * byte
+         * */
+        unsigned        ra: 1;          /*%< recursion available */
+        unsigned        unused :1;      /*%< unused bits (MBZ as of 4.9.3a3) */
+        unsigned        ad: 1;          /*%< authentic data from named */
+        unsigned        cd: 1;          /*%< checking disabled by resolver */
+        unsigned        rcode :4;       /*%< response code */
+     #endif
+     #if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN
+        /* fields
+         * in
+         * third
+         * byte
+         * */
+        unsigned        rd :1;          /*%< recursion desired */
+        unsigned        tc :1;          /*%< truncated message */
+        unsigned        aa :1;          /*%< authoritive answer */
+        unsigned        opcode :4;      /*%< purpose of message */
+        unsigned        qr :1;          /*%< response flag */
+        /* fields
+         * in
+         * fourth
+         * byte
+         * */
+        unsigned        rcode :4;       /*%< response code */
+        unsigned        cd: 1;          /*%< checking disabled by resolver */
+        unsigned        ad: 1;          /*%< authentic data from named */
+        unsigned        unused :1;      /*%< unused bits (MBZ as of 4.9.3a3) */
+        unsigned        ra :1;          /*%< recursion available */
+     #endif
+        /* remaining
+         * bytes
+         * */
+        unsigned        qdcount :16;    /*%< number of question entries */
+        unsigned        ancount :16;    /*%< number of answer entries */
+        unsigned        nscount :16;    /*%< number of authority entries */
+        unsigned        arcount :16;    /*%< number of resource entries */
+    } HEADER;
+    
+    static int done = 0;
+    
+    /* Packets to modify.  0 for the odd packets and 1 for even packets.  */
+    static const int mod_packet = 0;
+    
+    /* Set to true if the first request should result in an error, resulting in a
+       search query.  */
+    static bool first_error = true;
+    
+    static ssize_t (*real_recvfrom) (int sockfd, void *buf, size_t len, int flags,
+                         struct sockaddr *src_addr, socklen_t *addrlen);
+    
+    void
+    __attribute__ ((constructor))
+    init (void)
+    {
+      real_recvfrom = dlsym (RTLD_NEXT, "recvfrom");
+    
+      if (real_recvfrom == NULL)
+        {
+          printf ("Failed to get reference to recvfrom: %s\n", dlerror ());
+          printf ("Cannot simulate test\n");
+          abort ();
+        }
+    }
+    
+    /* Modify the second packet that we receive to set the header in a manner as to
+       reproduce BZ #845218.  */
+    static void
+    mod_buf (HEADER *h, int port)
+    {
+      if (done % 2 == mod_packet || (first_error && done == 1))
+        {
+          printf ("(Modifying header)");
+    
+          if (first_error && done == 1)
+       h->rcode = 3;
+          else
+       h->rcode = 0;   /* NOERROR == 0.  */
+          h->ancount = 0;
+          h->aa = 0;
+          h->ra = 0;
+          h->arcount = 0;
+        }
+      done++;
+    }
+    
+    ssize_t
+    recvfrom (int sockfd, void *buf, size_t len, int flags,
+         struct sockaddr *src_addr, socklen_t *addrlen)
+    {
+      ssize_t ret = real_recvfrom (sockfd, buf, len, flags, src_addr, addrlen);
+      int port = htons (((struct sockaddr_in *) src_addr)->sin_port);
+      struct in_addr addr = ((struct sockaddr_in *) src_addr)->sin_addr;
+      const char *host = inet_ntoa (addr);
+      printf ("\n*** From %s:%d: ", host, port);
+    
+      mod_buf (buf, port);
+    
+      printf ("returned %zd\n", ret);
+      return ret;
+    }
+
+diff --git a/resolv/res_query.c b/resolv/res_query.c
+index a9db837..4e6612c 100644
+--- a/resolv/res_query.c
++++ b/resolv/res_query.c
+@@ -382,7 +382,9 @@ __libc_res_nsearch(res_state statp,
+               ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
+                                             answer, anslen, answerp,
+                                             answerp2, nanswerp2, resplen2);
+-              if (ret > 0 || trailing_dot)
++              if (ret > 0 || trailing_dot
++                  /* If the second response is valid then we use that.  */
++                  || (ret == 0 && answerp2 != NULL && resplen2 > 0))
+                       return (ret);
+               saved_herrno = h_errno;
+               tried_as_is++;
+@@ -422,7 +424,8 @@ __libc_res_nsearch(res_state statp,
+                                                     answer, anslen, answerp,
+                                                     answerp2, nanswerp2,
+                                                     resplen2);
+-                      if (ret > 0)
++                      if (ret > 0 || (ret == 0 && answerp2 != NULL
++                                      && resplen2 > 0))
+                               return (ret);
+                       if (answerp && *answerp != answer) {
+diff --git a/resolv/res_send.c b/resolv/res_send.c
+index 60743df..3273d55 100644
+--- a/resolv/res_send.c
++++ b/resolv/res_send.c
+@@ -1351,6 +1351,7 @@ send_dg(res_state statp,
+                               (*thisresplenp > *thisanssizp)
+                               ? *thisanssizp : *thisresplenp);
++              next_ns:
+                       if (recvresp1 || (buf2 != NULL && recvresp2)) {
+                         *resplen2 = 0;
+                         return resplen;
+@@ -1368,7 +1369,6 @@ send_dg(res_state statp,
+                           goto wait;
+                         }
+-              next_ns:
+                       __res_iclose(statp, false);
+                       /* don't retry if called from dig */
+                       if (!statp->pfcode)
diff --git a/src/patches/glibc/glibc-rh848748.patch b/src/patches/glibc/glibc-rh848748.patch
new file mode 100644 (file)
index 0000000..b75a368
--- /dev/null
@@ -0,0 +1,70 @@
+2013-04-30  Patsy Franklin <pfrankli@redhat.com>
+
+        * nis/yp_xdr.c: Defined XDRMAXNAME and XDRMAXRECORD.
+        (xdr_domainname): Use XDRMAXNAME as maxsize.
+        (xdr_mapname): Use XDRMAXNAME as maxsize.
+        (xdr_peername): Use XDRMAXNAME as maxsize.
+        (xdr_keydat): Use XDRMAXRECORD as maxsize.
+        (xdr_valdat): Use XDRMAXRECORD as maxsize.
+
+diff -Nrup a/nis/yp_xdr.c b/nis/yp_xdr.c
+--- a/nis/yp_xdr.c     2012-06-30 15:12:34.000000000 -0400
++++ b/nis/yp_xdr.c     2013-04-30 05:36:02.492835503 -0400
+@@ -32,6 +32,14 @@
+ #include <rpcsvc/yp.h>
+ #include <rpcsvc/ypclnt.h>
++/* The specification suggests 1024 as a maximum length of all fields,
++   but current linux systems usually don't use any limits. So, to stay
++   as much compatible as possible with recent linux systems we choose
++   limits large enough to avoid problems. */
++
++#define XDRMAXNAME 1024
++#define XDRMAXRECORD 16 * 1024 * 1024
++
+ bool_t
+ xdr_ypstat (XDR *xdrs, ypstat *objp)
+ {
+@@ -49,21 +57,21 @@ libnsl_hidden_def (xdr_ypxfrstat)
+ bool_t
+ xdr_domainname (XDR *xdrs, domainname *objp)
+ {
+-  return xdr_string (xdrs, objp, ~0);
++  return xdr_string (xdrs, objp, XDRMAXNAME);
+ }
+ libnsl_hidden_def (xdr_domainname)
+ bool_t
+ xdr_mapname (XDR *xdrs, mapname *objp)
+ {
+-  return xdr_string (xdrs, objp, ~0);
++  return xdr_string (xdrs, objp, XDRMAXNAME);
+ }
+ libnsl_hidden_def (xdr_mapname)
+ bool_t
+ xdr_peername (XDR *xdrs, peername *objp)
+ {
+-  return xdr_string (xdrs, objp, ~0);
++  return xdr_string (xdrs, objp, XDRMAXNAME);
+ }
+ libnsl_hidden_def (xdr_peername)
+@@ -71,7 +79,7 @@ bool_t
+ xdr_keydat (XDR *xdrs, keydat *objp)
+ {
+   return xdr_bytes (xdrs, (char **) &objp->keydat_val,
+-                  (u_int *) &objp->keydat_len, ~0);
++                  (u_int *) &objp->keydat_len, XDRMAXRECORD);
+ }
+ libnsl_hidden_def (xdr_keydat)
+@@ -79,7 +87,7 @@ bool_t
+ xdr_valdat (XDR *xdrs, valdat *objp)
+ {
+   return xdr_bytes (xdrs, (char **) &objp->valdat_val,
+-                  (u_int *) &objp->valdat_len, ~0);
++                  (u_int *) &objp->valdat_len, XDRMAXRECORD);
+ }
+ libnsl_hidden_def (xdr_valdat)
diff --git a/src/patches/glibc/glibc-rh851470.patch b/src/patches/glibc/glibc-rh851470.patch
new file mode 100644 (file)
index 0000000..94915da
--- /dev/null
@@ -0,0 +1,52 @@
+commit 050af9c4e86eeecd484ed44b7765e750523276eb
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date:   Wed Aug 29 10:03:39 2012 +0530
+
+    Don't make ttyname* fail if proc filesystem is not available
+    
+    The ttyname and ttyname_r functions on Linux now fall back to
+    searching for the tty file descriptor in /dev/pts or /dev if /proc is
+    not available.  This allows creation of chroots without the procfs
+    mounted on /proc.
+    
+    Fixes BZ #14516.
+
+ 2012-08-29  Siddhesh Poyarekar  <siddhesh@redhat.com>
+       [BZ #14516]
+       * sysdeps/unix/sysv/linux/ttyname.c (ttyname): Don't return
+       failure if reading from procfs failed.
+       * sysdeps/unix/sysv/linux/ttyname_r.c (ttyname_r): Likewise.
+diff -rup a/sysdeps/unix/sysv/linux/ttyname.c b/sysdeps/unix/sysv/linux/ttyname.c
+--- a/sysdeps/unix/sysv/linux/ttyname.c        2010-05-04 05:27:23.000000000 -0600
++++ b/sysdeps/unix/sysv/linux/ttyname.c        2012-08-27 10:53:29.326671475 -0600
+@@ -146,12 +146,6 @@ ttyname (int fd)
+     }
+   ssize_t len = __readlink (procname, ttyname_buf, buflen);
+-  if (__builtin_expect (len == -1 && errno == ENOENT, 0))
+-    {
+-      __set_errno (EBADF);
+-      return NULL;
+-    }
+-
+   if (__builtin_expect (len != -1
+ #ifndef __ASSUME_PROC_SELF_FD_SYMLINK
+                       /* This is for Linux 2.0.  */
+diff -rup a/sysdeps/unix/sysv/linux/ttyname_r.c b/sysdeps/unix/sysv/linux/ttyname_r.c
+--- a/sysdeps/unix/sysv/linux/ttyname_r.c      2010-05-04 05:27:23.000000000 -0600
++++ b/sysdeps/unix/sysv/linux/ttyname_r.c      2012-08-27 10:54:05.406528501 -0600
+@@ -126,12 +126,6 @@ __ttyname_r (int fd, char *buf, size_t b
+   *_fitoa_word (fd, __stpcpy (procname, "/proc/self/fd/"), 10, 0) = '\0';
+   ssize_t ret = __readlink (procname, buf, buflen - 1);
+-  if (__builtin_expect (ret == -1 && errno == ENOENT, 0))
+-    {
+-      __set_errno (EBADF);
+-      return EBADF;
+-    }
+-
+   if (__builtin_expect (ret == -1 && errno == ENAMETOOLONG, 0))
+     {
+       __set_errno (ERANGE);
diff --git a/src/patches/glibc/glibc-rh859965.patch b/src/patches/glibc/glibc-rh859965.patch
new file mode 100644 (file)
index 0000000..8fcbcd4
--- /dev/null
@@ -0,0 +1,854 @@
+#
+# Based on the following patch:
+#
+# Upstream bug: https://sourceware.org/bugzilla/show_bug.cgi?id=14906
+# URL: https://sourceware.org/ml/libc-alpha/2015-02/msg00504.html
+#
+# 2015-02-17  Carlos O'Donell  <carlos@redhat.com>
+#  
+#      [BZ #14906]
+#      * nscd/cache.c (prune_cache): Use TRACED_FILE. Compare and update
+#      traced file mtime. Use consistent log message.
+#      * nscd/connections.c [HAVE_INOTIFY] (install_watches): New function.
+#      (register_traced_file): Call install_watches. Always set mtime.
+#      (invalidate_cache): Iterate over all trace files. Call install_watches.
+#      (inotify_check_files): Don't inline. Handle watching parent
+#      directories and configuration file movement in and out.
+#      (handle_inotify_events): New function.
+#      (main_loop_poll): Call handle_inotify_events.
+#      (main_loop_epoll): Likewise.
+#      * nscd/nscd.h: Define TRACED_FILE, TRACED_DIR, and PATH_MAX.
+#      (struct traced_file): Use array of inotify fds. Add parent directory,
+#      and basename.
+#      (struct database_dyn): Remove unused file_mtime.
+#      (init_traced_file): New inline function.
+#      (define_traced_file): New macro.
+#      * nss/nss_db/db-init.c: Use define_traced_file.
+#      (_nss_db_init): Use init_traced_file.
+#      * nss/nss_files/files-init.c: Use define_traced_file.
+#      (_nss_files_init): Use init_traced_file.
+# 
+diff -urN glibc-2.12-2-gc4ccff1.orig/misc/sys/cdefs.h glibc-2.12-2-gc4ccff1.mod1/misc/sys/cdefs.h
+--- glibc-2.12-2-gc4ccff1.orig/misc/sys/cdefs.h        2015-02-18 04:42:12.115187116 -0500
++++ glibc-2.12-2-gc4ccff1.mod1/misc/sys/cdefs.h        2015-02-18 04:02:03.635159090 -0500
+@@ -362,6 +362,14 @@
+ # endif
+ #endif
++#if __GNUC__ >= 3
++# define __glibc_unlikely(cond) __builtin_expect ((cond), 0)
++# define __glibc_likely(cond)   __builtin_expect ((cond), 1)
++#else
++# define __glibc_unlikely(cond) (cond)
++# define __glibc_likely(cond)   (cond)
++#endif
++
+ #include <bits/wordsize.h>
+ #if defined __LONG_DOUBLE_MATH_OPTIONAL && defined __NO_LONG_DOUBLE_MATH
+diff -urN glibc-2.12-2-gc4ccff1.orig/nscd/cache.c glibc-2.12-2-gc4ccff1.mod1/nscd/cache.c
+--- glibc-2.12-2-gc4ccff1.orig/nscd/cache.c    2015-02-18 04:42:12.329180362 -0500
++++ glibc-2.12-2-gc4ccff1.mod1/nscd/cache.c    2015-02-18 04:02:03.635159090 -0500
+@@ -266,29 +266,52 @@
+   /* If we check for the modification of the underlying file we invalidate
+      the entries also in this case.  */
+-  if (table->inotify_descr < 0 && table->check_file && now != LONG_MAX)
++  if (table->check_file && now != LONG_MAX)
+     {
+-      struct stat64 st;
++      struct traced_file *runp = table->traced_files;
+-      if (stat64 (table->filename, &st) < 0)
++      while (runp != NULL)
+       {
+-        char buf[128];
+-        /* We cannot stat() the file, disable file checking if the
+-             file does not exist.  */
+-        dbg_log (_("cannot stat() file `%s': %s"),
+-                 table->filename, strerror_r (errno, buf, sizeof (buf)));
+-        if (errno == ENOENT)
+-          table->check_file = 0;
+-      }
+-      else
+-      {
+-        if (st.st_mtime != table->file_mtime)
++#ifdef HAVE_INOTIFY
++        if (runp->inotify_descr[TRACED_FILE] == -1)
++#endif
+           {
+-            /* The file changed.  Invalidate all entries.  */
+-            now = LONG_MAX;
+-            table->file_mtime = st.st_mtime;
++            struct stat64 st;
++
++            if (stat64 (runp->fname, &st) < 0)
++              {
++                /* Print a diagnostic that the traced file was missing.
++                   We must not disable tracing since the file might return
++                   shortly and we want to reload it at the next pruning.
++                   Disabling tracing here would go against the configuration
++                   as specified by the user via check-files.  */
++                char buf[128];
++                dbg_log (_("checking for monitored file `%s': %s"),
++                         runp->fname, strerror_r (errno, buf, sizeof (buf)));
++              }
++            else
++              {
++                /* This must be `!=` to catch cases where users turn the
++                   clocks back and we still want to detect any time difference
++                   in mtime.  */
++                if (st.st_mtime != runp->mtime)
++                  {
++                    dbg_log (_("monitored file `%s` changed (mtime)"),
++                             runp->fname);
++                    /* The file changed. Invalidate all entries.  */
++                    now = LONG_MAX;
++                    runp->mtime = st.st_mtime;
++#ifdef HAVE_INOTIFY
++                    /* Attempt to install a watch on the file.  */
++                    install_watches (runp);
++#endif
++                  }
++              }
+           }
++
++        runp = runp->next;
+       }
++
+     }
+   /* We run through the table and find values which are not valid anymore.
+diff -urN glibc-2.12-2-gc4ccff1.orig/nscd/connections.c glibc-2.12-2-gc4ccff1.mod1/nscd/connections.c
+--- glibc-2.12-2-gc4ccff1.orig/nscd/connections.c      2015-02-18 04:42:12.333180236 -0500
++++ glibc-2.12-2-gc4ccff1.mod1/nscd/connections.c      2015-02-18 04:40:51.674726008 -0500
+@@ -74,6 +74,25 @@
+ static void begin_drop_privileges (void);
+ static void finish_drop_privileges (void);
++/* Define the traced files.  */
++#define PWD_FILENAME "/etc/passwd"
++define_traced_file (pwd, PWD_FILENAME);
++
++#define GRP_FILENAME "/etc/group"
++define_traced_file (grp, GRP_FILENAME);
++
++#define HST_FILENAME "/etc/hosts"
++define_traced_file (hst, HST_FILENAME);
++
++#define RESOLV_FILENAME "/etc/resolv.conf"
++define_traced_file (resolv, RESOLV_FILENAME);
++
++#define SERV_FILENAME "/etc/services"
++define_traced_file (serv, SERV_FILENAME);
++
++#define NETGR_FILENAME "/etc/netgroup"
++define_traced_file (netgr, NETGR_FILENAME);
++
+ /* Map request type to a string.  */
+ const char *const serv2str[LASTREQ] =
+ {
+@@ -115,8 +134,6 @@
+     .shared = 0,
+     .max_db_size = DEFAULT_MAX_DB_SIZE,
+     .suggested_module = DEFAULT_SUGGESTED_MODULE,
+-   .reset_res = 0,
+-    .filename = "/etc/passwd",
+     .db_filename = _PATH_NSCD_PASSWD_DB,
+     .disabled_iov = &pwd_iov_disabled,
+     .postimeout = 3600,
+@@ -136,8 +153,6 @@
+     .shared = 0,
+     .max_db_size = DEFAULT_MAX_DB_SIZE,
+     .suggested_module = DEFAULT_SUGGESTED_MODULE,
+-    .reset_res = 0,
+-    .filename = "/etc/group",
+     .db_filename = _PATH_NSCD_GROUP_DB,
+     .disabled_iov = &grp_iov_disabled,
+     .postimeout = 3600,
+@@ -157,8 +172,6 @@
+     .shared = 0,
+     .max_db_size = DEFAULT_MAX_DB_SIZE,
+     .suggested_module = DEFAULT_SUGGESTED_MODULE,
+-    .reset_res = 1,
+-    .filename = "/etc/hosts",
+     .db_filename = _PATH_NSCD_HOSTS_DB,
+     .disabled_iov = &hst_iov_disabled,
+     .postimeout = 3600,
+@@ -178,8 +191,6 @@
+     .shared = 0,
+     .max_db_size = DEFAULT_MAX_DB_SIZE,
+     .suggested_module = DEFAULT_SUGGESTED_MODULE,
+-    .reset_res = 0,
+-    .filename = "/etc/services",
+     .db_filename = _PATH_NSCD_SERVICES_DB,
+     .disabled_iov = &serv_iov_disabled,
+     .postimeout = 28800,
+@@ -199,8 +210,6 @@
+     .shared = 0,
+     .max_db_size = DEFAULT_MAX_DB_SIZE,
+     .suggested_module = DEFAULT_SUGGESTED_MODULE,
+-    .reset_res = 0,
+-    .filename = "/etc/netgroup",
+     .db_filename = _PATH_NSCD_NETGROUP_DB,
+     .disabled_iov = &netgroup_iov_disabled,
+     .postimeout = 28800,
+@@ -863,41 +872,26 @@
+           dbs[cnt].shared = 0;
+           assert (dbs[cnt].ro_fd == -1);
+         }
++      }
+-      dbs[cnt].inotify_descr = -1;
+-      if (dbs[cnt].check_file)
+-        {
+-#ifdef HAVE_INOTIFY
+-          if (inotify_fd < 0
+-              || (dbs[cnt].inotify_descr
+-                  = inotify_add_watch (inotify_fd, dbs[cnt].filename,
+-                                       IN_DELETE_SELF | IN_MODIFY)) < 0)
+-            /* We cannot notice changes in the main thread.  */
+-#endif
+-            {
+-              /* We need the modification date of the file.  */
+-              struct stat64 st;
++  /* Initialize and register the traced files.  */
++  init_traced_file (&pwd_traced_file.file, PWD_FILENAME, 0);
++  register_traced_file (pwddb, &pwd_traced_file.file);
+-              if (stat64 (dbs[cnt].filename, &st) < 0)
+-                {
+-                  /* We cannot stat() the file, disable file checking.  */
+-                  dbg_log (_("cannot stat() file `%s': %s"),
+-                           dbs[cnt].filename, strerror (errno));
+-                  dbs[cnt].check_file = 0;
+-                }
+-              else
+-                dbs[cnt].file_mtime = st.st_mtime;
+-            }
+-        }
++  init_traced_file (&grp_traced_file.file, GRP_FILENAME, 0);
++  register_traced_file (grpdb, &grp_traced_file.file);
+-#ifdef HAVE_INOTIFY
+-      if (cnt == hstdb && inotify_fd >= -1)
+-        /* We also monitor the resolver configuration file.  */
+-        resolv_conf_descr = inotify_add_watch (inotify_fd,
+-                                               _PATH_RESCONF,
+-                                               IN_DELETE_SELF | IN_MODIFY);
+-#endif
+-      }
++  init_traced_file (&hst_traced_file.file, HST_FILENAME, 0);
++  register_traced_file (hstdb, &hst_traced_file.file);
++
++  init_traced_file (&resolv_traced_file.file, RESOLV_FILENAME, 1);
++  register_traced_file (hstdb, &resolv_traced_file.file);
++
++  init_traced_file (&serv_traced_file.file, SERV_FILENAME, 0);
++  register_traced_file (servdb, &serv_traced_file.file);
++
++  init_traced_file (&netgr_traced_file.file, NETGR_FILENAME, 0);
++  register_traced_file (netgrdb, &netgr_traced_file.file);
+   /* Create the socket.  */
+ #ifndef __ASSUME_SOCK_CLOEXEC
+@@ -968,6 +962,92 @@
+     finish_drop_privileges ();
+ }
++#ifdef HAVE_INOTIFY
++#define TRACED_FILE_MASK (IN_DELETE_SELF | IN_CLOSE_WRITE | IN_MOVE_SELF)
++#define TRACED_DIR_MASK (IN_DELETE_SELF | IN_CREATE | IN_MOVED_TO | IN_MOVE_SELF)
++void
++install_watches (struct traced_file *finfo)
++{
++  /* If we have inotify support use it exclusively with no fallback
++     to stat.  This is a design decision to make the implementation
++     sipmler.  Either we use fstat for the file name or we use inotify
++     for both the file and parent directory.  */
++  if (finfo->inotify_descr[TRACED_FILE] < 0)
++    finfo->inotify_descr[TRACED_FILE] = inotify_add_watch (inotify_fd,
++                                                         finfo->fname,
++                                                         TRACED_FILE_MASK);
++  if (finfo->inotify_descr[TRACED_FILE] < 0)
++    {
++      dbg_log (_("disabled inotify-based monitoring for file `%s': %s"),
++               finfo->fname, strerror (errno));
++      return;
++    }
++  dbg_log (_("monitoring file `%s` (%d)"),
++         finfo->fname, finfo->inotify_descr[TRACED_FILE]);
++  /* Additionally listen for IN_CREATE events in the files parent
++     directory.  We do this because the file to be watched might be
++     deleted and then added back again.  When it is added back again
++     we must re-add the watch.  We must also cover IN_MOVED_TO to
++     detect a file being moved into the directory.  */
++  if (finfo->inotify_descr[TRACED_DIR] < 0)
++    finfo->inotify_descr[TRACED_DIR] = inotify_add_watch (inotify_fd,
++                                                        finfo->dname,
++                                                        TRACED_DIR_MASK);
++  if (finfo->inotify_descr[TRACED_DIR] < 0)
++    {
++      dbg_log (_("disabled inotify-based monitoring for directory `%s': %s"),
++               finfo->fname, strerror (errno));
++      return;
++    }
++  dbg_log (_("monitoring directory `%s` (%d)"),
++         finfo->dname, finfo->inotify_descr[TRACED_DIR]);
++}
++#endif
++
++/* Register the file in FINFO as a traced file for the database DBS[DBIX].
++
++   We support registering multiple files per database. Each call to
++   register_traced_file adds to the list of registered files.
++
++   When we prune the database, either through timeout or a request to
++   invalidate, we will check to see if any of the registered files has changed.
++   When we accept new connections to handle a cache request we will also
++   check to see if any of the registered files has changed.
++
++   If we have inotify support then we install an inotify fd to notify us of
++   file deletion or modification, both of which will require we invalidate
++   the cache for the database.  Without inotify support we stat the file and
++   store st_mtime to determine if the file has been modified.  */
++void
++register_traced_file (size_t dbidx, struct traced_file *finfo)
++{
++  /* If the database is disabled or file checking is disabled
++     then ignore the registration.  */
++  if (! dbs[dbidx].enabled || ! dbs[dbidx].check_file)
++    return;
++
++  if (__glibc_unlikely (debug_level > 0))
++    dbg_log (_("monitoring file %s for database %s"),
++           finfo->fname, dbnames[dbidx]);
++
++#ifdef HAVE_INOTIFY
++  install_watches (finfo);
++#endif
++  struct stat64 st;
++  if (stat64 (finfo->fname, &st) < 0)
++    {
++      /* We cannot stat() the file, disable file checking.  */
++      dbg_log (_("disabled monitoring for file `%s': %s"),
++             finfo->fname, strerror (errno));
++      finfo->mtime = 0;
++    }
++  else
++    finfo->mtime = st.st_mtime;
++
++  /* Queue up the file name.  */
++  finfo->next = dbs[dbidx].traced_files;
++  dbs[dbidx].traced_files = finfo;
++}
+ /* Close the connections.  */
+ void
+@@ -986,9 +1066,25 @@
+   for (number = pwddb; number < lastdb; ++number)
+     if (strcmp (key, dbnames[number]) == 0)
+       {
+-      if (dbs[number].reset_res)
+-        res_init ();
+-
++      struct traced_file *runp = dbs[number].traced_files;
++      while (runp != NULL)
++        {
++          /* Make sure we reload from file when checking mtime.  */
++          runp->mtime = 0;
++#ifdef HAVE_INOTIFY
++          /* During an invalidation we try to reload the traced
++             file watches.  This allows the user to re-sync if
++             inotify events were lost.  Similar to what we do during
++             pruning.  */
++          install_watches (runp);
++#endif
++          if (runp->call_res_init)
++            {
++              res_init ();
++              break;
++            }
++          runp = runp->next;
++        }
+       break;
+       }
+@@ -1817,6 +1913,231 @@
+ /* Array for times a connection was accepted.  */
+ static time_t *starttime;
++#ifdef HAVE_INOTIFY
++/* Inotify event for changed file.  */
++union __inev
++{
++  struct inotify_event i;
++# ifndef PATH_MAX
++#  define PATH_MAX 1024
++# endif
++  char buf[sizeof (struct inotify_event) + PATH_MAX];
++};
++
++/* Returns 0 if the file is there and matches the last mtime
++   on record, otherwise -1.  */
++int
++check_file (struct traced_file *finfo)
++{
++  struct stat64 st;
++  if (stat64 (finfo->fname, &st) < 0)
++    return -1;
++  return 0;
++}
++
++/* Process the inotify event in INEV. If the event matches any of the files
++   registered with a database then mark that database as requiring its cache
++   to be cleared. We indicate the cache needs clearing by setting
++   TO_CLEAR[DBCNT] to true for the matching database.  */
++static void
++inotify_check_files (bool *to_clear, union __inev *inev)
++{
++  /* Check which of the files changed.  */
++  for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt)
++    {
++      struct traced_file *finfo = dbs[dbcnt].traced_files;
++
++      while (finfo != NULL)
++      {
++        /* The configuration file was moved or deleted.
++           We stop watching it at that point, and reinitialize.  */
++        if (finfo->inotify_descr[TRACED_FILE] == inev->i.wd
++            && ((inev->i.mask & IN_MOVE_SELF)
++                || (inev->i.mask & IN_DELETE_SELF)
++                || (inev->i.mask & IN_IGNORED)))
++          {
++            int ret;
++            bool moved = (inev->i.mask & IN_MOVE_SELF) != 0;
++
++            if (check_file (finfo) == 0)
++              {
++                dbg_log (_("ignored out of order inotify event for `%s`"),
++                         finfo->fname);
++                return;
++              }
++
++            dbg_log (_("monitored file `%s` was %s, removing watch"),
++                     finfo->fname, moved ? "moved" : "deleted");
++            /* File was moved out, remove the watch.  Watches are
++               automatically removed when the file is deleted.  */
++            if (moved)
++              {
++                ret = inotify_rm_watch (inotify_fd, inev->i.wd);
++                if (ret < 0)
++                  dbg_log (_("failed to remove file watch `%s`: %s"),
++                           finfo->fname, strerror (errno));
++              }
++            finfo->inotify_descr[TRACED_FILE] = -1;
++            to_clear[dbcnt] = true;
++            if (finfo->call_res_init)
++              res_init ();
++            return;
++          }
++        /* The configuration file was open for writing and has just closed.
++           We reset the cache and reinitialize.  */
++        if (finfo->inotify_descr[TRACED_FILE] == inev->i.wd
++            && inev->i.mask & IN_CLOSE_WRITE)
++          {
++            /* Mark cache as needing to be cleared and reinitialize.  */
++            dbg_log (_("monitored file `%s` was written to"), finfo->fname);
++            to_clear[dbcnt] = true;
++            if (finfo->call_res_init)
++              res_init ();
++            return;
++          }
++        /* The parent directory was moved or deleted.  There is no coming
++           back from this.  We do not track the parent of the parent, and
++           once this happens we trigger one last invalidation.  You must
++           restart nscd to track subsequent changes.   We track this to
++           do one last robust re-initialization and then we're done.  */
++        if (finfo->inotify_descr[TRACED_DIR] == inev->i.wd
++            && ((inev->i.mask & IN_DELETE_SELF)
++                || (inev->i.mask & IN_MOVE_SELF)
++                || (inev->i.mask & IN_IGNORED)))
++          {
++            bool moved = (inev->i.mask & IN_MOVE_SELF) != 0;
++            /* The directory watch may have already been removed
++               but we don't know so we just remove it again and
++               ignore the error.  Then we remove the file watch.
++               Note: watches are automatically removed for deleted
++               files.  */
++            if (moved)
++              inotify_rm_watch (inotify_fd, inev->i.wd);
++            if (finfo->inotify_descr[TRACED_FILE] != -1)
++              {
++                dbg_log (_("monitored parent directory `%s` was %s, removing watch on `%s`"),
++                         finfo->dname, moved ? "moved" : "deleted", finfo->fname);
++                if (inotify_rm_watch (inotify_fd, finfo->inotify_descr[TRACED_FILE]) < 0)
++                  dbg_log (_("failed to remove file watch `%s`: %s"),
++                           finfo->dname, strerror (errno));
++              }
++            finfo->inotify_descr[TRACED_FILE] = -1;
++            finfo->inotify_descr[TRACED_DIR] = -1;
++            to_clear[dbcnt] = true;
++            if (finfo->call_res_init)
++              res_init ();
++            /* Continue to the next entry since this might be the
++               parent directory for multiple registered files and
++               we want to remove watches for all registered files.  */
++            continue;
++          }
++        /* The parent directory had a create or moved to event.  */
++        if (finfo->inotify_descr[TRACED_DIR] == inev->i.wd
++            && ((inev->i.mask & IN_MOVED_TO)
++                || (inev->i.mask & IN_CREATE))
++            && strcmp (inev->i.name, finfo->sfname) == 0)
++          {
++            /* We detected a directory change.  We look for the creation
++               of the file we are tracking or the move of the same file
++               into the directory.  */
++            int ret;
++            dbg_log (_("monitored file `%s` was %s, adding watch"),
++                     finfo->fname,
++                     inev->i.mask & IN_CREATE ? "created" : "moved into place");
++            /* File was moved in or created.  Regenerate the watch.  */
++            if (finfo->inotify_descr[TRACED_FILE] != -1)
++              inotify_rm_watch (inotify_fd,
++                                finfo->inotify_descr[TRACED_FILE]);
++
++            ret = inotify_add_watch (inotify_fd,
++                                     finfo->fname,
++                                     TRACED_FILE_MASK);
++            if (ret < 0)
++              dbg_log (_("failed to add file watch `%s`: %s"),
++                       finfo->fname, strerror (errno));
++
++            finfo->inotify_descr[TRACED_FILE] = ret;
++
++            /* The file is new or moved so mark cache as needing to
++               be cleared and reinitialize.  */
++            to_clear[dbcnt] = true;
++            if (finfo->call_res_init)
++              res_init ();
++
++            /* Done re-adding the watch.  Don't return, we may still
++               have other files in this same directory, same watch
++               descriptor, and need to process them.  */
++          }
++        /* Other events are ignored, and we move on to the next file.  */
++        finfo = finfo->next;
++        }
++    }
++}
++
++/* If an entry in the array of booleans TO_CLEAR is TRUE then clear the cache
++   for the associated database, otherwise do nothing. The TO_CLEAR array must
++   have LASTDB entries.  */
++static inline void
++clear_db_cache (bool *to_clear)
++{
++  for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt)
++    if (to_clear[dbcnt])
++      {
++      pthread_mutex_lock (&dbs[dbcnt].prune_lock);
++      dbs[dbcnt].clear_cache = 1;
++      pthread_mutex_unlock (&dbs[dbcnt].prune_lock);
++      pthread_cond_signal (&dbs[dbcnt].prune_cond);
++      }
++}
++
++int
++handle_inotify_events (void)
++{
++  bool to_clear[lastdb] = { false, };
++  union __inev inev;
++
++  /* Read all inotify events for files registered via
++     register_traced_file().  */
++  while (1)
++    {
++      /* Potentially read multiple events into buf.  */
++      ssize_t nb = TEMP_FAILURE_RETRY (read (inotify_fd,
++                                           &inev.buf,
++                                           sizeof (inev)));
++      if (nb < (ssize_t) sizeof (struct inotify_event))
++      {
++        /* Not even 1 event.  */
++        if (__glibc_unlikely (nb == -1 && errno != EAGAIN))
++          return -1;
++        /* Done reading events that are ready.  */
++        break;
++      }
++      /* Process all events.  The normal inotify interface delivers
++       complete events on a read and never a partial event.  */
++      char *eptr = &inev.buf[0];
++      ssize_t count;
++      while (1)
++      {
++        /* Check which of the files changed.  */
++        inotify_check_files (to_clear, &inev);
++        count = sizeof (struct inotify_event) + inev.i.len;
++        eptr += count;
++        nb -= count;
++        if (nb >= (ssize_t) sizeof (struct inotify_event))
++          memcpy (&inev, eptr, nb);
++        else
++          break;
++      }
++      continue;
++    }
++  /* Actually perform the cache clearing.  */
++  clear_db_cache (to_clear);
++  return 0;
++}
++
++
++#endif
++
+ static void
+ __attribute__ ((__noreturn__))
+@@ -1910,66 +2231,21 @@
+           {
+             if (conns[1].revents != 0)
+               {
+-                bool to_clear[lastdb] = { false, };
+-                union
+-                {
+-# ifndef PATH_MAX
+-#  define PATH_MAX 1024
+-# endif
+-                  struct inotify_event i;
+-                  char buf[sizeof (struct inotify_event) + PATH_MAX];
+-                } inev;
++                int ret;
++                ret = handle_inotify_events ();
+-                while (1)
++                if (ret == -1)
+                   {
+-                    ssize_t nb = TEMP_FAILURE_RETRY (read (inotify_fd, &inev,
+-                                                           sizeof (inev)));
+-                    if (nb < (ssize_t) sizeof (struct inotify_event))
+-                      {
+-                        if (__builtin_expect (nb == -1 && errno != EAGAIN,
+-                                              0))
+-                          {
+-                            /* Something went wrong when reading the inotify
+-                               data.  Better disable inotify.  */
+-                            dbg_log (_("\
+-disabled inotify after read error %d"),
+-                                     errno);
+-                            conns[1].fd = -1;
+-                            firstfree = 1;
+-                            if (nused == 2)
+-                              nused = 1;
+-                            close (inotify_fd);
+-                            inotify_fd = -1;
+-                          }
+-                        break;
+-                      }
+-
+-                    /* Check which of the files changed.  */
+-                    for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt)
+-                      if (inev.i.wd == dbs[dbcnt].inotify_descr)
+-                        {
+-                          to_clear[dbcnt] = true;
+-                          goto next;
+-                        }
+-
+-                    if (inev.i.wd == resolv_conf_descr)
+-                      {
+-                        res_init ();
+-                        to_clear[hstdb] = true;
+-                      }
+-                  next:;
++                    /* Something went wrong when reading the inotify
++                       data.  Better disable inotify.  */
++                    dbg_log (_("disabled inotify-based monitoring after read error %d"), errno);
++                    conns[1].fd = -1;
++                    firstfree = 1;
++                    if (nused == 2)
++                      nused = 1;
++                    close (inotify_fd);
++                    inotify_fd = -1;
+                   }
+-
+-                /* Actually perform the cache clearing.  */
+-                for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt)
+-                  if (to_clear[dbcnt])
+-                    {
+-                      pthread_mutex_lock (&dbs[dbcnt].prune_lock);
+-                      dbs[dbcnt].clear_cache = 1;
+-                      pthread_mutex_unlock (&dbs[dbcnt].prune_lock);
+-                      pthread_cond_signal (&dbs[dbcnt].prune_cond);
+-                    }
+-
+                 --n;
+               }
+@@ -2112,58 +2388,18 @@
+ # ifdef HAVE_INOTIFY
+       else if (revs[cnt].data.fd == inotify_fd)
+         {
+-          bool to_clear[lastdb] = { false, };
+-          union
+-          {
+-            struct inotify_event i;
+-            char buf[sizeof (struct inotify_event) + PATH_MAX];
+-          } inev;
+-
+-          while (1)
++          int ret;
++          ret = handle_inotify_events ();
++          if (ret == -1)
+             {
+-              ssize_t nb = TEMP_FAILURE_RETRY (read (inotify_fd, &inev,
+-                                               sizeof (inev)));
+-              if (nb < (ssize_t) sizeof (struct inotify_event))
+-                {
+-                  if (__builtin_expect (nb == -1 && errno != EAGAIN, 0))
+-                    {
+-                      /* Something went wrong when reading the inotify
+-                         data.  Better disable inotify.  */
+-                      dbg_log (_("disabled inotify after read error %d"),
+-                               errno);
+-                      (void) epoll_ctl (efd, EPOLL_CTL_DEL, inotify_fd,
+-                                        NULL);
+-                      close (inotify_fd);
+-                      inotify_fd = -1;
+-                    }
+-                  break;
+-                }
+-
+-              /* Check which of the files changed.  */
+-              for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt)
+-                if (inev.i.wd == dbs[dbcnt].inotify_descr)
+-                  {
+-                    to_clear[dbcnt] = true;
+-                    goto next;
+-                  }
+-
+-              if (inev.i.wd == resolv_conf_descr)
+-                {
+-                  res_init ();
+-                  to_clear[hstdb] = true;
+-                }
+-            next:;
++              /* Something went wrong when reading the inotify
++                 data.  Better disable inotify.  */
++              dbg_log (_("disabled inotify-based monitoring after read error %d"), errno);
++              (void) epoll_ctl (efd, EPOLL_CTL_DEL, inotify_fd, NULL);
++              close (inotify_fd);
++              inotify_fd = -1;
++              break;
+             }
+-
+-          /* Actually perform the cache clearing.  */
+-          for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt)
+-            if (to_clear[dbcnt])
+-              {
+-                pthread_mutex_lock (&dbs[dbcnt].prune_lock);
+-                dbs[dbcnt].clear_cache = 1;
+-                pthread_mutex_unlock (&dbs[dbcnt].prune_lock);
+-                pthread_cond_signal (&dbs[dbcnt].prune_cond);
+-              }
+         }
+ # endif
+       else
+diff -urN glibc-2.12-2-gc4ccff1.orig/nscd/nscd.h glibc-2.12-2-gc4ccff1.mod1/nscd/nscd.h
+--- glibc-2.12-2-gc4ccff1.orig/nscd/nscd.h     2015-02-18 04:42:12.329180362 -0500
++++ glibc-2.12-2-gc4ccff1.mod1/nscd/nscd.h     2015-02-18 04:02:03.636159059 -0500
+@@ -62,6 +62,67 @@
+    80% of the thread stack size.  */
+ #define MAX_STACK_USE ((8 * NSCD_THREAD_STACKSIZE) / 10)
++/* Records the file registered per database that when changed
++   or modified requires invalidating the database.  */
++struct traced_file
++{
++  /* Tracks the last modified time of the traced file.  */
++  time_t mtime;
++  /* Support multiple registered files per database.  */
++  struct traced_file *next;
++  int call_res_init;
++  /* Requires Inotify support to do anything useful.  */
++#define TRACED_FILE   0
++#define TRACED_DIR    1
++  int inotify_descr[2];
++# ifndef PATH_MAX
++#  define PATH_MAX 1024
++# endif
++  /* The parent directory is used to scan for creation/deletion.  */
++  char dname[PATH_MAX];
++  /* Just the name of the file with no directory component.  */
++  char *sfname;
++  /* The full-path name of the registered file.  */
++  char fname[];
++};
++
++/* Initialize a `struct traced_file`.  As input we need the name
++   of the file, and if invalidation requires calling res_init.
++   If CRINIT is 1 then res_init will be called after invalidation
++   or if the traced file is changed in any way, otherwise it will
++   not.  */
++static inline void
++init_traced_file(struct traced_file *file, const char *fname, int crinit)
++{
++   char *dname;
++   file->mtime = 0;
++   file->inotify_descr[TRACED_FILE] = -1;
++   file->inotify_descr[TRACED_DIR] = -1;
++   strcpy (file->fname, fname);
++   /* Compute the parent directory name and store a copy.  The copy makes
++      it much faster to add/remove watches while nscd is running instead
++      of computing this over and over again in a temp buffer.  */
++   file->dname[0] = '\0';
++   dname = strrchr (fname, '/');
++   if (dname != NULL)
++     {
++       size_t len = (size_t)(dname - fname);
++       if (len > sizeof (file->dname))
++       abort ();
++       strncpy (file->dname, file->fname, len);
++       file->dname[len] = '\0';
++     }
++   /* The basename is the name just after the last forward slash.  */
++   file->sfname = &dname[1];
++   file->call_res_init = crinit;
++}
++
++#define define_traced_file(id, filename)                      \
++static union                                                  \
++{                                                             \
++  struct traced_file file;                                    \
++  char buf[sizeof (struct traced_file) + sizeof (filename)];  \
++} id##_traced_file;
+ /* Structure describing dynamic part of one database.  */
+ struct database_dyn
+@@ -74,15 +135,12 @@
+   int enabled;
+   int check_file;
+-  int inotify_descr;
+   int clear_cache;
+   int persistent;
+   int shared;
+   int propagate;
+-  int reset_res;
+-  const char filename[16];
++  struct traced_file *traced_files;
+   const char *db_filename;
+-  time_t file_mtime;
+   size_t suggested_module;
+   size_t max_db_size;
+@@ -199,6 +257,10 @@
+ /* connections.c */
+ extern void nscd_init (void);
++extern void register_traced_file (size_t dbidx, struct traced_file *finfo);
++#ifdef HAVE_INOTIFY
++extern void install_watches (struct traced_file *finfo);
++#endif
+ extern void close_sockets (void);
+ extern void start_threads (void) __attribute__ ((__noreturn__));
diff --git a/src/patches/glibc/glibc-rh862094.patch b/src/patches/glibc/glibc-rh862094.patch
new file mode 100644 (file)
index 0000000..6e7fe0a
--- /dev/null
@@ -0,0 +1,68 @@
+From bc5fb0374c3ce6eca92f44d13a55b066e707c4a0 Mon Sep 17 00:00:00 2001
+From: Andreas Schwab <schwab@redhat.com>
+Date: Wed, 15 Sep 2010 07:20:57 -0700
+Subject: [PATCH] Don't try to free rpath strings allocated during startup
+
+---
+ ChangeLog        |   10 ++++++++++
+ elf/dl-load.c    |    3 ---
+ elf/dl-support.c |    3 +++
+ elf/rtld.c       |    4 ++++
+ 4 files changed, 17 insertions(+), 3 deletions(-)
+
+ 2010-09-13  Andreas Schwab  <schwab@redhat.com>
+           Ulrich Drepper  <drepper@redhat.com>
+
+       * elf/rtld.c (dl_main): Set GLRO(dl_init_all_dirs) just before
+       re-relocationg ld.so.
+       * elf/dl-support.c (_dl_non_dynamic_init): And here after the
+       _dl_init_paths call.
+       * elf/dl-load.c (_dl_init_paths).  Don't set GLRO(dl_init_all_dirs)
+       here anymore.
+diff --git a/elf/dl-load.c b/elf/dl-load.c
+index 0adddf5..a7162eb 100644
+--- a/elf/dl-load.c
++++ b/elf/dl-load.c
+@@ -787,9 +787,6 @@ _dl_init_paths (const char *llp)
+     }
+   else
+     env_path_list.dirs = (void *) -1;
+-
+-  /* Remember the last search directory added at startup.  */
+-  GLRO(dl_init_all_dirs) = GL(dl_all_dirs);
+ }
+diff --git a/elf/dl-support.c b/elf/dl-support.c
+index f94d2c4..5897b32 100644
+--- a/elf/dl-support.c
++++ b/elf/dl-support.c
+@@ -264,6 +264,9 @@ _dl_non_dynamic_init (void)
+      objects.  */
+   _dl_init_paths (getenv ("LD_LIBRARY_PATH"));
++  /* Remember the last search directory added at startup.  */
++  _dl_init_all_dirs = GL(dl_all_dirs);
++
+   _dl_lazy = *(getenv ("LD_BIND_NOW") ?: "") == '\0';
+   _dl_bind_not = *(getenv ("LD_BIND_NOT") ?: "") != '\0';
+diff --git a/elf/rtld.c b/elf/rtld.c
+index 90f3ff1..5ecc4fe 100644
+--- a/elf/rtld.c
++++ b/elf/rtld.c
+@@ -2291,6 +2291,10 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
+                         lossage);
+     }
++  /* Remember the last search directory added at startup, now that
++     malloc will no longer be the one from dl-minimal.c.  */
++  GLRO(dl_init_all_dirs) = GL(dl_all_dirs);
++
+   if (! prelinked && rtld_multiple_ref)
+     {
+       /* There was an explicit ref to the dynamic linker as a shared lib.
+-- 
+1.7.1
+
diff --git a/src/patches/glibc/glibc-rh863384.patch b/src/patches/glibc/glibc-rh863384.patch
new file mode 100644 (file)
index 0000000..7644a4e
--- /dev/null
@@ -0,0 +1,14 @@
+diff -pruN glibc-2.12-2-gc4ccff1/sysdeps/posix/getaddrinfo.c glibc-2.12-2-gc4ccff1.fixed/sysdeps/posix/getaddrinfo.c
+--- glibc-2.12-2-gc4ccff1/sysdeps/posix/getaddrinfo.c  2013-07-23 15:23:42.011941780 +0530
++++ glibc-2.12-2-gc4ccff1.fixed/sysdeps/posix/getaddrinfo.c    2013-07-23 15:24:54.032938976 +0530
+@@ -562,8 +562,8 @@ gaih_inet (const char *name, const struc
+         /* If we do not have to look for IPv6 addresses, use
+            the simple, old functions, which do not support
+-           IPv6 scope ids. */
+-        if (req->ai_family == AF_INET)
++           IPv6 scope ids, nor retrieving the canonical name. */
++        if (req->ai_family == AF_INET && (req->ai_flags & AI_CANONNAME) == 0)
+           {
+               /* Add room for struct host_data in resolv/nss_dns/dns-host.c */
+               size_t tmpbuflen = 512 + (MAX_NR_ALIASES+MAX_NR_ADDRS+1)*sizeof(char*)
diff --git a/src/patches/glibc/glibc-rh867679.patch b/src/patches/glibc/glibc-rh867679.patch
new file mode 100644 (file)
index 0000000..3e823c8
--- /dev/null
@@ -0,0 +1,139 @@
+commit 9fab36eb583c0e585e83a01253299afed9ea9a11
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date:   Tue Sep 25 14:10:29 2012 +0530
+
+    Shrink heap on linux when overcommit_memory == 2
+    
+    Using madvise with MADV_DONTNEED to release memory back to the kernel
+    is not sufficient to change the commit charge accounted against the
+    process on Linux.  It is OK however, when overcommit is enabled or is
+    heuristic.  However, when overcommit is restricted to a percentage of
+    memory setting the contents of /proc/sys/vm/overcommit_memory as 2, it
+    makes a difference since memory requests will fail.  Hence, we do what
+    we do with secure exec binaries, which is to call mmap on the region
+    to be dropped with MAP_FIXED. This internally unmaps the pages in
+    question and reduces the amount of memory accounted against the
+    process.
+
+diff --git a/malloc/arena.c b/malloc/arena.c
+index f24e76c..b209e3b 100644
+--- a/malloc/arena.c
++++ b/malloc/arena.c
+@@ -19,6 +19,9 @@
+ #include <stdbool.h>
++/* Get the implementation for check_may_shrink_heap.  */
++#include <malloc-sysdep.h>
++
+ /* Compile-time constants.  */
+ #define HEAP_MIN_SIZE (32*1024)
+@@ -621,10 +624,10 @@ shrink_heap(heap_info *h, long diff)
+   new_size = (long)h->size - diff;
+   if(new_size < (long)sizeof(*h))
+     return -1;
+-  /* Try to re-map the extra heap space freshly to save memory, and
+-     make it inaccessible. */
+ #ifdef _LIBC
+-  if (__builtin_expect (__libc_enable_secure, 0))
++  /* Try to re-map the extra heap space freshly to save memory, and make it
++     inaccessible.  See malloc-sysdep.h to know when this is true.  */
++  if (__builtin_expect (check_may_shrink_heap (), 0))
+ #else
+   if (1)
+ #endif
+diff --git a/sysdeps/generic/malloc-sysdep.h b/sysdeps/generic/malloc-sysdep.h
+new file mode 100644
+index 0000000..bbc48c0
+--- /dev/null
++++ b/sysdeps/generic/malloc-sysdep.h
+@@ -0,0 +1,25 @@
++/* System-specific malloc support functions.  Generic version.
++   Copyright (C) 2012 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
++   <http://www.gnu.org/licenses/>.  */
++
++/* Force an unmap when the heap shrinks in a secure exec.  This ensures that
++   the old data pages immediately cease to be accessible.  */
++static inline bool
++check_may_shrink_heap (void)
++{
++  return __libc_enable_secure;
++}
+diff --git a/sysdeps/unix/sysv/linux/malloc-sysdep.h b/sysdeps/unix/sysv/linux/malloc-sysdep.h
+new file mode 100644
+index 0000000..f926aea
+--- /dev/null
++++ b/sysdeps/unix/sysv/linux/malloc-sysdep.h
+@@ -0,0 +1,57 @@
++/* System-specific malloc support functions.  Linux version.
++   Copyright (C) 2012 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
++   <http://www.gnu.org/licenses/>.  */
++
++#include <fcntl.h>
++#include <not-cancel.h>
++
++/* The Linux kernel overcommits address space by default and if there is not
++   enough memory available, it uses various parameters to decide the process to
++   kill.  It is however possible to disable or curb this overcommit behavior
++   by setting the proc sysctl vm.overcommit_memory to the value '2' and with
++   that, a process is only allowed to use the maximum of a pre-determined
++   fraction of the total address space.  In such a case, we want to make sure
++   that we are judicious with our heap usage as well, and explicitly give away
++   the freed top of the heap to reduce our commit charge.  See the proc(5) man
++   page to know more about overcommit behavior.
++
++   Other than that, we also force an unmap in a secure exec.  */
++static inline bool
++check_may_shrink_heap (void)
++{
++  static int may_shrink_heap = -1;
++
++  if (__builtin_expect (may_shrink_heap >= 0, 1))
++    return may_shrink_heap;
++
++  may_shrink_heap = __libc_enable_secure;
++
++  if (__builtin_expect (may_shrink_heap == 0, 1))
++    {
++      int fd = open_not_cancel_2 ("/proc/sys/vm/overcommit_memory",
++                                O_RDONLY | O_CLOEXEC);
++      if (fd >= 0)
++      {
++        char val;
++        ssize_t n = read_not_cancel (fd, &val, 1);
++        may_shrink_heap = n > 0 && val == '2';
++        close_not_cancel_no_status (fd);
++      }
++    }
++
++  return may_shrink_heap;
++}
diff --git a/src/patches/glibc/glibc-rh868808.patch b/src/patches/glibc/glibc-rh868808.patch
new file mode 100644 (file)
index 0000000..27a10b2
--- /dev/null
@@ -0,0 +1,99 @@
+From d6f67f7d833b4e2039f832355fb0edd65522c9f4 Mon Sep 17 00:00:00 2001
+From: Ulrich Drepper <drepper@gmail.com>
+Date: Sat, 14 May 2011 10:46:17 -0400
+Subject: [PATCH] Handle recursive calls in backtrace better
+
+---
+ ChangeLog                |    7 +++++++
+ NEWS                     |   12 ++++++------
+ sysdeps/ia64/backtrace.c |   27 +++++++++++++++++++++++----
+ 3 files changed, 36 insertions(+), 10 deletions(-)
+
+ 2011-05-14  Ulrich Drepper  <drepper@gmail.com>
+       [BZ #12432]
+       * sysdeps/ia64/backtrace.c (struct trace_reg): Add cfa element.
+       (dummy_getcfa): New function.
+       (init): Get _Unwind_GetCFA address, use dummy if not found.
+       (backtrace_helper): In recursion check, also check whether CFA changes.
+       (__backtrace): Completely initialize arg.
+diff --git a/sysdeps/ia64/backtrace.c b/sysdeps/ia64/backtrace.c
+index 5cefb86..d4ff291 100644
+--- a/sysdeps/ia64/backtrace.c
++++ b/sysdeps/ia64/backtrace.c
+@@ -1,5 +1,5 @@
+ /* Return backtrace of current program state.
+-   Copyright (C) 2003, 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
++   Copyright (C) 2003-2005, 2007, 2009, 2011 Free Software Foundation, Inc.
+    This file is part of the GNU C Library.
+    Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+@@ -27,14 +27,26 @@
+ struct trace_arg
+ {
+   void **array;
+-  int cnt, size;
++  _Unwind_Word cfa;
++  int cnt;
++  int size;
+ };
+ #ifdef SHARED
+ static _Unwind_Reason_Code (*unwind_backtrace) (_Unwind_Trace_Fn, void *);
+ static _Unwind_Ptr (*unwind_getip) (struct _Unwind_Context *);
++static _Unwind_Word (*unwind_getcfa) (struct _Unwind_Context *);
+ static void *libgcc_handle;
++
++/* Dummy version in case libgcc_s does not contain the real code.  */
++static _Unwind_Word
++dummy_getcfa (struct _Unwind_Context *ctx __attribute__ ((unused)))
++{
++  return 0;
++}
++
++
+ static void
+ init (void)
+ {
+@@ -47,10 +59,13 @@ init (void)
+   unwind_getip = __libc_dlsym (libgcc_handle, "_Unwind_GetIP");
+   if (unwind_getip == NULL)
+     unwind_backtrace = NULL;
++  unwind_getcfa = (__libc_dlsym (libgcc_handle, "_Unwind_GetCFA")
++                 ?: dummy_getcfa);
+ }
+ #else
+ # define unwind_backtrace _Unwind_Backtrace
+ # define unwind_getip _Unwind_GetIP
++# define unwind_getcfa _Unwind_GetCFA
+ #endif
+ static _Unwind_Reason_Code
+@@ -65,8 +80,12 @@ backtrace_helper (struct _Unwind_Context *ctx, void *a)
+       arg->array[arg->cnt] = (void *) unwind_getip (ctx);
+       /* Check whether we make any progress.  */
+-      if (arg->cnt > 0 && arg->array[arg->cnt - 1] == arg->array[arg->cnt])
++      _Unwind_Word cfa = unwind_getcfa (ctx);
++
++      if (arg->cnt > 0 && arg->array[arg->cnt - 1] == arg->array[arg->cnt]
++        && cfa == arg->cfa)
+       return _URC_END_OF_STACK;
++      arg->cfa = cfa;
+     }
+   if (++arg->cnt == arg->size)
+     return _URC_END_OF_STACK;
+@@ -78,7 +97,7 @@ __backtrace (array, size)
+      void **array;
+      int size;
+ {
+-  struct trace_arg arg = { .array = array, .size = size, .cnt = -1 };
++  struct trace_arg arg = { .array = array, .cfa = 0, .size = size, .cnt = -1 };
+ #ifdef SHARED
+   __libc_once_define (static, once);
+-- 
+1.7.1
+
diff --git a/src/patches/glibc/glibc-rh905941.patch b/src/patches/glibc/glibc-rh905941.patch
new file mode 100644 (file)
index 0000000..d5d50f2
--- /dev/null
@@ -0,0 +1,146 @@
+diff -pruN a/nptl/sysdeps/pthread/unwind-forcedunwind.c b/nptl/sysdeps/pthread/unwind-forcedunwind.c
+--- a/nptl/sysdeps/pthread/unwind-forcedunwind.c       2010-05-04 16:57:23.000000000 +0530
++++ b/nptl/sysdeps/pthread/unwind-forcedunwind.c       2014-06-02 23:00:02.901013275 +0530
+@@ -45,8 +45,10 @@ pthread_cancel_init (void)
+   if (__builtin_expect (libgcc_s_handle != NULL, 1))
+     {
+-      /* Force gcc to reload all values.  */
+-      asm volatile ("" ::: "memory");
++      /* Order reads so as to prevent speculation of loads
++       of libgcc_s_{resume,personality,forcedunwind,getcfa}
++       to points prior to the write barrier.  */
++      atomic_read_barrier ();
+       return;
+     }
+@@ -72,9 +74,14 @@ pthread_cancel_init (void)
+   libgcc_s_forcedunwind = forcedunwind;
+   PTR_MANGLE (getcfa);
+   libgcc_s_getcfa = getcfa;
+-  /* Make sure libgcc_s_handle is written last.  Otherwise,
+-     pthread_cancel_init might return early even when the pointer the
+-     caller is interested in is not initialized yet.  */
++  /* At the point at which any thread writes the handle
++     to libgcc_s_handle, the initialization is complete.
++     The writing of libgcc_s_handle is atomic. All other
++     threads reading libgcc_s_handle do so atomically. Any
++     thread that does not execute this function must issue
++     a read barrier to ensure that all of the above has
++     actually completed and that the values of the
++     function pointers are correct.   */
+   atomic_write_barrier ();
+   libgcc_s_handle = handle;
+ }
+@@ -91,11 +98,19 @@ __unwind_freeres (void)
+     }
+ }
+-void
+-_Unwind_Resume (struct _Unwind_Exception *exc)
++static __always_inline void
++_maybe_pthread_cancel_init (void)
+ {
+   if (__builtin_expect (libgcc_s_handle == NULL, 0))
+     pthread_cancel_init ();
++  else
++    atomic_read_barrier ();
++}
++
++void
++_Unwind_Resume (struct _Unwind_Exception *exc)
++{
++  _maybe_pthread_cancel_init ();
+   void (*resume) (struct _Unwind_Exception *exc) = libgcc_s_resume;
+   PTR_DEMANGLE (resume);
+@@ -108,8 +123,7 @@ __gcc_personality_v0 (int version, _Unwi
+                       struct _Unwind_Exception *ue_header,
+                       struct _Unwind_Context *context)
+ {
+-  if (__builtin_expect (libgcc_s_handle == NULL, 0))
+-    pthread_cancel_init ();
++  _maybe_pthread_cancel_init ();
+   _Unwind_Reason_Code (*personality)
+     (int, _Unwind_Action, _Unwind_Exception_Class, struct _Unwind_Exception *,
+@@ -122,8 +136,7 @@ _Unwind_Reason_Code
+ _Unwind_ForcedUnwind (struct _Unwind_Exception *exc, _Unwind_Stop_Fn stop,
+                     void *stop_argument)
+ {
+-  if (__builtin_expect (libgcc_s_handle == NULL, 0))
+-    pthread_cancel_init ();
++  _maybe_pthread_cancel_init ();
+   _Unwind_Reason_Code (*forcedunwind)
+     (struct _Unwind_Exception *, _Unwind_Stop_Fn, void *)
+@@ -135,8 +148,7 @@ _Unwind_ForcedUnwind (struct _Unwind_Exc
+ _Unwind_Word
+ _Unwind_GetCFA (struct _Unwind_Context *context)
+ {
+-  if (__builtin_expect (libgcc_s_handle == NULL, 0))
+-    pthread_cancel_init ();
++  _maybe_pthread_cancel_init ();
+   _Unwind_Word (*getcfa) (struct _Unwind_Context *) = libgcc_s_getcfa;
+   PTR_DEMANGLE (getcfa);
+diff -pruN a/sysdeps/gnu/unwind-resume.c b/sysdeps/gnu/unwind-resume.c
+--- a/sysdeps/gnu/unwind-resume.c      2010-05-04 16:57:23.000000000 +0530
++++ b/sysdeps/gnu/unwind-resume.c      2014-06-02 23:02:26.812007078 +0530
+@@ -20,8 +20,11 @@
+ #include <dlfcn.h>
+ #include <stdio.h>
+ #include <unwind.h>
++#include <pthreadP.h>
++#include <sysdep.h>
+ #include <libgcc_s.h>
++static void *libgcc_s_handle;
+ static void (*libgcc_s_resume) (struct _Unwind_Exception *exc);
+ static _Unwind_Reason_Code (*libgcc_s_personality)
+   (int, _Unwind_Action, _Unwind_Exception_Class, struct _Unwind_Exception *,
+@@ -42,13 +45,32 @@ init (void)
+   libgcc_s_resume = resume;
+   libgcc_s_personality = personality;
++  atomic_write_barrier ();
++  /* At the point at which any thread writes the handle
++     to libgcc_s_handle, the initialization is complete.
++     The writing of libgcc_s_handle is atomic. All other
++     threads reading libgcc_s_handle do so atomically. Any
++     thread that does not execute this function must issue
++     a read barrier to ensure that all of the above has
++     actually completed and that the values of the
++     function pointers are correct.   */
++  libgcc_s_handle = handle;
+ }
++static __always_inline void
++_maybe_init (void)
++{
++  if (__builtin_expect (libgcc_s_handle == NULL, 0))
++    init ();
++  else
++    atomic_read_barrier ();
++}
++
++
+ void
+ _Unwind_Resume (struct _Unwind_Exception *exc)
+ {
+-  if (__builtin_expect (libgcc_s_resume == NULL, 0))
+-    init ();
++  _maybe_init ();
+   libgcc_s_resume (exc);
+ }
+@@ -58,8 +80,7 @@ __gcc_personality_v0 (int version, _Unwi
+                       struct _Unwind_Exception *ue_header,
+                       struct _Unwind_Context *context)
+ {
+-  if (__builtin_expect (libgcc_s_personality == NULL, 0))
+-    init ();
++  _maybe_init ();
+   return libgcc_s_personality (version, actions, exception_class,
+                              ue_header, context);
+ }
diff --git a/src/patches/glibc/glibc-rh929302.patch b/src/patches/glibc/glibc-rh929302.patch
new file mode 100644 (file)
index 0000000..305b339
--- /dev/null
@@ -0,0 +1,98 @@
+From decadad73858bc108828eed5540c7955dc2a977b Mon Sep 17 00:00:00 2001
+From: Adhemerval Zanella <azanella@linux.vnet.ibm.com>
+Date: Fri, 7 Jun 2013 14:44:58 -0500
+Subject: [PATCH 1/2] PowerPC: Change sched_getcpu to use vDSO getcpu instead of syscall.
+
+Backport of d5e0b9bd6e296f3ec5263fa296d39f3fed9b8fa2 from master.
+---
+ sysdeps/unix/sysv/linux/powerpc/Versions         |    1 +
+ sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h |    2 +
+ sysdeps/unix/sysv/linux/powerpc/init-first.c     |    3 ++
+ sysdeps/unix/sysv/linux/powerpc/sched_getcpu.c   |   30 ++++++++++++++++++++++
+ 4 files changed, 36 insertions(+), 0 deletions(-)
+ create mode 100644 sysdeps/unix/sysv/linux/powerpc/sched_getcpu.c
+
+diff --git a/sysdeps/unix/sysv/linux/powerpc/Versions b/sysdeps/unix/sysv/linux/powerpc/Versions
+index 1ef53b9..396a423 100644
+--- a/sysdeps/unix/sysv/linux/powerpc/Versions
++++ b/sysdeps/unix/sysv/linux/powerpc/Versions
+@@ -3,5 +3,6 @@ libc {
+     __vdso_get_tbfreq;
+     __vdso_clock_gettime;
+     __vdso_clock_getres;
++    __vdso_getcpu;
+   }
+ }
+diff --git a/sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h b/sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h
+index 746d9ce..c3026d5 100644
+--- a/sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h
++++ b/sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h
+@@ -31,6 +31,8 @@ extern void *__vdso_clock_getres;
+ extern void *__vdso_get_tbfreq;
++extern void *__vdso_getcpu;
++
+ #endif
+ #endif /* _LIBC_VDSO_H */
+diff --git a/sysdeps/unix/sysv/linux/powerpc/init-first.c b/sysdeps/unix/sysv/linux/powerpc/init-first.c
+index 92dacc7..cfed655 100644
+--- a/sysdeps/unix/sysv/linux/powerpc/init-first.c
++++ b/sysdeps/unix/sysv/linux/powerpc/init-first.c
+@@ -27,6 +27,7 @@ void *__vdso_gettimeofday attribute_hidden;
+ void *__vdso_clock_gettime;
+ void *__vdso_clock_getres;
+ void *__vdso_get_tbfreq;
++void *__vdso_getcpu;
+ static inline void
+@@ -41,6 +42,8 @@ _libc_vdso_platform_setup (void)
+   __vdso_clock_getres = _dl_vdso_vsym ("__kernel_clock_getres", &linux2615);
+   __vdso_get_tbfreq = _dl_vdso_vsym ("__kernel_vdso_get_tbfreq", &linux2615);
++
++  __vdso_getcpu = _dl_vdso_vsym ("__kernel_getcpu", &linux2615);
+ }
+ # define VDSO_SETUP _libc_vdso_platform_setup
+diff --git a/sysdeps/unix/sysv/linux/powerpc/sched_getcpu.c b/sysdeps/unix/sysv/linux/powerpc/sched_getcpu.c
+new file mode 100644
+index 0000000..617e6f1
+--- /dev/null
++++ b/sysdeps/unix/sysv/linux/powerpc/sched_getcpu.c
+@@ -0,0 +1,30 @@
++/* Copyright (C) 2013 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
++   <http://www.gnu.org/licenses/>.  */
++
++#include <sched.h>
++#include <sysdep.h>
++#include <bits/libc-vdso.h>
++
++
++int
++sched_getcpu (void)
++{
++  unsigned int cpu;
++  int r = INLINE_VSYSCALL (getcpu, 3, &cpu, NULL, NULL);
++
++  return r == -1 ? r : cpu;
++}
+-- 
+1.7.1
+
diff --git a/src/patches/glibc/glibc-rh970776.patch b/src/patches/glibc/glibc-rh970776.patch
new file mode 100644 (file)
index 0000000..ec2f2a6
--- /dev/null
@@ -0,0 +1,279 @@
+Patch attached to bugzilla by Ankit Patel, from Red Hat translation team.
+
+Index: glibc-2.12-2-gc4ccff1/po/de.po
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/po/de.po        2010-05-04 08:27:23.000000000 -0300
++++ glibc-2.12-2-gc4ccff1/po/de.po     2013-07-23 20:35:03.213177408 -0300
+@@ -2396,14 +2396,14 @@ msgstr "Zu viele Benutzer"
+ msgid "Disk quota exceeded"
+ msgstr "Der zugewiesene Plattenplatz (Quota) ist überschritten"
+-#. TRANS Stale NFS file handle.  This indicates an internal confusion in the NFS
+-#. TRANS system which is due to file system rearrangements on the server host.
+-#. TRANS Repairing this condition usually requires unmounting and remounting
+-#. TRANS the NFS file system on the local host.
+-#: stdio-common/../sysdeps/gnu/errlist.c:779
+-#: stdio-common/../sysdeps/unix/sysv/sysv4/solaris2/sparc/errlist.c:181
+-msgid "Stale NFS file handle"
+-msgstr "Veraltete NFS-Dateizugriffsnummer"
++#. TRANS Stale file handle.  This indicates an internal confusion in the
++#. TRANS file system which is due to file system rearrangements on the server host
++#. TRANS for NFS filesystems or corruption in other filesystems.
++#. TRANS Repairing this condition usually requires unmounting, possibly
++#. TRANS repairing and remounting the file system.
++#: sysdeps/gnu/errlist.c:787
++msgid "Stale file handle"
++msgstr "Veraltetes Datei-Handle"
+ #. TRANS An attempt was made to NFS-mount a remote file system with a file name that
+ #. TRANS already specifies an NFS-mounted file.
+Index: glibc-2.12-2-gc4ccff1/po/es.po
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/po/es.po        2010-05-04 08:27:23.000000000 -0300
++++ glibc-2.12-2-gc4ccff1/po/es.po     2013-07-23 20:35:03.243175029 -0300
+@@ -2533,14 +2533,14 @@ msgstr "Se ha excedido la cuota de disco
+ # Muy bien, he buscado "stale" y por lo que parece es algo que "caduca"
+ # o que "vence", como las letras comerciales. Me he decidido por "en desuso".
+ #
+-#. TRANS Stale NFS file handle.  This indicates an internal confusion in the NFS
+-#. TRANS system which is due to file system rearrangements on the server host.
+-#. TRANS Repairing this condition usually requires unmounting and remounting
+-#. TRANS the NFS file system on the local host.
+-#: stdio-common/../sysdeps/gnu/errlist.c:779
+-#: stdio-common/../sysdeps/unix/sysv/sysv4/solaris2/sparc/errlist.c:181
+-msgid "Stale NFS file handle"
+-msgstr "`handle' de fichero NFS en desuso"
++#. TRANS Stale file handle.  This indicates an internal confusion in the
++#. TRANS file system which is due to file system rearrangements on the server host
++#. TRANS for NFS filesystems or corruption in other filesystems.
++#. TRANS Repairing this condition usually requires unmounting, possibly
++#. TRANS repairing and remounting the file system.
++#: sysdeps/gnu/errlist.c:787
++msgid "Stale file handle"
++msgstr "Identificador de archivos obsoletos"
+ #. TRANS An attempt was made to NFS-mount a remote file system with a file name that
+ #. TRANS already specifies an NFS-mounted file.
+Index: glibc-2.12-2-gc4ccff1/po/fr.po
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/po/fr.po        2010-05-04 08:27:23.000000000 -0300
++++ glibc-2.12-2-gc4ccff1/po/fr.po     2013-07-23 20:35:03.250174474 -0300
+@@ -5802,13 +5802,14 @@ msgstr "Trop d'usagers"
+ msgid "Disk quota exceeded"
+ msgstr "Débordement du quota d'espace disque"
+-#. TRANS Stale NFS file handle.  This indicates an internal confusion in the NFS
+-#. TRANS system which is due to file system rearrangements on the server host.
+-#. TRANS Repairing this condition usually requires unmounting and remounting
+-#. TRANS the NFS file system on the local host.
++#. TRANS Stale file handle.  This indicates an internal confusion in the
++#. TRANS file system which is due to file system rearrangements on the server host
++#. TRANS for NFS filesystems or corruption in other filesystems.
++#. TRANS Repairing this condition usually requires unmounting, possibly
++#. TRANS repairing and remounting the file system.
+ #: sysdeps/gnu/errlist.c:787
+-msgid "Stale NFS file handle"
+-msgstr "Panne d'accès au fichier NFS"
++msgid "Stale file handle"
++msgstr "Gestionnaire de fichiers périmés"
+ #. TRANS An attempt was made to NFS-mount a remote file system with a file name that
+ #. TRANS already specifies an NFS-mounted file.
+Index: glibc-2.12-2-gc4ccff1/po/it.po
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/po/it.po        2010-05-04 08:27:23.000000000 -0300
++++ glibc-2.12-2-gc4ccff1/po/it.po     2013-07-23 20:35:03.253174237 -0300
+@@ -1662,6 +1662,15 @@ msgstr "Superata la quota di disco"
+ msgid "Disk quota exceeded"
+ msgstr "Superata la quota di disco"
++#. TRANS Stale file handle.  This indicates an internal confusion in the
++#. TRANS file system which is due to file system rearrangements on the server host
++#. TRANS for NFS filesystems or corruption in other filesystems.
++#. TRANS Repairing this condition usually requires unmounting, possibly
++#. TRANS repairing and remounting the file system.
++#: sysdeps/gnu/errlist.c:787
++msgid "Stale file handle"
++msgstr "Gestione file obsoleti"
++
+ #: nscd/nscd.c:86
+ msgid "Do not fork and display messages on the current tty"
+ msgstr "Non fa fork e stampa i messaggi sul tty corrente"
+Index: glibc-2.12-2-gc4ccff1/po/ja.po
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/po/ja.po        2013-07-23 04:01:34.628665260 -0300
++++ glibc-2.12-2-gc4ccff1/po/ja.po     2013-07-23 20:35:03.304170193 -0300
+@@ -2333,14 +2333,14 @@ msgstr "¥æ¡¼¥¶¤¬Â¿¤¹¤®¤Þ¤¹"
+ msgid "Disk quota exceeded"
+ msgstr "¥Ç¥£¥¹¥¯»ÈÍÑÎÌÀ©¸Â¤òĶ²á¤·¤Þ¤·¤¿"
+-#. TRANS Stale NFS file handle.  This indicates an internal confusion in the NFS
+-#. TRANS system which is due to file system rearrangements on the server host.
+-#. TRANS Repairing this condition usually requires unmounting and remounting
+-#. TRANS the NFS file system on the local host.
+-#: stdio-common/../sysdeps/gnu/errlist.c:779
+-#: stdio-common/../sysdeps/unix/sysv/sysv4/solaris2/sparc/errlist.c:181
+-msgid "Stale NFS file handle"
+-msgstr "¼Â¸úÀ­¤Î¤Ê¤¤NFS¥Õ¥¡¥¤¥ë¥Ï¥ó¥É¥ë¤Ç¤¹"
++#. TRANS Stale file handle.  This indicates an internal confusion in the
++#. TRANS file system which is due to file system rearrangements on the server host
++#. TRANS for NFS filesystems or corruption in other filesystems.
++#. TRANS Repairing this condition usually requires unmounting, possibly
++#. TRANS repairing and remounting the file system.
++#: sysdeps/gnu/errlist.c:787
++msgid "Stale file handle"
++msgstr "¸Å¤¤¥Õ¥¡¥¤¥ë¥Ï¥ó¥É¥ë¤Ç¤¹"
+ #. TRANS An attempt was made to NFS-mount a remote file system with a file name that
+ #. TRANS already specifies an NFS-mounted file.
+Index: glibc-2.12-2-gc4ccff1/po/ko.po
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/po/ko.po        2010-05-04 08:27:23.000000000 -0300
++++ glibc-2.12-2-gc4ccff1/po/ko.po     2013-07-23 20:35:03.311169638 -0300
+@@ -5803,13 +5803,14 @@ msgstr "사용자가 너무 많음"
+ msgid "Disk quota exceeded"
+ msgstr "디스크 할당량이 초과됨"
+-#. TRANS Stale NFS file handle.  This indicates an internal confusion in the NFS
+-#. TRANS system which is due to file system rearrangements on the server host.
+-#. TRANS Repairing this condition usually requires unmounting and remounting
+-#. TRANS the NFS file system on the local host.
++#. TRANS Stale file handle.  This indicates an internal confusion in the
++#. TRANS file system which is due to file system rearrangements on the server host
++#. TRANS for NFS filesystems or corruption in other filesystems.
++#. TRANS Repairing this condition usually requires unmounting, possibly
++#. TRANS repairing and remounting the file system.
+ #: sysdeps/gnu/errlist.c:787
+-msgid "Stale NFS file handle"
+-msgstr "끊어진 NFS 파일 핸들"
++msgid "Stale file handle"
++msgstr "오래된 파일 처리"
+ #. TRANS An attempt was made to NFS-mount a remote file system with a file name that
+ #. TRANS already specifies an NFS-mounted file.
+Index: glibc-2.12-2-gc4ccff1/po/libc.pot
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/po/libc.pot     2010-05-04 08:27:23.000000000 -0300
++++ glibc-2.12-2-gc4ccff1/po/libc.pot  2013-07-23 20:35:03.326168449 -0300
+@@ -5696,12 +5696,13 @@ msgstr ""
+ msgid "Disk quota exceeded"
+ msgstr ""
+-#. TRANS Stale NFS file handle.  This indicates an internal confusion in the NFS
+-#. TRANS system which is due to file system rearrangements on the server host.
+-#. TRANS Repairing this condition usually requires unmounting and remounting
+-#. TRANS the NFS file system on the local host.
++#. TRANS Stale file handle.  This indicates an internal confusion in the
++#. TRANS file system which is due to file system rearrangements on the server host
++#. TRANS for NFS filesystems or corruption in other filesystems.
++#. TRANS Repairing this condition usually requires unmounting, possibly
++#. TRANS repairing and remounting the file system.
+ #: sysdeps/gnu/errlist.c:787
+-msgid "Stale NFS file handle"
++msgid "Stale file handle"
+ msgstr ""
+ #. TRANS An attempt was made to NFS-mount a remote file system with a file name that
+Index: glibc-2.12-2-gc4ccff1/po/pt_BR.po
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/po/pt_BR.po     2010-05-04 08:27:23.000000000 -0300
++++ glibc-2.12-2-gc4ccff1/po/pt_BR.po  2013-07-23 20:35:03.331168053 -0300
+@@ -2287,13 +2287,14 @@ msgstr "Erro de Srmount"
+ msgid "Stack fault"
+ msgstr "Falha de pilha"
+-#. TRANS Stale NFS file handle.  This indicates an internal confusion in the NFS
+-#. TRANS system which is due to file system rearrangements on the server host.
+-#. TRANS Repairing this condition usually requires unmounting and remounting
+-#. TRANS the NFS file system on the local host.
+-#: stdio-common/../sysdeps/gnu/errlist.c:506
+-msgid "Stale NFS file handle"
+-msgstr "Manipulador de arquivo NFS corrompido"
++#. TRANS Stale file handle.  This indicates an internal confusion in the
++#. TRANS file system which is due to file system rearrangements on the server host
++#. TRANS for NFS filesystems or corruption in other filesystems.
++#. TRANS Repairing this condition usually requires unmounting, possibly
++#. TRANS repairing and remounting the file system.
++#: sysdeps/gnu/errlist.c:787
++msgid "Stale file handle"
++msgstr "Manipulador de arquivo obsoleto"
+ #: nscd/nscd.c:81
+ msgid "Start NUMBER threads"
+Index: glibc-2.12-2-gc4ccff1/po/ru.po
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/po/ru.po        2010-05-04 08:27:23.000000000 -0300
++++ glibc-2.12-2-gc4ccff1/po/ru.po     2013-07-23 20:35:03.338167498 -0300
+@@ -5798,13 +5798,14 @@ msgstr "Слишком много пол
+ msgid "Disk quota exceeded"
+ msgstr "Превышена дисковая квота"
+-#. TRANS Stale NFS file handle.  This indicates an internal confusion in the NFS
+-#. TRANS system which is due to file system rearrangements on the server host.
+-#. TRANS Repairing this condition usually requires unmounting and remounting
+-#. TRANS the NFS file system on the local host.
++#. TRANS Stale file handle.  This indicates an internal confusion in the
++#. TRANS file system which is due to file system rearrangements on the server host
++#. TRANS for NFS filesystems or corruption in other filesystems.
++#. TRANS Repairing this condition usually requires unmounting, possibly
++#. TRANS repairing and remounting the file system.
+ #: sysdeps/gnu/errlist.c:787
+-msgid "Stale NFS file handle"
+-msgstr "Устаревший хэндл файла NFS"
++msgid "Stale file handle"
++msgstr "Устаревший дескриптор файла"
+ #. TRANS An attempt was made to NFS-mount a remote file system with a file name that
+ #. TRANS already specifies an NFS-mounted file.
+Index: glibc-2.12-2-gc4ccff1/po/zh_CN.po
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/po/zh_CN.po     2010-05-04 08:27:23.000000000 -0300
++++ glibc-2.12-2-gc4ccff1/po/zh_CN.po  2013-07-23 20:35:03.344167022 -0300
+@@ -5519,13 +5519,14 @@ msgstr "用户过多"
+ msgid "Disk quota exceeded"
+ msgstr "超出磁盘限额"
+-#. TRANS Stale NFS file handle.  This indicates an internal confusion in the NFS
+-#. TRANS system which is due to file system rearrangements on the server host.
+-#. TRANS Repairing this condition usually requires unmounting and remounting
+-#. TRANS the NFS file system on the local host.
++#. TRANS Stale file handle.  This indicates an internal confusion in the
++#. TRANS file system which is due to file system rearrangements on the server host
++#. TRANS for NFS filesystems or corruption in other filesystems.
++#. TRANS Repairing this condition usually requires unmounting, possibly
++#. TRANS repairing and remounting the file system.
+ #: sysdeps/gnu/errlist.c:787
+-msgid "Stale NFS file handle"
+-msgstr ""
++msgid "Stale file handle"
++msgstr "失效文件句柄"
+ #. TRANS An attempt was made to NFS-mount a remote file system with a file name that
+ #. TRANS already specifies an NFS-mounted file.
+Index: glibc-2.12-2-gc4ccff1/po/zh_TW.po
+===================================================================
+--- glibc-2.12-2-gc4ccff1.orig/po/zh_TW.po     2010-05-04 08:27:23.000000000 -0300
++++ glibc-2.12-2-gc4ccff1/po/zh_TW.po  2013-07-23 20:35:03.349166626 -0300
+@@ -2333,14 +2333,14 @@ msgstr "太多使用者"
+ msgid "Disk quota exceeded"
+ msgstr "硬碟 quota 滿了"
+-#. TRANS Stale NFS file handle.  This indicates an internal confusion in the NFS
+-#. TRANS system which is due to file system rearrangements on the server host.
+-#. TRANS Repairing this condition usually requires unmounting and remounting
+-#. TRANS the NFS file system on the local host.
+-#: stdio-common/../sysdeps/gnu/errlist.c:779
+-#: stdio-common/../sysdeps/unix/sysv/sysv4/solaris2/sparc/errlist.c:181
+-msgid "Stale NFS file handle"
+-msgstr "過舊的 NFS 檔案控制碼"
++#. TRANS Stale file handle.  This indicates an internal confusion in the
++#. TRANS file system which is due to file system rearrangements on the server host
++#. TRANS for NFS filesystems or corruption in other filesystems.
++#. TRANS Repairing this condition usually requires unmounting, possibly
++#. TRANS repairing and remounting the file system.
++#: sysdeps/gnu/errlist.c:787
++msgid "Stale file handle"
++msgstr "過舊的檔案處理"
+ #. TRANS An attempt was made to NFS-mount a remote file system with a file name that
+ #. TRANS already specifies an NFS-mounted file.
diff --git a/src/patches/glibc/glibc-rh978098.patch b/src/patches/glibc/glibc-rh978098.patch
new file mode 100644 (file)
index 0000000..0b53dcc
--- /dev/null
@@ -0,0 +1,124 @@
+#
+# Based on commit e6c61494125126d2ba77e5d99f83887a2ed49783.
+#
+# 2011-04-10  Ulrich Drepper  <drepper@gmail.com>
+# 
+#      [BZ #12650]
+#      * sysdeps/i386/dl-tls.h: Define TLS_DTV_UNALLOCATED.
+#      * sysdeps/ia64/dl-tls.h: Likewise.
+#      * sysdeps/powerpc/dl-tls.h: Likewise.
+#      * sysdeps/s390/dl-tls.h: Likewise.
+#      * sysdeps/sh/dl-tls.h: Likewise.
+#      * sysdeps/sparc/dl-tls.h: Likewise.
+#      * sysdeps/x86_64/dl-tls.h: Likewise.
+#      * elf/dl-tls.c: Don't define TLS_DTV_UNALLOCATED here.
+#
+diff -urN glibc-2.12-2-gc4ccff1/elf/dl-tls.c glibc-2.12-2-gc4ccff1.mod/elf/dl-tls.c
+--- glibc-2.12-2-gc4ccff1/elf/dl-tls.c 2015-02-18 05:16:56.087096028 -0500
++++ glibc-2.12-2-gc4ccff1.mod/elf/dl-tls.c     2015-02-18 05:21:04.018424445 -0500
+@@ -33,9 +33,6 @@
+    to allow dynamic loading of modules defining IE-model TLS data.  */
+ #define TLS_STATIC_SURPLUS    64 + DL_NNS * 100
+-/* Value used for dtv entries for which the allocation is delayed.  */
+-#define TLS_DTV_UNALLOCATED   ((void *) -1l)
+-
+ /* Out-of-memory handler.  */
+ #ifdef SHARED
+diff -urN glibc-2.12-2-gc4ccff1/nptl/allocatestack.c glibc-2.12-2-gc4ccff1.mod/nptl/allocatestack.c
+--- glibc-2.12-2-gc4ccff1/nptl/allocatestack.c 2015-02-18 05:16:56.101095594 -0500
++++ glibc-2.12-2-gc4ccff1.mod/nptl/allocatestack.c     2015-02-18 05:21:04.019424414 -0500
+@@ -26,6 +26,7 @@
+ #include <sys/mman.h>
+ #include <sys/param.h>
+ #include <dl-sysdep.h>
++#include <dl-tls.h>
+ #include <tls.h>
+ #include <list.h>
+ #include <lowlevellock.h>
+@@ -242,6 +243,10 @@
+   /* Clear the DTV.  */
+   dtv_t *dtv = GET_DTV (TLS_TPADJ (result));
++  for (size_t cnt = 0; cnt < dtv[-1].counter; ++cnt)
++    if (! dtv[1 + cnt].pointer.is_static
++      && dtv[1 + cnt].pointer.val != TLS_DTV_UNALLOCATED)
++      free (dtv[1 + cnt].pointer.val);
+   memset (dtv, '\0', (dtv[-1].counter + 1) * sizeof (dtv_t));
+   /* Re-initialize the TLS.  */
+diff -urN glibc-2.12-2-gc4ccff1/sysdeps/i386/dl-tls.h glibc-2.12-2-gc4ccff1.mod/sysdeps/i386/dl-tls.h
+--- glibc-2.12-2-gc4ccff1/sysdeps/i386/dl-tls.h        2010-05-04 07:27:23.000000000 -0400
++++ glibc-2.12-2-gc4ccff1.mod/sysdeps/i386/dl-tls.h    2015-02-18 05:21:04.019424414 -0500
+@@ -58,3 +58,6 @@
+ # endif
+ #endif
++
++/* Value used for dtv entries for which the allocation is delayed.  */
++#define TLS_DTV_UNALLOCATED   ((void *) -1l)
+diff -urN glibc-2.12-2-gc4ccff1/sysdeps/ia64/dl-tls.h glibc-2.12-2-gc4ccff1.mod/sysdeps/ia64/dl-tls.h
+--- glibc-2.12-2-gc4ccff1/sysdeps/ia64/dl-tls.h        2010-05-04 07:27:23.000000000 -0400
++++ glibc-2.12-2-gc4ccff1.mod/sysdeps/ia64/dl-tls.h    2015-02-18 05:21:04.019424414 -0500
+@@ -28,3 +28,6 @@
+ #define DONT_USE_TLS_INDEX    1
+ extern void *__tls_get_addr (size_t m, size_t offset);
++
++/* Value used for dtv entries for which the allocation is delayed.  */
++#define TLS_DTV_UNALLOCATED   ((void *) -1l)
+diff -urN glibc-2.12-2-gc4ccff1/sysdeps/powerpc/dl-tls.h glibc-2.12-2-gc4ccff1.mod/sysdeps/powerpc/dl-tls.h
+--- glibc-2.12-2-gc4ccff1/sysdeps/powerpc/dl-tls.h     2010-05-04 07:27:23.000000000 -0400
++++ glibc-2.12-2-gc4ccff1.mod/sysdeps/powerpc/dl-tls.h 2015-02-18 05:21:04.019424414 -0500
+@@ -47,3 +47,6 @@
+ # define GET_ADDR_OFFSET      (ti->ti_offset + TLS_DTV_OFFSET)
+ # define __TLS_GET_ADDR(__ti) (__tls_get_addr (__ti) - TLS_DTV_OFFSET)
+ #endif
++
++/* Value used for dtv entries for which the allocation is delayed.  */
++#define TLS_DTV_UNALLOCATED   ((void *) -1l)
+diff -urN glibc-2.12-2-gc4ccff1/sysdeps/s390/dl-tls.h glibc-2.12-2-gc4ccff1.mod/sysdeps/s390/dl-tls.h
+--- glibc-2.12-2-gc4ccff1/sysdeps/s390/dl-tls.h        2010-05-04 07:27:23.000000000 -0400
++++ glibc-2.12-2-gc4ccff1.mod/sysdeps/s390/dl-tls.h    2015-02-18 05:21:04.019424414 -0500
+@@ -72,6 +72,9 @@
+ # define __TLS_GET_ADDR(__ti) \
+   ({ extern char _GLOBAL_OFFSET_TABLE_[] attribute_hidden;              \
+      (void *) __tls_get_offset ((char *) (__ti) - _GLOBAL_OFFSET_TABLE_)  \
+-     + (unsigned long) __builtin_thread_pointer (); }) 
++     + (unsigned long) __builtin_thread_pointer (); })
+ #endif
++
++/* Value used for dtv entries for which the allocation is delayed.  */
++#define TLS_DTV_UNALLOCATED   ((void *) -1l)
+diff -urN glibc-2.12-2-gc4ccff1/sysdeps/sh/dl-tls.h glibc-2.12-2-gc4ccff1.mod/sysdeps/sh/dl-tls.h
+--- glibc-2.12-2-gc4ccff1/sysdeps/sh/dl-tls.h  2010-05-04 07:27:23.000000000 -0400
++++ glibc-2.12-2-gc4ccff1.mod/sysdeps/sh/dl-tls.h      2015-02-18 05:21:04.019424414 -0500
+@@ -27,3 +27,6 @@
+ extern void *__tls_get_addr (tls_index *ti);
++
++/* Value used for dtv entries for which the allocation is delayed.  */
++#define TLS_DTV_UNALLOCATED   ((void *) -1l)
+diff -urN glibc-2.12-2-gc4ccff1/sysdeps/sparc/dl-tls.h glibc-2.12-2-gc4ccff1.mod/sysdeps/sparc/dl-tls.h
+--- glibc-2.12-2-gc4ccff1/sysdeps/sparc/dl-tls.h       2010-05-04 07:27:23.000000000 -0400
++++ glibc-2.12-2-gc4ccff1.mod/sysdeps/sparc/dl-tls.h   2015-02-18 05:21:04.019424414 -0500
+@@ -27,3 +27,6 @@
+ extern void *__tls_get_addr (tls_index *ti);
++
++/* Value used for dtv entries for which the allocation is delayed.  */
++#define TLS_DTV_UNALLOCATED   ((void *) -1l)
+diff -urN glibc-2.12-2-gc4ccff1/sysdeps/x86_64/dl-tls.h glibc-2.12-2-gc4ccff1.mod/sysdeps/x86_64/dl-tls.h
+--- glibc-2.12-2-gc4ccff1/sysdeps/x86_64/dl-tls.h      2010-05-04 07:27:23.000000000 -0400
++++ glibc-2.12-2-gc4ccff1.mod/sysdeps/x86_64/dl-tls.h  2015-02-18 05:21:04.019424414 -0500
+@@ -27,3 +27,6 @@
+ extern void *__tls_get_addr (tls_index *ti);
++
++/* Value used for dtv entries for which the allocation is delayed.  */
++#define TLS_DTV_UNALLOCATED   ((void *) -1l)
diff --git a/src/patches/glibc/glibc-rh981942.patch b/src/patches/glibc/glibc-rh981942.patch
new file mode 100644 (file)
index 0000000..cbe1ab8
--- /dev/null
@@ -0,0 +1,22 @@
+commit 2e96f1c73b06e81da59ef7fffa426dc201875f31
+Author: Andreas Schwab <schwab@redhat.com>
+Date:   Thu Aug 4 15:42:10 2011 -0400
+
+    Fix encoding name for IDN in getaddrinfo
+
+diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
+index 6d574c5..a5aafe9 100644
+--- a/sysdeps/posix/getaddrinfo.c
++++ b/sysdeps/posix/getaddrinfo.c
+@@ -432,7 +432,10 @@ gaih_inet (const char *name, const struct gaih_service *service,
+         /* In case the output string is the same as the input string
+            no new string has been allocated.  */
+         if (p != name)
+-          malloc_name = true;
++          {
++            name = p;
++            malloc_name = true;
++          }
+       }
+ #endif
diff --git a/src/patches/glibc/glibc-rh988931.patch b/src/patches/glibc/glibc-rh988931.patch
new file mode 100644 (file)
index 0000000..38594a4
--- /dev/null
@@ -0,0 +1,33 @@
+commit e23fe25b33324a9ea992276c1a4f04127bf9ba4b
+Author: Andreas Schwab <schwab@redhat.com>
+Date:   Sun Feb 20 07:24:56 2011 -0500
+
+    Move setting variable in relro data earlier in ld.so.
+
+diff --git a/elf/rtld.c b/elf/rtld.c
+index 8510380..174954b 100644
+--- a/elf/rtld.c
++++ b/elf/rtld.c
+@@ -2179,6 +2179,10 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
+      we need it in the memory handling later.  */
+   GLRO(dl_initial_searchlist) = *GL(dl_ns)[LM_ID_BASE]._ns_main_searchlist;
++  /* Remember the last search directory added at startup, now that
++     malloc will no longer be the one from dl-minimal.c.  */
++  GLRO(dl_init_all_dirs) = GL(dl_all_dirs);
++
+   if (prelinked)
+     {
+       if (main_map->l_info [ADDRIDX (DT_GNU_CONFLICT)] != NULL)
+@@ -2298,9 +2302,8 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
+                         lossage);
+     }
+-  /* Remember the last search directory added at startup, now that
+-     malloc will no longer be the one from dl-minimal.c.  */
+-  GLRO(dl_init_all_dirs) = GL(dl_all_dirs);
++  /* Make sure no new search directories have been added.  */
++  assert (GLRO(dl_init_all_dirs) == GL(dl_all_dirs));
+   if (! prelinked && rtld_multiple_ref)
+     {
diff --git a/src/patches/openssl-1.0.2g-disable-sslv2v3.patch b/src/patches/openssl-1.0.2g-disable-sslv2v3.patch
new file mode 100644 (file)
index 0000000..06f5132
--- /dev/null
@@ -0,0 +1,18 @@
+diff -up openssl-1.0.2g/ssl/ssl_lib.c.v2v3 openssl-1.0.2g/ssl/ssl_lib.c
+--- openssl-1.0.2g/ssl/ssl_lib.c.v2v3  2016-03-01 16:38:26.879142021 +0100
++++ openssl-1.0.2g/ssl/ssl_lib.c       2016-03-01 16:41:32.977353769 +0100
+@@ -2055,11 +2055,11 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *m
+     ret->options |= SSL_OP_LEGACY_SERVER_CONNECT;
+     /*
+-     * Disable SSLv2 by default, callers that want to enable SSLv2 will have to
+-     * explicitly clear this option via either of SSL_CTX_clear_options() or
++     * Disable SSLv2 and SSLv3 by default, callers that want to enable these will have to
++     * explicitly clear these options via either of SSL_CTX_clear_options() or
+      * SSL_clear_options().
+      */
+-    ret->options |= SSL_OP_NO_SSLv2;
++    ret->options |= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
+     return (ret);
+  err:
diff --git a/src/patches/openssl-disable-sslv2-sslv3.patch b/src/patches/openssl-disable-sslv2-sslv3.patch
deleted file mode 100644 (file)
index e42dfac..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
---- openssl-1.0.1m/ssl/ssl_lib.c.old   2015-03-19 15:56:40.966287977 +0100
-+++ openssl-1.0.1m/ssl/ssl_lib.c       2015-03-19 15:57:07.976160846 +0100
-@@ -1892,6 +1892,9 @@
-      */
-     ret->options |= SSL_OP_LEGACY_SERVER_CONNECT;
-+    /* Disable SSLv2 and SSLv3 by default (affects the SSLv23_method() only) */
-+    ret->options |= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
-+
-     return (ret);
-  err:
-     SSLerr(SSL_F_SSL_CTX_NEW, ERR_R_MALLOC_FAILURE);
diff --git a/src/patches/squid-3.4-13230.patch b/src/patches/squid-3.4-13230.patch
new file mode 100644 (file)
index 0000000..597d135
--- /dev/null
@@ -0,0 +1,44 @@
+------------------------------------------------------------
+revno: 13230
+revision-id: squid3@treenet.co.nz-20160212045316-zwx4r9we4gf27rx3
+parent: squid3@treenet.co.nz-20151119051038-vwclso11p68sgvxc
+fixes bug: http://bugs.squid-cache.org/show_bug.cgi?id=4431
+author: Marcos Mello <marcosfrm@gmail.com>
+committer: Amos Jeffries <squid3@treenet.co.nz>
+branch nick: 3.4
+timestamp: Fri 2016-02-12 17:53:16 +1300
+message:
+  Bug 4431: C code is not compiled with CFLAGS
+------------------------------------------------------------
+# Bazaar merge directive format 2 (Bazaar 0.90)
+# revision_id: squid3@treenet.co.nz-20160212045316-zwx4r9we4gf27rx3
+# target_branch: http://bzr.squid-cache.org/bzr/squid3/3.4
+# testament_sha1: 53c8d70db04dad826815fb86995cda7e99f1d8e2
+# timestamp: 2016-02-12 05:50:53 +0000
+# source_branch: http://bzr.squid-cache.org/bzr/squid3/3.4
+# base_revision_id: squid3@treenet.co.nz-20151119051038-\
+#   vwclso11p68sgvxc
+# 
+# Begin patch
+=== modified file 'acinclude/compiler-flags.m4'
+--- acinclude/compiler-flags.m4        2015-01-09 10:30:44 +0000
++++ acinclude/compiler-flags.m4        2016-02-12 04:53:16 +0000
+@@ -36,7 +36,7 @@
+   AC_CACHE_CHECK([whether compiler accepts $2],[$1],
+   [{
+     AC_REQUIRE([AC_PROG_CC])
+-    SAVED_FLAGS="$CFLAGS"
++    SAVED_CFLAGS="$CFLAGS"
+     SAVED_CXXFLAGS="$CXXFLAGS"
+     CFLAGS="$CFLAGS $2"
+     CXXFLAGS="$CXXFLAGS $2"
+@@ -60,7 +60,7 @@
+   AC_CACHE_CHECK([whether compiler requires $2],[$1],
+   [{
+     AC_REQUIRE([AC_PROG_CC])
+-    SAVED_FLAGS="$CFLAGS"
++    SAVED_CFLAGS="$CFLAGS"
+     SAVED_CXXFLAGS="$CXXFLAGS"
+     AC_COMPILE_IFELSE([AC_LANG_PROGRAM($3,$4)],[$1=no],[],[$1=no])
+     if test "x$1" != "xno" ; then
+