Bug 1454367

Summary: QEMU fails to reject IPv4 connections when IPv4 listening is disabled
Product: Red Hat Enterprise Linux 7 Reporter: Daniel Berrangé <berrange>
Component: qemu-kvm-rhevAssignee: Eric Blake <eblake>
Status: CLOSED ERRATA QA Contact: Yiqian Wei <yiwei>
Severity: high Docs Contact:
Priority: high    
Version: 7.4CC: areis, chayang, eblake, jinzhao, juzhang, knoel, michen, mrezanin, mtessun, pezhang, virt-maint, xfu, xiywang
Target Milestone: rc   
Target Release: ---   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: qemu-kvm-rhev-2.10.0-1.el7 Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2018-04-11 00:23:04 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description Daniel Berrangé 2017-05-22 14:48:26 UTC
Description of problem:
The QEMU network backends (VNC, migration, chardev) accept flags  "ipv6=on|off" and "ipv4=on|off" as a way to control which protocols they listen for connections.

When setting either  ipv4=off, ipv6=on, or ipv6, QEMU should not accept connections from IPv4 clients. This is not, however, the case currently - the following combinations:

$QEMU -incoming tcp::9000,ipv6=on
$QEMU -incoming tcp:[::]:9000,ipv6=on
$QEMU -chardev socket,id=cdev0,host=,port=9000,server,nowait,ipv4=off
$QEMU -chardev socket,id=cdev0,host=,port=9000,server,nowait,ipv6=on
$QEMU -chardev socket,id=cdev0,host=::,port=9000,server,nowait,ipv4=off
$QEMU -chardev socket,id=cdev0,host=::,port=9000,server,nowait,ipv6=on
$QEMU -vnc :0,ipv4=off
$QEMU -vnc :0,ipv6=on
$QEMU -vnc :::0,ipv4=off
$QEMU -vnc :::0,ipv6=on

all allow an IPv4 client to connect, despite being told to accept IPv6 only.

This is due to a bug in QEMU whereby it sets IPV6_V6ONLY=0, instead of =1, thereby allowing IPv4 clients over the IPv6 socket.

Version-Release number of selected component (if applicable):
qemu-kvm-rhev-2.9.0-1.el7

How reproducible:
Always

Steps to Reproduce:
1. $QEMU -incoming tcp::9000,ipv6=on
2. telnet 127.0.0.1 9000
3.

(Repeat for all the examples shown earlier)

Actual results:
Client succesfully connects to 127.0.0.1, port 9000

Expected results:
Client fails to connect to 127.0.0.1 with "COnnection refused" message.

Additional info:

Comment 2 Daniel Berrangé 2017-05-22 14:55:19 UTC
The scenarios describe are fixed by patches 3 & 4 in this small series

https://lists.gnu.org/archive/html/qemu-devel/2017-05/msg04707.html

Comment 6 Eric Blake 2017-07-17 16:47:35 UTC
Will be picked up for 7.5 via rebase, because it is included in upstream 2.10:

commit 563a3987b980a36e6941720a99d5cf36960f78ea
Author: Daniel P. Berrange <berrange>
Date:   Wed May 17 14:34:36 2017 +0100

    io: preserve ipv4/ipv6 flags when resolving InetSocketAddress
    
    The original InetSocketAddress struct may have has_ipv4 and
    has_ipv6 fields set, which will control both the ai_family
    used during DNS resolution, and later use of the V6ONLY
    flag.
    
    Currently the standalone DNS resolver code drops the
    has_ipv4 & has_ipv6 flags after resolving, which means
    the later bind() code won't correctly set V6ONLY.
    
    This fixes the following scenarios
    
      -vnc :0,ipv4=off
      -vnc :0,ipv6=on
      -vnc :::0,ipv4=off
      -vnc :::0,ipv6=on
    
    which all mistakenly accepted IPv4 clients
    
    Acked-by: Gerd Hoffmann <kraxel>
    Reviewed-by: Philippe Mathieu-Daudé <f4bug>
    Reviewed-by: Eric Blake <eblake>
    Signed-off-by: Daniel P. Berrange <berrange>

commit 94bc0d19789b6f5ce881c4a06a3e1c431874cbbd
Author: Daniel P. Berrange <berrange>
Date:   Wed May 17 14:17:55 2017 +0100

    sockets: ensure we don't accept IPv4 clients when IPv4 is disabled
    
    Currently if you disable listening on IPv4 addresses, via the
    CLI flag ipv4=off, we still mistakenly accept IPv4 clients via
    the IPv6 listener socket due to IPV6_V6ONLY flag being unset.
    
    We must ensure IPV6_V6ONLY is always set if ipv4=off
    
    This fixes the following scenarios
    
      -incoming tcp::9000,ipv6=on
      -incoming tcp:[::]:9000,ipv6=on
      -chardev socket,id=cdev0,host=,port=9000,server,nowait,ipv4=off
      -chardev socket,id=cdev0,host=,port=9000,server,nowait,ipv6=on
      -chardev socket,id=cdev0,host=::,port=9000,server,nowait,ipv4=off
      -chardev socket,id=cdev0,host=::,port=9000,server,nowait,ipv6=on
    
    which all mistakenly accepted IPv4 clients
    
    Acked-by: Gerd Hoffmann <kraxel>
    Reviewed-by: Philippe Mathieu-Daudé <f4bug>
    Reviewed-by: Eric Blake <eblake>
    Signed-off-by: Daniel P. Berrange <berrange>

Comment 10 Yiqian Wei 2017-10-17 02:09:14 UTC
Reproduce
host version:
qemu-kvm-rhev-2.9.0-1.el7.x86_64
kernel-3.10.0-737.el7.x86_64
test scenarios:
# /usr/libexec/qemu-kvm -monitor stdio -vnc :0,ipv4=off
# /usr/libexec/qemu-kvm -monitor stdio -vnc :::0,ipv4=off
# /usr/libexec/qemu-kvm -monitor stdio -vnc :0,ipv6=on
# /usr/libexec/qemu-kvm -monitor stdio -vnc :::0,ipv6=on

# /usr/libexec/qemu-kvm -monitor stdio -incoming tcp::9000,ipv6=on
# /usr/libexec/qemu-kvm -monitor stdio -incoming tcp:[::]:9000,ipv6=on

# /usr/libexec/qemu-kvm -monitor stdio -chardev socket,id=cdev0,host=,port=9000,server,nowait,ipv4=off
# /usr/libexec/qemu-kvm -monitor stdio -chardev socket,id=cdev0,host=,port=9000,server,nowait,ipv6=on
# /usr/libexec/qemu-kvm -monitor stdio -chardev socket,id=cdev0,host=::,port=9000,server,nowait,ipv4=off
# /usr/libexec/qemu-kvm -monitor stdio -chardev socket,id=cdev0,host=::,port=9000,server,nowait,ipv6=on

test steps:
1.usr/libexec/qemu-kvm -monitor stdio -incoming tcp::9000,ipv6=on
2.telnet 127.0.0.1 9000

(Repeat for test scenarios shown earlier)

Actual results: Client succesfully connects to 127.0.0.1, port 9000
# telnet 127.0.0.1 9000
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'
----------------------------
Verify this bug on qemu-kvm-rhev-2.10.0-2.el7.x86_64 as same steps above.
Actual results: Client fails to connect to 127.0.0.1 with "Connection refused" message.
# telnet 127.0.0.1 9000
Trying 127.0.0.1...
telnet: connect to address 127.0.0.1: Connection refused


According to result above,this bug has been fixed.

Comment 11 jingzhao 2017-10-17 06:51:58 UTC
According to comment 10, change to verified status

Comment 13 errata-xmlrpc 2018-04-11 00:23:04 UTC
Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.

For information on the advisory, and where to find the updated
files, follow the link below.

If the solution does not work for you, open a new bug report.

https://access.redhat.com/errata/RHSA-2018:1104