Bug 2229902

Summary: Data sent through a socket bound using bind(2) may escape to another interface
Product: [Fedora] Fedora Reporter: lagoho7
Component: kernelAssignee: Kernel Maintainer List <kernel-maint>
Status: NEW --- QA Contact: Fedora Extras Quality Assurance <extras-qa>
Severity: unspecified Docs Contact:
Priority: unspecified    
Version: 38CC: acaringi, adscvr, airlied, alciregi, bskeggs, gnault, hdegoede, hpa, jarod, josef, kernel-maint, lgoncalv, linville, masami256, mchehab, ptalbert, steved
Target Milestone: ---   
Target Release: ---   
Hardware: x86_64   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 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:
Attachments:
Description Flags
ifconfig output, tcpdump output and kernel logs none

Description lagoho7 2023-08-08 07:07:16 UTC
Created attachment 1982239 [details]
ifconfig output, tcpdump output and kernel logs

1. Please describe the problem:

   It is possible for data that was sent through a socket bound to an IP address
   using bind(2) to escape to another interface.

   To demonstrate the problem, you need one interface with Internet access and
   another interface with no Internet access. You should bind a socket to the
   interface with no Internet access, then try to send data through that socket
   to a destination on the Internet. You will find that the data gets sent
   successfully.

   If you capture the packets using tcpdump, you will see that while the source
   IP of of the packets are correct, the interface name belongs to the other
   interface, the one with Internet access.

   FYI, please find attached my tcpdump output and ifconfig output.


2. What is the Version-Release number of the kernel:

   Linux f38-test 6.4.7-200.fc38.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Jul 27 20:01:18 UTC 2023 x86_64 GNU/Linux


3. Did it work previously in Fedora? If so, what kernel version did the issue
   *first* appear?  Old kernels are available for download at
   https://koji.fedoraproject.org/koji/packageinfo?packageID=8 :

   Sorry I have no idea, I have not tried this in previous releases.


4. Can you reproduce this issue? If so, please provide the steps to reproduce
   the issue below:

   This can be reproduced every time.

   4.1. Set up a Fedora 38 VM (I am using VirtualBox) that has one NAT interface
        (has Internet access) and one host-only interface (no Internet access).

   4.2. Try to send a request using curl that is bound to the host-only
        interface using its interface name. It should fail to connect as
        expected.
        $ curl --interface enp0s8 icanhazip.com

   4.3. Try to send another request, this time bind to the host-only interface
        using its IP address. It will somehow successfully get a response.
        $ curl --interface 192.168.56.103 icanhazip.com

   Note: When --interface is specified, curl binds using SO_BINDTODEVICE when
         given an interface name, and bind(2) when given an IP address.
         https://github.com/curl/curl/issues/11599#issuecomment-1667391636


5. Does this problem occur with the latest Rawhide kernel? To install the
   Rawhide kernel, run ``sudo dnf install fedora-repos-rawhide`` followed by
   ``sudo dnf update --enablerepo=rawhide kernel``:

   Yes.


6. Are you running any modules that not shipped with directly Fedora's kernel?:

   No, I am running a fresh installation.


7. Please attach the kernel logs. You can get the complete kernel log
   for a boot with ``journalctl --no-hostname -k > dmesg.txt``. If the
   issue occurred on a previous boot, use the journalctl ``-b`` flag.

Comment 1 Guillaume Nault 2023-08-11 12:07:43 UTC
(In reply to lagoho7 from comment #0)
> Created attachment 1982239 [details]
> ifconfig output, tcpdump output and kernel logs
> 
> 1. Please describe the problem:
> 
>    It is possible for data that was sent through a socket bound to an IP
> address
>    using bind(2) to escape to another interface.

This sentence doesn't really make sense. In the context of IP sockets, bind(2)
works on IP addresses, not on network interfaces. It has no reason to put any
restriction on the output device.

>    To demonstrate the problem, you need one interface with Internet access
> and
>    another interface with no Internet access. You should bind a socket to the
>    interface with no Internet access, then try to send data through that
> socket
>    to a destination on the Internet. You will find that the data gets sent
>    successfully.

This is expected. By default routing is done based on the destination IP. If
that destination IP is routed through a given interface, that's where the
packets will go. Without specific configuration, the restrictions put on the
source IP are not supposed to influence the routing decision.

>    This can be reproduced every time.
> 
>    4.1. Set up a Fedora 38 VM (I am using VirtualBox) that has one NAT
> interface
>         (has Internet access) and one host-only interface (no Internet
> access).
> 
>    4.2. Try to send a request using curl that is bound to the host-only
>         interface using its interface name. It should fail to connect as
>         expected.
>         $ curl --interface enp0s8 icanhazip.com

There you bind the socket to a specific network device. If the packet can't
be routed through this device, the packet can't go out.

>    4.3. Try to send another request, this time bind to the host-only
> interface
>         using its IP address. It will somehow successfully get a response.
>         $ curl --interface 192.168.56.103 icanhazip.com

There you bind the socket to an IP address. You put no restriction on the
network device to use. The system is free to pick the most suitable one.

>    Note: When --interface is specified, curl binds using SO_BINDTODEVICE when
>          given an interface name, and bind(2) when given an IP address.
>          https://github.com/curl/curl/issues/11599#issuecomment-1667391636

SO_BINDTODEVICE and bind(2) are two different things, made for two different
purposes. They're _not_ supposed to work the same way.

Also, note that by IP addresses identify network nodes, not network interfaces.
When you add an IP address on a given interface, you don't bind it to that
interface. It remains reachable from the other interfaces on the same node
(assuming proper routing and no extra isolation is set up).

I think this can be closed as NOTABUG.

Comment 2 lagoho7 2023-08-11 12:49:17 UTC
Hi Guillaume,

Thanks for replying in such detail.

> Also, note that by IP addresses identify network nodes, not network interfaces.
> When you add an IP address on a given interface, you don't bind it to that
> interface. It remains reachable from the other interfaces on the same node

Hmm, I suppose this makes sense, otherwise routers can't function.

I also did the test over on FreeBSD, and the result was as I originally expected.
Could you provide any insight as to why that is?

As far as I know, most operating systems derived their network API from BSD, so I
(mistakenly?) took that test result as the "definitive" reference.

Comment 3 Guillaume Nault 2023-08-11 13:56:21 UTC
(In reply to lagoho7 from comment #2)
> I also did the test over on FreeBSD, and the result was as I originally
> expected.
> Could you provide any insight as to why that is?
> 
> As far as I know, most operating systems derived their network API from BSD,
> so I
> (mistakenly?) took that test result as the "definitive" reference.

Well, I have no experience with FreeBSD or any other BSD variant.
So I really have no insight about how things should work there, sorry.