getaddrinfo() dont work correct with ipv4+ipv6 addreses aftrer upgrade libc6 in Ubuntu Precise

Bug #1674776 reported by helodron on 2017-03-21
54
This bug affects 10 people
Affects Status Importance Assigned to Milestone
GLibC
Fix Released
Medium
eglibc (Ubuntu)
Precise
Critical
Unassigned

Bug Description

getaddrinfo() dont work correct with ipv4+ipv6 addreses aftrer upgrade libc6 in Ubuntu Precise.

server has only ipv6 address.
Ubuntu 12.04.5 LTS \n \l
libc6 = 2.15-0ubuntu10.16

host ya.ru
YA.ru has address 93.158.134.3
YA.ru has address 213.180.193.3
YA.ru has address 213.180.204.3
YA.ru has IPv6 address 2a02:6b8::3

strace -e connect nc -zv ya.ru http
connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("213.180.193.3")}, 16) = -1 ENETUNREACH (Network is unreachable)
connect(3, {sa_family=AF_UNSPEC, sa_data="\0\0\0\0\0\0\0\0\0\0\0\0\0\0"}, 16) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("213.180.204.3")}, 16) = -1 ENETUNREACH (Network is unreachable)
connect(3, {sa_family=AF_UNSPEC, sa_data="\0\0\0\0\0\0\0\0\0\0\0\0\0\0"}, 16) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("93.158.134.3")}, 16) = -1 ENETUNREACH (Network is unreachable)
connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("213.180.193.3")}, 16) = -1 ENETUNREACH (Network is unreachable)
nc: connect to ya.ru port 80 (tcp) failed: Network is unreachable
connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("213.180.204.3")}, 16) = -1 ENETUNREACH (Network is unreachable)
nc: connect to ya.ru port 80 (tcp) failed: Network is unreachable
connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("93.158.134.3")}, 16) = -1 ENETUNREACH (Network is unreachable)

nc: connect to ya.ru port 80 (tcp) failed: Network is unreachable

python -c 'import socket; print socket.getaddrinfo("ya.ru.", 0, socket.AF_UNSPEC, 0)[0][4]'; python -c 'import socket; print socket.getaddrinfo("ya.ru.", 0, socket.AF_INET6, 0)[0][4]'
('93.158.134.3', 0)
('2a02:6b8::3', 0, 0, 0)

before update libc6=2.15-0ubuntu10.15

strace -e connect nc -zv ya.ru http
connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
connect(3, {sa_family=AF_INET6, sin6_port=htons(80), inet_pton(AF_INET6, "2a02:6b8::3", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 28) = 0
connect(3, {sa_family=AF_UNSPEC, sa_data="\0\0\0\0\0\0\0\0\0\0\0\0\0\0"}, 16) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("93.158.134.3")}, 16) = -1 ENETUNREACH (Network is unreachable)
connect(3, {sa_family=AF_UNSPEC, sa_data="\0\0\0\0\0\0\0\0\0\0\0\0\0\0"}, 16) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("213.180.193.3")}, 16) = -1 ENETUNREACH (Network is unreachable)
connect(3, {sa_family=AF_UNSPEC, sa_data="\0\0\0\0\0\0\0\0\0\0\0\0\0\0"}, 16) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("213.180.204.3")}, 16) = -1 ENETUNREACH (Network is unreachable)
connect(3, {sa_family=AF_INET6, sin6_port=htons(80), inet_pton(AF_INET6, "2a02:6b8::3", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 28) = -1 EINPROGRESS (Operation now in progress)

Connection to ya.ru 80 port [tcp/http] succeeded!

python -c 'import socket; print socket.getaddrinfo("ya.ru.", 0, socket.AF_UNSPEC, 0)[0][4]'; python -c 'import socket; print socket.getaddrinfo("ya.ru.", 0, socket.AF_INET6, 0)[0][4]'
('2a02:6b8::3', 0, 0, 0)
('2a02:6b8::3', 0, 0, 0)

I think problem with patch: CVE-2016-3706: getaddrinfo: stack overflow in hostent conversion [BZ #20010]
https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=blobdiff;f=sysdeps/posix/getaddrinfo.c;h=df6ce8b13e3897f3ed47877b029da39abafe9f25;hp=d2283bcd4ad4fe7e41cf9c6ee74ec8c63ab32e34;hb=762aafec34478bcef01a16acf1959732ab8bb2b6;hpb=e97fb84811238c627f93e5e703a11eb841601947;ds=sidebyside

CVE References

helodron (helodron) on 2017-03-21
description: updated
description: updated
Launchpad Janitor (janitor) wrote :

Status changed to 'Confirmed' because the bug affects multiple users.

Changed in eglibc (Ubuntu):
status: New → Confirmed
Steve Beattie (sbeattie) wrote :

Hi, thanks for reporting your issue. I think this is actually the fix for CVE-2015-5180 (due to an internal ABI change around T_UNSPEC). I have uploaded a test version of eglibc with the commit to address that issue reverted to https://launchpad.net/~ubuntu-security-proposed/+archive/ubuntu/ppa/ ; is it possible to test the version there to confirm or disprove that reverting that addresses your issue?

Thanks.

helodron (helodron) wrote :

not working :(

ii libc-bin 2.15-0ubuntu10.17~test.1
ii libc-dev-bin 2.15-0ubuntu10.17~test.1
ii libc6 2.15-0ubuntu10.17~test.1
ii libc6-dev 2.15-0ubuntu10.17~test.1

strace -e connect nc -zv ya.ru http
connect(3, {sa_family=AF_FILE, path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
connect(3, {sa_family=AF_FILE, path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
connect(3, {sa_family=AF_FILE, path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
connect(3, {sa_family=AF_FILE, path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("213.180.193.3")}, 16) = -1 ENETUNREACH (Network is unreachable)
connect(3, {sa_family=AF_UNSPEC, sa_data="\0\0\0\0\0\0\0\0\0\0\0\0\0\0"}, 16) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("213.180.204.3")}, 16) = -1 ENETUNREACH (Network is unreachable)
connect(3, {sa_family=AF_UNSPEC, sa_data="\0\0\0\0\0\0\0\0\0\0\0\0\0\0"}, 16) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("93.158.134.3")}, 16) = -1 ENETUNREACH (Network is unreachable)
connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("213.180.193.3")}, 16) = -1 ENETUNREACH (Network is unreachable)
nc: connect to ya.ru port 80 (tcp) failed: Network is unreachable
connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("213.180.204.3")}, 16) = -1 ENETUNREACH (Network is unreachable)
nc: connect to ya.ru port 80 (tcp) failed: Network is unreachable
connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("93.158.134.3")}, 16) = -1 ENETUNREACH (Network is unreachable)
nc: connect to ya.ru port 80 (tcp) failed: Network is unreachable

python -c 'import socket; print socket.getaddrinfo("ya.ru.", 0, socket.AF_UNSPEC, 0)[0][4]'; python -c 'import socket; print socket.getaddrinfo("ya.ru.", 0, socket.AF_INET6, 0)[0][4]'
('213.180.204.3', 0)
('2a02:6b8::3', 0, 0, 0)

helodron (helodron) wrote :

ii libc-bin 2.15-0ubuntu10.17
ii libc-dev-bin 2.15-0ubuntu10.17
ii libc6 2.15-0ubuntu10.17
ii libc6-dev 2.15-0ubuntu10.17

dont working too

strace -e connect nc -zv ya.ru http
connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("213.180.193.3")}, 16) = -1 ENETUNREACH (Network is unreachable)
connect(3, {sa_family=AF_UNSPEC, sa_data="\0\0\0\0\0\0\0\0\0\0\0\0\0\0"}, 16) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("213.180.204.3")}, 16) = -1 ENETUNREACH (Network is unreachable)
connect(3, {sa_family=AF_UNSPEC, sa_data="\0\0\0\0\0\0\0\0\0\0\0\0\0\0"}, 16) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("93.158.134.3")}, 16) = -1 ENETUNREACH (Network is unreachable)
connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("213.180.193.3")}, 16) = -1 ENETUNREACH (Network is unreachable)
nc: connect to ya.ru port 80 (tcp) failed: Network is unreachable
connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("213.180.204.3")}, 16) = -1 ENETUNREACH (Network is unreachable)
nc: connect to ya.ru port 80 (tcp) failed: Network is unreachable
connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("93.158.134.3")}, 16) = -1 ENETUNREACH (Network is unreachable)
nc: connect to ya.ru port 80 (tcp) failed: Network is unreachable

python -c 'import socket; print socket.getaddrinfo("ya.ru.", 0, socket.AF_UNSPEC, 0)[0][4]'; python -c 'import socket; print socket.getaddrinfo("ya.ru.", 0, socket.AF_INET6, 0)[0][4]'
('93.158.134.3', 0)
('2a02:6b8::3', 0, 0, 0)

Dmitry Bilunov (dbilunov) wrote :

It seems that sequential A-type DNS reply data overwrites data returned by AAAA-type DNS reply data prior to that.

convert_hostent_to_gaih_addrtuple: replacing "free(*result);" with "while(*result) result = &result->next;" does the trick.

You can try it out on libc6=2.15-0ubuntu10.17 by a simple change:

cd157: e8 84 1e f5 ff -> e8 56 01 00 00
cd2b2: 66 66 66 66 66 2e 0f 1f 84 00 00 -> e3 08 49 89 cf 48 8b 09 eb f6 c3

The attachment "0001-getaddrinfo-do-not-overwrite-IPv6-IPs-with-IPv4-when.patch" seems to be a patch. If it isn't, please remove the "patch" flag from the attachment, remove the "patch" tag, and if you are a member of the ~ubuntu-reviewers, unsubscribe the team.

[This is an automated message performed by a Launchpad user owned by ~brian-murray, for any issues please contact him.]

tags: added: patch
Dmitry Bilunov (dbilunov) wrote :

The same patch has been submitted upstream, see libc-alpha@ and BZ#21295.
However it is not likely to be accepted because newer libc versions use a different interface (gethostbyname4_r) in libnss_dns module which activates a different libc codepath avoiding the issue by requesting IPv4 and IPv6 entries in parallel.

Changed in eglibc:
importance: Unknown → Medium
status: Unknown → New
Steve Beattie (sbeattie) wrote :

Dmitry, thanks for the analysis. It looks like the conversion to using gethostbyname4_r for PF_UNSPEC only was for https://sourceware.org/bugzilla/show_bug.cgi?id=14505 (glibc git commit https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=8479f23aa1d5e5477a37f46823856bdafaedfa46 ). This change is in 14.04's (trusty) libc, but not 12.04 (precise).

Can people confirm that they're only seeing this on 12.04? The reason I ask is that the exact same patch for CVE-2016-3706 was applied in 14.04 as well as 12.04.

Using both the testcase you posted in the upstream glibc bug report and the reproducer from upstream #14505, I am now able to reproduce this with the libc 2.15-0ubuntu10.17 from precise, and confirm that things behaved correctly with eglibc 2.15-0ubuntu10.15. I also get correct results with eglibc 2.19-0ubuntu6.11 in 14.04.

At this point I'm inclined to revert the fix for CVE-2016-3706 for 12.04 as a less risky option, despite the appreciated effort you've taken, Dmitry, to come up with a patch to fix the issue. There is an eglibc package for precise that has that revert building in the ubuntu-security-proposed ppa https://launchpad.net/~ubuntu-security-proposed/+archive/ubuntu/ppa/ and would very much appreciate any testing you can give it.

Thanks, and my apologies for how this update has gone.

Changed in eglibc (Ubuntu Precise):
importance: Undecided → Critical
status: New → In Progress
Launchpad Janitor (janitor) wrote :

This bug was fixed in the package eglibc - 2.15-0ubuntu10.18

---------------
eglibc (2.15-0ubuntu10.18) precise-security; urgency=medium

  * REGRESSION UPDATE: IPv6 addresses not being returned from a
    dual-stack ipv4-ipv6 host query.
    - Revert patches/any/CVE-2016-3706.diff (LP: #1674776)

 -- Steve Beattie <email address hidden> Thu, 23 Mar 2017 11:38:25 -0700

Changed in eglibc (Ubuntu Precise):
status: In Progress → Fix Released
Steve Beattie (sbeattie) on 2017-03-24
Changed in eglibc (Ubuntu):
status: Confirmed → Invalid
Dmitry Bilunov (dbilunov) wrote :

Test failes on 2.15-0ubuntu10.17, succeeds on 2.15-0ubuntu10.18.
Tested on docker image ubuntu:12.04 (b384dd9703db).

helodron (helodron) wrote :

Working!! :) thx :D

ii libc-bin 2.15-0ubuntu10.18
ii libc-dev-bin 2.15-0ubuntu10.18
ii libc6 2.15-0ubuntu10.18
ii libc6-dev 2.15-0ubuntu10.18

strace -e connect nc -zv ya.ru http
connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
connect(3, {sa_family=AF_INET6, sin6_port=htons(80), inet_pton(AF_INET6, "2a02:6b8::3", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 28) = 0
connect(3, {sa_family=AF_UNSPEC, sa_data="\0\0\0\0\0\0\0\0\0\0\0\0\0\0"}, 16) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("213.180.193.3")}, 16) = -1 ENETUNREACH (Network is unreachable)
connect(3, {sa_family=AF_UNSPEC, sa_data="\0\0\0\0\0\0\0\0\0\0\0\0\0\0"}, 16) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("213.180.204.3")}, 16) = -1 ENETUNREACH (Network is unreachable)
connect(3, {sa_family=AF_UNSPEC, sa_data="\0\0\0\0\0\0\0\0\0\0\0\0\0\0"}, 16) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("93.158.134.3")}, 16) = -1 ENETUNREACH (Network is unreachable)
connect(3, {sa_family=AF_INET6, sin6_port=htons(80), inet_pton(AF_INET6, "2a02:6b8::3", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 28) = -1 EINPROGRESS (Operation now in progress)
Connection to ya.ru 80 port [tcp/http] succeeded!

python -c 'import socket; print socket.getaddrinfo("ya.ru.", 0, socket.AF_UNSPEC, 0)[0][4]'; python -c 'import socket; print socket.getaddrinfo("ya.ru.", 0, socket.AF_INET6, 0)[0][4]'
('2a02:6b8::3', 0, 0, 0)
('2a02:6b8::3', 0, 0, 0)

no longer affects: eglibc (Ubuntu)
affects: eglibc → glibc
Dominic (m-hallo) wrote :

This is not working for me on Ubuntu 14.04:

ii libc-bin 2.19-0ubuntu6.11
ii libc-dev-bin 2.19-0ubuntu6.11
ii libc6:amd64 2.19-0ubuntu6.11
ii libc6-dev:amd64 2.19-0ubuntu6.11

Dominic (m-hallo) wrote :

It is working for me, sorry about that. Forgot to restart Apache...

Changed in glibc:
status: New → In Progress
Changed in glibc:
status: In Progress → Fix Released
To post a comment you must log in.
This report contains Public information  Edit
Everyone can see this information.

Other bug subscribers

Bug attachments

Remote bug watches

Bug watches keep track of this bug in other bug trackers.