WSL Antivirus and Firewall Compatibility


The purpose of this post is to enlighten antivirus (AV) companies to new security considerations for correctly interfacing with Bash on Ubuntu on Windows powered by the Windows Subsystem for Linux (WSL). This post will provide a background description of WSL and its underlying technologies including Pico processes. This, in combination with guidance surrounding new Pico process APIs, will provide the means necessary to prepare AV companies to properly support Pico Processes and WSL.

The Windows Subsystem for Linux

The Windows Subsystem for Linux (WSL) is a collection of components that enables native Linux ELF64 binaries to run on Windows. It was released April 1st 2016 at the Microsoft //Build conference and included as an optional component in the Anniversary Update of Windows 10. It contains both user mode and kernel mode components and is primarily comprised of:

  1. User mode session manager service that handles the Linux instance life cycle
  2. Pico provider drivers (lxss.sys, lxcore.sys) that emulate a Linux kernel by translating Linux system calls
  3. Pico processes that host the unmodified user mode Linux (e.g. /bin/bash)

Pico Processes

As part of Project Drawbridge, the Windows kernel introduced the concept of Pico processes and Pico drivers. Pico processes are OS processes without the trappings of OS services associated with subystems like a Win32 Process Environment Block (PEB). Furthermore, for a Pico process, system calls and user mode exceptions are dispatched to a paired driver.

Pico processes and drivers provide the foundation for the Windows Subsystem for Linux, which runs native unmodified Linux binaries by loading executable ELF binaries into a Pico process’s address space and executes them atop a Linux-compatible layer of syscalls.

WSL File System Interactions

To bridge the gap between Linux and Windows WSL uses two different systems to provide users seamless access to their data. Lxfs allows access to Windows files by emulating full Linux behavior for the internal Linux file system within WSL. DrvFs allows full access to Windows drives and files on NTFS. DrvF enables some of the functionality of Linux file systems, such as case sensitivity and symbolic links, while still supporting interoperability with Windows.

file system graphic

Figure 1: WSL File System Architecture

Windows 10 WSL Antivirus/Firewall Deficiencies

Since WSL was released in the Windows Anniversary Update as a beta feature there was no work done to ensure smooth operation with external AV manufacturers. This has caused a variety of issues that has impacted user experience:

  • prevented users from accessing the internet
  • prevented installation of WSL
  • prevented access to certain directories
  • Caused unexpected file permissions behaviors within the Bash environment

Changes for Improved WSL Antivirus/Firewall Interactions

The Ps notifications exist so kernel mode drivers can run code when a state of the system changes. The expectation is that drivers use these callbacks to build up state about the system which is later used to perform some function. Vendors can use the notifications to develop firewalls or anti-virus software, but the APIs are generic enough that it could be applied to other scenarios.

For the next release of Windows, we are planning to introduce the following changes. We feel that with these additions 3rd party antivirus and firewall vendors should be able to properly interface with WSL without affecting existing threat detection logic.

  • Added the ability to query the subsystem type of processes and threads
  • Extended PS thread and process notifications for subsystems


Process Notify

Original registration code

Status = PsSetCreateProcessNotifyRoutineEx(Callback,FALSE);

New registration code

Type = PsCreateProcessNotifySubsystems; Status = PsSetCreateProcessNotifyRoutineEx2(Type, Callback,FALSE);

Callback Example

void Callback (_In_ HANDLE ParentId, _In_ HANDLE ProcessId, _Inout_opt_ PPS_CREATE_NOTIFY_INFO CreateInfo) {     if (CreateInfo->Flags.IsSubsystemProcess == 0) {         /* Original callback code goes here */     } else {         Type = ProcessSubsystemInformation;         Status = NtQueryInformationProcess(ProcessHandle, Type, &Subsystem, sizeof(Subsystem), NULL);         if (Subsystem == SubsystemInformationTypeWSL) {             /* New callback code to handle WSL processes goes here */         }     } }

Thread Notify

Original registration code

Status = PsSetCreateThreadNotifyRoutine(Callback);

New registration code

Type = PsCreateThreadNotifySubsystems; Status = PsSetCreateThreadNotifyRoutineEx(Type, Callback);

Callback Example

void Callback (_In_ HANDLE ProcssId, _In_ HANDLE ThreadId, _In_ BOOLEAN Create) {     Type = ThreadSubsystemInformation;     Status = NtQueryInformationThread(ThreadHandle, Type, &Subsystem, sizeof(Subsystem), NULL);     if (Subsystem == SubsystemInformationTypeWin32) {         /* Original callback code goes here */     } else if (Subsystem == SubsystemInformationTypeWSL) {         /* New callback code to handle WSL processes goes here */     } }


Windows Kernel-Mode Process and Thread Manager Process and Thread Manager Routines PsSetCreateProcessNotifyRoutineEx