gns3-server
gns3-server copied to clipboard
Security issue with Docker
It has been reported that it is really easy to access the host filesystem from inside a Docker container which obviously isn't something we want. Here is the report:
Just do: mount /dev/sda* /mnt This will give you root access to the file system.
This isn’t a gns3-thing per-se and I don’t think rootless docker can do what you are doing with containers.
The reason for this is the option --privileged
, that GNS3 uses to start containers.
The same issue arises outside GNS3, when using --privileged
, here an example:
behlers@iMac:~$ docker run -ti alpine
/ # mount /dev/sda4 /mnt
mount: permission denied (are you root?)
/ # exit
behlers@iMac:~$ docker run -ti --privileged alpine
/ # mount /dev/sda4 /mnt
/ # ls /mnt
bin initrd.img.old opt sys
boot lib proc tmp
dev lib64 root usr
etc lost+found run var
home media sbin vmlinuz
initrd.img mnt srv vmlinuz.old
/ # umount /mnt
/ # exit
behlers@iMac:~$
To stop this, someone has to research, what capabilities are really needed for GNS3. Perhaps the handling of docker containers can be changed to run with fewer capabilities. Or some capabilities can be dropped after running the injected /gns3/init.sh
. But all that is a lot of work.
Thanks for the input. If I remember correctly, we need that to move interfaces to the network namespace of a container allowing it to communicate with other nodes in a GNS3 topology.
https://github.com/GNS3/gns3-server/blob/2.2/gns3server/compute/docker/docker_vm.py#L912L916
I'm not sure, docker needs extended privileges for that. I think moving the interfaces to the namespace is done outside docker by ubridge. Therefore ubridge runs with the capabilities cap_net_admin and cap_net_raw.
I assume docker needs some privileges to set IP addresses and routes within the container. Also the handling of persistent directories (uses bind mount) may need some privileges. There may be more reasons for extended privileges, that needs some investigation.
Checked some privilege needs of https://github.com/GNS3/gns3-server/blob/master/gns3server/compute/docker/resources/init.sh:
IP setup works by using only cap_net_admin
:
behlers@iMac:~$ docker run -ti alpine
/ # ip link set eth0 down
ip: ioctl 0x8914 failed: Operation not permitted
/ # ip address add 1.1.1.1/24 dev eth0
ip: RTNETLINK answers: Operation not permitted
/ # ip route add 1.2.3.0/24 via 127.0.0.1
ip: RTNETLINK answers: Operation not permitted
/ # exit
behlers@iMac:~$
behlers@iMac:~$ docker run -ti --cap-add cap_net_admin alpine
/ # ip link set eth0 down
/ # ip link set eth0 up
/ # ip address add 1.1.1.1/24 dev eth0
/ # ip route add 1.2.3.0/24 via 127.0.0.1
/ # exit
behlers@iMac:~$
But most critical is the mount --bind
in https://github.com/GNS3/gns3-server/blob/731152c75a2a6172b9b10ed381651fd812b87cbd/gns3server/compute/docker/resources/init.sh#L43
Allowing that mount would also allow any other mount, which results in this issue. So the implementation of persistent direcoties has to be rewritten to work without mount --bind
.
You are right, we need a workaround for mount --bind "/gns3volumes$i" "$i"
Also, I tried to at least run without privileges by changing https://github.com/GNS3/gns3-server/blob/2.2/gns3server/compute/docker/docker_vm.py#L339L343 to this:
"HostConfig": {
"CapAdd": ["SYS_ADMIN", "NET_ADMIN"],
"SecurityOptions": ["apparmor:unconfined"], # https://github.com/moby/moby/issues/16429
"Binds": mount_binds,
},
Unfortunately, mount gets a permission deny. I tried a few workaround without any success...
The only other solution I can think of would be to use volumes...
https://docs.docker.com/storage/volumes/
This will have to wait for version >= 3.0 since there will be a lot of changes to make it work with volumes