Docker Tips : mind the --privileged flag

TL;DR

If you use the --privileged flag when running a container, make sure you know what you are doing.

Setup a test environment

To illustrate the usage of the --privileged flag, we’ll first create a VM on VirtualBox using Vagrant.

Note: if you do not know this tool (another one from Hashicorp), I recommend you give it a try as it’s super convenient.

# Init the vagrant box (based on bionic64)
$ vagrant init ubuntu/bionic64
# Launch the VM
$ vagrant up
# ssh in the newly created VM
$ vagrant ssh

The next few commands (from Docker documentation) install Docker on our newly created Linux box.

$ sudo apt-get update
$ sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
software-properties-common
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
$ sudo add-apt-repository \
“deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable”
$ sudo apt-get update
$ sudo apt-get install docker-ce

Purpose of the --privileged flag

Running a container with the --privileged flag gives all the capabilities to the container and also access to the host’s devices (everything that is under the /dev folder). Let’s check this out.

List of available devices from a container running without the --privileged flag
List of available devices from a container running with the --privileged flag

That means the container has access to the hard drives attached to the host. As a lot of containers run with the fully privileged root user, the consequences can be quite disastrous.

Doing nasty things with the privileged flag

Let’s run a shell in an alpine based container and provide it some additional capabilities with the --privileged flag.

$ docker run -ti --privileged alpine

Once in the container, let’s use the access to the host’s devices to do some really bad things like deleting a disk partition.

/ # fdisk -l
Disk /dev/sda: 10 GB, 10737418240 bytes, 20971520 sectors
4209 cylinders, 106 heads, 47 sectors/track
Units: cylinders of 4982 * 512 = 2550784 bytes
Device  Boot StartCHS    EndCHS        StartLBA     EndLBA    Sectors  Size Id Type
/dev/sda1 * 0,32,33 281,105,47 2048 20971486 20969439 9.9G 83 Linux
Disk /dev/sdb: 10 MB, 10485760 bytes, 20480 sectors
10 cylinders, 64 heads, 32 sectors/track
Units: cylinders of 2048 * 512 = 1048576 bytes
Disk /dev/sdb doesn't contain a valid partition table
/ # fdisk /dev/sda
The number of cylinders for this disk is set to 4209.
There is nothing wrong with that, but this is larger than 1024,
and could in certain setups cause problems with:
1) software that runs at boot time (e.g., old versions of LILO)
2) booting and partitioning software from other OSs
(e.g., DOS FDISK, OS/2 FDISK)
Command (m for help): d
Selected partition 1
Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table
fdisk: WARNING: rereading partition table failed, kernel still uses old table: Resource busy

Then, we exit from the container and reboot the host.

root@ubuntu-bionic:/home/vagrant# reboot

If we look at the Virtualbox console, it seems something bad happened… the VM cannot start anymore.

We have quickly illustrated here how to use the fdisk utility manually to harm our host from within a privileged container. But… what if this task is automated in a container without we knowing about it ? Other disk utilities, like parted or sfdisk, could make this automation quite simple.

Summary

If you run an image that does not come from a trusted source, be careful if it requires the --privileged flag. Of course, there are cases when this flag is needed, for instance when running containers on devices like Raspberry Pi. It is indeed used to access the GPIO interfaces and to be able to interact with the external world (and make a LED blinks :) ).