mirror of https://github.com/microsoft/WSL
Merge branch 'user/ptrivedi/cont-network-mode' of https://github.com/microsoft/WSL into user/ptrivedi/cont-network-mode
This commit is contained in:
commit
c19e851f52
|
|
@ -29,7 +29,7 @@ parameters:
|
|||
type: object
|
||||
default:
|
||||
- target: "wsl;libwsl;wslg;wslservice;wslhost;wslrelay;wslinstaller;wslinstall;initramfs;wslserviceproxystub;wslsettings;wslinstallerproxystub;testplugin;wslaclient;wsltests"
|
||||
pattern: "wsl.exe,libwsl.dll,wslg.exe,wslservice.exe,wslhost.exe,wslrelay.exe,wslinstaller.exe,wslinstall.dll,wslserviceproxystub.dll,wslsettings.dll,wslsettings.exe,wslinstallerproxystub.dll,wsldevicehost.dll,WSLDVCPlugin.dll,testplugin.dll,wsldeps.dll,wslaclient.dll"
|
||||
pattern: "wsl.exe,libwsl.dll,wslg.exe,wslservice.exe,wslhost.exe,wslrelay.exe,wslinstaller.exe,wslinstall.dll,wslserviceproxystub.dll,wslsettings/wslsettings.dll,wslsettings/wslsettings.exe,wslinstallerproxystub.dll,wsldevicehost.dll,WSLDVCPlugin.dll,testplugin.dll,wsldeps.dll,wslaclient.dll"
|
||||
- target: "msixgluepackage"
|
||||
pattern: "gluepackage.msix"
|
||||
- target: "msipackage"
|
||||
|
|
@ -125,6 +125,11 @@ stages:
|
|||
ob_sdl_codeSignValidation_excludes: -|**testbin\**
|
||||
Codeql.PublishDatabaseLog: true
|
||||
Codeql.SourceRoot: src
|
||||
packageStagingDir: '$(Build.SourcesDirectory)\packageStagingDir'
|
||||
${{ if eq(parameters.isRelease, 'true') }}:
|
||||
packageInputDirArg: '-DPACKAGE_INPUT_DIR=$(packageStagingDir)'
|
||||
${{ else }}:
|
||||
packageInputDirArg: ''
|
||||
|
||||
steps:
|
||||
|
||||
|
|
@ -171,7 +176,7 @@ stages:
|
|||
displayName: "CMake ${{ platform }}"
|
||||
inputs:
|
||||
workingDirectory: "."
|
||||
cmakeArgs: . --fresh -A ${{ platform }} -DCMAKE_BUILD_TYPE=Release -DCMAKE_SYSTEM_VERSION=10.0.26100.0 -DPACKAGE_VERSION=$(version.WSL_PACKAGE_VERSION) -DWSL_NUGET_PACKAGE_VERSION=$(version.WSL_NUGET_PACKAGE_VERSION) -DSKIP_PACKAGE_SIGNING=${{ parameters.isRelease }} -DOFFICIAL_BUILD=${{ parameters.isRelease }} -DPIPELINE_BUILD_ID=$(Build.BuildId) -DVSO_ORG=${{ parameters.vsoOrg }} -DVSO_PROJECT=${{ parameters.vsoProject }} -DWSL_BUILD_WSL_SETTINGS=true
|
||||
cmakeArgs: . --fresh -A ${{ platform }} -DCMAKE_BUILD_TYPE=Release -DCMAKE_SYSTEM_VERSION=10.0.26100.0 -DPACKAGE_VERSION=$(version.WSL_PACKAGE_VERSION) -DWSL_NUGET_PACKAGE_VERSION=$(version.WSL_NUGET_PACKAGE_VERSION) -DSKIP_PACKAGE_SIGNING=${{ parameters.isRelease }} -DOFFICIAL_BUILD=${{ parameters.isRelease }} -DPIPELINE_BUILD_ID=$(Build.BuildId) -DVSO_ORG=${{ parameters.vsoOrg }} -DVSO_PROJECT=${{ parameters.vsoProject }} -DWSL_BUILD_WSL_SETTINGS=true $(packageInputDirArg)\${{ platform }}
|
||||
|
||||
# This additional Restore NuGet package task is added as a workaround for WSL Settings to have its packages restored properly.
|
||||
# Without this, building wsl settings may encounter the following error:
|
||||
|
|
@ -201,7 +206,7 @@ stages:
|
|||
AuthSignCertName: ${{ parameters.esrp.AuthSignCertName }}
|
||||
AppRegistrationClientId: ${{ parameters.esrp.AppRegistrationClientId }}
|
||||
AppRegistrationTenantId: ${{ parameters.esrp.AppRegistrationTenantId }}
|
||||
FolderPath: "bin\\${{ platform }}"
|
||||
FolderPath: "bin\\${{ platform }}\\Release"
|
||||
Pattern: "${{ target.pattern }}"
|
||||
UseMSIAuthentication: true
|
||||
EsrpClientId: ${{ parameters.esrp.EsrpClientId }}
|
||||
|
|
@ -229,20 +234,27 @@ stages:
|
|||
}
|
||||
]
|
||||
|
||||
# Replace the intermediate wslsettings binaries file with the signed versions so that any future steps building wslsettings will use the signed versions
|
||||
- task: PowerShell@2
|
||||
displayName: 'Replace wslsettings binaries in intermediate folder with signed versions'
|
||||
condition: and(succeeded(), eq('${{ parameters.isRelease }}', true))
|
||||
inputs:
|
||||
targetType: inline
|
||||
script: |
|
||||
$arch = '${{ platform }}'
|
||||
$wslsettingsbinpath = "bin\$arch\release\wslsettings"
|
||||
$wslsettingsobjpath = "src\windows\wslsettings\obj\$arch\release"
|
||||
# Update the timestamp of wslsettings.exe so that it doesn't get rebuilt
|
||||
(Get-Item $wslsettingsbinpath\wslsettings.exe).LastWriteTime = Get-Date
|
||||
Copy-Item $wslsettingsbinpath\wslsettings.dll $wslsettingsobjpath\wslsettings.dll -Force
|
||||
Copy-Item $wslsettingsbinpath\wslsettings.exe $wslsettingsobjpath\apphost.exe -Force
|
||||
- task: PowerShell@2
|
||||
displayName: "Copy signed ${{ target.target }} to staging (${{ platform }})"
|
||||
condition: and(succeeded(), eq('${{ parameters.isRelease }}', true))
|
||||
inputs:
|
||||
targetType: inline
|
||||
script: |
|
||||
$arch = '${{ platform }}'
|
||||
$pattern = '${{ target.pattern }}'
|
||||
$inputDir = "bin\$arch\Release"
|
||||
$outputDir = "$(packageStagingDir)\$arch"
|
||||
New-Item -ItemType Directory -Path "$outputDir\wslsettings" -Force
|
||||
foreach ($file in $pattern.Split(',')) {
|
||||
$sourcePath = Join-Path $inputDir $file
|
||||
if (Test-Path $sourcePath) {
|
||||
$destPath = Join-Path $outputDir $file
|
||||
Write-Host "Copying signed file: $sourcePath -> $destPath"
|
||||
Copy-Item -Path $sourcePath -Destination $destPath -Force
|
||||
} else {
|
||||
Write-Warning "File not found: $sourcePath"
|
||||
}
|
||||
}
|
||||
|
||||
- script: cmake --build . --config Release -- -m
|
||||
displayName: "Build installer msix and tests (${{ platform }})"
|
||||
|
|
@ -388,7 +400,7 @@ stages:
|
|||
Move-Item -Path "bin\x64\cloudtest" -Destination "$(ob_outputDirectory)\testbin\x64\cloudtest"
|
||||
Move-Item -Path "tools\test\test-setup.ps1" -Destination "$(ob_outputDirectory)\testbin\test-setup.ps1"
|
||||
Move-Item -Path "tools\test\CloudTest-Setup.bat" -Destination "$(ob_outputDirectory)\testbin\CloudTest-Setup.bat"
|
||||
Move-Item -Path "tools\wsl.wprp" -Destination "$(ob_outputDirectory)\testbin\wsl.wprp"
|
||||
Move-Item -Path "diagnostics\wsl.wprp" -Destination "$(ob_outputDirectory)\testbin\wsl.wprp"
|
||||
Move-Item -Path "test\linux\unit_tests" -Destination "$(ob_outputDirectory)\testbin\unit_tests"
|
||||
|
||||
Move-Item -Path bundle\release\* -Destination $(ob_outputDirectory)\bundle
|
||||
|
|
@ -417,3 +429,4 @@ stages:
|
|||
|
||||
- task: CodeQL3000Finalize@0
|
||||
condition: ${{ and(parameters.isNightly, eq(variables['Build.SourceBranch'], 'refs/heads/main'))}}
|
||||
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ find_nuget_package(Microsoft.WSL.Kernel KERNEL /build/native)
|
|||
find_nuget_package(Microsoft.WSL.bsdtar BSDTARD /build/native/bin)
|
||||
find_nuget_package(Microsoft.WSL.LinuxSdk LINUXSDK /)
|
||||
find_nuget_package(Microsoft.WSL.TestDistro TEST_DISTRO /)
|
||||
find_nuget_package(Microsoft.WSL.WSLATestDistro WSLA_TEST_DISTRO /)
|
||||
find_nuget_package(Microsoft.WSL.WslaRootfs WSLA_TEST_DISTRO /build/native/bin/${TARGET_PLATFORM})
|
||||
find_nuget_package(Microsoft.WSLg WSLG /build/native/bin)
|
||||
find_nuget_package(StrawberryPerl PERL /)
|
||||
find_nuget_package(vswhere VSWHERE /tools)
|
||||
|
|
@ -376,7 +376,7 @@ if (DEFINED WSL_DEV_BINARY_PATH) # Development shortcut to make the package smal
|
|||
WSL_GPU_LIB_PATH="${WSL_DEV_BINARY_PATH}/lib")
|
||||
|
||||
if (NOT OFFICIAL_BUILD AND ${TARGET_PLATFORM} STREQUAL "x64")
|
||||
add_compile_definitions(WSLA_TEST_DISTRO_PATH="${WSLA_TEST_DISTRO_SOURCE_DIR}/wslatestrootfs.vhd")
|
||||
add_compile_definitions(WSLA_TEST_DISTRO_PATH="${WSLA_TEST_DISTRO_SOURCE_DIR}/rootfs.vhd")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
|
|
|||
153
NOTICE.txt
153
NOTICE.txt
|
|
@ -643,6 +643,159 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
|||
Microsoft.NETCore.App.Runtime.win-arm64 10.0.0 - MIT
|
||||
|
||||
|
||||
Copyright (c) 2021
|
||||
Copyright (c) Six Labors
|
||||
(c) Microsoft Corporation
|
||||
Copyright (c) 2022 FormatJS
|
||||
Copyright (c) Andrew Arnott
|
||||
Copyright 2019 LLVM Project
|
||||
Copyright (c) 1998 Microsoft
|
||||
Copyright 2018 Daniel Lemire
|
||||
Copyright (c) .NET Foundation
|
||||
Copyright 1995-2022 Mark Adler
|
||||
Copyright 1995-2024 Mark Adler
|
||||
Copyright (c) 2011, Google Inc.
|
||||
Copyright (c) 2020 Dan Shechter
|
||||
(c) 1997-2005 Sean Eron Anderson
|
||||
Copyright (c) 2015 Andrew Gallant
|
||||
Copyright (c) 2022, Wojciech Mula
|
||||
Copyright (c) 2017 Yoshifumi Kawai
|
||||
Copyright (c) 2022, Geoff Langdale
|
||||
Copyright (c) 2005-2020 Rich Felker
|
||||
Copyright (c) 2012-2021 Yann Collet
|
||||
Copyright (c) Microsoft Corporation
|
||||
Copyright (c) 2007 James Newton-King
|
||||
Copyright (c) 1991-2024 Unicode, Inc.
|
||||
Copyright (c) 2013-2017, Alfred Klomp
|
||||
Copyright (c) 2018 Nemanja Mijailovic
|
||||
Copyright 2012 the V8 project authors
|
||||
Copyright (c) 1999 Lucent Technologies
|
||||
Copyright (c) 2008-2016, Wojciech Mula
|
||||
Copyright (c) 2011-2020 Microsoft Corp
|
||||
Copyright (c) 2015-2017, Wojciech Mula
|
||||
Copyright (c) 2015-2018, Wojciech Mula
|
||||
Copyright (c) 2005-2007, Nick Galbreath
|
||||
Copyright (c) 2015 The Chromium Authors
|
||||
Copyright (c) 2018 Alexander Chermyanin
|
||||
Copyright (c) The Internet Society 1997
|
||||
Copyright (c) 2004-2006 Intel Corporation
|
||||
Copyright (c) 2011-2015 Intel Corporation
|
||||
Copyright (c) 2013-2017, Milosz Krajewski
|
||||
Copyright (c) 2016-2017, Matthieu Darbois
|
||||
Copyright (c) The Internet Society (2003)
|
||||
Copyright (c) .NET Foundation Contributors
|
||||
(c) 1995-2024 Jean-loup Gailly and Mark Adler
|
||||
Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se>
|
||||
Copyright (c) .NET Foundation and Contributors
|
||||
Copyright (c) 2012 - present, Victor Zverovich
|
||||
Copyright (c) 2006 Jb Evain (jbevain@gmail.com)
|
||||
Copyright (c) 2008-2020 Advanced Micro Devices, Inc.
|
||||
Copyright (c) 2019 Microsoft Corporation, Daan Leijen
|
||||
Copyright (c) 2011 Novell, Inc (http://www.novell.com)
|
||||
Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com)
|
||||
Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors
|
||||
Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com
|
||||
Copyright 1995-2024 Jean-loup Gailly and Mark Adler Qkkbal
|
||||
Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
|
||||
Portions (c) International Organization for Standardization 1986
|
||||
Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers
|
||||
Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip
|
||||
Copyright (c) 1980, 1986, 1993 The Regents of the University of California
|
||||
Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California
|
||||
Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) .NET Foundation and Contributors
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
---------------------------------------------------------
|
||||
|
||||
---------------------------------------------------------
|
||||
|
||||
Microsoft.NETCore.App.Runtime.win-x64 10.0.0 - MIT
|
||||
|
||||
|
||||
Copyright (c) 2021
|
||||
Copyright (c) Six Labors
|
||||
(c) Microsoft Corporation
|
||||
Copyright (c) 2022 FormatJS
|
||||
Copyright (c) Andrew Arnott
|
||||
Copyright 2019 LLVM Project
|
||||
Copyright (c) 1998 Microsoft
|
||||
Copyright 2018 Daniel Lemire
|
||||
Copyright (c) .NET Foundation
|
||||
Copyright 1995-2022 Mark Adler
|
||||
Copyright 1995-2024 Mark Adler
|
||||
Copyright (c) 2011, Google Inc.
|
||||
Copyright (c) 2020 Dan Shechter
|
||||
(c) 1997-2005 Sean Eron Anderson
|
||||
Copyright (c) 2015 Andrew Gallant
|
||||
Copyright (c) 2022, Wojciech Mula
|
||||
Copyright (c) 2017 Yoshifumi Kawai
|
||||
Copyright (c) 2022, Geoff Langdale
|
||||
Copyright (c) 2005-2020 Rich Felker
|
||||
Copyright (c) 2012-2021 Yann Collet
|
||||
Copyright (c) Microsoft Corporation
|
||||
Copyright (c) 2007 James Newton-King
|
||||
Copyright (c) 1991-2024 Unicode, Inc.
|
||||
Copyright (c) 2013-2017, Alfred Klomp
|
||||
Copyright (c) 2018 Nemanja Mijailovic
|
||||
Copyright 2012 the V8 project authors
|
||||
Copyright (c) 1999 Lucent Technologies
|
||||
Copyright (c) 2008-2016, Wojciech Mula
|
||||
Copyright (c) 2011-2020 Microsoft Corp
|
||||
Copyright (c) 2015-2017, Wojciech Mula
|
||||
Copyright (c) 2015-2018, Wojciech Mula
|
||||
Copyright (c) 2005-2007, Nick Galbreath
|
||||
Copyright (c) 2015 The Chromium Authors
|
||||
Copyright (c) 2018 Alexander Chermyanin
|
||||
Copyright (c) The Internet Society 1997
|
||||
Copyright (c) 2004-2006 Intel Corporation
|
||||
Copyright (c) 2011-2015 Intel Corporation
|
||||
Copyright (c) 2013-2017, Milosz Krajewski
|
||||
Copyright (c) 2016-2017, Matthieu Darbois
|
||||
Copyright (c) The Internet Society (2003)
|
||||
Copyright (c) .NET Foundation Contributors
|
||||
(c) 1995-2024 Jean-loup Gailly and Mark Adler
|
||||
Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se>
|
||||
Copyright (c) .NET Foundation and Contributors
|
||||
Copyright (c) 2012 - present, Victor Zverovich
|
||||
Copyright (c) 2006 Jb Evain (jbevain@gmail.com)
|
||||
Copyright (c) 2008-2020 Advanced Micro Devices, Inc.
|
||||
Copyright (c) 2019 Microsoft Corporation, Daan Leijen
|
||||
Copyright (c) 2011 Novell, Inc (http://www.novell.com)
|
||||
Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com)
|
||||
Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors
|
||||
Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com
|
||||
Copyright 1995-2024 Jean-loup Gailly and Mark Adler Qkkbal
|
||||
Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
|
||||
Portions (c) International Organization for Standardization 1986
|
||||
Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers
|
||||
Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip
|
||||
Copyright (c) 1980, 1986, 1993 The Regents of the University of California
|
||||
Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California
|
||||
Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
<EventProvider Id="wslclient" Name="8cbb7724-7223-5d6f-8137-564dac45104d"/>
|
||||
<EventProvider Id="wslaservice" Name="0383CE62-8F86-4766-AFB2-9D66A7FB1E90"/>
|
||||
<EventProvider Id="wslapi" Name="beb94edf-1a7b-5058-0696-ff9e6b1798d1"/>
|
||||
<EventProvider Id="vfpext" Name="9F2660EA-CFE7-428F-9850-AECA612619B0" />
|
||||
<EventProvider Id="vm_chipset" Name="de9ba731-7f33-4f44-98c9-6cac856b9f83"/>
|
||||
<EventProvider Id="vmcompute_dll" Name="AF7FD3A7-B248-460C-A9F5-FEC39EF8468C"/>
|
||||
<EventProvider Id="vmcompute" Name="17103E3F-3C6E-4677-BB17-3B267EB5BE57"/>
|
||||
|
|
@ -20,7 +21,7 @@
|
|||
<EventProvider Id="vmwp" Name="51DDFA29-D5C8-4803-BE4B-2ECB715570FE"/>
|
||||
<EventProvider Id="9p" Name="e13c8d52-b153-571f-78c5-1d4098af2a1e"/>
|
||||
<EventProvider Id="9p_errors" Name="06C601B3-6957-4F8C-A15F-74875B24429D" />
|
||||
<EventProvider Id="p9rdr" Name="bb1d36f0-e0e0-48cc-9493-fef0e3d0b28c" />
|
||||
<EventProvider Id="p9rdr" Name="bb1d36f0-e0e0-48cc-9493-fef0e3d0b28c" NonPagedMemory="true" Strict="true"/>
|
||||
<EventProvider Id="mup" Name="20c46239-d059-4214-a11e-7d6769cbe020" />
|
||||
<EventProvider Id="rfsmon" Name="51734B23-5B7E-4892-BA8E-45BC110B735C" />
|
||||
<EventProvider Id="hyperv_storage" Name="c7ad62c6-5c99-5a1b-bbc4-0821ae5b765e" />
|
||||
|
|
@ -116,6 +117,7 @@
|
|||
<EventProviderId Value="wsl_devicehost"/>
|
||||
<EventProviderId Value="wslclient"/>
|
||||
<EventProviderId Value="wslapi"/>
|
||||
<EventProviderId Value="vfpext"/>
|
||||
<EventProviderId Value="vm_chipset"/>
|
||||
<EventProviderId Value="vmcompute_dll"/>
|
||||
<EventProviderId Value="vmcompute"/>
|
||||
|
|
|
|||
|
|
@ -1194,7 +1194,7 @@ Zie de herstelinstructies voor: https://aka.ms/wsldiskmountrecovery</value>
|
|||
<value>Een absoluut Windows-pad naar een aangepaste Linux-kernel.</value>
|
||||
</data>
|
||||
<data name="Settings_CustomKernelPathBrowseButton.Content" xml:space="preserve">
|
||||
<value>Koor kernels bladeren</value>
|
||||
<value>Door kernels bladeren</value>
|
||||
</data>
|
||||
<data name="Settings_CustomKernelPathTextBox.AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Aangepaste kernel</value>
|
||||
|
|
|
|||
|
|
@ -1,16 +1,29 @@
|
|||
set(BIN ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_BUILD_TYPE})
|
||||
|
||||
# For pipeline builds, use PACKAGE_INPUT_DIR if specified (contains signed binaries)
|
||||
# For local builds, use bin directory
|
||||
if(DEFINED PACKAGE_INPUT_DIR)
|
||||
message(STATUS "Using signed binaries from ${PACKAGE_INPUT_DIR} for MSI packaging")
|
||||
else()
|
||||
set(PACKAGE_INPUT_DIR ${BIN})
|
||||
endif()
|
||||
|
||||
set(OUTPUT_PACKAGE ${BIN}/wsl.msi)
|
||||
set(PACKAGE_WIX_IN ${CMAKE_CURRENT_LIST_DIR}/package.wix.in)
|
||||
set(PACKAGE_WIX ${BIN}/package.wix)
|
||||
set(CAB_CACHE ${BIN}/cab)
|
||||
set(BINARIES wsl.exe;wslg.exe;wslhost.exe;wslrelay.exe;wslservice.exe;wslserviceproxystub.dll;init;initrd.img;wslinstall.dll;wslaserviceproxystub.dll;wslaservice.exe;wsladiag.exe)
|
||||
|
||||
set(WINDOWS_BINARIES wsl.exe;wslg.exe;wslhost.exe;wslrelay.exe;wslservice.exe;wslserviceproxystub.dll;wslinstall.dll;wslaservice.exe;wsladiag.exe)
|
||||
if (WSL_BUILD_WSL_SETTINGS)
|
||||
list(APPEND BINARIES_DEPENDENCIES "wslsettings/wslsettings.dll;wslsettings/wslsettings.exe;libwsl.dll")
|
||||
list(APPEND WINDOWS_BINARIES "wslsettings/wslsettings.dll;wslsettings/wslsettings.exe;libwsl.dll")
|
||||
endif()
|
||||
|
||||
set(BINARIES_DEPENDENCIES)
|
||||
foreach(binary ${BINARIES})
|
||||
foreach(binary ${WINDOWS_BINARIES})
|
||||
list(APPEND BINARIES_DEPENDENCIES "${PACKAGE_INPUT_DIR}/${binary}")
|
||||
endforeach()
|
||||
|
||||
set(LINUX_BINARIES init;initrd.img)
|
||||
foreach(binary ${LINUX_BINARIES})
|
||||
list(APPEND BINARIES_DEPENDENCIES "${BIN}/${binary}")
|
||||
endforeach()
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
|
||||
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
|
||||
<Package Name="Windows Subsystem for Linux" Language="1033" InstallerVersion="500" Version="${PACKAGE_VERSION}" Manufacturer="Microsoft Corporation" UpgradeCode="6D5B792B-1EDC-4DE9-8EAD-201B820F8E82" Scope="perMachine" Compressed="${COMPRESS_PACKAGE}">
|
||||
<MajorUpgrade AllowDowngrades="yes" Disallow="no" />
|
||||
<MediaTemplate EmbedCab="yes" />
|
||||
|
|
@ -19,22 +19,22 @@
|
|||
<DirectoryRef Id="INSTALLDIR">
|
||||
<Component Id="wsl" Guid="F0C8D6BA-1502-41E7-BF72-D93DFA134730" UninstallWhenSuperseded="yes" DisableRegistryReflection="yes" Bitness="always64">
|
||||
<RemoveFile Id="CleanUpWSLShortCut" Directory="ProgramMenuFolder" Name="WSL" On="uninstall"/>
|
||||
<File Id="wsl.exe" Name="wsl.exe" Source="${BIN}/wsl.exe" KeyPath="yes">
|
||||
<File Id="wsl.exe" Name="wsl.exe" Source="${PACKAGE_INPUT_DIR}/wsl.exe" KeyPath="yes">
|
||||
<Shortcut Id="WSLShortcut" Name="WSL" Description="Windows Subsystem for Linux" Arguments="--cd ~" Advertise="yes" Directory="ProgramMenuFolder" Icon="wsl.ico">
|
||||
<ShortcutProperty Key="System.AppUserModel.ID" Value="Microsoft.WSL"/>
|
||||
<ShortcutProperty Key="System.AppUserModel.ToastActivatorCLSID" Value="{2B9C59C3-98F1-45C8-B87B-12AE3C7927E8}"/>
|
||||
</Shortcut>
|
||||
</File>
|
||||
|
||||
<File Id="wslg.exe" Name="wslg.exe" Source="${BIN}/wslg.exe" />
|
||||
<File Id="wsladiag.exe" Name="wsladiag.exe" Source="${BIN}/wsladiag.exe" />
|
||||
<File Id="wslhost.exe" Name="wslhost.exe" Source="${BIN}/wslhost.exe" />
|
||||
<File Id="wslrelay.exe" Name="wslrelay.exe" Source="${BIN}/wslrelay.exe" />
|
||||
<File Id="wslserviceproxystub.dll" Name="wslserviceproxystub.dll" Source="${BIN}/wslserviceproxystub.dll" />
|
||||
<File Id="wsldeps.dll" Name="wsldeps.dll" Source="${BIN}/wsldeps.dll" />
|
||||
<File Id="wslg.exe" Name="wslg.exe" Source="${PACKAGE_INPUT_DIR}/wslg.exe" />
|
||||
<File Id="wsladiag.exe" Name="wsladiag.exe" Source="${PACKAGE_INPUT_DIR}/wsladiag.exe" />
|
||||
<File Id="wslhost.exe" Name="wslhost.exe" Source="${PACKAGE_INPUT_DIR}/wslhost.exe" />
|
||||
<File Id="wslrelay.exe" Name="wslrelay.exe" Source="${PACKAGE_INPUT_DIR}/wslrelay.exe" />
|
||||
<File Id="wslserviceproxystub.dll" Name="wslserviceproxystub.dll" Source="${PACKAGE_INPUT_DIR}/wslserviceproxystub.dll" />
|
||||
<File Id="wsldeps.dll" Name="wsldeps.dll" Source="${PACKAGE_INPUT_DIR}/wsldeps.dll" />
|
||||
|
||||
<?if "${WSL_BUILD_WSL_SETTINGS}" = "true" ?>
|
||||
<File Id="libwsl.dll" Name="libwsl.dll" Source="${BIN}/libwsl.dll" />
|
||||
<File Id="libwsl.dll" Name="libwsl.dll" Source="${PACKAGE_INPUT_DIR}/libwsl.dll" />
|
||||
<?endif?>
|
||||
|
||||
<?if "${WSL_DEV_BINARY_PATH}" = "" ?>
|
||||
|
|
@ -44,7 +44,7 @@
|
|||
|
||||
<!-- Temporary runtime VHD. TODO: Update once the final VHD is available. -->
|
||||
<?if "${WSL_DEV_BINARY_PATH}" = "" AND "${TARGET_PLATFORM}" = "x64" ?>
|
||||
<File Id="wslarootfs.vhd" Name="wslarootfs.vhd" Source="${WSLA_TEST_DISTRO_SOURCE_DIR}/wslatestrootfs.vhd"/>
|
||||
<File Id="wslarootfs.vhd" Name="wslarootfs.vhd" Source="${WSLA_TEST_DISTRO_SOURCE_DIR}/rootfs.vhd"/>
|
||||
<?endif?>
|
||||
|
||||
<!-- Installation folder -->
|
||||
|
|
@ -231,7 +231,7 @@
|
|||
</RegistryKey>
|
||||
|
||||
<!-- Session 0 service -->
|
||||
<File Id="wslservice.exe" Source="${BIN}/wslservice.exe" KeyPath="yes" />
|
||||
<File Id="wslservice.exe" Source="${PACKAGE_INPUT_DIR}/wslservice.exe" KeyPath="yes" />
|
||||
<ServiceInstall Name="WSLService" DisplayName="WSL Service" Description="WSL Service" Start="auto" Type="ownProcess" ErrorControl="normal" Account="LocalSystem" Vital="yes" Interactive="no" />
|
||||
|
||||
<!-- The service is stopped on uninstall and upgrade.
|
||||
|
|
@ -345,6 +345,7 @@
|
|||
</RegistryKey>
|
||||
|
||||
<!-- wsldevicehost.dll -->
|
||||
<!-- TODO: WSL currently has two AppID registrations for wsldevicehost, is that needed? -->
|
||||
<RegistryKey Root="HKCR" Key="AppID\{C457EA11-5486-4174-B90D-089909EDB170}">
|
||||
<RegistryValue Name="DllSurrogate" Value="" Type="string" />
|
||||
<RegistryValue Name="AppIDFlags" Value="2048" Type="integer" />
|
||||
|
|
@ -354,9 +355,42 @@
|
|||
<RegistryValue Name="LaunchPermission" Value="01000480580000006800000000000000140000000200440003000000000014000B00000001010000000000050B000000000014000B00000001010000000000050A000000000014000B0000000101000000000005120000000102000000000005200000002002000001020000000000052000000020020000" Type="binary" />
|
||||
</RegistryKey>
|
||||
|
||||
<!-- WslDeviceHost_VirtioNet -->
|
||||
<!-- WslDeviceHost WSLA_VIRTIO_FS_ADMIN_CLASS_ID -->
|
||||
<RegistryKey Root="HKCR" Key="CLSID\{8F7C2A3B-D9E4-4C1F-A2B8-5E3D7C9F1A6E}">
|
||||
<RegistryValue Value="WslDeviceHost_VirtioFsAdmin" Type="string" />
|
||||
<RegistryValue Name="AppId" Value="{C457EA11-5486-4174-B90D-089909EDB170}" Type="string" />
|
||||
|
||||
<RegistryKey Key="InProcServer32">
|
||||
<RegistryValue Value="[INSTALLDIR]wsldevicehost.dll" Type="string" />
|
||||
<RegistryValue Name="ThreadingModel" Value="Both" Type="string" />
|
||||
</RegistryKey>
|
||||
</RegistryKey>
|
||||
|
||||
<!-- WslDeviceHost WSLA_VIRTIO_FS_CLASS_ID -->
|
||||
<RegistryKey Root="HKCR" Key="CLSID\{06ED032F-C528-41C1-B75D-905EEE823BBA}">
|
||||
<RegistryValue Value="WslDeviceHost_VirtioFs" Type="string" />
|
||||
<RegistryValue Name="AppId" Value="{C457EA11-5486-4174-B90D-089909EDB170}" Type="string" />
|
||||
|
||||
<RegistryKey Key="InProcServer32">
|
||||
<RegistryValue Value="[INSTALLDIR]wsldevicehost.dll" Type="string" />
|
||||
<RegistryValue Name="ThreadingModel" Value="Both" Type="string" />
|
||||
</RegistryKey>
|
||||
</RegistryKey>
|
||||
|
||||
<!-- WslDeviceHost WSLA_VIRTIO_NET_CLASS_ID -->
|
||||
<RegistryKey Root="HKCR" Key="CLSID\{7B3C9A42-8E1F-4D5A-9F2E-C4A7B8D3E6F1}">
|
||||
<RegistryValue Value="WslDeviceHost_Net" Type="string" />
|
||||
<RegistryValue Value="WslDeviceHost_VirtioNet" Type="string" />
|
||||
<RegistryValue Name="AppId" Value="{C457EA11-5486-4174-B90D-089909EDB170}" Type="string" />
|
||||
|
||||
<RegistryKey Key="InProcServer32">
|
||||
<RegistryValue Value="[INSTALLDIR]wsldevicehost.dll" Type="string" />
|
||||
<RegistryValue Name="ThreadingModel" Value="Both" Type="string" />
|
||||
</RegistryKey>
|
||||
</RegistryKey>
|
||||
|
||||
<!-- WslDeviceHost WSLA_VIRTIO_PMEM_CLASS_ID -->
|
||||
<RegistryKey Root="HKCR" Key="CLSID\{ABB755FC-1B86-4255-83E2-E5787ABCF6C2}">
|
||||
<RegistryValue Value="WslDeviceHost_VirtioPmem" Type="string" />
|
||||
<RegistryValue Name="AppId" Value="{C457EA11-5486-4174-B90D-089909EDB170}" Type="string" />
|
||||
|
||||
<RegistryKey Key="InProcServer32">
|
||||
|
|
@ -380,8 +414,8 @@
|
|||
<File Id="rdpnanoTransport.dll" Source="${MSRDC_SOURCE_DIR}/${TARGET_PLATFORM}/rdpnanoTransport.dll" />
|
||||
<File Id="RdpWinStlHelper.dll" Source="${MSRDC_SOURCE_DIR}/${TARGET_PLATFORM}/RdpWinStlHelper.dll" />
|
||||
<?endif?>
|
||||
<File Id="wsldevicehost.dll" Source="${BIN}/wsldevicehost.dll" />
|
||||
<File Id="${WSLG_TS_PLUGIN_DLL}" Source="${BIN}/${WSLG_TS_PLUGIN_DLL}" />
|
||||
<File Id="wsldevicehost.dll" Source="${PACKAGE_INPUT_DIR}/wsldevicehost.dll" />
|
||||
<File Id="${WSLG_TS_PLUGIN_DLL}" Source="${PACKAGE_INPUT_DIR}/${WSLG_TS_PLUGIN_DLL}" />
|
||||
|
||||
<!-- MSRDC Plugin registration -->
|
||||
<RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Terminal Server Client\Default\OptionalAddIns\WSLDVC_PACKAGE">
|
||||
|
|
@ -431,7 +465,7 @@
|
|||
<ComponentGroup Id="wslsettings" Directory="WSLSETTINGS" Source="${BIN}/wslsettings">
|
||||
<Component Id="wslsettingsnonserver" Guid="AB166073-8855-492B-95C8-C6E5939B66A5" Bitness="always64" DisableRegistryReflection="yes" UninstallWhenSuperseded="yes" Condition="MsiNTProductType = 1">
|
||||
<RemoveFile Id="CleanUpWSLSettingsShortCutNonServer" Directory="ProgramMenuFolder" Name="WSLSettings" On="uninstall"/>
|
||||
<File Id="wslsettings.exe_nonserver" Source="${BIN}/wslsettings/wslsettings.exe" KeyPath="yes" ShortName="kyk8fs6a.exe">
|
||||
<File Id="wslsettings.exe_nonserver" Source="${PACKAGE_INPUT_DIR}/wslsettings/wslsettings.exe" KeyPath="yes" ShortName="kyk8fs6a.exe">
|
||||
<Shortcut Id="WSLSettingsShortcutNonServer" Name="WSL Settings" Description="Windows Subsystem for Linux Settings" Advertise="yes" Directory="ProgramMenuFolder" Icon="wsl.ico">
|
||||
<ShortcutProperty Key="System.AppUserModel.IsSystemComponent" Value="true"/>
|
||||
</Shortcut>
|
||||
|
|
@ -462,7 +496,7 @@
|
|||
</Component>
|
||||
<Component Id="wslsettingsserver" Guid="EE2D69A0-4F55-4EC5-9576-4FAD70BC798E" Bitness="always64" DisableRegistryReflection="yes" UninstallWhenSuperseded="yes" Condition="MsiNTProductType > 1">
|
||||
<RemoveFile Id="CleanUpWSLSettingsShortCutServer" Directory="ProgramMenuFolder" Name="WSLSettings" On="uninstall"/>
|
||||
<File Id="wslsettings.exe_server" Source="${BIN}/wslsettings/wslsettings.exe" KeyPath="yes" ShortName="kyk8fs6b.exe">
|
||||
<File Id="wslsettings.exe_server" Source="${PACKAGE_INPUT_DIR}/wslsettings/wslsettings.exe" KeyPath="yes" ShortName="kyk8fs6b.exe">
|
||||
<Shortcut Id="WSLSettingsShortcutServer" Name="WSL Settings" Description="Windows Subsystem for Linux Settings" Advertise="yes" Directory="ProgramMenuFolder" Icon="wsl.ico"/>
|
||||
</File>
|
||||
<!-- Protocol registration -->
|
||||
|
|
@ -489,7 +523,10 @@
|
|||
</RegistryKey>
|
||||
</RegistryKey>
|
||||
</Component>
|
||||
<Files Include="*.dll"/>
|
||||
<File Id="wslsettings.dll" Source="${PACKAGE_INPUT_DIR}/wslsettings/wslsettings.dll"/>
|
||||
<Files Include="*.dll">
|
||||
<Exclude Files="wslsettings.dll" />
|
||||
</Files>
|
||||
<Files Include="*.exe">
|
||||
<Exclude Files="wslsettings.exe" />
|
||||
</Files>
|
||||
|
|
@ -525,8 +562,8 @@
|
|||
|
||||
</Feature>
|
||||
|
||||
<Binary Id="wslinstall.dll" SourceFile="${BIN}/wslinstall.dll" />
|
||||
<Binary Id="msixpackage" SourceFile="${BIN}/gluepackage.msix"/>
|
||||
<Binary Id="wslinstall.dll" SourceFile="${PACKAGE_INPUT_DIR}/wslinstall.dll" />
|
||||
<Binary Id="msixpackage" SourceFile="${PACKAGE_INPUT_DIR}/gluepackage.msix"/>
|
||||
|
||||
<CustomAction Id="ValidateInstall"
|
||||
Impersonate="no"
|
||||
|
|
@ -699,3 +736,4 @@
|
|||
<Property Id="MSIRMSHUTDOWN" Value="0" Secure="yes" />
|
||||
</Package>
|
||||
</Wix>
|
||||
|
||||
|
|
|
|||
|
|
@ -26,4 +26,3 @@
|
|||
<clear />
|
||||
</disabledPackageSources>
|
||||
</configuration>
|
||||
|
||||
|
|
|
|||
|
|
@ -18,11 +18,11 @@
|
|||
<package id="Microsoft.WSL.bsdtar" version="0.0.2-2" />
|
||||
<package id="Microsoft.WSL.Dependencies.amd64fre" version="10.0.27820.1000-250318-1700.rs-base2-hyp" targetFramework="native" />
|
||||
<package id="Microsoft.WSL.Dependencies.arm64fre" version="10.0.27820.1000-250318-1700.rs-base2-hyp" targetFramework="native" />
|
||||
<package id="Microsoft.WSL.DeviceHost" version="1.0.0-20251202.1" />
|
||||
<package id="Microsoft.WSL.DeviceHost" version="1.1.6-0" />
|
||||
<package id="Microsoft.WSL.Kernel" version="6.6.114.1-1" targetFramework="native" />
|
||||
<package id="Microsoft.WSL.LinuxSdk" version="1.20.0" targetFramework="native" />
|
||||
<package id="Microsoft.WSL.TestDistro" version="2.5.7-47" />
|
||||
<package id="Microsoft.WSL.WSLATestDistro" version="0.1.0" />
|
||||
<package id="Microsoft.WSL.WslaRootfs" version="0.1.0" />
|
||||
<package id="Microsoft.WSLg" version="1.0.71" />
|
||||
<package id="Microsoft.Xaml.Behaviors.WinUI.Managed" version="3.0.0" />
|
||||
<package id="StrawberryPerl" version="5.32.1.1" />
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@
|
|||
#include <netinet/ip.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <linux/unistd.h>
|
||||
#include <linux/sock_diag.h>
|
||||
#include <linux/inet_diag.h>
|
||||
#include <lxwil.h>
|
||||
#include <linux/if_tun.h>
|
||||
|
||||
|
|
@ -21,85 +23,67 @@
|
|||
#include "SecCompDispatcher.h"
|
||||
#include "seccomp_defs.h"
|
||||
#include "CommandLine.h"
|
||||
#include "NetlinkChannel.h"
|
||||
#include "NetlinkTransactionError.h"
|
||||
|
||||
#define TCP_LISTEN 10
|
||||
|
||||
namespace {
|
||||
|
||||
std::vector<sockaddr_storage> ParseTcpFile(int family, FILE* file)
|
||||
std::vector<sockaddr_storage> QueryListeningSockets(NetlinkChannel& channel)
|
||||
{
|
||||
char* line = nullptr;
|
||||
auto freeLine = wil::scope_exit([&line]() { free(line); });
|
||||
|
||||
// Skip the first line which contains a header.
|
||||
size_t lineLength = 0;
|
||||
auto bytesRead = getline(&line, &lineLength, file);
|
||||
THROW_LAST_ERROR_IF(bytesRead < 0);
|
||||
|
||||
// Each line contains information about TCP sockets on the system, the fields
|
||||
// we are interested are for sockets that are or have been listening:
|
||||
// 1: Socket address and port number
|
||||
// 3: Socket status
|
||||
std::vector<sockaddr_storage> sockets{};
|
||||
while ((bytesRead = getline(&line, &lineLength, file)) != -1)
|
||||
try
|
||||
{
|
||||
sockaddr_storage sock{};
|
||||
int index = 0;
|
||||
int status = 0;
|
||||
for (char *sp, *field = strtok_r(line, " \n", &sp); field != nullptr; field = strtok_r(NULL, " \n", &sp))
|
||||
inet_diag_req_v2 message{};
|
||||
message.sdiag_protocol = IPPROTO_TCP;
|
||||
message.idiag_states = (1 << TCP_LISTEN);
|
||||
|
||||
auto onMessage = [&](const NetlinkResponse& response) {
|
||||
for (const auto& e : response.Messages<inet_diag_msg>(SOCK_DIAG_BY_FAMILY))
|
||||
{
|
||||
const auto* payload = e.Payload();
|
||||
sockaddr_storage sock{};
|
||||
|
||||
if (payload->idiag_family == AF_INET)
|
||||
{
|
||||
auto* ipv4 = reinterpret_cast<sockaddr_in*>(&sock);
|
||||
ipv4->sin_family = AF_INET;
|
||||
ipv4->sin_addr.s_addr = payload->id.idiag_src[0];
|
||||
ipv4->sin_port = payload->id.idiag_sport;
|
||||
}
|
||||
else if (payload->idiag_family == AF_INET6)
|
||||
{
|
||||
auto* ipv6 = reinterpret_cast<sockaddr_in6*>(&sock);
|
||||
ipv6->sin6_family = AF_INET6;
|
||||
static_assert(sizeof(ipv6->sin6_addr.s6_addr32) == sizeof(payload->id.idiag_src));
|
||||
memcpy(ipv6->sin6_addr.s6_addr32, payload->id.idiag_src, sizeof(ipv6->sin6_addr.s6_addr32));
|
||||
ipv6->sin6_port = payload->id.idiag_sport;
|
||||
}
|
||||
|
||||
sockets.emplace_back(sock);
|
||||
}
|
||||
};
|
||||
|
||||
// Query IPv4 listening sockets.
|
||||
{
|
||||
if (index == 1)
|
||||
{
|
||||
int port;
|
||||
const char* portString = strchr(field, ':');
|
||||
if (portString == nullptr)
|
||||
{
|
||||
break;
|
||||
}
|
||||
portString += 1;
|
||||
port = static_cast<int>(strtol(portString, nullptr, 16));
|
||||
if (port == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (family == AF_INET)
|
||||
{
|
||||
sockaddr_in ipv4Sock{};
|
||||
ipv4Sock.sin_family = family;
|
||||
ipv4Sock.sin_addr.s_addr = strtol(field, nullptr, 16);
|
||||
ipv4Sock.sin_port = port;
|
||||
memcpy(&sock, &ipv4Sock, sizeof(ipv4Sock));
|
||||
}
|
||||
else if (family == AF_INET6)
|
||||
{
|
||||
sockaddr_in6 ipv6Sock{};
|
||||
ipv6Sock.sin6_family = family;
|
||||
ipv6Sock.sin6_port = port;
|
||||
for (int part = 0; part < 4; ++part)
|
||||
{
|
||||
char next[5];
|
||||
next[4] = 0;
|
||||
memcpy(next, field + part * 4, 4);
|
||||
ipv6Sock.sin6_addr.__in6_union.__s6_addr32[part] = strtol(next, nullptr, 16);
|
||||
}
|
||||
memcpy(&sock, &ipv6Sock, sizeof(ipv6Sock));
|
||||
}
|
||||
}
|
||||
else if (index == 3)
|
||||
{
|
||||
status = static_cast<int>(strtol(field, nullptr, 16));
|
||||
break;
|
||||
}
|
||||
|
||||
index += 1;
|
||||
message.sdiag_family = AF_INET;
|
||||
auto transaction = channel.CreateTransaction(message, SOCK_DIAG_BY_FAMILY, NLM_F_DUMP);
|
||||
transaction.Execute(onMessage);
|
||||
}
|
||||
|
||||
if ((status == TCP_LISTEN) && (sock.ss_family != 0))
|
||||
// Query IPv6 listening sockets.
|
||||
{
|
||||
sockets.emplace_back(sock);
|
||||
message.sdiag_family = AF_INET6;
|
||||
auto transaction = channel.CreateTransaction(message, SOCK_DIAG_BY_FAMILY, NLM_F_DUMP);
|
||||
transaction.Execute(onMessage);
|
||||
}
|
||||
}
|
||||
catch (const NetlinkTransactionError& e)
|
||||
{
|
||||
// Log but don't fail - network state might be temporarily unavailable
|
||||
LOG_ERROR("Failed to query listening sockets via sock_diag: {}", e.what());
|
||||
}
|
||||
|
||||
return sockets;
|
||||
}
|
||||
|
|
@ -127,12 +111,12 @@ LX_GNS_PORT_LISTENER_RELAY SockToRelayMessage(const sockaddr_storage& sock)
|
|||
{
|
||||
auto ipv4 = reinterpret_cast<const sockaddr_in*>(&sock);
|
||||
message.Address[0] = ipv4->sin_addr.s_addr;
|
||||
message.Port = ipv4->sin_port;
|
||||
message.Port = ntohs(ipv4->sin_port);
|
||||
}
|
||||
else if (sock.ss_family == AF_INET6)
|
||||
{
|
||||
auto ipv6 = reinterpret_cast<const sockaddr_in6*>(&sock);
|
||||
message.Port = ipv6->sin6_port;
|
||||
message.Port = ntohs(ipv6->sin6_port);
|
||||
memcpy(message.Address, ipv6->sin6_addr.__in6_union.__s6_addr, sizeof(message.Address));
|
||||
}
|
||||
return message;
|
||||
|
|
@ -177,53 +161,23 @@ bool IsSameSockAddr(const sockaddr_storage& left, const sockaddr_storage& right)
|
|||
{
|
||||
auto leftIpv6 = reinterpret_cast<const sockaddr_in6*>(&left);
|
||||
auto rightIpv6 = reinterpret_cast<const sockaddr_in6*>(&right);
|
||||
if (leftIpv6->sin6_port != rightIpv6->sin6_port)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (int part = 0; part < 4; ++part)
|
||||
{
|
||||
if (leftIpv6->sin6_addr.__in6_union.__s6_addr32[part] != rightIpv6->sin6_addr.__in6_union.__s6_addr32[part])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
FATAL_ERROR("Unrecognized socket family {}", left.ss_family);
|
||||
return false;
|
||||
return (leftIpv6->sin6_port == rightIpv6->sin6_port && memcmp(&leftIpv6->sin6_addr, &rightIpv6->sin6_addr, sizeof(in6_addr)) == 0);
|
||||
}
|
||||
|
||||
FATAL_ERROR("Unrecognized socket family {}", left.ss_family);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Start looking for ports bound to localhost or wildcard.
|
||||
int ScanProcNetTCP(wsl::shared::SocketChannel& channel)
|
||||
// Monitor listening TCP sockets using sock_diag netlink interface.
|
||||
int MonitorListeningSockets(wsl::shared::SocketChannel& channel)
|
||||
{
|
||||
// Periodically scan procfs for listening TCP sockets.
|
||||
NetlinkChannel netlinkChannel(SOCK_RAW, NETLINK_SOCK_DIAG);
|
||||
std::vector<sockaddr_storage> relays{};
|
||||
int result = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
std::vector<sockaddr_storage> sockets;
|
||||
wil::unique_file tcp4File{fopen("/proc/net/tcp", "r")};
|
||||
if (tcp4File)
|
||||
{
|
||||
sockets = ParseTcpFile(AF_INET, tcp4File.get());
|
||||
}
|
||||
|
||||
wil::unique_file tcp6File{fopen("/proc/net/tcp6", "r")};
|
||||
if (tcp6File)
|
||||
{
|
||||
auto ipv6Sockets = ParseTcpFile(AF_INET6, tcp6File.get());
|
||||
sockets.insert(sockets.end(), ipv6Sockets.begin(), ipv6Sockets.end());
|
||||
}
|
||||
|
||||
if (!tcp4File && !tcp6File)
|
||||
{
|
||||
LOG_ERROR("Failed to open /proc/net/tcp and /proc/net/tcp6, closing port relay");
|
||||
return 1;
|
||||
}
|
||||
auto sockets = QueryListeningSockets(netlinkChannel);
|
||||
|
||||
// Stop any relays that no longer match listening ports.
|
||||
std::erase_if(relays, [&](const auto& entry) {
|
||||
|
|
@ -267,9 +221,7 @@ int ScanProcNetTCP(wsl::shared::SocketChannel& channel)
|
|||
}
|
||||
|
||||
// Sleep before scanning again.
|
||||
//
|
||||
// TODO: Investigate using EBPF notifications instead of a sleep.
|
||||
sleep(1);
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
@ -433,7 +385,7 @@ try
|
|||
|
||||
if (ScanForPorts)
|
||||
{
|
||||
return ScanProcNetTCP(channel);
|
||||
return MonitorListeningSockets(channel);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1741,7 +1741,7 @@ Return Value:
|
|||
TimeoutSeconds.value(),
|
||||
[&]() {
|
||||
errno = wil::ResultFromCaughtException();
|
||||
return errno == ENOENT || errno == ENXIO || errno == EIO;
|
||||
return errno == ENOENT || errno == ENXIO || errno == EIO || ((strcmp(Type, VIRTIO_FS_TYPE) == 0) && (errno == EINVAL));
|
||||
});
|
||||
}
|
||||
else
|
||||
|
|
@ -1752,7 +1752,7 @@ Return Value:
|
|||
catch (...)
|
||||
{
|
||||
errno = wil::ResultFromCaughtException();
|
||||
LOG_ERROR("mount({}, {}, {}, 0x{}x, {}) failed {}", Source, Target, Type, MountFlags, Options, errno);
|
||||
LOG_ERROR("mount({}, {}, {}, {:#x}, {}) failed {}", Source, Target, Type, MountFlags, Options, errno);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1584,9 +1584,10 @@ struct WSLA_MOUNT
|
|||
enum MountType : uint8_t
|
||||
{
|
||||
None,
|
||||
Chroot = 1,
|
||||
OverlayFs = 2,
|
||||
KernelModules = 4
|
||||
ReadOnly = 1,
|
||||
Chroot = 2,
|
||||
OverlayFs = 4,
|
||||
KernelModules = 8
|
||||
};
|
||||
|
||||
char Buffer[];
|
||||
|
|
|
|||
|
|
@ -64,6 +64,30 @@ GUID DeviceHostProxy::AddNewDevice(const GUID& Type, const wil::com_ptr<IPlan9Fi
|
|||
return instanceId;
|
||||
}
|
||||
|
||||
void DeviceHostProxy::RemoveDevice(const GUID& Type, const GUID& InstanceId)
|
||||
{
|
||||
{
|
||||
auto lock = m_devicesLock.lock_exclusive();
|
||||
THROW_HR_IF(E_CHANGED_STATE, m_devicesShutdown);
|
||||
THROW_HR_IF(E_INVALIDARG, m_devices.find(InstanceId) == m_devices.end());
|
||||
|
||||
m_devices.erase(InstanceId);
|
||||
}
|
||||
|
||||
// N.B. Removing the FlexIov device is best effort since not all versions of Windows support it.
|
||||
try
|
||||
{
|
||||
ModifySettingRequest<FlexibleIoDevice> request;
|
||||
request.RequestType = ModifyRequestType::Remove;
|
||||
request.ResourcePath = L"VirtualMachine/Devices/FlexibleIov/";
|
||||
request.ResourcePath += wsl::shared::string::GuidToString<wchar_t>(InstanceId, wsl::shared::string::GuidToStringFlags::None);
|
||||
request.Settings.EmulatorId = Type;
|
||||
request.Settings.HostingModel = FlexibleIoDeviceHostingModel::ExternalRestricted;
|
||||
wsl::windows::common::hcs::ModifyComputeSystem(m_system.get(), wsl::shared::ToJsonW(request).c_str());
|
||||
}
|
||||
CATCH_LOG()
|
||||
}
|
||||
|
||||
void DeviceHostProxy::AddRemoteFileSystem(const GUID& ImplementationClsid, const std::wstring& Tag, const wil::com_ptr<IPlan9FileSystem>& Plan9Fs)
|
||||
{
|
||||
auto lock = m_lock.lock_exclusive();
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ public:
|
|||
|
||||
GUID AddNewDevice(const GUID& Type, const wil::com_ptr<IPlan9FileSystem>& Plan9Fs, const std::wstring& VirtIoTag);
|
||||
|
||||
void RemoveDevice(const GUID& Type, const GUID& InstanceId);
|
||||
|
||||
void AddRemoteFileSystem(const GUID& ImplementationClsid, const std::wstring& Tag, const wil::com_ptr<IPlan9FileSystem>& Plan9Fs);
|
||||
|
||||
wil::com_ptr<IPlan9FileSystem> GetRemoteFileSystem(const GUID& ImplementationClsid, std::wstring_view Tag);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,15 @@ GuestDeviceManager::GuestDeviceManager(_In_ const std::wstring& machineId, _In_
|
|||
{
|
||||
}
|
||||
|
||||
GuestDeviceManager::~GuestDeviceManager()
|
||||
{
|
||||
try
|
||||
{
|
||||
m_deviceHostSupport->Shutdown();
|
||||
}
|
||||
CATCH_LOG()
|
||||
}
|
||||
|
||||
_Requires_lock_not_held_(m_lock)
|
||||
GUID GuestDeviceManager::AddGuestDevice(
|
||||
_In_ const GUID& DeviceId, _In_ const GUID& ImplementationClsid, _In_ PCWSTR AccessName, _In_opt_ PCWSTR Options, _In_ PCWSTR Path, _In_ UINT32 Flags, _In_ HANDLE UserToken)
|
||||
|
|
@ -40,18 +49,20 @@ GUID GuestDeviceManager::AddHdvShareWithOptions(
|
|||
if (!server)
|
||||
{
|
||||
server = wil::CoCreateInstance<IPlan9FileSystem>(ImplementationClsid, (CLSCTX_LOCAL_SERVER | CLSCTX_ENABLE_CLOAKING | CLSCTX_ENABLE_AAA));
|
||||
AddRemoteFileSystem(ImplementationClsid, c_defaultDeviceTag.c_str(), server);
|
||||
m_deviceHostSupport->AddRemoteFileSystem(ImplementationClsid, c_defaultDeviceTag.c_str(), server);
|
||||
}
|
||||
|
||||
THROW_IF_FAILED(server->AddSharePath(nameWithOptions.c_str(), Path, Flags));
|
||||
}
|
||||
|
||||
// This requires more privileges than the user may have, so impersonation is disabled.
|
||||
return AddNewDevice(DeviceId, server, AccessName);
|
||||
return m_deviceHostSupport->AddNewDevice(DeviceId, server, AccessName);
|
||||
}
|
||||
|
||||
_Requires_lock_not_held_(m_lock)
|
||||
GUID GuestDeviceManager::AddNewDevice(_In_ const GUID& deviceId, _In_ const wil::com_ptr<IPlan9FileSystem>& server, _In_ PCWSTR tag)
|
||||
{
|
||||
auto guestDeviceLock = m_lock.lock_exclusive();
|
||||
return m_deviceHostSupport->AddNewDevice(deviceId, server, tag);
|
||||
}
|
||||
|
||||
|
|
@ -135,9 +146,9 @@ wil::com_ptr<IPlan9FileSystem> GuestDeviceManager::GetRemoteFileSystem(_In_ REFC
|
|||
return m_deviceHostSupport->GetRemoteFileSystem(clsid, tag);
|
||||
}
|
||||
|
||||
void GuestDeviceManager::Shutdown()
|
||||
try
|
||||
_Requires_lock_not_held_(m_lock)
|
||||
void GuestDeviceManager::RemoveGuestDevice(_In_ const GUID& DeviceId, _In_ const GUID& InstanceId)
|
||||
{
|
||||
m_deviceHostSupport->Shutdown();
|
||||
auto guestDeviceLock = m_lock.lock_exclusive();
|
||||
m_deviceHostSupport->RemoveDevice(DeviceId, InstanceId);
|
||||
}
|
||||
CATCH_LOG()
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ class GuestDeviceManager
|
|||
{
|
||||
public:
|
||||
GuestDeviceManager(_In_ const std::wstring& machineId, _In_ const GUID& runtimeId);
|
||||
~GuestDeviceManager();
|
||||
|
||||
_Requires_lock_not_held_(m_lock)
|
||||
GUID AddGuestDevice(
|
||||
|
|
@ -33,6 +34,7 @@ public:
|
|||
_In_ UINT32 Flags,
|
||||
_In_ HANDLE UserToken);
|
||||
|
||||
_Requires_lock_not_held_(m_lock)
|
||||
GUID AddNewDevice(_In_ const GUID& deviceId, _In_ const wil::com_ptr<IPlan9FileSystem>& server, _In_ PCWSTR tag);
|
||||
|
||||
void AddRemoteFileSystem(_In_ REFCLSID clsid, _In_ PCWSTR tag, _In_ const wil::com_ptr<IPlan9FileSystem>& server);
|
||||
|
|
@ -41,7 +43,8 @@ public:
|
|||
|
||||
wil::com_ptr<IPlan9FileSystem> GetRemoteFileSystem(_In_ REFCLSID clsid, _In_ std::wstring_view tag);
|
||||
|
||||
void Shutdown();
|
||||
_Requires_lock_not_held_(m_lock)
|
||||
void RemoveGuestDevice(_In_ const GUID& DeviceId, _In_ const GUID& InstanceId);
|
||||
|
||||
private:
|
||||
_Requires_lock_held_(m_lock)
|
||||
|
|
|
|||
|
|
@ -169,18 +169,6 @@ RunningWSLAProcess::ProcessResult RunningWSLAProcess::WaitAndCaptureOutput(DWORD
|
|||
return result;
|
||||
}
|
||||
|
||||
ClientRunningWSLAProcess WSLAProcessLauncher::Launch(IWSLASession& Session)
|
||||
{
|
||||
auto [hresult, error, process] = LaunchNoThrow(Session);
|
||||
if (FAILED(hresult))
|
||||
{
|
||||
auto commandLine = wsl::shared::string::Join(m_arguments, ' ');
|
||||
THROW_HR_MSG(hresult, "Failed to launch process: %hs (commandline: %hs). Errno = %i", m_executable.c_str(), commandLine.c_str(), error);
|
||||
}
|
||||
|
||||
return std::move(process.value());
|
||||
}
|
||||
|
||||
std::tuple<HRESULT, int, std::optional<ClientRunningWSLAProcess>> WSLAProcessLauncher::LaunchNoThrow(IWSLASession& Session)
|
||||
{
|
||||
auto [options, commandLine, env] = CreateProcessOptions();
|
||||
|
|
@ -198,6 +186,24 @@ std::tuple<HRESULT, int, std::optional<ClientRunningWSLAProcess>> WSLAProcessLau
|
|||
return {S_OK, 0, ClientRunningWSLAProcess{std::move(process), std::move(m_fds)}};
|
||||
}
|
||||
|
||||
std::tuple<HRESULT, int, std::optional<ClientRunningWSLAProcess>> WSLAProcessLauncher::LaunchNoThrow(IWSLAContainer& Container)
|
||||
{
|
||||
auto [options, commandLine, env] = CreateProcessOptions();
|
||||
options.Executable = nullptr; // Must be null for exec.
|
||||
|
||||
wil::com_ptr<IWSLAProcess> process;
|
||||
int error = -1;
|
||||
auto result = Container.Exec(&options, &process, &error);
|
||||
if (FAILED(result))
|
||||
{
|
||||
return std::make_tuple(result, error, std::optional<ClientRunningWSLAProcess>());
|
||||
}
|
||||
|
||||
wsl::windows::common::security::ConfigureForCOMImpersonation(process.get());
|
||||
|
||||
return {S_OK, 0, ClientRunningWSLAProcess{std::move(process), std::move(m_fds)}};
|
||||
}
|
||||
|
||||
IWSLAProcess& ClientRunningWSLAProcess::Get()
|
||||
{
|
||||
return *m_process.get();
|
||||
|
|
|
|||
|
|
@ -91,9 +91,23 @@ public:
|
|||
void AddFd(WSLA_PROCESS_FD Fd);
|
||||
void SetTtySize(ULONG Rows, ULONG Columns);
|
||||
|
||||
// TODO: Add overloads for IWSLAContainer once implemented.
|
||||
ClientRunningWSLAProcess Launch(IWSLASession& Session);
|
||||
std::tuple<HRESULT, int, std::optional<ClientRunningWSLAProcess>> LaunchNoThrow(IWSLASession& Session);
|
||||
std::tuple<HRESULT, int, std::optional<ClientRunningWSLAProcess>> LaunchNoThrow(IWSLAContainer& Container);
|
||||
|
||||
template <typename T>
|
||||
auto Launch(T& Context)
|
||||
{
|
||||
auto [hresult, error, process] = LaunchNoThrow(Context);
|
||||
if (FAILED(hresult))
|
||||
{
|
||||
auto commandLine = wsl::shared::string::Join(m_arguments, ' ');
|
||||
THROW_HR_MSG(
|
||||
hresult, "Failed to launch process: %hs (commandline: %hs). Errno = %i", m_executable.c_str(), commandLine.c_str(), error);
|
||||
}
|
||||
|
||||
return std::move(process.value());
|
||||
}
|
||||
|
||||
std::string FormatResult(const RunningWSLAProcess::ProcessResult& result);
|
||||
std::string FormatResult(const int code);
|
||||
|
||||
|
|
|
|||
|
|
@ -1552,6 +1552,8 @@ int WslaShell(_In_ std::wstring_view commandLine)
|
|||
parser.AddArgument(Utf8String(shell), L"--shell");
|
||||
parser.AddArgument(
|
||||
SetFlag<int, WslaFeatureFlagsDnsTunneling>(reinterpret_cast<int&>(sessionSettings.FeatureFlags)), L"--dns-tunneling");
|
||||
parser.AddArgument(
|
||||
SetFlag<int, WslaFeatureFlagsVirtioFs>(reinterpret_cast<int&>(sessionSettings.FeatureFlags)), L"--virtiofs");
|
||||
parser.AddArgument(Integer(sessionSettings.MemoryMb), L"--memory");
|
||||
parser.AddArgument(Integer(sessionSettings.CpuCount), L"--cpu");
|
||||
parser.AddArgument(Utf8String(rootVhdTypeOverride), L"--fstype");
|
||||
|
|
@ -1565,7 +1567,7 @@ int WslaShell(_In_ std::wstring_view commandLine)
|
|||
if (help)
|
||||
{
|
||||
const auto usage = std::format(
|
||||
LR"({} --wsla [--vhd </path/to/vhd>] [--shell </path/to/shell>] [--memory <memory-mb>] [--cpu <cpus>] [--dns-tunneling] [--networking-mode <mode>] [--fstype <fstype>] [--container-vhd </path/to/vhd>] [--help])",
|
||||
LR"({} --wsla [--vhd </path/to/vhd>] [--shell </path/to/shell>] [--memory <memory-mb>] [--cpu <cpus>] [--dns-tunneling] [--virtiofs] [--networking-mode <mode>] [--fstype <fstype>] [--container-vhd </path/to/vhd>] [--help])",
|
||||
WSL_BINARY_NAME);
|
||||
|
||||
wprintf(L"%ls\n", usage.c_str());
|
||||
|
|
|
|||
|
|
@ -67,8 +67,10 @@ void wsl::core::filesystem::CreateVhd(_In_ LPCWSTR target, _In_ ULONGLONG maximu
|
|||
// to the VHD because the operation is done while impersonating the user.
|
||||
auto sd = windows::common::security::CreateSecurityDescriptor(userSid);
|
||||
wil::unique_hfile vhd{};
|
||||
THROW_IF_WIN32_ERROR(
|
||||
::CreateVirtualDisk(&storageType, target, VIRTUAL_DISK_ACCESS_NONE, &sd, flags, 0, &createVhdParameters, nullptr, &vhd));
|
||||
THROW_IF_WIN32_ERROR_MSG(
|
||||
::CreateVirtualDisk(&storageType, target, VIRTUAL_DISK_ACCESS_NONE, &sd, flags, 0, &createVhdParameters, nullptr, &vhd),
|
||||
"Path: %ls",
|
||||
target);
|
||||
}
|
||||
|
||||
wil::unique_handle wsl::core::filesystem::OpenVhd(_In_ LPCWSTR Path, _In_ VIRTUAL_DISK_ACCESS_MASK Mask)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ Abstract:
|
|||
|
||||
using wsl::windows::common::relay::EventHandle;
|
||||
using wsl::windows::common::relay::IOHandleStatus;
|
||||
using wsl::windows::common::relay::LineBasedReadHandle;
|
||||
using wsl::windows::common::relay::MultiHandleWait;
|
||||
using wsl::windows::common::relay::OverlappedIOHandle;
|
||||
using wsl::windows::common::relay::ReadHandle;
|
||||
|
|
@ -1123,6 +1124,38 @@ HANDLE ReadHandle::GetHandle() const
|
|||
return Event.get();
|
||||
}
|
||||
|
||||
LineBasedReadHandle::LineBasedReadHandle(wil::unique_handle&& MovedHandle, std::function<void(const gsl::span<char>& Line)>&& OnLine) :
|
||||
ReadHandle(std::move(MovedHandle), [this](const gsl::span<char>& Buffer) { OnRead(Buffer); }), OnLine(OnLine)
|
||||
{
|
||||
}
|
||||
|
||||
LineBasedReadHandle::~LineBasedReadHandle()
|
||||
{
|
||||
// Call the callback with any pending data (in case of an incomplete line).
|
||||
if (!PendingBuffer.empty())
|
||||
{
|
||||
OnLine(PendingBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
void LineBasedReadHandle::OnRead(const gsl::span<char>& Buffer)
|
||||
{
|
||||
auto begin = Buffer.begin();
|
||||
auto end = std::ranges::find(Buffer, '\n');
|
||||
while (end != Buffer.end())
|
||||
{
|
||||
PendingBuffer.insert(PendingBuffer.end(), begin, end);
|
||||
|
||||
OnLine(PendingBuffer);
|
||||
PendingBuffer.clear();
|
||||
|
||||
begin = end + 1;
|
||||
end = std::ranges::find(begin, Buffer.end(), '\n');
|
||||
}
|
||||
|
||||
PendingBuffer.insert(PendingBuffer.end(), begin, end);
|
||||
}
|
||||
|
||||
WriteHandle::WriteHandle(wil::unique_handle&& MovedHandle, const std::vector<char>& Buffer) :
|
||||
Handle(std::move(MovedHandle)), Buffer(Buffer)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ public:
|
|||
NON_MOVABLE(ReadHandle);
|
||||
|
||||
ReadHandle(wil::unique_handle&& MovedHandle, std::function<void(const gsl::span<char>& Buffer)>&& OnRead);
|
||||
~ReadHandle();
|
||||
virtual ~ReadHandle();
|
||||
void Schedule() override;
|
||||
void Collect() override;
|
||||
HANDLE GetHandle() const override;
|
||||
|
|
@ -214,6 +214,22 @@ private:
|
|||
std::vector<char> Buffer = std::vector<char>(LX_RELAY_BUFFER_SIZE);
|
||||
};
|
||||
|
||||
class LineBasedReadHandle : public ReadHandle
|
||||
{
|
||||
public:
|
||||
NON_COPYABLE(LineBasedReadHandle);
|
||||
NON_MOVABLE(LineBasedReadHandle);
|
||||
|
||||
LineBasedReadHandle(wil::unique_handle&& MovedHandle, std::function<void(const gsl::span<char>& Buffer)>&& OneLine);
|
||||
~LineBasedReadHandle();
|
||||
|
||||
private:
|
||||
void OnRead(const gsl::span<char>& Buffer);
|
||||
|
||||
std::function<void(const gsl::span<char>& Buffer)> OnLine;
|
||||
std::string PendingBuffer;
|
||||
};
|
||||
|
||||
class WriteHandle : public OverlappedIOHandle
|
||||
{
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -774,10 +774,7 @@ WslCoreVm::~WslCoreVm() noexcept
|
|||
}
|
||||
|
||||
// Shutdown virtio device hosts.
|
||||
if (m_guestDeviceManager)
|
||||
{
|
||||
m_guestDeviceManager->Shutdown();
|
||||
}
|
||||
m_guestDeviceManager.reset();
|
||||
|
||||
// Call RevokeVmAccess on each VHD that was added to the utility VM. This
|
||||
// ensures that the ACL on the VHD does not grow unbounded.
|
||||
|
|
@ -1755,8 +1752,10 @@ void WslCoreVm::InitializeGuest()
|
|||
{
|
||||
try
|
||||
{
|
||||
m_guestDeviceManager->AddSharedMemoryDevice(
|
||||
VIRTIO_FS_CLASS_ID, L"wslg", L"wslg", WSLG_SHARED_MEMORY_SIZE_MB, m_userToken.get());
|
||||
// Use the appropriate virtiofs class ID based on m_userToken elevation.
|
||||
const bool admin = wsl::windows::common::security::IsTokenElevated(m_userToken.get());
|
||||
const GUID classId = admin ? VIRTIO_FS_ADMIN_CLASS_ID : VIRTIO_FS_CLASS_ID;
|
||||
m_guestDeviceManager->AddSharedMemoryDevice(classId, L"wslg", L"wslg", WSLG_SHARED_MEMORY_SIZE_MB, m_userToken.get());
|
||||
m_sharedMemoryRoot = std::format(L"WSL\\{}\\wslg", m_machineId);
|
||||
}
|
||||
CATCH_LOG()
|
||||
|
|
|
|||
|
|
@ -128,36 +128,20 @@ void ContainerEventTracker::Run(ServiceRunningProcess& process)
|
|||
{
|
||||
try
|
||||
{
|
||||
std::string pendingBuffer;
|
||||
|
||||
wsl::windows::common::relay::MultiHandleWait io;
|
||||
|
||||
auto onStdout = [&](const gsl::span<char>& buffer) {
|
||||
auto oneLineWritten = [&](const gsl::span<char>& buffer) {
|
||||
// nerdctl events' output is line based. Call OnEvent() for each completed line.
|
||||
|
||||
auto begin = buffer.begin();
|
||||
auto end = std::ranges::find(buffer, '\n');
|
||||
while (end != buffer.end())
|
||||
if (!buffer.empty()) // nerdctl inserts empty lines between events, skip those.
|
||||
{
|
||||
pendingBuffer.insert(pendingBuffer.end(), begin, end);
|
||||
|
||||
if (!pendingBuffer.empty()) // nerdctl inserts empty lines between events, skip those.
|
||||
{
|
||||
OnEvent(pendingBuffer);
|
||||
}
|
||||
|
||||
pendingBuffer.clear();
|
||||
|
||||
begin = end + 1;
|
||||
end = std::ranges::find(begin, buffer.end(), '\n');
|
||||
OnEvent(std::string{buffer.begin(), buffer.end()});
|
||||
}
|
||||
|
||||
pendingBuffer.insert(pendingBuffer.end(), begin, end);
|
||||
};
|
||||
|
||||
auto onStop = [&]() { io.Cancel(); };
|
||||
|
||||
io.AddHandle(std::make_unique<common::relay::ReadHandle>(process.GetStdHandle(1), std::move(onStdout)));
|
||||
io.AddHandle(std::make_unique<common::relay::LineBasedReadHandle>(process.GetStdHandle(1), std::move(oneLineWritten)));
|
||||
io.AddHandle(std::make_unique<common::relay::EventHandle>(m_stopEvent.get(), std::move(onStop)));
|
||||
|
||||
if (io.Run({}))
|
||||
|
|
|
|||
|
|
@ -51,10 +51,26 @@ void ServiceRunningProcess::GetState(WSLA_PROCESS_STATE* State, int* Code)
|
|||
THROW_IF_FAILED(m_process->GetState(State, Code));
|
||||
}
|
||||
|
||||
ServiceRunningProcess ServiceProcessLauncher::Launch(WSLAVirtualMachine& virtualMachine)
|
||||
std::tuple<HRESULT, int, std::optional<ServiceRunningProcess>> ServiceProcessLauncher::LaunchNoThrow(WSLAVirtualMachine& virtualMachine)
|
||||
{
|
||||
auto [options, commandLine, env] = CreateProcessOptions();
|
||||
int Error = -1;
|
||||
int error = -1;
|
||||
|
||||
return ServiceRunningProcess(virtualMachine.CreateLinuxProcess(options, &Error), std::move(m_fds));
|
||||
std::optional<ServiceRunningProcess> process;
|
||||
auto result =
|
||||
wil::ResultFromException([&]() { process.emplace(virtualMachine.CreateLinuxProcess(options, &error), std::move(m_fds)); });
|
||||
|
||||
return {result, error, std::move(process)};
|
||||
}
|
||||
|
||||
ServiceRunningProcess ServiceProcessLauncher::Launch(WSLAVirtualMachine& virtualMachine)
|
||||
{
|
||||
auto [hresult, error, process] = LaunchNoThrow(virtualMachine);
|
||||
if (FAILED(hresult))
|
||||
{
|
||||
auto commandLine = wsl::shared::string::Join(m_arguments, ' ');
|
||||
THROW_HR_MSG(hresult, "Failed to launch process: %hs (commandline: %hs). Errno = %i", m_executable.c_str(), commandLine.c_str(), error);
|
||||
}
|
||||
|
||||
return std::move(process.value());
|
||||
}
|
||||
|
|
@ -45,6 +45,7 @@ public:
|
|||
NON_MOVABLE(ServiceProcessLauncher);
|
||||
using WSLAProcessLauncher::WSLAProcessLauncher;
|
||||
|
||||
std::tuple<HRESULT, int, std::optional<ServiceRunningProcess>> LaunchNoThrow(WSLAVirtualMachine& virtualMachine);
|
||||
ServiceRunningProcess Launch(WSLAVirtualMachine& virtualMachine);
|
||||
};
|
||||
} // namespace wsl::windows::service::wsla
|
||||
|
|
@ -126,6 +126,7 @@ try
|
|||
m_state);
|
||||
ServiceProcessLauncher launcher(
|
||||
nerdctlPath, {nerdctlPath, "stop", m_name, "--time", std::to_string(static_cast<ULONG>(std::round(TimeoutMs / 1000)))});
|
||||
|
||||
// TODO: Figure out how we want to handle custom signals.
|
||||
// nerdctl stop has a --time and a --signal option that can be used
|
||||
// By default, it uses SIGTERM and a default timeout of 10 seconds.
|
||||
|
|
@ -195,35 +196,93 @@ CATCH_RETURN();
|
|||
HRESULT WSLAContainer::Exec(const WSLA_PROCESS_OPTIONS* Options, IWSLAProcess** Process, int* Errno)
|
||||
try
|
||||
{
|
||||
// auto process = wil::MakeOrThrow<WSLAProcess>();
|
||||
*Errno = -1;
|
||||
THROW_HR_IF_MSG(E_INVALIDARG, Options->Executable != nullptr, "Executable must be null");
|
||||
|
||||
// process.CopyTo(__uuidof(IWSLAProcess), (void**)Process);
|
||||
std::lock_guard lock{m_lock};
|
||||
|
||||
THROW_HR_IF_MSG(
|
||||
HRESULT_FROM_WIN32(ERROR_INVALID_STATE),
|
||||
State() != WslaContainerStateRunning,
|
||||
"Container %hs is not running. State: %i",
|
||||
m_name.c_str(),
|
||||
m_state);
|
||||
|
||||
auto [hasStdin, hasTty] = ParseFdStatus(*Options);
|
||||
|
||||
std::vector<std::string> args{nerdctlPath, "exec"};
|
||||
|
||||
if (hasStdin)
|
||||
{
|
||||
args.push_back("-i");
|
||||
}
|
||||
|
||||
if (hasTty)
|
||||
{
|
||||
args.push_back("-t");
|
||||
}
|
||||
|
||||
AddEnvironmentVariables(args, *Options);
|
||||
|
||||
args.emplace_back(m_id);
|
||||
|
||||
for (ULONG i = 0; i < Options->CommandLineCount; i++)
|
||||
{
|
||||
args.emplace_back(Options->CommandLine[i]);
|
||||
}
|
||||
|
||||
ServiceProcessLauncher launcher(nerdctlPath, args, {}, common::ProcessFlags::None);
|
||||
for (auto i = 0; i < Options->FdsCount; i++)
|
||||
{
|
||||
launcher.AddFd(Options->Fds[i]);
|
||||
}
|
||||
|
||||
std::optional<ServiceRunningProcess> process;
|
||||
HRESULT result = E_FAIL;
|
||||
std::tie(result, *Errno, process) = launcher.LaunchNoThrow(*m_parentVM);
|
||||
THROW_IF_FAILED(result);
|
||||
|
||||
THROW_IF_FAILED(process->Get().QueryInterface(__uuidof(IWSLAProcess), (void**)Process));
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
CATCH_RETURN();
|
||||
|
||||
Microsoft::WRL::ComPtr<WSLAContainer> WSLAContainer::Create(
|
||||
const WSLA_CONTAINER_OPTIONS& containerOptions, WSLAVirtualMachine& parentVM, ContainerEventTracker& eventTracker)
|
||||
std::pair<bool, bool> WSLAContainer::ParseFdStatus(const WSLA_PROCESS_OPTIONS& Options)
|
||||
{
|
||||
// TODO: Switch to nerdctl create, and call nerdctl start in Start().
|
||||
|
||||
bool hasStdin = false;
|
||||
bool hasTty = false;
|
||||
for (size_t i = 0; i < containerOptions.InitProcessOptions.FdsCount; i++)
|
||||
for (size_t i = 0; i < Options.FdsCount; i++)
|
||||
{
|
||||
if (containerOptions.InitProcessOptions.Fds[i].Fd == 0)
|
||||
if (Options.Fds[i].Fd == 0)
|
||||
{
|
||||
hasStdin = true;
|
||||
}
|
||||
|
||||
if (containerOptions.InitProcessOptions.Fds[i].Type == WSLAFdTypeTerminalInput ||
|
||||
containerOptions.InitProcessOptions.Fds[i].Type == WSLAFdTypeTerminalOutput)
|
||||
if (Options.Fds[i].Type == WSLAFdTypeTerminalInput || Options.Fds[i].Type == WSLAFdTypeTerminalOutput)
|
||||
{
|
||||
hasTty = true;
|
||||
}
|
||||
}
|
||||
|
||||
return {hasStdin, hasTty};
|
||||
}
|
||||
|
||||
void WSLAContainer::AddEnvironmentVariables(std::vector<std::string>& args, const WSLA_PROCESS_OPTIONS& options)
|
||||
{
|
||||
for (ULONG i = 0; i < options.EnvironmentCount; i++)
|
||||
{
|
||||
THROW_HR_IF_MSG(E_INVALIDARG, options.Environment[i][0] == '-', "Invalid environment string: %hs", options.Environment[i]);
|
||||
|
||||
args.insert(args.end(), {"-e", options.Environment[i]});
|
||||
}
|
||||
}
|
||||
|
||||
Microsoft::WRL::ComPtr<WSLAContainer> WSLAContainer::Create(
|
||||
const WSLA_CONTAINER_OPTIONS& containerOptions, WSLAVirtualMachine& parentVM, ContainerEventTracker& eventTracker)
|
||||
{
|
||||
auto [hasStdin, hasTty] = ParseFdStatus(containerOptions.InitProcessOptions);
|
||||
|
||||
// Don't support stdin for now since it will hang.
|
||||
// TODO: Remove once stdin is fixed in nerdctl.
|
||||
THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED), hasStdin && !hasTty);
|
||||
|
|
@ -239,6 +298,8 @@ Microsoft::WRL::ComPtr<WSLAContainer> WSLAContainer::Create(
|
|||
inputOptions.push_back("-t");
|
||||
}
|
||||
|
||||
AddEnvironmentVariables(inputOptions, containerOptions.InitProcessOptions);
|
||||
|
||||
auto args = PrepareNerdctlCreateCommand(containerOptions, std::move(inputOptions));
|
||||
|
||||
ServiceProcessLauncher launcher(nerdctlPath, args, {});
|
||||
|
|
@ -301,17 +362,6 @@ std::vector<std::string> WSLAContainer::PrepareNerdctlCreateCommand(const WSLA_C
|
|||
args.insert(args.end(), defaultNerdctlCreateArgs.begin(), defaultNerdctlCreateArgs.end());
|
||||
args.insert(args.end(), inputOptions.begin(), inputOptions.end());
|
||||
|
||||
for (ULONG i = 0; i < options.InitProcessOptions.EnvironmentCount; i++)
|
||||
{
|
||||
THROW_HR_IF_MSG(
|
||||
E_INVALIDARG,
|
||||
options.InitProcessOptions.Environment[i][0] == L'-',
|
||||
"Invalid environment string: %hs",
|
||||
options.InitProcessOptions.Environment[i]);
|
||||
|
||||
args.insert(args.end(), {"-e", options.InitProcessOptions.Environment[i]});
|
||||
}
|
||||
|
||||
if (options.InitProcessOptions.Executable != nullptr)
|
||||
{
|
||||
args.push_back("--entrypoint");
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ private:
|
|||
|
||||
std::optional<std::string> GetNerdctlStatus();
|
||||
|
||||
std::recursive_mutex m_lock;
|
||||
wil::unique_event m_startedEvent{wil::EventOptions::ManualReset};
|
||||
std::optional<ServiceRunningProcess> m_containerProcess;
|
||||
std::string m_name;
|
||||
|
|
@ -56,9 +57,10 @@ private:
|
|||
std::string m_id;
|
||||
WSLA_CONTAINER_STATE m_state = WslaContainerStateInvalid;
|
||||
WSLAVirtualMachine* m_parentVM = nullptr;
|
||||
std::recursive_mutex m_lock;
|
||||
ContainerEventTracker::ContainerTrackingReference m_trackingReference;
|
||||
|
||||
static std::vector<std::string> PrepareNerdctlCreateCommand(const WSLA_CONTAINER_OPTIONS& options, std::vector<std::string>&& inputOptions);
|
||||
static std::pair<bool, bool> ParseFdStatus(const WSLA_PROCESS_OPTIONS& Options);
|
||||
static void AddEnvironmentVariables(std::vector<std::string>& args, const WSLA_PROCESS_OPTIONS& options);
|
||||
};
|
||||
} // namespace wsl::windows::service::wsla
|
||||
|
|
@ -22,6 +22,8 @@ Abstract:
|
|||
using wsl::windows::service::wsla::WSLASession;
|
||||
using wsl::windows::service::wsla::WSLAVirtualMachine;
|
||||
|
||||
constexpr auto c_containerdStorage = "/var/lib/containerd";
|
||||
|
||||
WSLASession::WSLASession(ULONG id, const WSLA_SESSION_SETTINGS& Settings, WSLAUserSessionImpl& userSessionImpl) :
|
||||
|
||||
m_id(id), m_sessionSettings(Settings), m_userSession(&userSessionImpl), m_displayName(Settings.DisplayName)
|
||||
|
|
@ -39,27 +41,33 @@ WSLASession::WSLASession(ULONG id, const WSLA_SESSION_SETTINGS& Settings, WSLAUs
|
|||
|
||||
ConfigureStorage(Settings);
|
||||
|
||||
// Launch the init script.
|
||||
// TODO: Replace with something more robust once the final VHD is ready.
|
||||
try
|
||||
{
|
||||
ServiceProcessLauncher launcher{"/bin/sh", {"/bin/sh", "-c", "/etc/lsw-init.sh"}};
|
||||
auto result = launcher.Launch(*m_virtualMachine.Get()).WaitAndCaptureOutput();
|
||||
// Make sure that everything is destroyed correctly if an exception is thrown.
|
||||
auto errorCleanup = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&]() {
|
||||
m_sessionTerminatingEvent.SetEvent();
|
||||
|
||||
THROW_HR_IF_MSG(E_FAIL, result.Code != 0, "Init script failed: %hs", launcher.FormatResult(result).c_str());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Ignore issues launching the init script with custom root VHD's, for convenience.
|
||||
// TODO: Remove once the final VHD is ready.
|
||||
if (Settings.RootVhdOverride == nullptr)
|
||||
if (m_containerdThread.joinable())
|
||||
{
|
||||
throw;
|
||||
m_containerdThread.join();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Launch containerd
|
||||
// TODO: Rework the daemon logic so we can have only one thread watching all daemons.
|
||||
ServiceProcessLauncher launcher{
|
||||
"/usr/bin/containerd",
|
||||
{"/usr/bin/containerd"},
|
||||
{{"PATH=/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/sbin"}},
|
||||
common::ProcessFlags::Stdout | common::ProcessFlags::Stderr};
|
||||
m_containerdThread = std::thread(&WSLASession::MonitorContainerd, this, launcher.Launch(*m_virtualMachine.Get()));
|
||||
|
||||
// Wait for containerd to be ready before starting the event tracker.
|
||||
// TODO: Configurable timeout.
|
||||
THROW_WIN32_IF_MSG(ERROR_TIMEOUT, !m_containerdReadyEvent.wait(10 * 1000), "Timed out waiting for containerd to start");
|
||||
|
||||
// Start the event tracker.
|
||||
m_eventTracker.emplace(*m_virtualMachine.Get());
|
||||
|
||||
errorCleanup.release();
|
||||
}
|
||||
|
||||
WSLAVirtualMachine::Settings WSLASession::CreateVmSettings(const WSLA_SESSION_SETTINGS& Settings)
|
||||
|
|
@ -91,7 +99,7 @@ WSLAVirtualMachine::Settings WSLASession::CreateVmSettings(const WSLA_SESSION_SE
|
|||
|
||||
#endif
|
||||
|
||||
vmSettings.RootVhdType = "squashfs";
|
||||
vmSettings.RootVhdType = "ext4";
|
||||
}
|
||||
|
||||
if (Settings.DmesgOutput != 0)
|
||||
|
|
@ -116,12 +124,20 @@ WSLASession::~WSLASession()
|
|||
|
||||
m_containers.clear();
|
||||
|
||||
m_sessionTerminatingEvent.SetEvent();
|
||||
|
||||
// N.B. The containerd thread can only run if the VM is running.
|
||||
if (m_containerdThread.joinable())
|
||||
{
|
||||
m_containerdThread.join();
|
||||
}
|
||||
|
||||
if (m_virtualMachine)
|
||||
{
|
||||
m_virtualMachine->OnSessionTerminated();
|
||||
// N.B. containerd has exited by this point, so unmounting the VHD is safe since no container can be running.
|
||||
|
||||
// TODO: Signal containerd to exit before unmounting /root.
|
||||
LOG_IF_FAILED(m_virtualMachine->Unmount("/root"));
|
||||
m_virtualMachine->OnSessionTerminated();
|
||||
LOG_IF_FAILED(m_virtualMachine->Unmount(c_containerdStorage));
|
||||
|
||||
m_virtualMachine.Reset();
|
||||
}
|
||||
|
|
@ -137,7 +153,7 @@ void WSLASession::ConfigureStorage(const WSLA_SESSION_SETTINGS& Settings)
|
|||
if (Settings.StoragePath == nullptr)
|
||||
{
|
||||
// If no storage path is specified, use a tmpfs for convenience.
|
||||
m_virtualMachine->Mount("", "/root", "tmpfs", "", 0);
|
||||
m_virtualMachine->Mount("", c_containerdStorage, "tmpfs", "", 0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -192,7 +208,7 @@ void WSLASession::ConfigureStorage(const WSLA_SESSION_SETTINGS& Settings)
|
|||
}
|
||||
|
||||
// Mount the device to /root.
|
||||
m_virtualMachine->Mount(diskDevice.c_str(), "/root", "ext4", "", 0);
|
||||
m_virtualMachine->Mount(diskDevice.c_str(), c_containerdStorage, "ext4", "", 0);
|
||||
|
||||
deleteVhdOnFailure.release();
|
||||
}
|
||||
|
|
@ -213,6 +229,68 @@ void WSLASession::CopyDisplayName(_Out_writes_z_(bufferLength) PWSTR buffer, siz
|
|||
wcscpy_s(buffer, bufferLength, m_displayName.c_str());
|
||||
}
|
||||
|
||||
void WSLASession::OnContainerdLog(const gsl::span<char>& buffer)
|
||||
try
|
||||
{
|
||||
if (buffer.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
constexpr auto c_containerdReadyLogLine = "containerd successfully booted";
|
||||
|
||||
std::string entry = {buffer.begin(), buffer.end()};
|
||||
WSL_LOG("ContainerdLog", TraceLoggingValue(entry.c_str(), "Content"), TraceLoggingValue(m_displayName.c_str(), "Name"));
|
||||
|
||||
auto parsed = nlohmann::json::parse(entry);
|
||||
|
||||
if (!m_containerdReadyEvent.is_signaled())
|
||||
{
|
||||
auto it = parsed.find("msg");
|
||||
if (it != parsed.end())
|
||||
{
|
||||
if (it->get<std::string>().starts_with(c_containerdReadyLogLine))
|
||||
{
|
||||
m_containerdReadyEvent.SetEvent();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CATCH_LOG();
|
||||
|
||||
void WSLASession::MonitorContainerd(ServiceRunningProcess&& process)
|
||||
try
|
||||
{
|
||||
windows::common::relay::MultiHandleWait io;
|
||||
|
||||
// Read stdout & stderr.
|
||||
io.AddHandle(std::make_unique<windows::common::relay::LineBasedReadHandle>(
|
||||
process.GetStdHandle(1), [&](const auto& data) { OnContainerdLog(data); }));
|
||||
|
||||
io.AddHandle(std::make_unique<windows::common::relay::LineBasedReadHandle>(
|
||||
process.GetStdHandle(2), [&](const auto& data) { OnContainerdLog(data); }));
|
||||
|
||||
// Exit if either the VM terminates or containerd exits.
|
||||
io.AddHandle(std::make_unique<windows::common::relay::EventHandle>(process.GetExitEvent(), [&]() { io.Cancel(); }));
|
||||
io.AddHandle(std::make_unique<windows::common::relay::EventHandle>(m_sessionTerminatingEvent.get(), [&]() { io.Cancel(); }));
|
||||
|
||||
io.Run({});
|
||||
|
||||
if (!m_sessionTerminatingEvent.is_signaled())
|
||||
{
|
||||
// If containerd exited before the VM starts terminating, then it exited unexpectedly.
|
||||
WSL_LOG("UnexpectedContainerdExit", TraceLoggingValue(m_displayName.c_str(), "SessionDisplayName"));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise, the session is shutting down; terminate containerd before exiting.
|
||||
process.Get().Signal(15); // SIGTERM
|
||||
|
||||
process.Wait(30 * 1000); // TODO: Configurable timeout.
|
||||
}
|
||||
}
|
||||
CATCH_LOG();
|
||||
|
||||
HRESULT WSLASession::PullImage(LPCWSTR Image, const WSLA_REGISTRY_AUTHENTICATION_INFORMATION* RegistryInformation, IProgressCallback* ProgressCallback)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
|
|
|
|||
|
|
@ -65,14 +65,19 @@ private:
|
|||
void ConfigureStorage(const WSLA_SESSION_SETTINGS& Settings);
|
||||
void Ext4Format(const std::string& Device);
|
||||
void ClearDeletedContainers();
|
||||
void OnContainerdLog(const gsl::span<char>& Data);
|
||||
void MonitorContainerd(ServiceRunningProcess&& process);
|
||||
|
||||
WSLA_SESSION_SETTINGS m_sessionSettings; // TODO: Revisit to see if we should have session settings as a member or not
|
||||
WSLAUserSessionImpl* m_userSession = nullptr;
|
||||
Microsoft::WRL::ComPtr<WSLAVirtualMachine> m_virtualMachine;
|
||||
std::optional<ContainerEventTracker> m_eventTracker;
|
||||
wil::unique_event m_containerdReadyEvent{wil::EventOptions::ManualReset};
|
||||
std::thread m_containerdThread;
|
||||
std::wstring m_displayName;
|
||||
std::filesystem::path m_storageVhdPath;
|
||||
std::map<std::string, Microsoft::WRL::ComPtr<WSLAContainer>> m_containers;
|
||||
wil::unique_event m_sessionTerminatingEvent{wil::EventOptions::ManualReset};
|
||||
std::recursive_mutex m_lock;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,10 @@ constexpr auto SAVED_STATE_FILE_PREFIX = L"saved-state-";
|
|||
constexpr auto RECEIVE_TIMEOUT = 30 * 1000;
|
||||
|
||||
// WSLA-specific virtio device class IDs.
|
||||
DEFINE_GUID(WSLA_VIRTIO_FS_ADMIN_CLASS_ID, 0x8F7C2A3B, 0xD9E4, 0x4C1F, 0xA2, 0xB8, 0x5E, 0x3D, 0x7C, 0x9F, 0x1A, 0x6E); // {8F7C2A3B-D9E4-4C1F-A2B8-5E3D7C9F1A6E}
|
||||
DEFINE_GUID(WSLA_VIRTIO_FS_CLASS_ID, 0x06ED032F, 0xC528, 0x41C1, 0xB7, 0x5D, 0x90, 0x5E, 0xEE, 0x82, 0x3B, 0xBA); // {06ED032F-C528-41C1-B75D-905EEE823BBA}
|
||||
DEFINE_GUID(WSLA_VIRTIO_NET_CLASS_ID, 0x7B3C9A42, 0x8E1F, 0x4D5A, 0x9F, 0x2E, 0xC4, 0xA7, 0xB8, 0xD3, 0xE6, 0xF1); // {7B3C9A42-8E1F-4D5A-9F2E-C4A7B8D3E6F1}
|
||||
DEFINE_GUID(WSLA_VIRTIO_PMEM_CLASS_ID, 0xABB755FC, 0x1B86, 0x4255, 0x83, 0xE2, 0xE5, 0x78, 0x7A, 0xBC, 0xF6, 0xC2); // {ABB755FC-1B86-4255-83E2-E5787ABCF6C2}
|
||||
|
||||
WSLAVirtualMachine::WSLAVirtualMachine(WSLAVirtualMachine::Settings&& Settings, PSID UserSid) :
|
||||
m_settings(std::move(Settings)), m_userSid(UserSid)
|
||||
|
|
@ -89,10 +92,7 @@ WSLAVirtualMachine::~WSLAVirtualMachine()
|
|||
WSL_LOG("WSLATerminateVm", TraceLoggingValue(forceTerminate, "forced"), TraceLoggingValue(m_running, "running"));
|
||||
|
||||
// Shutdown DeviceHostProxy before resetting compute system
|
||||
if (m_guestDeviceManager)
|
||||
{
|
||||
m_guestDeviceManager->Shutdown();
|
||||
}
|
||||
m_guestDeviceManager.reset();
|
||||
|
||||
m_computeSystem.reset();
|
||||
|
||||
|
|
@ -306,8 +306,7 @@ void WSLAVirtualMachine::Start()
|
|||
WI_ASSERT(IsEqualGUID(m_vmId, runtimeId));
|
||||
|
||||
// Initialize DeviceHostProxy for virtio device support.
|
||||
// N.B. This is currently only needed for VirtioProxy networking mode but would also be needed for virtiofs.
|
||||
if (m_settings.NetworkingMode == WSLANetworkingModeVirtioProxy)
|
||||
if (FeatureEnabled(WslaFeatureFlagsVirtioFs) || m_settings.NetworkingMode == WSLANetworkingModeVirtioProxy)
|
||||
{
|
||||
m_guestDeviceManager = std::make_shared<GuestDeviceManager>(m_vmIdString, m_vmId);
|
||||
}
|
||||
|
|
@ -384,10 +383,11 @@ void WSLAVirtualMachine::ConfigureMounts()
|
|||
Mount(m_initChannel, nullptr, "/sys", "sysfs", "", 0);
|
||||
Mount(m_initChannel, nullptr, "/proc", "proc", "", 0);
|
||||
Mount(m_initChannel, nullptr, "/dev/pts", "devpts", "noatime,nosuid,noexec,gid=5,mode=620", 0);
|
||||
Mount(m_initChannel, nullptr, "/sys/fs/cgroup", "cgroup2", "", 0);
|
||||
|
||||
if (FeatureEnabled(WslaFeatureFlagsGPU)) // TODO: re-think how GPU settings should work at the session level API.
|
||||
{
|
||||
MountGpuLibraries("/usr/lib/wsl/lib", "/usr/lib/wsl/drivers", WSLAMountFlagsNone);
|
||||
MountGpuLibraries("/usr/lib/wsl/lib", "/usr/lib/wsl/drivers");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -396,6 +396,11 @@ bool WSLAVirtualMachine::FeatureEnabled(WSLAFeatureFlags Value) const
|
|||
return static_cast<ULONG>(m_settings.FeatureFlags) & static_cast<ULONG>(Value);
|
||||
}
|
||||
|
||||
const wil::unique_event& WSLAVirtualMachine::TerminatingEvent()
|
||||
{
|
||||
return m_vmTerminatingEvent;
|
||||
}
|
||||
|
||||
void WSLAVirtualMachine::WatchForExitedProcesses(wsl::shared::SocketChannel& Channel)
|
||||
try
|
||||
{
|
||||
|
|
@ -931,6 +936,7 @@ void WSLAVirtualMachine::Mount(LPCSTR Source, LPCSTR Target, LPCSTR Type, LPCSTR
|
|||
void WSLAVirtualMachine::Mount(shared::SocketChannel& Channel, LPCSTR Source, LPCSTR Target, LPCSTR Type, LPCSTR Options, ULONG Flags)
|
||||
{
|
||||
static_assert(WSLAMountFlagsNone == WSLA_MOUNT::None);
|
||||
static_assert(WSLAMountFlagsReadOnly == WSLA_MOUNT::ReadOnly);
|
||||
static_assert(WSLAMountFlagsChroot == WSLA_MOUNT::Chroot);
|
||||
static_assert(WSLAMountFlagsWriteableOverlayFs == WSLA_MOUNT::OverlayFs);
|
||||
|
||||
|
|
@ -1151,91 +1157,144 @@ CATCH_RETURN();
|
|||
|
||||
HRESULT WSLAVirtualMachine::MountWindowsFolder(_In_ LPCWSTR WindowsPath, _In_ LPCSTR LinuxPath, _In_ BOOL ReadOnly)
|
||||
{
|
||||
return MountWindowsFolderImpl(WindowsPath, LinuxPath, ReadOnly, WSLAMountFlagsNone);
|
||||
return MountWindowsFolderImpl(WindowsPath, LinuxPath, ReadOnly ? WSLAMountFlagsReadOnly : WSLAMountFlagsNone);
|
||||
}
|
||||
|
||||
HRESULT WSLAVirtualMachine::MountWindowsFolderImpl(_In_ LPCWSTR WindowsPath, _In_ LPCSTR LinuxPath, _In_ BOOL ReadOnly, _In_ WSLAMountFlags Flags)
|
||||
HRESULT WSLAVirtualMachine::MountWindowsFolderImpl(_In_ LPCWSTR WindowsPath, _In_ LPCSTR LinuxPath, _In_ WSLAMountFlags Flags)
|
||||
try
|
||||
{
|
||||
std::filesystem::path Path(WindowsPath);
|
||||
THROW_HR_IF_MSG(E_INVALIDARG, !Path.is_absolute(), "Path is not absolute: '%ls'", WindowsPath);
|
||||
std::filesystem::path path(WindowsPath);
|
||||
THROW_HR_IF_MSG(E_INVALIDARG, !path.is_absolute(), "Path is not absolute: '%ls'", WindowsPath);
|
||||
THROW_HR_IF_MSG(
|
||||
HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), !std::filesystem::is_directory(Path), "Path is not a directory: '%ls'", WindowsPath);
|
||||
HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), !std::filesystem::is_directory(path), "Path is not a directory: '%ls'", WindowsPath);
|
||||
|
||||
GUID shareGuid{};
|
||||
THROW_IF_FAILED(CoCreateGuid(&shareGuid));
|
||||
|
||||
auto shareName = shared::string::GuidToString<wchar_t>(shareGuid, shared::string::None);
|
||||
|
||||
const auto userToken = wsl::windows::common::security::GetUserToken(TokenImpersonation);
|
||||
|
||||
std::optional<GUID> instanceId;
|
||||
{
|
||||
// Create the plan9 share on the host
|
||||
// Create the share on the host.
|
||||
std::lock_guard lock(m_lock);
|
||||
|
||||
// Verify that this folder isn't already mounted.
|
||||
auto it = m_plan9Mounts.find(LinuxPath);
|
||||
THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS), it != m_plan9Mounts.end());
|
||||
auto it = m_mountedWindowsFolders.find(LinuxPath);
|
||||
THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS), it != m_mountedWindowsFolders.end());
|
||||
|
||||
hcs::AddPlan9Share(
|
||||
m_computeSystem.get(),
|
||||
shareName.c_str(),
|
||||
shareName.c_str(),
|
||||
WindowsPath,
|
||||
LX_INIT_UTILITY_VM_PLAN9_PORT,
|
||||
hcs::Plan9ShareFlags::AllowOptions | (ReadOnly ? hcs::Plan9ShareFlags::ReadOnly : hcs::Plan9ShareFlags::None),
|
||||
wsl::windows::common::security::GetUserToken(TokenImpersonation).get());
|
||||
if (!FeatureEnabled(WslaFeatureFlagsVirtioFs))
|
||||
{
|
||||
auto flags = hcs::Plan9ShareFlags::AllowOptions;
|
||||
WI_SetFlagIf(flags, hcs::Plan9ShareFlags::ReadOnly, WI_IsFlagSet(Flags, WSLAMountFlagsReadOnly));
|
||||
hcs::AddPlan9Share(
|
||||
m_computeSystem.get(),
|
||||
shareName.c_str(),
|
||||
shareName.c_str(),
|
||||
WindowsPath,
|
||||
LX_INIT_UTILITY_VM_PLAN9_PORT,
|
||||
flags,
|
||||
userToken.get());
|
||||
}
|
||||
else
|
||||
{
|
||||
const bool admin = wsl::windows::common::security::IsTokenElevated(userToken.get());
|
||||
m_guestDeviceManager->AddGuestDevice(
|
||||
VIRTIO_FS_DEVICE_ID,
|
||||
admin ? WSLA_VIRTIO_FS_ADMIN_CLASS_ID : WSLA_VIRTIO_FS_CLASS_ID,
|
||||
shareName.c_str(),
|
||||
L"",
|
||||
WindowsPath,
|
||||
VIRTIO_FS_FLAGS_TYPE_FILES,
|
||||
userToken.get());
|
||||
}
|
||||
|
||||
m_plan9Mounts.emplace(LinuxPath, shareName);
|
||||
m_mountedWindowsFolders.emplace(LinuxPath, MountedFolderInfo{shareName, instanceId});
|
||||
}
|
||||
|
||||
auto deleteOnFailure = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&]() {
|
||||
std::lock_guard lock(m_lock);
|
||||
|
||||
LOG_HR_IF(E_UNEXPECTED, m_plan9Mounts.erase(LinuxPath) != 1);
|
||||
auto mountIt = m_mountedWindowsFolders.find(LinuxPath);
|
||||
if (WI_VERIFY(mountIt != m_mountedWindowsFolders.end()))
|
||||
{
|
||||
auto mountInfo = mountIt->second;
|
||||
m_mountedWindowsFolders.erase(mountIt);
|
||||
RemoveShare(mountInfo);
|
||||
}
|
||||
});
|
||||
|
||||
// Create the guest mount
|
||||
auto [_, __, channel] = Fork(WSLA_FORK::Thread);
|
||||
|
||||
WSLA_CONNECT message;
|
||||
message.HostPort = LX_INIT_UTILITY_VM_PLAN9_PORT;
|
||||
|
||||
auto fd = channel.Transaction(message).Result;
|
||||
THROW_HR_IF_MSG(E_FAIL, fd < 0, "WSLA_CONNECT failed with %i", fd);
|
||||
|
||||
auto shareNameUtf8 = shared::string::WideToMultiByte(shareName);
|
||||
auto mountOptions =
|
||||
std::format("msize={},trans=fd,rfdno={},wfdno={},aname={},cache=mmap", LX_INIT_UTILITY_VM_PLAN9_BUFFER_SIZE, fd, fd, shareNameUtf8);
|
||||
if (!FeatureEnabled(WslaFeatureFlagsVirtioFs))
|
||||
{
|
||||
auto [_, __, channel] = Fork(WSLA_FORK::Thread);
|
||||
|
||||
Mount(channel, shareNameUtf8.c_str(), LinuxPath, "9p", mountOptions.c_str(), Flags);
|
||||
WSLA_CONNECT message;
|
||||
message.HostPort = LX_INIT_UTILITY_VM_PLAN9_PORT;
|
||||
|
||||
auto fd = channel.Transaction(message).Result;
|
||||
THROW_HR_IF_MSG(E_FAIL, fd < 0, "WSLA_CONNECT failed with %i", fd);
|
||||
|
||||
auto mountOptions = std::format(
|
||||
"{},msize={},trans=fd,rfdno={},wfdno={},aname={},cache=mmap",
|
||||
WI_IsFlagSet(Flags, WSLAMountFlagsReadOnly) ? "ro" : "rw",
|
||||
LX_INIT_UTILITY_VM_PLAN9_BUFFER_SIZE,
|
||||
fd,
|
||||
fd,
|
||||
shareNameUtf8);
|
||||
|
||||
Mount(channel, shareNameUtf8.c_str(), LinuxPath, "9p", mountOptions.c_str(), Flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string options = WI_IsFlagSet(Flags, WSLAMountFlagsReadOnly) ? "ro" : "rw";
|
||||
Mount(m_initChannel, shareNameUtf8.c_str(), LinuxPath, "virtiofs", options.c_str(), Flags);
|
||||
}
|
||||
|
||||
deleteOnFailure.release();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
CATCH_RETURN();
|
||||
|
||||
void WSLAVirtualMachine::RemoveShare(_In_ const MountedFolderInfo& MountInfo)
|
||||
{
|
||||
if (!FeatureEnabled(WslaFeatureFlagsVirtioFs))
|
||||
{
|
||||
WI_ASSERT(!MountInfo.InstanceId.has_value());
|
||||
hcs::RemovePlan9Share(m_computeSystem.get(), MountInfo.ShareName.c_str(), LX_INIT_UTILITY_VM_PLAN9_PORT);
|
||||
}
|
||||
else if (WI_VERIFY(MountInfo.InstanceId.has_value()))
|
||||
{
|
||||
m_guestDeviceManager->RemoveGuestDevice(VIRTIO_FS_DEVICE_ID, MountInfo.InstanceId.value());
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT WSLAVirtualMachine::UnmountWindowsFolder(_In_ LPCSTR LinuxPath)
|
||||
try
|
||||
{
|
||||
std::lock_guard lock(m_lock);
|
||||
|
||||
// Verify that this folder is mounted.
|
||||
auto it = m_plan9Mounts.find(LinuxPath);
|
||||
THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_NOT_FOUND), it == m_plan9Mounts.end());
|
||||
auto it = m_mountedWindowsFolders.find(LinuxPath);
|
||||
THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_NOT_FOUND), it == m_mountedWindowsFolders.end());
|
||||
|
||||
// Unmount the folder from the guest. If the mount is not found, this most likely means that the guest unmounted it.
|
||||
auto result = Unmount(LinuxPath);
|
||||
THROW_HR_IF(result, FAILED(result) && result != HRESULT_FROM_WIN32(ERROR_NOT_FOUND));
|
||||
|
||||
// Remove the share from the host
|
||||
hcs::RemovePlan9Share(m_computeSystem.get(), it->second.c_str(), LX_INIT_UTILITY_VM_PLAN9_PORT);
|
||||
auto mountInfo = it->second;
|
||||
m_mountedWindowsFolders.erase(it);
|
||||
|
||||
m_plan9Mounts.erase(it);
|
||||
// Remove the share from the host
|
||||
RemoveShare(mountInfo);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
CATCH_RETURN();
|
||||
|
||||
void WSLAVirtualMachine::MountGpuLibraries(_In_ LPCSTR LibrariesMountPoint, _In_ LPCSTR DriversMountpoint, _In_ DWORD Flags)
|
||||
void WSLAVirtualMachine::MountGpuLibraries(_In_ LPCSTR LibrariesMountPoint, _In_ LPCSTR DriversMountpoint)
|
||||
{
|
||||
THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_CONFIG_VALUE), !FeatureEnabled(WslaFeatureFlagsGPU));
|
||||
|
||||
|
|
@ -1245,7 +1304,7 @@ void WSLAVirtualMachine::MountGpuLibraries(_In_ LPCSTR LibrariesMountPoint, _In_
|
|||
|
||||
// Mount drivers.
|
||||
THROW_IF_FAILED(MountWindowsFolderImpl(
|
||||
std::format(L"{}\\System32\\DriverStore\\FileRepository", windowsPath).c_str(), DriversMountpoint, true, static_cast<WSLAMountFlags>(Flags)));
|
||||
std::format(L"{}\\System32\\DriverStore\\FileRepository", windowsPath).c_str(), DriversMountpoint, WSLAMountFlagsReadOnly));
|
||||
|
||||
// Mount the inbox libraries.
|
||||
auto inboxLibPath = std::format(L"{}\\System32\\lxss\\lib", windowsPath);
|
||||
|
|
@ -1253,7 +1312,7 @@ void WSLAVirtualMachine::MountGpuLibraries(_In_ LPCSTR LibrariesMountPoint, _In_
|
|||
if (std::filesystem::is_directory(inboxLibPath))
|
||||
{
|
||||
inboxLibMountPoint = std::format("{}/inbox", LibrariesMountPoint);
|
||||
THROW_IF_FAILED(MountWindowsFolder(inboxLibPath.c_str(), inboxLibMountPoint->c_str(), true));
|
||||
THROW_IF_FAILED(MountWindowsFolderImpl(inboxLibPath.c_str(), inboxLibMountPoint->c_str(), WSLAMountFlagsReadOnly));
|
||||
}
|
||||
|
||||
// Mount the packaged libraries.
|
||||
|
|
@ -1269,7 +1328,7 @@ void WSLAVirtualMachine::MountGpuLibraries(_In_ LPCSTR LibrariesMountPoint, _In_
|
|||
#endif
|
||||
|
||||
auto packagedLibMountPoint = std::format("{}/packaged", LibrariesMountPoint);
|
||||
THROW_IF_FAILED(MountWindowsFolder(packagedLibPath.c_str(), packagedLibMountPoint.c_str(), true));
|
||||
THROW_IF_FAILED(MountWindowsFolderImpl(packagedLibPath.c_str(), packagedLibMountPoint.c_str(), WSLAMountFlagsReadOnly));
|
||||
|
||||
// Mount an overlay containing both inbox and packaged libraries (the packaged mount takes precedence).
|
||||
std::string options = "lowerdir=" + packagedLibMountPoint;
|
||||
|
|
@ -1278,7 +1337,7 @@ void WSLAVirtualMachine::MountGpuLibraries(_In_ LPCSTR LibrariesMountPoint, _In_
|
|||
options += ":" + inboxLibMountPoint.value();
|
||||
}
|
||||
|
||||
Mount(m_initChannel, "none", LibrariesMountPoint, "overlay", options.c_str(), Flags);
|
||||
Mount(m_initChannel, "none", LibrariesMountPoint, "overlay", options.c_str(), 0);
|
||||
}
|
||||
|
||||
std::filesystem::path WSLAVirtualMachine::GetCrashDumpFolder()
|
||||
|
|
|
|||
|
|
@ -27,8 +27,9 @@ namespace wsl::windows::service::wsla {
|
|||
enum WSLAMountFlags
|
||||
{
|
||||
WSLAMountFlagsNone = 0,
|
||||
WSLAMountFlagsChroot = 1,
|
||||
WSLAMountFlagsWriteableOverlayFs = 2,
|
||||
WSLAMountFlagsReadOnly = 1,
|
||||
WSLAMountFlagsChroot = 2,
|
||||
WSLAMountFlagsWriteableOverlayFs = 4,
|
||||
};
|
||||
|
||||
class WSLAUserSessionImpl;
|
||||
|
|
@ -44,6 +45,12 @@ public:
|
|||
wil::unique_socket Socket;
|
||||
};
|
||||
|
||||
struct MountedFolderInfo
|
||||
{
|
||||
std::wstring ShareName;
|
||||
std::optional<GUID> InstanceId; // Only used for VirtioFS devices
|
||||
};
|
||||
|
||||
struct Settings
|
||||
{
|
||||
std::wstring DisplayName;
|
||||
|
|
@ -74,7 +81,6 @@ public:
|
|||
IFACEMETHOD(Unmount(_In_ const char* Path)) override;
|
||||
IFACEMETHOD(MountWindowsFolder(_In_ LPCWSTR WindowsPath, _In_ LPCSTR LinuxPath, _In_ BOOL ReadOnly)) override;
|
||||
IFACEMETHOD(UnmountWindowsFolder(_In_ LPCSTR LinuxPath)) override;
|
||||
void MountGpuLibraries(_In_ LPCSTR LibrariesMountPoint, _In_ LPCSTR DriversMountpoint, _In_ DWORD Flags);
|
||||
|
||||
void OnProcessReleased(int Pid);
|
||||
void RegisterCallback(_In_ ITerminationCallback* callback);
|
||||
|
|
@ -86,8 +92,11 @@ public:
|
|||
void DetachDisk(_In_ ULONG Lun);
|
||||
void Mount(_In_ LPCSTR Source, _In_ LPCSTR Target, _In_ LPCSTR Type, _In_ LPCSTR Options, _In_ ULONG Flags);
|
||||
|
||||
const wil::unique_event& TerminatingEvent();
|
||||
|
||||
private:
|
||||
static void Mount(wsl::shared::SocketChannel& Channel, LPCSTR Source, _In_ LPCSTR Target, _In_ LPCSTR Type, _In_ LPCSTR Options, _In_ ULONG Flags);
|
||||
void MountGpuLibraries(_In_ LPCSTR LibrariesMountPoint, _In_ LPCSTR DriversMountpoint);
|
||||
static void CALLBACK s_OnExit(_In_ HCS_EVENT* Event, _In_opt_ void* Context);
|
||||
static bool ParseTtyInformation(
|
||||
const WSLA_PROCESS_FD* Fds, ULONG FdCount, const WSLA_PROCESS_FD** TtyInput, const WSLA_PROCESS_FD** TtyOutput, const WSLA_PROCESS_FD** TtyControl);
|
||||
|
|
@ -106,6 +115,7 @@ private:
|
|||
ConnectedSocket ConnectSocket(wsl::shared::SocketChannel& Channel, int32_t Fd);
|
||||
static void OpenLinuxFile(wsl::shared::SocketChannel& Channel, const char* Path, uint32_t Flags, int32_t Fd);
|
||||
void LaunchPortRelay();
|
||||
void RemoveShare(_In_ const MountedFolderInfo& MountInfo);
|
||||
|
||||
std::filesystem::path GetCrashDumpFolder();
|
||||
void CreateVmSavedStateFile();
|
||||
|
|
@ -116,7 +126,7 @@ private:
|
|||
Microsoft::WRL::ComPtr<WSLAProcess> CreateLinuxProcessImpl(
|
||||
_In_ const WSLA_PROCESS_OPTIONS& Options, int* Errno = nullptr, const TPrepareCommandLine& PrepareCommandLine = [](const auto&) {});
|
||||
|
||||
HRESULT MountWindowsFolderImpl(_In_ LPCWSTR WindowsPath, _In_ LPCSTR LinuxPath, _In_ BOOL ReadOnly, _In_ WSLAMountFlags Flags);
|
||||
HRESULT MountWindowsFolderImpl(_In_ LPCWSTR WindowsPath, _In_ LPCSTR LinuxPath, _In_ WSLAMountFlags Flags = WSLAMountFlagsNone);
|
||||
|
||||
void WatchForExitedProcesses(wsl::shared::SocketChannel& Channel);
|
||||
|
||||
|
|
@ -162,7 +172,7 @@ private:
|
|||
wil::unique_handle m_portRelayChannelWrite;
|
||||
|
||||
std::map<ULONG, AttachedDisk> m_attachedDisks;
|
||||
std::map<std::string, std::wstring> m_plan9Mounts;
|
||||
std::map<std::string, MountedFolderInfo> m_mountedWindowsFolders;
|
||||
std::recursive_mutex m_lock;
|
||||
std::mutex m_portRelaylock;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -242,10 +242,11 @@ typedef enum _WSLANetworkingMode
|
|||
|
||||
typedef enum _WSLAFeatureFlags
|
||||
{
|
||||
WslaFeatureFlagsNone = 0,
|
||||
WslaFeatureFlagsDnsTunneling = 1,
|
||||
WslaFeatureFlagsEarlyBootDmesg = 2,
|
||||
WslaFeatureFlagsGPU = 4,
|
||||
WslaFeatureFlagsNone = 0,
|
||||
WslaFeatureFlagsDnsTunneling = 1,
|
||||
WslaFeatureFlagsEarlyBootDmesg = 2,
|
||||
WslaFeatureFlagsGPU = 4,
|
||||
WslaFeatureFlagsVirtioFs = 8,
|
||||
} WSLAFeatureFlags;
|
||||
|
||||
struct WSLA_SESSION_SETTINGS {
|
||||
|
|
@ -261,7 +262,7 @@ struct WSLA_SESSION_SETTINGS {
|
|||
ULONG DmesgOutput;
|
||||
|
||||
// Below options are used for debugging purposes only.
|
||||
[unique] LPCWSTR RootVhdOverride;
|
||||
[unique] LPCWSTR RootVhdOverride;
|
||||
[unique] LPCSTR RootVhdTypeOverride;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -276,7 +276,7 @@ public:
|
|||
SKIP_TEST_ARM64();
|
||||
|
||||
TerminateDistribution();
|
||||
WslKeepAlive keelAlive;
|
||||
WslKeepAlive keepAlive;
|
||||
|
||||
ValidateDrvfsMounts(CREATE_UNICODE_ENVIRONMENT | EXTENDED_STARTUPINFO_PRESENT, Mode);
|
||||
}
|
||||
|
|
@ -288,7 +288,7 @@ public:
|
|||
SKIP_TEST_ARM64();
|
||||
|
||||
TerminateDistribution();
|
||||
WslKeepAlive keelAlive;
|
||||
WslKeepAlive keepAlive;
|
||||
|
||||
ValidateDrvfsMounts(CREATE_UNICODE_ENVIRONMENT | EXTENDED_STARTUPINFO_PRESENT | CREATE_NEW_CONSOLE, Mode);
|
||||
}
|
||||
|
|
@ -302,7 +302,7 @@ public:
|
|||
TerminateDistribution();
|
||||
|
||||
const auto nonElevatedToken = GetNonElevatedToken();
|
||||
WslKeepAlive keelAlive(nonElevatedToken.get());
|
||||
WslKeepAlive keepAlive(nonElevatedToken.get());
|
||||
|
||||
ValidateDrvfsMounts(CREATE_UNICODE_ENVIRONMENT | EXTENDED_STARTUPINFO_PRESENT, Mode);
|
||||
}
|
||||
|
|
@ -316,11 +316,37 @@ public:
|
|||
TerminateDistribution();
|
||||
|
||||
const auto nonElevatedToken = GetNonElevatedToken();
|
||||
WslKeepAlive keelAlive(nonElevatedToken.get());
|
||||
WslKeepAlive keepAlive(nonElevatedToken.get());
|
||||
|
||||
ValidateDrvfsMounts(CREATE_UNICODE_ENVIRONMENT | EXTENDED_STARTUPINFO_PRESENT | CREATE_NEW_CONSOLE, Mode);
|
||||
}
|
||||
|
||||
void DrvfsMountElevatedSystemDistroEnabled(DrvFsMode Mode)
|
||||
{
|
||||
WSL2_TEST_ONLY();
|
||||
WINDOWS_11_TEST_ONLY(); // TODO: Enable on Windows 10 when virtio support is added
|
||||
SKIP_TEST_ARM64();
|
||||
|
||||
WslConfigChange config(LxssGenerateTestConfig({.guiApplications = true, .drvFsMode = Mode}));
|
||||
WslKeepAlive keepAlive;
|
||||
|
||||
ValidateDrvfsMounts(CREATE_UNICODE_ENVIRONMENT | EXTENDED_STARTUPINFO_PRESENT, Mode);
|
||||
}
|
||||
|
||||
void DrvfsMountNonElevatedSystemDistroEnabled(DrvFsMode Mode)
|
||||
{
|
||||
WSL2_TEST_ONLY();
|
||||
WINDOWS_11_TEST_ONLY(); // TODO: Enable on Windows 10 when virtio support is added
|
||||
SKIP_TEST_ARM64();
|
||||
|
||||
WslConfigChange config(LxssGenerateTestConfig({.guiApplications = true, .drvFsMode = Mode}));
|
||||
|
||||
const auto nonElevatedToken = GetNonElevatedToken();
|
||||
WslKeepAlive keepAlive(nonElevatedToken.get());
|
||||
|
||||
ValidateDrvfsMounts(CREATE_UNICODE_ENVIRONMENT | EXTENDED_STARTUPINFO_PRESENT, Mode);
|
||||
}
|
||||
|
||||
static void XattrDrvFs(DrvFsMode Mode)
|
||||
{
|
||||
SKIP_TEST_ARM64();
|
||||
|
|
@ -946,6 +972,31 @@ private:
|
|||
|
||||
const auto nonElevatedToken = GetNonElevatedToken();
|
||||
validate(nonElevatedType, nonElevatedToken.get());
|
||||
|
||||
// Elevated token should be able to create files at the root of the drive (/mnt/c)
|
||||
{
|
||||
const auto commandLine =
|
||||
LxssGenerateWslCommandLine(L"touch /mnt/c/elevated_test_file.tmp && rm /mnt/c/elevated_test_file.tmp");
|
||||
|
||||
wsl::windows::common::SubProcess process(nullptr, commandLine.c_str(), CreateProcessFlags);
|
||||
process.SetToken(nullptr);
|
||||
process.SetShowWindow(SW_HIDE);
|
||||
|
||||
const auto output = process.RunAndCaptureOutput();
|
||||
VERIFY_ARE_EQUAL(0, output.ExitCode, L"Elevated token should be able to create files at /mnt/c");
|
||||
}
|
||||
|
||||
// Non-elevated token should NOT be able to create files at the root of the drive (/mnt/c)
|
||||
{
|
||||
const auto commandLine = LxssGenerateWslCommandLine(L"touch /mnt/c/nonelevated_test_file.tmp");
|
||||
|
||||
wsl::windows::common::SubProcess process(nullptr, commandLine.c_str(), CreateProcessFlags);
|
||||
process.SetToken(nonElevatedToken.get());
|
||||
process.SetShowWindow(SW_HIDE);
|
||||
|
||||
const auto output = process.RunAndCaptureOutput();
|
||||
VERIFY_ARE_NOT_EQUAL(0, output.ExitCode, L"Non-elevated token should NOT be able to create files at /mnt/c (C:\\)");
|
||||
}
|
||||
}
|
||||
|
||||
static VOID VerifyDrvFsSymlink(const std::wstring& Path, const std::wstring& ExpectedTarget, bool Directory)
|
||||
|
|
@ -1198,6 +1249,18 @@ class WSL1 : public DrvFsTests
|
|||
WSL2_TEST_ONLY(); \
|
||||
DrvFsTests::DrvfsMountNonElevatedDifferentConsole(DrvFsMode::##_mode##); \
|
||||
} \
|
||||
\
|
||||
TEST_METHOD(DrvfsMountElevatedSystemDistroEnabled) \
|
||||
{ \
|
||||
WSL2_TEST_ONLY(); \
|
||||
DrvFsTests::DrvfsMountElevatedSystemDistroEnabled(DrvFsMode::##_mode##); \
|
||||
} \
|
||||
\
|
||||
TEST_METHOD(DrvfsMountNonElevatedSystemDistroEnabled) \
|
||||
{ \
|
||||
WSL2_TEST_ONLY(); \
|
||||
DrvFsTests::DrvfsMountNonElevatedSystemDistroEnabled(DrvFsMode::##_mode##); \
|
||||
} \
|
||||
\
|
||||
TEST_METHOD(XattrDrvFs) \
|
||||
{ \
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -31,6 +31,8 @@ using wsl::windows::common::relay::WriteHandle;
|
|||
|
||||
DEFINE_ENUM_FLAG_OPERATORS(WSLAFeatureFlags);
|
||||
|
||||
static std::filesystem::path storagePath;
|
||||
|
||||
class WSLATests
|
||||
{
|
||||
WSL_TEST_CLASS(WSLATests)
|
||||
|
|
@ -46,6 +48,7 @@ class WSLATests
|
|||
|
||||
auto vhdPath = wsl::windows::common::registry::ReadString(distroKey.get(), nullptr, L"BasePath");
|
||||
testVhd = std::filesystem::path{vhdPath} / "ext4.vhdx";
|
||||
storagePath = std::filesystem::current_path() / "test-storage";
|
||||
|
||||
WslShutdown();
|
||||
return true;
|
||||
|
|
@ -53,6 +56,16 @@ class WSLATests
|
|||
|
||||
TEST_CLASS_CLEANUP(TestClassCleanup)
|
||||
{
|
||||
if (!storagePath.empty())
|
||||
{
|
||||
std::error_code error;
|
||||
std::filesystem::remove_all(storagePath, error);
|
||||
if (error)
|
||||
{
|
||||
LogError("Failed to cleanup storage path %ws: %hs", storagePath.c_str(), error.message().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -63,6 +76,9 @@ class WSLATests
|
|||
settings.CpuCount = 4;
|
||||
settings.MemoryMb = 2024;
|
||||
settings.BootTimeoutMs = 30 * 1000;
|
||||
settings.StoragePath = storagePath.c_str();
|
||||
settings.MaximumStorageSizeMb = 1000; // 1GB.
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
|
|
@ -182,6 +198,7 @@ class WSLATests
|
|||
WSL2_TEST_ONLY();
|
||||
|
||||
auto settings = GetDefaultSessionSettings();
|
||||
settings.StoragePath = nullptr;
|
||||
settings.DisplayName = L"wsla-test-list";
|
||||
|
||||
wil::com_ptr<IWSLAUserSession> userSession;
|
||||
|
|
@ -209,6 +226,7 @@ class WSLATests
|
|||
WSL2_TEST_ONLY();
|
||||
|
||||
auto settings = GetDefaultSessionSettings();
|
||||
settings.StoragePath = nullptr;
|
||||
settings.DisplayName = L"wsla-open-by-name-test";
|
||||
|
||||
wil::com_ptr<IWSLAUserSession> userSession;
|
||||
|
|
@ -395,9 +413,9 @@ class WSLATests
|
|||
};
|
||||
|
||||
// Expect the shell prompt to be displayed
|
||||
validateTtyOutput("/ #");
|
||||
validateTtyOutput("\033[?2004hsh-5.2# ");
|
||||
writeTty("echo OK\n");
|
||||
validateTtyOutput(" echo OK\r\nOK");
|
||||
validateTtyOutput("echo OK\r\n\033[?2004l\rOK");
|
||||
|
||||
// Exit the shell
|
||||
writeTty("exit\n");
|
||||
|
|
@ -543,7 +561,7 @@ class WSLATests
|
|||
{{0, WSLAFdTypeLinuxFileInput, "/proc/self/comm"}, {1, WSLAFdTypeLinuxFileInput, "/tmp/output"}, {2, WSLAFdTypeDefault, nullptr}});
|
||||
|
||||
auto result = process->WaitAndCaptureOutput();
|
||||
VERIFY_ARE_EQUAL(result.Output[2], "cat: write error: Bad file descriptor\n");
|
||||
VERIFY_ARE_EQUAL(result.Output[2], "/bin/cat: write error: Bad file descriptor\n");
|
||||
VERIFY_ARE_EQUAL(result.Code, 1);
|
||||
}
|
||||
|
||||
|
|
@ -551,7 +569,7 @@ class WSLATests
|
|||
auto process = createProcess({"/bin/cat"}, {{0, WSLAFdTypeLinuxFileOutput, "/tmp/output"}, {2, WSLAFdTypeDefault, nullptr}});
|
||||
auto result = process->WaitAndCaptureOutput();
|
||||
|
||||
VERIFY_ARE_EQUAL(result.Output[2], "cat: read error: Bad file descriptor\n");
|
||||
VERIFY_ARE_EQUAL(result.Output[2], "/bin/cat: standard output: Bad file descriptor\n");
|
||||
VERIFY_ARE_EQUAL(result.Code, 1);
|
||||
}
|
||||
}
|
||||
|
|
@ -711,16 +729,29 @@ class WSLATests
|
|||
StopWslaService();
|
||||
}
|
||||
|
||||
TEST_METHOD(WindowsMounts)
|
||||
void ValidateWindowsMounts(bool enableVirtioFs)
|
||||
{
|
||||
WSL2_TEST_ONLY();
|
||||
auto settings = GetDefaultSessionSettings();
|
||||
WI_SetFlagIf(settings.FeatureFlags, WslaFeatureFlagsVirtioFs, enableVirtioFs);
|
||||
|
||||
auto session = CreateSession();
|
||||
auto session = CreateSession(settings);
|
||||
|
||||
wil::com_ptr<IWSLAVirtualMachine> vm;
|
||||
VERIFY_SUCCEEDED(session->GetVirtualMachine(&vm));
|
||||
wsl::windows::common::security::ConfigureForCOMImpersonation(vm.get());
|
||||
|
||||
auto expectedMountOptions = [&](bool readOnly) -> std::string {
|
||||
if (enableVirtioFs)
|
||||
{
|
||||
return std::format("/win-path*virtiofs*{},relatime*", readOnly ? "ro" : "rw");
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::format(
|
||||
"/win-path*9p*{},relatime,aname=*,cache=5,access=client,msize=65536,trans=fd,rfd=*,wfd=*", readOnly ? "ro" : "rw");
|
||||
}
|
||||
};
|
||||
|
||||
auto expectMount = [&](const std::string& target, const std::optional<std::string>& options) {
|
||||
auto cmd = std::format("set -o pipefail ; findmnt '{}' | tail -n 1", target);
|
||||
|
||||
|
|
@ -749,7 +780,7 @@ class WSLATests
|
|||
// Validate writeable mount.
|
||||
{
|
||||
VERIFY_SUCCEEDED(vm->MountWindowsFolder(testFolder.c_str(), "/win-path", false));
|
||||
expectMount("/win-path", "/win-path*9p*rw,relatime,aname=*,cache=5,access=client,msize=65536,trans=fd,rfd=*,wfd=*");
|
||||
expectMount("/win-path", expectedMountOptions(false));
|
||||
|
||||
// Validate that mount can't be stacked on each other
|
||||
VERIFY_ARE_EQUAL(vm->MountWindowsFolder(testFolder.c_str(), "/win-path", false), HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS));
|
||||
|
|
@ -765,7 +796,7 @@ class WSLATests
|
|||
// Validate read-only mount.
|
||||
{
|
||||
VERIFY_SUCCEEDED(vm->MountWindowsFolder(testFolder.c_str(), "/win-path", true));
|
||||
expectMount("/win-path", "/win-path*9p*rw,relatime,aname=*,cache=5,access=client,msize=65536,trans=fd,rfd=*,wfd=*");
|
||||
expectMount("/win-path", expectedMountOptions(true));
|
||||
|
||||
// Validate that folder is not writeable from linux
|
||||
ExpectCommandResult(session.get(), {"/bin/sh", "-c", "echo -n content > /win-path/file.txt"}, 1);
|
||||
|
|
@ -783,13 +814,25 @@ class WSLATests
|
|||
|
||||
// Validate that folders that are manually unmounted from the guest are handled properly
|
||||
VERIFY_SUCCEEDED(vm->MountWindowsFolder(testFolder.c_str(), "/win-path", true));
|
||||
expectMount("/win-path", "/win-path*9p*rw,relatime,aname=*,cache=5,access=client,msize=65536,trans=fd,rfd=*,wfd=*");
|
||||
expectMount("/win-path", expectedMountOptions(true));
|
||||
|
||||
ExpectCommandResult(session.get(), {"/usr/bin/umount", "/win-path"}, 0);
|
||||
VERIFY_SUCCEEDED(vm->UnmountWindowsFolder("/win-path"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_METHOD(WindowsMounts)
|
||||
{
|
||||
WSL2_TEST_ONLY();
|
||||
ValidateWindowsMounts(false);
|
||||
}
|
||||
|
||||
TEST_METHOD(WindowsMountsVirtioFs)
|
||||
{
|
||||
WSL2_TEST_ONLY();
|
||||
ValidateWindowsMounts(true);
|
||||
}
|
||||
|
||||
// This test case validates that no file descriptors are leaked to user processes.
|
||||
TEST_METHOD(Fd)
|
||||
{
|
||||
|
|
@ -800,7 +843,7 @@ class WSLATests
|
|||
ExpectCommandResult(session.get(), {"/bin/sh", "-c", "echo /proc/self/fd/* && (readlink -v /proc/self/fd/* || true)"}, 0);
|
||||
|
||||
// Note: fd/0 is opened by readlink to read the actual content of /proc/self/fd.
|
||||
if (!PathMatchSpecA(result.Output[1].c_str(), "/proc/self/fd/0 /proc/self/fd/1 /proc/self/fd/2\n"))
|
||||
if (!PathMatchSpecA(result.Output[1].c_str(), "/proc/self/fd/0 /proc/self/fd/1 /proc/self/fd/2\nsocket:*\nsocket:*"))
|
||||
{
|
||||
LogInfo("Found additional fds: %hs", result.Output[1].c_str());
|
||||
VERIFY_FAIL();
|
||||
|
|
@ -816,9 +859,6 @@ class WSLATests
|
|||
|
||||
auto session = CreateSession(settings);
|
||||
|
||||
wil::com_ptr<IWSLAVirtualMachine> vm;
|
||||
VERIFY_SUCCEEDED(session->GetVirtualMachine(&vm));
|
||||
|
||||
// Validate that the GPU device is available.
|
||||
ExpectCommandResult(session.get(), {"/bin/sh", "-c", "test -c /dev/dxg"}, 0);
|
||||
auto expectMount = [&](const std::string& target, const std::optional<std::string>& options) {
|
||||
|
|
@ -852,6 +892,8 @@ class WSLATests
|
|||
|
||||
// Validate that trying to mount the shares without GPU support disabled fails.
|
||||
{
|
||||
session.reset(); // Required to close the storage VHD.
|
||||
|
||||
WI_ClearFlag(settings.FeatureFlags, WslaFeatureFlagsGPU);
|
||||
session = CreateSession(settings);
|
||||
|
||||
|
|
@ -1039,7 +1081,7 @@ class WSLATests
|
|||
|
||||
// Dumps files are named with the format: wsl-crash-<sessionId>-<pid>-<processname>-<code>.dmp
|
||||
// Check if a new file was added in crashDumpsDir matching the pattern and not in existingDumps.
|
||||
std::string expectedPattern = std::format("wsl-crash-*-{}-_usr_bin_busybox-11.dmp", processId);
|
||||
std::string expectedPattern = std::format("wsl-crash-*-{}-_usr_bin_cat-11.dmp", processId);
|
||||
|
||||
auto dumpFile = wsl::shared::retry::RetryWithTimeout<std::filesystem::path>(
|
||||
[crashDumpsDir, expectedPattern, existingDumps]() {
|
||||
|
|
@ -1101,22 +1143,8 @@ class WSLATests
|
|||
WSL2_TEST_ONLY();
|
||||
SKIP_TEST_ARM64();
|
||||
|
||||
auto storagePath = std::filesystem::current_path() / "test-storage";
|
||||
|
||||
auto cleanup = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&]() {
|
||||
std::error_code error;
|
||||
|
||||
std::filesystem::remove_all(storagePath, error);
|
||||
if (error)
|
||||
{
|
||||
LogError("Failed to cleanup storage path %ws: %hs", storagePath.c_str(), error.message().c_str());
|
||||
}
|
||||
});
|
||||
|
||||
auto settings = GetDefaultSessionSettings();
|
||||
settings.NetworkingMode = WSLANetworkingModeNAT;
|
||||
settings.StoragePath = storagePath.c_str();
|
||||
settings.MaximumStorageSizeMb = 1024;
|
||||
|
||||
auto session = CreateSession(settings);
|
||||
|
||||
|
|
@ -1210,22 +1238,8 @@ class WSLATests
|
|||
WSL2_TEST_ONLY();
|
||||
SKIP_TEST_ARM64();
|
||||
|
||||
auto storagePath = std::filesystem::current_path() / "test-storage";
|
||||
|
||||
auto cleanup = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&]() {
|
||||
std::error_code error;
|
||||
|
||||
std::filesystem::remove_all(storagePath, error);
|
||||
if (error)
|
||||
{
|
||||
LogError("Failed to cleanup storage path %ws: %hs", storagePath.c_str(), error.message().c_str());
|
||||
}
|
||||
});
|
||||
|
||||
auto settings = GetDefaultSessionSettings();
|
||||
settings.NetworkingMode = WSLANetworkingModeNAT;
|
||||
settings.StoragePath = storagePath.c_str();
|
||||
settings.MaximumStorageSizeMb = 1024;
|
||||
|
||||
auto session = CreateSession(settings);
|
||||
|
||||
|
|
@ -1566,4 +1580,81 @@ class WSLATests
|
|||
}
|
||||
*/
|
||||
}
|
||||
|
||||
TEST_METHOD(Exec)
|
||||
{
|
||||
WSL2_TEST_ONLY();
|
||||
SKIP_TEST_ARM64();
|
||||
|
||||
auto settings = GetDefaultSessionSettings();
|
||||
settings.NetworkingMode = WSLANetworkingModeNAT;
|
||||
|
||||
auto session = CreateSession(settings);
|
||||
|
||||
// Create a container.
|
||||
WSLAContainerLauncher launcher(
|
||||
"debian:latest", "test-container-exec", {}, {"sleep", "99999"}, {}, ProcessFlags::Stdout | ProcessFlags::Stderr);
|
||||
|
||||
auto container = launcher.Launch(*session);
|
||||
|
||||
// Simple exec case.
|
||||
{
|
||||
auto process =
|
||||
WSLAProcessLauncher("/bin/echo", {"echo", "OK"}, {}, ProcessFlags::Stdout | ProcessFlags::Stderr).Launch(container.Get());
|
||||
|
||||
ValidateProcessOutput(process, {{1, "OK\n"}});
|
||||
}
|
||||
|
||||
// Validate that stdin is correctly wired.
|
||||
// TODO: Add test coverage for stdin being closed without anything written to it once the stdin hang issue is solved.
|
||||
{
|
||||
auto process = WSLAProcessLauncher({}, {"/bin/cat"}, {}, ProcessFlags::Stdin | ProcessFlags::Stdout | ProcessFlags::Stderr)
|
||||
.Launch(container.Get());
|
||||
|
||||
std::string shellInput = "foo";
|
||||
std::vector<char> inputBuffer{shellInput.begin(), shellInput.end()};
|
||||
|
||||
std::unique_ptr<OverlappedIOHandle> writeStdin(new WriteHandle(process.GetStdHandle(0), inputBuffer));
|
||||
|
||||
std::vector<std::unique_ptr<OverlappedIOHandle>> extraHandles;
|
||||
extraHandles.emplace_back(std::move(writeStdin));
|
||||
|
||||
auto result = process.WaitAndCaptureOutput(INFINITE, std::move(extraHandles));
|
||||
|
||||
VERIFY_ARE_EQUAL(result.Output[2], "");
|
||||
VERIFY_ARE_EQUAL(result.Output[1], "foo");
|
||||
VERIFY_ARE_EQUAL(result.Code, 0);
|
||||
}
|
||||
|
||||
// Validate that environmnent is correctly wired.
|
||||
{
|
||||
auto process =
|
||||
WSLAProcessLauncher({}, {"/bin/sh", "-c", "echo $testenv"}, {{"testenv=testvalue"}}, ProcessFlags::Stdout | ProcessFlags::Stderr)
|
||||
.Launch(container.Get());
|
||||
|
||||
ValidateProcessOutput(process, {{1, "testvalue\n"}});
|
||||
}
|
||||
|
||||
// Validate that an exec'd command returns when the container is stopped.
|
||||
{
|
||||
auto process = WSLAProcessLauncher({}, {"/bin/cat"}, {}, ProcessFlags::Stdin | ProcessFlags::Stdout | ProcessFlags::Stderr)
|
||||
.Launch(container.Get());
|
||||
|
||||
VERIFY_SUCCEEDED(container.Get().Stop(9, 0));
|
||||
|
||||
ExpectCommandResult(session.get(), {"/usr/bin/nerdctl", "stop", "-t", "0", "test-container-exec"}, 0);
|
||||
|
||||
auto result = process.WaitAndCaptureOutput();
|
||||
VERIFY_ARE_EQUAL(result.Code, 1);
|
||||
}
|
||||
|
||||
// Validate error paths
|
||||
{
|
||||
// Validate that processes can't be launched in stopped containers.
|
||||
auto [result, _, __] = WSLAProcessLauncher({}, {"/bin/cat"}).LaunchNoThrow(container.Get());
|
||||
VERIFY_ARE_EQUAL(result, HRESULT_FROM_WIN32(ERROR_INVALID_STATE));
|
||||
|
||||
// TODO: Implement proper handling of executables that don't exist in the container.
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -71,23 +71,41 @@ if ($Package) {
|
|||
try {
|
||||
if ($AllowUnsigned)
|
||||
{
|
||||
# unfortunately -AllowUnsigned isn't supported on vb so we need to manually import the certificate and trust it.
|
||||
(Get-AuthenticodeSignature $Package).SignerCertificate | Export-Certificate -FilePath private-wsl.cert | Out-Null
|
||||
try
|
||||
{
|
||||
Import-Certificate -FilePath .\private-wsl.cert -CertStoreLocation Cert:\LocalMachine\Root | Out-Null
|
||||
# Try to add with -AllowUnsigned first (supported in newer PowerShell)
|
||||
try {
|
||||
Add-AppxPackage $Package -AllowUnsigned -ErrorAction Stop
|
||||
}
|
||||
finally
|
||||
{
|
||||
Remove-Item -Path .\private-wsl.cert
|
||||
catch {
|
||||
# Fallback: manually import the certificate and trust it
|
||||
Write-Host "Attempting to import package certificate..."
|
||||
$signature = Get-AuthenticodeSignature -LiteralPath $Package
|
||||
if (-not $signature.SignerCertificate) {
|
||||
Write-Error "Package is not signed or has no certificate. Cannot import certificate."
|
||||
exit 1
|
||||
}
|
||||
|
||||
$cert = $signature.SignerCertificate
|
||||
$certPath = Join-Path $env:TEMP "wsl-package-cert.cer"
|
||||
try {
|
||||
$cert | Export-Certificate -FilePath $certPath | Out-Null
|
||||
Import-Certificate -FilePath $certPath -CertStoreLocation Cert:\LocalMachine\Root | Out-Null
|
||||
Write-Host "Certificate imported successfully. Retrying package installation..."
|
||||
}
|
||||
finally {
|
||||
Remove-Item -Path $certPath -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
# Retry installation after importing certificate
|
||||
Add-AppxPackage $Package -ErrorAction Stop
|
||||
}
|
||||
}
|
||||
|
||||
Add-AppxPackage $Package
|
||||
else {
|
||||
Add-AppxPackage $Package -ErrorAction Stop
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Host $_
|
||||
Get-AppPackageLog -All
|
||||
Write-Host "Error installing package: $_"
|
||||
Get-AppPackageLog | Select-Object -First 64 | Format-List
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,92 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<WindowsPerformanceRecorder Version="1">
|
||||
<Profiles>
|
||||
<EventCollector Id="Collector" Name="Collector">
|
||||
<BufferSize Value="256"/>
|
||||
<Buffers Value="1024"/>
|
||||
</EventCollector>
|
||||
|
||||
<EventProvider Id="lxcore_kernel" Name="0CD1C309-0878-4515-83DB-749843B3F5C9"/>
|
||||
<EventProvider Id="lxcore_user" Name="D90B9468-67F0-5B3B-42CC-82AC81FFD960"/>
|
||||
<EventProvider Id="lxcore_service" Name="B99CDB5A-039C-5046-E672-1A0DE0A40211"/>
|
||||
<EventProvider Id="vm_chipset" Name="de9ba731-7f33-4f44-98c9-6cac856b9f83"/>
|
||||
<EventProvider Id="vmcompute_dll" Name="AF7FD3A7-B248-460C-A9F5-FEC39EF8468C"/>
|
||||
<EventProvider Id="vmcompute" Name="17103E3F-3C6E-4677-BB17-3B267EB5BE57"/>
|
||||
<EventProvider Id="vmmm" Name="6066F867-7CA1-4418-85FD-36E3F9C0600C"/>
|
||||
<EventProvider Id="vmwp" Name="51DDFA29-D5C8-4803-BE4B-2ECB715570FE"/>
|
||||
<EventProvider Id="9p" Name="e13c8d52-b153-571f-78c5-1d4098af2a1e"/>
|
||||
<EventProvider Id="p9rdr" Name="bb1d36f0-e0e0-48cc-9493-fef0e3d0b28c" NonPagedMemory="true" Strict="true"/>
|
||||
<EventProvider Id="mup" Name="20c46239-d059-4214-a11e-7d6769cbe020" />
|
||||
<EventProvider Id="rfsmon" Name="51734B23-5B7E-4892-BA8E-45BC110B735C" />
|
||||
<EventProvider Id="hyperv_storage" Name="c7ad62c6-5c99-5a1b-bbc4-0821ae5b765e" />
|
||||
<EventProvider Id="hns" Name="0c885e0d-6eb6-476c-a048-2457eed3a5c1" />
|
||||
<EventProvider Id="wsl_devicehost" Name="9d6c7b9e-2581-4d8a-b8c5-b90b4a17094a"/>
|
||||
<EventProvider Id="vfpext" Name="9F2660EA-CFE7-428F-9850-AECA612619B0" />
|
||||
<EventProvider Id="EventProvider_Microsoft.Windows.Mobile.Provisioning.AppDownload" Name="0BBE6221-EF09-4A3F-82EE-BE00DBB6A98A" />
|
||||
<EventProvider Id="EventProvider_Microsoft.Windows.Mobile.Provisioning.Datastore" Name="42C60CEA-0FE7-4541-A86B-9E11F95BD9BF" />
|
||||
<EventProvider Id="EventProvider_Microsoft.Windows.Mobile.Provisioning.PhoneProvisioner" Name="B876B1FC-C7F1-443E-9012-86677F7DE580" />
|
||||
<EventProvider Id="EventProvider_Microsoft.Windows.Mobile.Provisioning.PPOEM" Name="7EDBED09-1FF7-4FEE-B8C3-5DB694420830" />
|
||||
<EventProvider Id="EventProvider_Microsoft.Windows.Provisioning.API" Name="82ADD491-01D7-4B85-9EAD-192C3CAACA23" />
|
||||
<EventProvider Id="EventProvider_Microsoft.Windows.Provisioning.CSP" Name="16E12400-A2D8-44B7-9479-004568EC7819" />
|
||||
<EventProvider Id="EventProvider_Microsoft.Windows.Provisioning.Engine" Name="A6A847B7-4429-49AA-BBA6-2AD8C191AC8C" />
|
||||
<EventProvider Id="EventProvider_Microsoft.Windows.Provisioning.Handlers" Name="0383D92C-2337-4F25-A0B5-A51767F04746" />
|
||||
<EventProvider Id="EventProvider_Microsoft.Windows.Provisioning.Migration" Name="A0AF985E-83F9-4E1A-B658-338DCFE27893" />
|
||||
<EventProvider Id="EventProvider_Microsoft.Windows.Provisioning.Operations" Name="7F99598F-B2C1-4371-9911-63DEE13B9EB1" />
|
||||
<EventProvider Id="EventProvider_Microsoft.Windows.Provisioning.Platform" Name="B1F30020-8BC3-4888-BB1B-4DD681F24209" />
|
||||
<EventProvider Id="EventProvider_Microsoft.Windows.Provisioning.Plugin.Engine" Name="55239D60-0EB6-495B-874E-15DE5D5F9A70" />
|
||||
<EventProvider Id="EventProvider_Microsoft.Windows.Provisioning.Plugin.RemovableMedia" Name="B55883E6-6C45-45C2-AB9D-800BB7B66B13" />
|
||||
<EventProvider Id="EventProvider_Microsoft.Windows.Provisioning.ProvTool" Name="2BF4B6BA-556E-4D05-8534-CAFEDF19FED8" />
|
||||
<EventProvider Id="EventProvider_Microsoft.Windows.Provisioning.CommandCsp" Name="00BB69FC-60BC-4502-9438-25608F375CCB" />
|
||||
<EventProvider Id="EventProvider_Microsoft.Windows.Provisioning.ProvLaunch" Name="08FACCFA-125D-4ED6-B0B7-B4A1A912E693" />
|
||||
<EventProvider Id="EventProvider_Microsoft.Windows.EMPS.Enrollment" Name="E74EFD1A-B62D-4B83-AB00-66F4A166A2D3" />
|
||||
<EventProvider Id="EventProvider_Microsoft.Windows.EnterpriseManagement.Enrollment" Name="F9E3B648-9AF1-4DC3-9A8E-BF42C0FBCE9A" />
|
||||
|
||||
<Profile
|
||||
Id="WSL.Verbose.File"
|
||||
Name="WSL"
|
||||
Description="Traces for all WSL components"
|
||||
LoggingMode="File"
|
||||
DetailLevel="Verbose"
|
||||
>
|
||||
<Collectors>
|
||||
<EventCollectorId Value="Collector">
|
||||
<EventProviders>
|
||||
<EventProviderId Value="lxcore_kernel"/>
|
||||
<EventProviderId Value="lxcore_user"/>
|
||||
<EventProviderId Value="lxcore_service"/>
|
||||
<EventProviderId Value="vm_chipset"/>
|
||||
<EventProviderId Value="vmcompute_dll"/>
|
||||
<EventProviderId Value="vmcompute"/>
|
||||
<EventProviderId Value="vmmm"/>
|
||||
<EventProviderId Value="vmwp"/>
|
||||
<EventProviderId Value="9p"/>
|
||||
<EventProviderId Value="p9rdr"/>
|
||||
<EventProviderId Value="mup"/>
|
||||
<EventProviderId Value="rfsmon"/>
|
||||
<EventProviderId Value="hyperv_storage"/>
|
||||
<EventProviderId Value="hns"/>
|
||||
<EventProviderId Value="wsl_devicehost"/>
|
||||
<EventProviderId Value="vfpext"/>
|
||||
<EventProviderId Value="EventProvider_Microsoft.Windows.Mobile.Provisioning.AppDownload"/>
|
||||
<EventProviderId Value="EventProvider_Microsoft.Windows.Mobile.Provisioning.Datastore"/>
|
||||
<EventProviderId Value="EventProvider_Microsoft.Windows.Mobile.Provisioning.PhoneProvisioner"/>
|
||||
<EventProviderId Value="EventProvider_Microsoft.Windows.Mobile.Provisioning.PPOEM"/>
|
||||
<EventProviderId Value="EventProvider_Microsoft.Windows.Provisioning.CSP"/>
|
||||
<EventProviderId Value="EventProvider_Microsoft.Windows.Provisioning.Engine"/>
|
||||
<EventProviderId Value="EventProvider_Microsoft.Windows.Provisioning.Migration"/>
|
||||
<EventProviderId Value="EventProvider_Microsoft.Windows.Provisioning.Platform"/>
|
||||
<EventProviderId Value="EventProvider_Microsoft.Windows.Provisioning.Operations"/>
|
||||
<EventProviderId Value="EventProvider_Microsoft.Windows.Provisioning.Plugin.Engine"/>
|
||||
<EventProviderId Value="EventProvider_Microsoft.Windows.Provisioning.Plugin.RemovableMedia"/>
|
||||
<EventProviderId Value="EventProvider_Microsoft.Windows.Provisioning.ProvTool"/>
|
||||
<EventProviderId Value="EventProvider_Microsoft.Windows.Provisioning.Operations"/>
|
||||
<EventProviderId Value="EventProvider_Microsoft.Windows.Provisioning.CommandCsp"/>
|
||||
<EventProviderId Value="EventProvider_Microsoft.Windows.Provisioning.ProvLaunch"/>
|
||||
<EventProviderId Value="EventProvider_Microsoft.Windows.EMPS.Enrollment"/>
|
||||
<EventProviderId Value="EventProvider_Microsoft.Windows.EnterpriseManagement.Enrollment"/>
|
||||
</EventProviders>
|
||||
</EventCollectorId>
|
||||
</Collectors>
|
||||
</Profile>
|
||||
</Profiles>
|
||||
</WindowsPerformanceRecorder>
|
||||
Loading…
Reference in New Issue