Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 27 additions & 15 deletions .pipelines/build-job.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,20 +64,32 @@ jobs:
pool: ${{ parameters.pool }}

variables:
NUGET_PLUGIN_HANDSHAKE_TIMEOUT_IN_SECONDS: 60
NUGET_PLUGIN_REQUEST_TIMEOUT_IN_SECONDS: 60
ob_outputDirectory: '$(Build.SourcesDirectory)\out'
ob_artifactBaseName: 'drop_wsl'
ob_artifactSuffix: '${{ parameters.artifactSuffix }}'
packageStagingDir: '$(Build.SourcesDirectory)\packageStagingDir'
ob_sdl_codeSignValidation_excludes: -|**\*.ps1;-|**\testbin\**
${{ if parameters.includeCodeQL }}:
Codeql.PublishDatabaseLog: true
Codeql.SourceRoot: src
${{ if eq(parameters.isRelease, true) }}:
packageInputDirArg: '-DPACKAGE_INPUT_DIR=$(packageStagingDir)'
${{ else }}:
packageInputDirArg: ''
- template: variables.yml
- name: NUGET_PLUGIN_HANDSHAKE_TIMEOUT_IN_SECONDS
value: 60
- name: NUGET_PLUGIN_REQUEST_TIMEOUT_IN_SECONDS
value: 60
- name: ob_outputDirectory
value: '$(Build.SourcesDirectory)\out'
- name: ob_artifactBaseName
value: 'drop_wsl'
- name: ob_artifactSuffix
value: '${{ parameters.artifactSuffix }}'
- name: packageStagingDir
value: '$(Build.SourcesDirectory)\packageStagingDir'
- name: ob_sdl_codeSignValidation_excludes
value: -|**\*.ps1;-|**\testbin\**
- ${{ if parameters.includeCodeQL }}:
- name: Codeql.PublishDatabaseLog
value: true
- name: Codeql.SourceRoot
value: src
- ${{ if eq(parameters.isRelease, true) }}:
- name: packageInputDirArg
value: '-DPACKAGE_INPUT_DIR=$(packageStagingDir)'
- ${{ else }}:
- name: packageInputDirArg
value: ''

steps:

Expand Down Expand Up @@ -124,7 +136,7 @@ jobs:
displayName: "CMake ${{ parameters.platform }}"
inputs:
workingDirectory: "."
cmakeArgs: . --fresh -A ${{ parameters.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 }} -DINCLUDE_PACKAGE_STAGE=${{ or(parameters.isRelease, parameters.isNightly) }} -DPIPELINE_BUILD_ID=$(Build.BuildId) -DVSO_ORG=${{ parameters.vsoOrg }} -DVSO_PROJECT=${{ parameters.vsoProject }} -DWSL_BUILD_WSL_SETTINGS=true -DWSL_INCLUDE_SDK_CSHARP=true $(packageInputDirArg)\${{ parameters.platform }}
cmakeArgs: . --fresh -A ${{ parameters.platform }} -DCMAKE_BUILD_TYPE=Release -DCMAKE_SYSTEM_VERSION=$(cmakeSystemVersion) -DPACKAGE_VERSION=$(version.WSL_PACKAGE_VERSION) -DWSL_NUGET_PACKAGE_VERSION=$(version.WSL_NUGET_PACKAGE_VERSION) -DSKIP_PACKAGE_SIGNING=${{ parameters.isRelease }} -DOFFICIAL_BUILD=${{ parameters.isRelease }} -DINCLUDE_PACKAGE_STAGE=${{ or(parameters.isRelease, parameters.isNightly) }} -DPIPELINE_BUILD_ID=$(Build.BuildId) -DVSO_ORG=${{ parameters.vsoOrg }} -DVSO_PROJECT=${{ parameters.vsoProject }} -DWSL_BUILD_WSL_SETTINGS=true -DWSL_INCLUDE_SDK_CSHARP=true $(packageInputDirArg)\${{ parameters.platform }}

# Workaround for WSL Settings NuGet restore authentication issue
- script: _deps\nuget.exe restore -NonInteractive
Expand Down
80 changes: 80 additions & 0 deletions .pipelines/fuzzing-stage.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Fuzzing stage — builds fuzz harnesses with ASAN/SanCov and submits to OneFuzz.

parameters:
- name: fuzzTargets
type: object
default:
- WslcCliArgumentFuzzing
- WslcSdkFuzzing
- WslcWinRtFuzzing

stages:
- stage: fuzzing
dependsOn: []
jobs:
- job: fuzzing_x64
displayName: "Build and submit WSLC fuzz targets (x64)"
timeoutInMinutes: 120
pool:
type: windows

# OneFuzz job notification (a team alias) and the bug assignee (a person) must be defined as secret pipeline variables.
variables:
- template: variables.yml
- name: ob_outputDirectory
value: '$(Build.SourcesDirectory)\out'
- name: fuzzingBinDir
value: '$(Build.SourcesDirectory)\bin\x64\Release'
- name: fuzzingStagingDir
value: '$(ob_outputDirectory)\fuzzing'

steps:
- task: CMake@1
displayName: "CMake configure (fuzzing)"
inputs:
workingDirectory: "."
cmakeArgs: . --fresh -A x64 -DCMAKE_BUILD_TYPE=Release -DCMAKE_SYSTEM_VERSION=$(cmakeSystemVersion) -DWSL_BUILD_FUZZING=true -DONEFUZZ_NOTIFICATION_EMAIL=$(oneFuzzNotificationEmail) -DONEFUZZ_ASSIGNED_TO=$(oneFuzzAssignedTo)

# Build the fuzzing targets, and the MSI for setting up the VMs
- task: CMake@1
displayName: "CMake build (fuzzing)"
inputs:
workingDirectory: "."
cmakeArgs: --build . --config Release --target ${{ join(' ', parameters.fuzzTargets) }} msipackage -- -m

- ${{ each target in parameters.fuzzTargets }}:
- task: PowerShell@2
displayName: "Stage ${{ target }} binaries"
inputs:
targetType: inline
script: |
$binDir = "$(fuzzingBinDir)"
$dropDir = "$(fuzzingStagingDir)"
New-Item -ItemType Directory -Path $dropDir -Force
Copy-Item "$binDir\${{ target }}.*" $dropDir

- task: PowerShell@2
displayName: "Stage shared fuzzing artifacts"
inputs:
targetType: inline
script: |
$binDir = "$(fuzzingBinDir)"
$dropDir = "$(fuzzingStagingDir)"

# CMake places OneFuzzConfig.json, setup.ps1, and per-harness extra dependencies
# (e.g. wslcsdk.dll/pdb) under the fuzzing output dir.
Copy-Item "$binDir\fuzzing\*" $dropDir -Force

# Shared runtime deps. CMake copies the ASAN runtime next to the build output.
Copy-Item "$binDir\wsl.msi" $dropDir
Copy-Item "$binDir\clang_rt.asan_dynamic*.dll" $dropDir

Get-ChildItem $dropDir -Recurse | Format-Table Name, Length

- task: onefuzz-task@0
displayName: "Submit to OneFuzz"
inputs:
onefuzzOSes: 'Windows'
env:
onefuzzDropDirectory: $(fuzzingStagingDir)
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
3 changes: 3 additions & 0 deletions .pipelines/variables.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
variables:
- name: cmakeSystemVersion
value: '10.0.26100.0'
2 changes: 2 additions & 0 deletions .pipelines/wsl-build-nightly-onebranch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ extends:
vsoOrg: microsoft
vsoProject: Microsoft.WSL

- template: fuzzing-stage.yml@self

- template: test-stage.yml@self
parameters:
rs_prerelease_only: false
Expand Down
50 changes: 44 additions & 6 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,10 @@ if (NOT DEFINED WSL_INCLUDE_SDK_CSHARP)
set(WSL_INCLUDE_SDK_CSHARP false)
endif ()

if (NOT DEFINED WSL_BUILD_FUZZING)
set(WSL_BUILD_FUZZING false)
endif ()

find_commit_hash(COMMIT_HASH)

if (NOT PACKAGE_VERSION)
Expand Down Expand Up @@ -314,18 +318,48 @@ endif ()
string(REPLACE "/Zi" "" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG}) # make sure /Zi is removed from the debug flags
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj /W3 /WX /ZH:SHA_256")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Z7 -DDEBUG -DDBG")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Zi /guard:cf /Qspectre")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Zi")

if (WSL_BUILD_FUZZING)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fsanitize=address")
add_compile_definitions(_DISABLE_VECTOR_ANNOTATION _DISABLE_STRING_ANNOTATION)

# All instrumented binaries import the dynamic ASAN runtime.
# We resolve its path so that we can include it in the MSI; we can find it next to the compiler.
# We also copy it next to the build output so that the pipeline can find it easily.
if (${TARGET_PLATFORM} STREQUAL "arm64")
set(ASAN_ARCH "aarch64")
else()
set(ASAN_ARCH "x86_64")
endif()
get_filename_component(MSVC_BIN_DIR ${CMAKE_CXX_COMPILER} DIRECTORY)
set(ASAN_RUNTIME_DLL ${MSVC_BIN_DIR}/clang_rt.asan_dynamic-${ASAN_ARCH}.dll)
file(COPY ${ASAN_RUNTIME_DLL} DESTINATION ${BIN})
endif ()

if (WSL_ENABLE_FUZZING_REPLAY)
add_compile_definitions(WSL_ENABLE_FUZZING_REPLAY)
endif ()

# Linker flags
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /debug:full /debugtype:cv,fixup /guard:cf /DYNAMICBASE")
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /debug:full /debugtype:cv,fixup /guard:cf /DYNAMICBASE")
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /debug:full /debugtype:cv,fixup /DYNAMICBASE")
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /debug:full /debugtype:cv,fixup /DYNAMICBASE")
if (DEFINED SOURCELINK_JSON)
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /SOURCELINK:\"${SOURCELINK_JSON}\"")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SOURCELINK:\"${SOURCELINK_JSON}\"")
endif()
if (${TARGET_PLATFORM} STREQUAL "x64")
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /CETCOMPAT")
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /CETCOMPAT")

# When WSL_BUILD_FUZZING is enabled, the entire build is compiled with ASAN.
# /fsanitize=address is incompatible with /guard:cf, /Qspectre, and /CETCOMPAT,
# so those are omitted for fuzzing builds.
if (NOT WSL_BUILD_FUZZING)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /guard:cf /Qspectre")
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /guard:cf")
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /guard:cf")
if (${TARGET_PLATFORM} STREQUAL "x64")
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /CETCOMPAT")
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /CETCOMPAT")
endif()
endif()

# Common link libraries
Expand Down Expand Up @@ -554,6 +588,10 @@ if (WSL_BUILD_WSL_SETTINGS)
add_subdirectory(src/windows/wslsettings)
endif()

if (WSL_BUILD_FUZZING)
add_subdirectory(src/windows/fuzzing)
endif()

add_subdirectory(src/linux/netlinkutil)
add_subdirectory(src/linux/mountutil)
add_subdirectory(src/linux/plan9)
Expand Down
9 changes: 9 additions & 0 deletions UserConfig.cmake.sample
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,12 @@ endif()
# # error - block the commit when formatting issues are found
# # fix - automatically fix formatting and re-stage files
# set(WSL_PRE_COMMIT_MODE "warn")

# # Uncomment to build fuzzing targets with ASAN and SanitizerCoverage for OneFuzz.
# # Harness binaries are written to bin/<platform>/<config>/ alongside OneFuzzConfig.json.
# # See src/windows/fuzzing/README.md for details.
# set(WSL_BUILD_FUZZING true)
#
# # Enable fuzzing replay mode: builds harnesses without libFuzzer so they can be run standalone
# # with a corpus file as argument. Useful for reproducing crashes locally.
# set(WSL_ENABLE_FUZZING_REPLAY true)
7 changes: 7 additions & 0 deletions msipackage/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ foreach(binary ${LINUX_BINARIES})
list(APPEND BINARIES_DEPENDENCIES "${BIN}/${binary}")
endforeach()

# When building with ASAN (fuzzing), the instrumented binaries import the dynamic ASAN runtime.
# Ship it alongside them in INSTALLDIR so they can load at runtime.
# ASAN_RUNTIME_DLL is resolved in the top-level CMakeLists.
if (WSL_BUILD_FUZZING)
list(APPEND BINARIES_DEPENDENCIES ${ASAN_RUNTIME_DLL})
endif()

if (${WSL_BUILD_THIN_PACKAGE})
set(COMPRESS_PACKAGE "no")
else()
Expand Down
4 changes: 4 additions & 0 deletions msipackage/package.wix.in
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@
<File Id="libwsl.dll" Name="libwsl.dll" Source="${PACKAGE_INPUT_DIR}/libwsl.dll" />
<?endif?>

<?if "${WSL_BUILD_FUZZING}" = "true" ?>
<File Id="asan_runtime" Source="${ASAN_RUNTIME_DLL}" />
<?endif?>

<?if "${WSL_DEV_BINARY_PATH}" = "" ?>
<File Id="system.vhd" Source="${WSLG_SOURCE_DIR}/${TARGET_PLATFORM}/system.vhd"/>
<?endif?>
Expand Down
25 changes: 20 additions & 5 deletions src/windows/common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -144,14 +144,29 @@ set(HEADERS
WSLCSessionDefaults.h
)

add_library(common STATIC ${SOURCES} ${HEADERS})
add_dependencies(common wslserviceidl localization wslservicemc wslinstalleridl yaml-cpp)
# Adds a target for the common static library.
# This is factored into a function so that we can have multiple variants with different options.
function(add_common_library TARGET_NAME)
add_library(${TARGET_NAME} STATIC ${SOURCES} ${HEADERS})
add_dependencies(${TARGET_NAME} wslserviceidl localization wslservicemc wslinstalleridl yaml-cpp)
target_precompile_headers(${TARGET_NAME} PRIVATE precomp.h)
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER windows)
target_include_directories(${TARGET_NAME} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/../service/mc/${TARGET_PLATFORM}/${CMAKE_BUILD_TYPE})
endfunction()

target_precompile_headers(common PRIVATE precomp.h)
set_target_properties(common PROPERTIES FOLDER windows)
target_include_directories(common PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/../service/mc/${TARGET_PLATFORM}/${CMAKE_BUILD_TYPE})
add_common_library(common)

# WSLCUserSettings.cpp uses yaml-cpp headers.
set_source_files_properties(WSLCUserSettings.cpp PROPERTIES
INCLUDE_DIRECTORIES "${yaml-cpp_SOURCE_DIR}/include"
COMPILE_DEFINITIONS "YAML_CPP_STATIC_DEFINE")

# For Fuzzing builds, there are some targets that cannot be built with ASAN instrumentation.
# These targets use a non-instrumented copy of the common library.
if (WSL_BUILD_FUZZING)
# Remove ASAN from all targets in this directory, then add it back only for the base variant.
string(REPLACE "/fsanitize=address" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
target_compile_options(common PRIVATE /fsanitize=address)

add_common_library(common_noasan)
endif()
79 changes: 79 additions & 0 deletions src/windows/fuzzing/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
set(FUZZING_OUT_DIR ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_BUILD_TYPE}/fuzzing)

# OneFuzz job notification (a team alias) and bug assignee (a person), substituted into
# OneFuzzConfigEntry.json.in. The pipeline passes these via -D from secret variables; local
# builds leave them empty since they never submit to OneFuzz.
if (NOT DEFINED ONEFUZZ_NOTIFICATION_EMAIL)
set(ONEFUZZ_NOTIFICATION_EMAIL "")
endif()
if (NOT DEFINED ONEFUZZ_ASSIGNED_TO)
set(ONEFUZZ_ASSIGNED_TO "")
endif()

function(add_fuzzing_harness TARGET)
cmake_parse_arguments(ARG "" "TARGET_NAME" "LINK_LIBRARIES;EXTRA_DEPENDENCIES;INCLUDE_DIRECTORIES" ${ARGN})

add_executable(${TARGET} ${TARGET}.cpp)
target_precompile_headers(${TARGET} REUSE_FROM common)

if (NOT WSL_ENABLE_FUZZING_REPLAY)
target_compile_options(${TARGET} PRIVATE /fsanitize=fuzzer)
endif()

if(ARG_LINK_LIBRARIES)
target_link_libraries(${TARGET} PRIVATE ${ARG_LINK_LIBRARIES})
endif()

if(ARG_INCLUDE_DIRECTORIES)
target_include_directories(${TARGET} PRIVATE ${ARG_INCLUDE_DIRECTORIES})
endif()

set_target_properties(${TARGET} PROPERTIES FOLDER fuzzing)

if(ARG_TARGET_NAME)
set(TARGET_NAME ${ARG_TARGET_NAME})
else()
set(TARGET_NAME ${TARGET})
endif()

# Add extra dependencies to the entry, and stage them into the shared fuzzing output dir
set(EXTRA_DEPENDENCIES_JSON "")
foreach(dep IN LISTS ARG_EXTRA_DEPENDENCIES)
string(APPEND EXTRA_DEPENDENCIES_JSON ", \"${dep}\"")

# Dependency file will be in the main binary output dir after build
add_custom_command(TARGET ${TARGET} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_BUILD_TYPE}/${dep}
${FUZZING_OUT_DIR}/${dep})
endforeach()

file(READ ${CMAKE_CURRENT_SOURCE_DIR}/OneFuzzConfigEntry.json.in ENTRY_TEMPLATE)
string(CONFIGURE "${ENTRY_TEMPLATE}" ENTRY_JSON)

# Append this harness's entry to OneFuzzConfig.json (written after all harnesses).
list(APPEND ONEFUZZ_ENTRIES "${ENTRY_JSON}")
set(ONEFUZZ_ENTRIES "${ONEFUZZ_ENTRIES}" PARENT_SCOPE)
endfunction()

configure_file(setup.ps1 ${FUZZING_OUT_DIR}/setup.ps1 COPYONLY)

add_fuzzing_harness(WslcCliArgumentFuzzing
TARGET_NAME cliArgumentParser
LINK_LIBRARIES wslclib)

add_fuzzing_harness(WslcSdkFuzzing
TARGET_NAME sdkApiFlow
LINK_LIBRARIES wslcsdk
INCLUDE_DIRECTORIES ${CMAKE_SOURCE_DIR}/src/windows/WslcSDK
EXTRA_DEPENDENCIES "wslcsdk.dll" "wslcsdk.pdb")

add_fuzzing_harness(WslcWinRtFuzzing
TARGET_NAME winrtApiFlow
LINK_LIBRARIES wslcsdk
INCLUDE_DIRECTORIES ${CMAKE_SOURCE_DIR}/src/windows/WslcSDK ${CMAKE_BINARY_DIR}/src/windows/WslcSDK/winrt/${TARGET_PLATFORM}/${CMAKE_BUILD_TYPE}
EXTRA_DEPENDENCIES "wslcsdk.dll" "wslcsdk.pdb")

# Write OneFuzzConfig.json with one entry per harness.
list(JOIN ONEFUZZ_ENTRIES ",\n" ONEFUZZ_ENTRIES)
configure_file(OneFuzzConfig.json.in ${FUZZING_OUT_DIR}/OneFuzzConfig.json)
Loading