Windows Subsystem for Linux (WSL)

Posted in linux on December 7, 2016 by Adrian Wyssmann ‐ 9 min read

Introduction

Since the Windows 10 anniversary update, Windows provides the Windows Subsystem for Linux (WSL) with the goal to provide Windows and Linux interoperability.

The Windows Subsystem for Linux (WSL) is a new Windows 10 feature that enables you to run native Linux command-line tools directly on Windows, alongside your traditional Windows desktop and modern store apps.

In other words, WSL executes unmodified Linux ELF64 binaries by emulating a Linux kernel interface on top of the Windows NT kernel - to be clear, this is not Ubuntu running in a virtual machine or in a container. It also allows you to directly invoke Windows binaries from directly from the WSL. This allows us to use the same shell using a mix of Windows and Linux binaries whether it is manipulating files on the file system using tools like vi or launching a graphical Windows editor like notepad. It is also possible to redirect input and output from Windows to Linux binaries and vice versa.

Installation

Before you actually can use it you need to install after you have enabled the Developer Features and then enabling it via “Turn Windows features on and off”. As of today this feature is only available on Windows 10 build 14951 and later.

WSL is NOT a server technology and so will not be available on Server SKUs. WSL is an optional Windows feature and can be enabled via the “Turn Windows features on or off” tool or using PowerShell or DISM via an (elevated) command-line."

Insides

The image below and this site actually explains it pretty well but I will try to summarize it a bit as it also helps me to understand the functionality. As you can see, the WSL consist of several components, which I will have a brief look at.

(c) https://blogs.msdn.microsoft.com/wsl/2016/10/19/windows-and-ubuntu-interoperability/
(c) https://blogs.msdn.microsoft.com/wsl/2016/10/19/windows-and-ubuntu-interoperability/

Linux Instance

Two Bash Shells running in parallel
Two Bash Shells running in parallel

The “Linux Instance” is a genuine Ubuntu user-mode image which is created by Canonical and downloaded when WSL is enabled. The image contains a lot of common tools like awk, sed, grep, ssh, rsync, gpg, curl, wget, vim, emacs, diff, … and you can even use apt-get to install other tools. Yes, there is a limitation what can be run, so for example it is not meant to run graphical desktops or applications.

The entity handling of the Linux instance is the LXSS Service Manager, described below.

Interpreter /init

WSL related processes on host
WSL related processes on host

Instances on “operating-system-level” share the same kernel i.e. it is not possible to run other OS than the host (though you may have different distributions with the same kernel)

  • full virtualized system get its own dedicated set of resource allocation
  • full virtualized are more isolated but therefore also require more resources (e.g. more hw resources, more disk space)
  • startup times of full virtualized is minutes, whereas docker containers are u
root@WIN10:~# ps -aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0      0     0 ?        Ss    2432   0:00 /init
root         2  0.0  0.0      0     0 ?        Ss    2432   0:00 /bin/bash
root        12  0.0  0.0      0     0 ?        R     2432   0:00 ps -aux

Checkout “Launching Processes in WSL” for details on how the this works and how the message flow looks like.

Linux Binaries

(c) https://blogs.msdn.microsoft.com/wsl/2016/05/23/pico-process-overview/
(c) https://blogs.msdn.microsoft.com/wsl/2016/05/23/pico-process-overview/

As mentioned above, the Linux image contains native Linux ELF64 binaries. These unmodified Linux binaries are placed into Pico processes which enables Linux system calls to be directed into the Windows kernel.

Pico processes btw. which were created by the idea of having a lightweight way to run an application in an isolated environment but with the dependencies of the application OS decoupled from the underlying host OS:

A pico process is simply a minimal process that is associated with a pico provider kernel-mode driver. This pico provider surfaces the entire kernel interface as far as the user-mode portion of the process is concerned. The Windows kernel passes all system calls and exceptions that originate from the user-mode portion of a pico process to the pico provider to handle as it sees fit. This allows the pico provider to model a different user/kernel contract separate from what Windows would normally provide.

Kernel Mode drivers

There are 2 kernel mode pico drivers (lxss.sys and lxcore.sys) which are responsible to handle Linux system calls issued by the unmodified Linux binaries. What these drivers do, is providing a Linux-compatible Kernel ABI and API and translating the Linux syscall into an Windows NT equivalent calls. You may have a view to the Release notes which show - at least partially - which syscalls are implemented so far.

For example, the Linux kernel includes things like fork, open, and kill while the Windows NT kernel has the comparable NtCreateProcess, NtOpenFile, and NtTerminateProcess.

Under wsl-system-calls you can find more detailed technical information on how system calls are handled.

LxBus

The LxBus is a socket like inter process communication bus and the communication channel between NT and WSL processes which allow to pass messages and share different things like memory, resources or handles. To establish the communication channel between NT and WSL the process which wants communicates issues an ioctls “register server” to register a LxBus server with the LxCore.sys driver which on successful registration returns a handle or file descriptor to the caller - it’s called LxBus ServerPort. The registered ServerPort object supports a “wait for connection” ioctl - similar to a socket listen call - and allows the the process on the other side to connect to the ServerPort via n “connect to server” ioctl. So in the end both sides of the communication have a reference - the NT process a handles, the WSL a file descriptor to an underlying file object called LxBus MessagePort, which support reading and writing for message passing.

This Microsoft Blog entry goes into more details about this and also explain pretty well the interoperability aspects.

LXSS Service Manager

LXSS Manger Library
LXSS Manger Library

As we have learned above, the /init process is the communication partner on the WSL side whereas on the Windows side it is the NT process (bash.exe). But he actually does not talk directly to the driver directly but rather via the LXSS Service Manager - which is the arbitrator between user mode NT processes and driver. Analog to the /init daemon on the WSL, the LXSS Service Manager is parsing the LxBus messages and marshalls NT handles. Additionally the service is also handling the Linux instance life cycle (Linux processes, threads) and does synchronization around install and uninstall, allowing only one process to do those operations at a time and blocking Linux binaries from being launched while the operation is pending. The service is creating the instance - the first time an NT process requests launching a Linux binary - and terminates the instance when the last NT client closes - termination of the Linux instance includes all processes inside the instance.

LXSS Service Manager is a trigger started service and runs as long as an bash.exe process is running in the system. LXSS Service Manager propagates a COM interface over which the Bash.exe is connected to the Service Manger. Based on this architecture it would be actually possible to create your own NT process which consumes the COM interface of the LXSS Service Manager. On the host machine you can find the related dlls under C:\Windows\System32\lxss

C:\>dir C:\Windows\System32\lxss
 Volume in drive C has no label.
 Volume Serial Number is B8AA-371F

 Directory of C:\Windows\System32\lxss

12/06/2016  01:45 AM           327,168 LxssManager.dll
12/06/2016  01:45 AM            12,288 LxssManagerProxyStub.dll
               2 File(s)        339,456 bytes
               0 Dir(s)  51,788,259,328 bytes free

File System

WSL allows the user to work with files on Linux the way a Linux user is used to but providing full interoperability with the files on the Windows system. This means, the user has direct access to the Windows drives from within the WSL. Both file systems - windows and Linux - are essentially different in data structure (objects in Windows, inodes on Linux) and mounting (driver letter in Windows, mount points in Linux). Linux uses the Virtual File System (VFS) to abstract from the underlying concrete file system letting the applications perform file operations the same way regardless what is underneath (ext, NTFS, NAS, …). There are also special file types and and pseudo file systems supported by Linux. On the other hand, Windows generalizes all system resources into objects. Have a look into this blog entry to get more details.

(c) https://blogs.msdn.microsoft.com/wsl/2016/06/15/wsl-file-system-support
(c) https://blogs.msdn.microsoft.com/wsl/2016/06/15/wsl-file-system-support

So the WSL must translate various Linux file system operations into NT kernel operations and therefore provides a mechanism to access to the Windows volumes on your system but as well take care of the special file systems on Linux, which are not files on a disk. Therefore WSL provides a VFS component which is modeled after VFS on Linux. Underneath it implements different file system plugins which represent files on disk (VolFs, DrvFs), in-memory file system (TmpFs) and pseudo file systems (ProcFs, SysFs, and CgroupFs). Checkout this blog entry to get more details about them.

I mentioned earlier that is is possible to work seamlessly with Windows file from within the WSL - the Windows drivers are mounted under /mnt so we can access or create a file from the Windows disk directly in bash:

WSL access windows fs
WSL access windows fs

But you actually also can access files from Windows which are inside the WSL. The root file system is actually mapped to C:\Users\<username>\AppData\Local\Lxss\rootfs\

access wslfs
access wslfs

IO Redirection and Launching Win32 apps

Beside of the interoperability aspects we already have seen, there are two other things to mention. The IO redirection which works in both directions and allows to you pipe to and from WSL processes as well as use NT files as input or output. This opens the possibility to combine Windows and Linux tools in a single script file - use bash inside windows scripts (by using the -c argument like bash -c 'command string') or use Windows apps within bash scripts. So you could do something like this from a Windows Command Line

PS C:\ProgramData\chocolatey\lib\sysinternals\tools> dir | bash -c "grep whois"
------        6/12/2016  10:09 AM         154264 whois.exe
------        6/12/2016  10:06 AM         169632 whois64.exe

Conclusion

It is an interesting approach which Microsoft follows, especially if you think about possible use cases in an environment where you develop x-platform software. You may write a TFS build script to build the binary for Linux as well as for Windows with the native Windows compiler. I summarized the most important aspects but to get deeper into this topic, especially understand more whats going on under the hood, here are some resources to consider