Docker on WSL for Windows 10

Configure Docker for Windows

In the general settings, you’ll want to expose the daemon without TLS. This step is necessary so that the daemon listens on a TCP endpoint. If you don’t do this then you won’t be able to connect from WSL.


You may also want to share any drives you plan on having your source code reside on. This step isn’t necessary but I keep my code on a regular HDD, so I shared my “E” drive too.

Can’t use Docker for Windows?

This is only necessary if you are NOT running Docker for Windows!

No problem, just configure your Docker daemon to use -H tcp:// and --tlsverify=false. Then you can follow along with the rest of this guide exactly.


Here’s the Ubuntu 16 installation notes taken from Docker’s documentation:

This will install the edge channel, change ‘edge’ to ‘stable’ if you want. You may also want to update the Docker Compose version based on the latest release.

# Environment variables you need to set so you don't have to edit the script below.
export DOCKER_CHANNEL=edge

# Update the apt package index.
sudo apt-get update

# Install packages to allow apt to use a repository over HTTPS.
sudo apt-get install -y \
    apt-transport-https \
    ca-certificates \
    curl \

# Add Docker's official GPG key.
curl -fsSL | sudo apt-key add -

# Verify the fingerprint.
sudo apt-key fingerprint 0EBFCD88

# Pick the release channel.
sudo add-apt-repository \
   "deb [arch=amd64] \
   $(lsb_release -cs) \

# Update the apt package index.
sudo apt-get update

# Install the latest version of Docker CE.
sudo apt-get install -y docker-ce

# Allow your user to access the Docker CLI without needing root.
sudo usermod -aG docker $USER

# Install Docker Compose.
sudo curl -L${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose &&
sudo chmod +x /usr/local/bin/docker-compose

At this point you must close your terminal and open a new one so that you can run Docker without sudo. You might as well do it now!

Configure WSL to Connect to Docker for Windows

The next step is to configure WSL so that it knows how to connect to the remote Docker daemon running in Docker for Windows (remember, it’s listening on port 2375).

Open up your ~/.bashrc file and add this line to the bottom:

export DOCKER_HOST=tcp://

Logout of your WSL shell and come back in, or run source ~/.bashrc to reload it now.

If you want to get cute, you could do all of that with this 1 liner:

echo "export DOCKER_HOST=tcp://" >> ~/.bashrc && source ~/.bashrc

You can verify it works by running docker info. You should get back a list of details. If you get a permission denied error then make sure you log out and log back in, because that’s necessary to apply the changes so non-root users can run Docker. That’s what the sudo usermod bit of the long command did in the command chain when installing Docker.

Ensure Volume Mounts Work

The last thing we need to do is set things up so that volume mounts work. This tripped me up for a while because check this out…

When using WSL, Docker for Windows expects you to supply your volume paths in a format that matches this: /c/Users/bcochran/dev/myapp.

But, WSL doesn’t work like that. Instead, it uses the /mnt/c/Users/bcochran/dev/myapp format.

To get things to work for now, you need to bind a custom mount for any drives that you shared with Docker for Windows.

Bind custom mount points to fix Docker for Windows and WSL differences:
sudo mkdir /c
sudo mount --bind /mnt/c /c

You’ll want to repeat those commands for any drives that you shared, such as d or e, etc..

Verify that it works by running: ls -la /c. You should see the same exact output as running ls -la /mnt/cbecause /mnt/c is mounted to /c.

You can use volume mount paths like .:/myapp in your Docker Compose files and everything will work like normal. That’s awesome because that format is what native Linux and MacOS users also use.

It’s worth noting that whenever you run a docker-compose up, you’ll want to make sure you navigate to the /c/Users/bcochran/dev/myapp location first, otherwise your volume won’t work. In other words, never access /mnt/cdirectly.


Automatically set up the bind mount:


You can do that with this 1 liner: echo "sudo mount --bind /mnt/c /c" >> ~/.bashrc && source ~/.bashrc and make sure to repeat the command for any additional drives you shared with Docker for Windows. By the way, you don’t need to mkdir because we already did it.

Allow your user to bind a mount without a root password:

To do that, run the sudo visudo command.

That should open up nano (a text editor). Goto the bottom of the file and add this line: bcochran ALL=(root) NOPASSWD: /bin/mount, but replace “bcochran” with your username.

That just allows your user to execute the sudo mount command without having to supply a password. You can save the file with CTRL+O, confirm and exit with CTRL+X.


The Jupyter service is now updated to the new JupyterLab environment.

If you haven’t used Jupyter before, please try it out. It’s a powerful  notebook environment for interactive programming. It also includes a fully-featured browser-based command-line terminal, which makes a convenient alternative to SSHing.


This update includes:

  • The new JupyterLab environment
  •  support for Julia 0.6.2, Python 3.6, Matlab R2017b and R 3.4.2 kernels.
  • Better web-based terminal, with full support for qsub/qstat and modules
  • Support for packages installed in your personal conda environments within Python notebooks, with

from rcs import *



Meltdown and Spectre

Meltdown and Spectre exploit critical vulnerabilities in modern processors. These hardware vulnerabilities allow programs to steal data which is currently processed on the computer. While programs are typically not permitted to read data from other programs, a malicious program can exploit Meltdown and Spectre to get hold of secrets stored in the memory of other running programs. This might include your passwords stored in a password manager or browser, your personal photos, emails, instant messages and even business-critical documents.

Meltdown and Spectre work on personal computers, mobile devices, and in the cloud. Depending on the cloud provider’s infrastructure, it might be possible to steal data from other customers.


Meltdown breaks the most fundamental isolation between user applications and the operating system. This attack allows a program to access the memory, and thus also the secrets, of other programs and the operating system.

If your computer has a vulnerable processor and runs an unpatched operating system, it is not safe to work with sensitive information without the chance of leaking the information. This applies both to personal computers as well as cloud infrastructure. Luckily, there are software patches against Meltdown.


Spectre breaks the isolation between different applications. It allows an attacker to trick error-free programs, which follow best practices, into leaking their secrets. In fact, the safety checks of said best practices actually increase the attack surface and may make applications more susceptible to Spectre

Spectre is harder to exploit than Meltdown, but it is also harder to mitigate. However, it is possible to prevent specific known exploits based on Spectre through software patches.

Out of Order / Speculative Execution

Modern CPUs do out-of-order execution whenever they see a branch (if/switch etc). They will typically execute code for multiple branches while the conditional is evaluated. So

if (a+b*c == d) {
  // first branch
else {
  // second branch

will involve both the conditions running simultaneously while the condition is evaluated. Once the CPU has the answer (say “true”), it scraps the work from the second branch and commits the first branch. The instructions that are executed out-of-order are called “transient instructions” till they are committed.

The Bug

The code in both the branches can do a lot of things. The assumption is that all of these things will be rolled back once a branch is picked. The attack is possible because cache-state is something that does not seem to be rolled back. This is the crux behind both Meltdown and Spectre attacks.

Meltdown specifically works because “any-random-memory-access” seems to work while in a transient instruction. This attack allows a program to access the memory, and thus also the secrets, of other programs and the operating system.

CPU Cache?

Reading data from RAM is slow when you are a CPU. CPU cache times are in the order of 1-10ns, while RAM access takes >100ns. Almost any memory read/write is placed in the cache: The cache is a mirror image of memory activity on the computer.

Cache Timing?

Let us say I have this piece of code:

$secrets = ["secret1", "secret2", "secret3", "secret4", "realSecret"];
$realSecret = $secrets[4];

This loads the real secret in memory. An attacker then does the following:

  1. Clear the CPU cache
  2. Runs the above program
  3. Try to access the specific memory address

The above access results in an error, and raises an exception. However, the attacker knows that the secret is in one of the 5 possible locations. Since only one of these is ever read by the actual program, it can repeatedly run the program and time the exception to figure out which one of the locations was being read. The one which is being read is cached, and the exception will be raised much faster as a result.

Cache Timing attacks are the building blocks of Meltdown, which uses them as a side channel to leak data.

Now that we’ve explained cache-timing attacks (which can tell you “what-memory” is being used by another program), we can get back to Meltdown. Meltdown happens because:

  • CPUs do not rollback CPU-cache after speculative execution, and
  • You can manipulate the cache in those transient instructions to create a “side-channel” and
  • Intel CPUs allow you to read memory from other processes while in a transient instruction.

Meltdown consists of 3 steps:

Step 1. The content of an attacker-chosen memory location, which is inaccessible to the attacker, is loaded into a register.

Step 2. A transient instruction accesses a cache line based on the secret content of the register.

Step 3. The attacker uses Flush+Reload to determine the accessed cache line and hence the secret stored at the chosen memory location.

In code:

c = *kernel_memory_address;
b = probe[c];

There are several caveats:

Exception Suppressing

If you try to actually read kernel-space memory directly, your program will crash. Meltdown works around this by making sure that the memory is only read in transient instructions that will be rolled back.

So you wrap the above code with:

if (check_function()) {

And make sure that check_function always returns false. What happens is that the CPU starts running the code inside meltdown function before it has the result from the check.

Cache Lines

CPU cache are broken down into several cache-lines. Think of them as lookup hashes for your CPU cache. Instead of accessing single-byte (probe[c]), meltdown multiples the memory addresses by 4096 to make sure that the code accessess a specific cache line. So more like:

b = probe[c * 4096];

If you’re wondering why we are doing a read instead of just printing c, or maybe copying it to another place, it is because CPU designers considered that, and rollback those instructions correctly, so any writes cannot be used to exfiltrate the data from a transient instruction.


Sometimes, the exception is raised before the code executes, and the value of c is set to 0 as part of the rollback. This makes the attack unreliable. So, the attack decides to ignore zero-value-reads and only prime the cache if it reads a non-zero value. Thus the whole code becomes

if (check_function()) {
  label retry:
  c = *kernel_memory_address;
  if (c != 0)
    b = probe[c * 4096];
    goto retry;

The similar assembly code (from the paper) is:

; rcx = kernel address
; rbx = probe array
mov al, byte [rcx] ; try to read rcx
shl rax, 0xc ; multiply the read value with 4096 by shifting left 12(0xc) bits
jz retry ; retry if the above is zero
mov rbx, qword [rbx + rax] ; read specific entry in rbx

The special condition where c actually is zero is handled in the cache-timing where we notice no memory address has been cached and decide it was a zero.

Windows Update


Microsoft have determined that your computer must have antivirus compatible with their new Spectre/Meltdown security patch. If you do not have the correct antivirus installed (and this includes having no antivirus) Windows Update will cease to function as of this month.

That’s right if you do not have the registry setting below you will not be getting any windows updates.

Windows 10, Windows 8.1, Windows Server 2012 R2 and Windows Server 2016

Microsoft recommends all customers protect their devices by running a compatible and supported antivirus program. Customers can take advantage of built-in antivirus protection, Windows Defender Antivirus, for Windows 8.1 and Windows 10 devices or a compatible third-party antivirus application. The antivirus software must set a registry key as described below in order to receive the January 2018 security updates.

Windows 7 SP1 and Windows Server 2008 R2 SP1 Customers

In a default installation of Windows 7 SP1 or Windows Server 2008 R2 SP1, customers will not have an antivirus application installed by default. In these situations, Microsoft recommends installing a compatible and supported antivirus application such as Microsoft Security Essentials or a third-party anti-virus  application. The anti-virus software must set a registry key as described below in order to receive the January 2018 security updates.

Customers without Antivirus

In cases where customers can’t install or run antivirus software, Microsoft recommends manually setting the registry key as described below in order to receive the January 2018 security updates.

Setting the Registry Key

Customers will not receive the January 2018 security updates (or any subsequent security updates) and will not be protected from security vulnerabilities unless their antivirus software vendor sets the following registry key:

Value=”cadca5fe-87d3-4b96-b7fb-a231484277cc” Type=”REG_DWORD”

Local Mirrors for Ubuntu, CentOS, Raspbian, Debian and PuTTY

We know that our researchers build upon many free software projects, as we do ourselves. And so, like many institutions, we choose to help with the distribution of this software by providing a ‘mirror’ of the software repositories for as many distributions & projects as we possibly can. Such a service is provided free of charge to our students, and the general public too.


You can access files from our new Mirror Service.

Update Problems?

CentOS 7 – Remove Old Kernels

If your /boot partition is getting filled, you may wish to automatically remove old kernels. I find the best way to do this is to install the yum utilities package and then use a command to delete all but 2 kernels (just in case there is a problem with the latest one).

sudo yum install yum-utils -y
sudo package-cleanup --oldkernels --count=2