SIOCGIFADDR returns success with stale ifreq data on IPv6-only interfaces
- Dominant language
- Go
- Stars
- 19.3k
- Forks
- 2k
- Avg merge
- 3d 5h
- Merged PRs (30d)
- 264
Description
## Description
On an IPv6-only interface, Linux returns `EADDRNOTAVAIL` for `SIOCGIFADDR`.
In gVisor, the same ioctl appears to return success and expose stale `ifreq` union data as an IPv4 address. This makes `ifconfig` show a fake IPv4 address on an IPv6-only interface.
## Environment
- gVisor version: `release-20260601.0`
- Network stack: netstack
- Runtime environment: Kubernetes / EKS pod using gVisor
- Interface: AWS VPC CNI IPv6 egress interface `v6if0`
## Linux behavior
On a non-gVisor runtime, the same IPv6-only interface returns:
```text
ioctl(5, SIOCGIFFLAGS, {ifr_name="v6if0", ifr_flags=IFF_UP|IFF_BROADCAST|IFF_RUNNING|IFF_MULTICAST}) = 0
ioctl(5, SIOCGIFHWADDR, {ifr_name="v6if0", ifr_hwaddr={sa_family=ARPHRD_ETHER, sa_data=fe:c2:9e:66:02:9d}}) = 0
ioctl(5, SIOCGIFMTU, {ifr_name="v6if0", ifr_mtu=9001}) = 0
ioctl(5, SIOCGIFMAP, {ifr_name="v6if0", ifr_map={mem_start=0, mem_end=0, base_addr=0, irq=0, dma=0, port=0}}) = 0
ioctl(5, SIOCGIFMAP, {ifr_name="v6if0", ifr_map={mem_start=0, mem_end=0, base_addr=0, irq=0, dma=0, port=0}}) = 0
ioctl(5, SIOCGIFTXQLEN, {ifr_name="v6if0", ifr_qlen=1000}) = 0
ioctl(4, SIOCGIFADDR, {ifr_name="v6if0"}) = -1 EADDRNOTAVAIL (Cannot assign requested address)
```
## gVisor behavior
In gVisor, the same IPv6-only interface returns success for IPv4-related ioctls:
```text
ioctl(5, SIOCGIFFLAGS, {ifr_name="v6if0", ifr_flags=IFF_UP|IFF_RUNNING}) = 0
ioctl(5, SIOCGIFHWADDR, {ifr_name="v6if0", ifr_hwaddr={sa_family=ARPHRD_ETHER, sa_data=ca:1d:34:71:26:8b}}) = 0
ioctl(5, SIOCGIFMTU, {ifr_name="v6if0", ifr_mtu=9001}) = 0
ioctl(5, SIOCGIFMAP, {ifr_name="v6if0", ifr_map={mem_start=0x8b26713400002329, mem_end=0, base_addr=0, irq=0, dma=0, port=0}}) = 0
ioctl(5, SIOCGIFMAP, {ifr_name="v6if0", ifr_map={mem_start=0x8b26713400002329, mem_end=0, base_addr=0, irq=0, dma=0, port=0}}) = 0
ioctl(5, SIOCGIFTXQLEN, {ifr_name="v6if0", ifr_qlen=9001}) = 0
ioctl(4, SIOCGIFADDR, {ifr_name="v6if0", ifr_addr={sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("52.113.38.139")}}) = 0
ioctl(4, SIOCGIFDSTADDR, {ifr_name="v6if0", ifr_dstaddr={sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("52.113.38.139")}}) = 0
ioctl(4, SIOCGIFBRDADDR, {ifr_name="v6if0", ifr_broadaddr={sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("52.113.38.139")}}) = 0
ioctl(4, SIOCGIFNETMASK, {ifr_name="v6if0", ifr_netmask={sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("52.113.38.139")}}) = 0
```
The IPv4 address shown by `SIOCGIFADDR` matches the last 4 bytes of the MAC address:
```text
MAC: ca:1d:34:71:26:8b
MAC suffix: 34:71:26:8b
IPv4 shown by ioctl: 52.113.38.139
Decimal bytes: 52 .113 . 38 .139
```
## `ip addr` output
Netlink output does not show any IPv4 address on `v6if0`:
```text
3: v6if0: mtu 9001
link/ether ca:1d:34:71:26:8b brd ff:ff:ff:ff:ff:ff
inet6 fd00::ac:27/118 scope global dynamic
inet6 fe80::c81d:34ff:fe71:268b/64 scope global dynamic
```
## `ifconfig` output
`ifconfig` shows a fake IPv4 address:
```text
v6if0: flags=65 mtu 9001
inet 52.113.38.139 netmask 52.113.38.139
inet6 fd00::ac:27 prefixlen 118 scopeid 0x0
inet6 fe80::c81d:34ff:fe71:268b prefixlen 64 scopeid 0x0
ether ca:1d:34:71:26:8b txqueuelen 9001 (Ethernet)
RX packets 2 bytes 192 (192.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
device memory 0x8b26713400002329-0
```
## Possible code locations
In `release-20260601.0`, `SIOCGIFADDR` scans for an AF_INET address, but if none is found the case does not appear to return an error:
- [`pkg/sentry/socket/netstack/netstack.go#L3634-L3643`](https://github.com/google/gvisor/blob/release-20260601.0/pkg/sentry/socket/netstack/netstack.go#L3634-L3643)
`SIOCGIFNETMASK` appears to use the same pattern:
- [`pkg/sentry/socket/netstack/netstack.go#L3670-L3685`](https://github.com/google/gvisor/blob/release-20260601.0/pkg/sentry/socket/netstack/netstack.go#L3670-L3685)
There may be a similar path in `plugin/stack`:
- [`pkg/sentry/socket/plugin/stack/socket.go#L347-L356`](https://github.com/google/gvisor/blob/release-20260601.0/pkg/sentry/socket/plugin/stack/socket.go#L347-L356)
- [`pkg/sentry/socket/plugin/stack/socket.go#L384-L398`](https://github.com/google/gvisor/blob/release-20260601.0/pkg/sentry/socket/plugin/stack/socket.go#L384-L398)
### Steps to reproduce
_No response_
### runsc version
```shell
runsc version release-20260601.0
spec: 1.2.1
```
### docker version (if using docker)
```shell
```
### uname
```shell
6.12.88-119.157.amzn2023.x86_64
```
### kubectl (if using Kubernetes)
```shell
v1.35.5-eks-0247562
```
### repo state (if built from source)
_No response_
### runsc debug logs (if available)
```shell
```
Contributor guide
Assessment
This issue has not been assessed yet.