Skip to content

Instantly share code, notes, and snippets.

@SpComb
Last active August 31, 2017 05:36
Show Gist options
  • Save SpComb/c8604792fc9d3ba0518d889ff8f89ccb to your computer and use it in GitHub Desktop.
Save SpComb/c8604792fc9d3ba0518d889ff8f89ccb to your computer and use it in GitHub Desktop.
Docker netns leak via netlink socket to forked docker-proxy process

See weaveworks/weave#2842 (comment)

Example

Running on CoreOS stable:

+ test -d /sys/class/net/br-test
+ docker rm -f victim bystander
victim
bystander
+ sleep 2
+ docker run -d --name victim redis
31446c7224085a52119ea81c4b69fa34ff4b62c4c22ef1230bbc96455b724a3d
++ docker inspect -f '{{.State.Pid}}' victim
+ victim_pid=3805
+ ip link add veth0 type veth peer name veth1
+ ip link set veth0 up master br-test
+ ip link set veth1 netns 3805
+ nsenter -t 3805 -n ip link set veth1 up
+ nsenter -t 3805 -n ip addr add 192.168.0.10/24 dev veth1
+ sleep 2
+ docker run -d --name bystander -p 6379:6379 redis
f49101e2ce82dc10dee7580c0aa4981c9fb24c11d6c7a12f016ed9acfdea6d47
+ sleep 2
+ echo '> With both containers running...'
> With both containers running...
+ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
f49101e2ce82        redis               "docker-entrypoint.sh"   2 seconds ago       Up 2 seconds        0.0.0.0:6379->6379/tcp   bystander
31446c722408        redis               "docker-entrypoint.sh"   5 seconds ago       Up 4 seconds        6379/tcp                 victim
+ ping -c 2 192.168.0.10
PING 192.168.0.10 (192.168.0.10) 56(84) bytes of data.
64 bytes from 192.168.0.10: icmp_seq=1 ttl=64 time=0.346 ms
64 bytes from 192.168.0.10: icmp_seq=2 ttl=64 time=0.183 ms

--- 192.168.0.10 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1041ms
rtt min/avg/max/mdev = 0.183/0.264/0.346/0.083 ms
+ echo '> victim netns 192.168.0.10 responds to ping '
> victim netns 192.168.0.10 responds to ping 
+ docker stop victim
victim
+ echo '> The victim has been stopped, and the veth should be gone...'
> The victim has been stopped, and the veth should be gone...
+ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                              PORTS                    NAMES
f49101e2ce82        redis               "docker-entrypoint.sh"   4 seconds ago       Up 3 seconds                        0.0.0.0:6379->6379/tcp   bystander
31446c722408        redis               "docker-entrypoint.sh"   7 seconds ago       Exited (0) Less than a second ago                            victim
+ ip link show veth0
61: veth0@if60: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-test state UP mode DEFAULT group default qlen 1000
    link/ether de:9b:6c:3d:76:5e brd ff:ff:ff:ff:ff:ff
+ echo '! veth0 still exists'
! veth0 still exists
+ ping -c 2 192.168.0.10
PING 192.168.0.10 (192.168.0.10) 56(84) bytes of data.
64 bytes from 192.168.0.10: icmp_seq=1 ttl=64 time=0.150 ms
64 bytes from 192.168.0.10: icmp_seq=2 ttl=64 time=0.122 ms

--- 192.168.0.10 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1027ms
rtt min/avg/max/mdev = 0.122/0.136/0.150/0.014 ms
+ echo '! container netns 192.168.0.10 still pings'
! container netns 192.168.0.10 still pings
+ grep NETLINK
++ pidof docker-proxy
+ lsof -p 3878
docker-pr 3878 root   22u     sock    0,8      0t0      34228 protocol: NETLINK
+ docker stop bystander
bystander
+ ip link show veth0
Device "veth0" does not exist.
+ echo '> veth0 is now gone'
> veth0 is now gone
#!/bin/sh -uex
test -d /sys/class/net/br-test || (
ip link add br-test type bridge
ip link set br-test up
ip addr add 192.168.0.1/24 dev br-test
)
docker rm -f victim bystander && sleep 2 || true
# setup victim
docker run -d --name victim redis
victim_pid=$(docker inspect -f '{{.State.Pid}}' victim)
ip link add veth0 type veth peer name veth1
ip link set veth0 up master br-test
ip link set veth1 netns $victim_pid
nsenter -t $victim_pid -n ip link set veth1 up
nsenter -t $victim_pid -n ip addr add 192.168.0.10/24 dev veth1
sleep 2
# setup capturing docker-proxy
docker run -d --name bystander -p 6379:6379 redis
sleep 2
echo "> With both containers running..."
docker ps -a
ping -c 2 192.168.0.10 && echo "> victim netns 192.168.0.10 responds to ping "
# trigger zombie
docker stop victim
# diag
echo "> The victim has been stopped, and the veth should be gone"...
docker ps -a
ip link show veth0 && echo '! veth0 still exists'
ping -c 2 192.168.0.10 && echo '! container netns 192.168.0.10 still pings'
lsof -p $(pidof docker-proxy) | grep NETLINK
# make the pain go away?
if false; then
docker stop bystander
ip link show veth0 || echo '> veth0 is now gone'
docker info
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment