Windows Equivalent to chroot: Process Isolation and File Access Control


1 views

In Unix-like systems, chroot is a powerful mechanism that changes the apparent root directory for a process and its children, effectively isolating them from the rest of the system. Windows administrators and developers often ask about similar capabilities when they need to:

  • Run untrusted applications securely
  • Prevent processes from accessing each other's files
  • Create sandboxed environments

While Windows doesn't have an exact equivalent to chroot, it offers several mechanisms that can achieve similar isolation:

1. Job Objects

Job objects allow you to group processes and set limits on their resource usage:

#include <windows.h>

int main() {
    HANDLE hJob = CreateJobObject(NULL, L"MySandboxJob");
    
    // Set basic UI restrictions
    JOBOBJECT_BASIC_UI_RESTRICTIONS uiRestrictions;
    uiRestrictions.UIRestrictionsClass = JOB_OBJECT_UILIMIT_WRITECLIPBOARD;
    SetInformationJobObject(hJob, JobObjectBasicUIRestrictions, &uiRestrictions, sizeof(uiRestrictions));
    
    // Assign process to job
    STARTUPINFO si = { sizeof(si) };
    PROCESS_INFORMATION pi;
    CreateProcess(NULL, L"notepad.exe", NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
    AssignProcessToJobObject(hJob, pi.hProcess);
    ResumeThread(pi.hThread);
    
    CloseHandle(pi.hThread);
    CloseHandle(pi.hProcess);
    CloseHandle(hJob);
    return 0;
}

2. Windows Containers

For more complete isolation similar to Linux containers, Windows Server 2016+ supports Windows Containers:

# Create a new container
New-Container -Name "MyIsolatedContainer" -ContainerImageName "microsoft/windowsservercore"

# Start the container
Start-Container -Name "MyIsolatedContainer"

# Run a process inside the container
Invoke-Command -ContainerName "MyIsolatedContainer" -ScriptBlock { Start-Process notepad.exe }

To prevent processes from accessing each other's files, consider these approaches:

1. Mandatory Integrity Control

Windows implements Mandatory Integrity Control (MIC) which can restrict file access:

// Set low integrity level for a process
HANDLE hToken;
OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken);

DWORD dwIntegrityLevel = SECURITY_MANDATORY_LOW_RID;
TOKEN_MANDATORY_LABEL tml = {0};
tml.Label.Attributes = SE_GROUP_INTEGRITY;
tml.Label.Sid = GetSidForIntegrityLevel(dwIntegrityLevel);

SetTokenInformation(hToken, TokenIntegrityLevel, &tml, sizeof(tml) + GetLengthSid(tml.Label.Sid));
CloseHandle(hToken);

2. File System Filter Drivers

For advanced scenarios, you can develop a file system filter driver to intercept and control file operations:

NTSTATUS FsFilterDispatchCreate(
    PDEVICE_OBJECT DeviceObject,
    PIRP Irp
) {
    // Check if process is allowed to access this file
    if (!IsAccessAllowed(Irp)) {
        Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
        IoCompleteRequest(Irp, IO_NO_INCREMENT);
        return STATUS_ACCESS_DENIED;
    }
    // Forward the request
    return FsFilterDispatchForward(Irp);
}

When implementing process isolation in Windows:

  • Test thoroughly - some APIs may have unexpected interactions
  • Consider performance overhead of virtualization
  • Document your security boundaries clearly
  • Combine multiple techniques for defense in depth

Several third-party tools provide chroot-like functionality:

  • Docker for Windows (uses Windows containers)
  • Sandboxie (process sandboxing)
  • Microsoft's Windows Sandbox (lightweight VM)

While Windows doesn't have a direct 1:1 equivalent to Unix's chroot, it offers several robust mechanisms for process isolation and file access control. The fundamental difference stems from Windows' security architecture being based on ACLs (Access Control Lists) rather than Unix-style permissions.

1. Job Objects provide process grouping and resource limitations:

HANDLE hJob = CreateJobObject(NULL, L"MyIsolatedJob");
JOBOBJECT_BASIC_LIMIT_INFORMATION jobLimit = {0};
jobLimit.LimitFlags = JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION;
SetInformationJobObject(hJob, JobObjectBasicLimitInformation, &jobLimit, sizeof(jobLimit));

// Assign process to job
AssignProcessToJobObject(hJob, hProcess);

2. Windows Containers (similar to Docker) offer stronger isolation:

docker run --isolation=process -it mcr.microsoft.com/windows/servercore:ltsc2019 cmd

For file isolation, consider these approaches:

Mandatory Integrity Control (MIC):

// Set low integrity level
icacls test.txt /setintegritylevel L

Per-User Virtual Store automatically redirects writes to protected locations.

For enterprise scenarios, consider:

  • Windows Sandbox (Windows 10/11 Pro/Enterprise)
  • Hyper-V Containers
  • AppContainer for UWP apps

Creating an isolated environment using job objects and restricted tokens:

// Create restricted token
HANDLE hRestrictedToken;
CreateRestrictedToken(GetCurrentProcess(), 
    DISABLE_MAX_PRIVILEGE, 
    0, NULL, 0, NULL, 0, NULL, 
    &hRestrictedToken);

// Create process with restricted token
STARTUPINFO si = {sizeof(si)};
PROCESS_INFORMATION pi;
CreateProcessAsUser(hRestrictedToken, NULL, L"notepad.exe", 
    NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);

// Assign to job object
AssignProcessToJobObject(hJob, pi.hProcess);

Remember that Windows security is fundamentally different from Unix. While you can achieve similar isolation goals, the implementation patterns vary significantly.