google / google/gvisor

SIOCGIFADDR returns success with stale ifreq data on IPv6-only interfaces

Open
#13,431 0 comments 0 reactions 0 assignees View on GitHub
type: bug
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.

Image

## 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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.