Skip to content
Draft
Show file tree
Hide file tree
Changes from 3 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
46 changes: 45 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin/${TARGET_PLATFORM})
# BUNDLE_ONLY mode: skip all source builds; only configure the msixbundle target and nuspec files.
# Used by the package pipeline stage to create the bundle from pre-built per-platform msix files.
option(BUNDLE_ONLY "Only configure the msixbundle target, skip all source builds" OFF)
option(INCLUDE_OPENVMM "Include OpenVMM build integrations" OFF)
if (BUNDLE_ONLY)
if (NOT PACKAGE_VERSION)
message(FATAL_ERROR "PACKAGE_VERSION is required for BUNDLE_ONLY mode")
Expand All @@ -63,7 +64,8 @@ include(FetchContent)

set(FETCHCONTENT_BASE_DIR ${CMAKE_BINARY_DIR}/_deps/${TARGET_PLATFORM})

# N.B. Changes to any of the FetchContent dependencies below (GSL, nlohmannjson) must be reflected in cgmanifest.json
# N.B. Changes to any of the FetchContent dependencies below (GSL, nlohmannjson, yaml-cpp, boost, protobuf)
# must be reflected in cgmanifest.json

FetchContent_Declare(GSL
URL https://github.com/microsoft/GSL/archive/refs/tags/v4.0.0.tar.gz
Expand Down Expand Up @@ -104,6 +106,48 @@ FetchContent_Declare(

FetchContent_MakeAvailable(boost_headers)

set(protobuf_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(protobuf_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
set(protobuf_INSTALL OFF CACHE BOOL "" FORCE)

if (INCLUDE_OPENVMM)
FetchContent_Declare(protobuf
URL https://github.com/protocolbuffers/protobuf/releases/download/v34.1/protobuf-34.1.tar.gz
URL_HASH SHA256=e4e6ff10760cf747a2decd1867741f561b216bd60cc4038c87564713a6da1848)

FetchContent_MakeAvailable(protobuf)
include(${protobuf_SOURCE_DIR}/cmake/protobuf-generate.cmake)
endif()

# Adds protobuf-generated C++ sources from VMService.proto to the given TARGET.
# The target must already exist. This function handles code generation, include
# directories, library linking, and MSVC warning suppression for generated code.
function(wsl_add_openvmm_proto TARGET)
set(_proto_file ${WSL_DEVICE_HOST_SOURCE_DIR}/proto/VMService.proto)
set(_proto_out_dir ${CMAKE_CURRENT_BINARY_DIR}/generated)

if (NOT EXISTS ${_proto_file})
message(FATAL_ERROR "Expected DeviceHost proto file was not found: ${_proto_file}")
endif()

protobuf_generate(
TARGET ${TARGET}
PROTOS ${_proto_file}
IMPORT_DIRS ${WSL_DEVICE_HOST_SOURCE_DIR}/proto ${protobuf_SOURCE_DIR}/src
PROTOC_OUT_DIR ${_proto_out_dir}
)

target_include_directories(${TARGET} PRIVATE ${_proto_out_dir})
target_link_libraries(${TARGET} protobuf::libprotobuf)

if (MSVC)
set_source_files_properties(
${_proto_out_dir}/VMService.pb.cc
TARGET_DIRECTORY ${TARGET}
PROPERTIES COMPILE_OPTIONS "/wd4267;/wd4244;/wd4018")
endif()
endfunction()


# Import modules
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
Expand Down
11 changes: 11 additions & 0 deletions cgmanifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,17 @@
"hash": "sha256:42f6e95cad6ec532fd372391373363b62a14af6d771056dbfc86160e6dfff7aa"
}
}
},
{
"component": {
"type": "other",
"other": {
"name": "protobuf",
"version": "34.1",
"downloadUrl": "https://github.com/protocolbuffers/protobuf/releases/download/v34.1/protobuf-34.1.tar.gz",
"hash": "sha256:e4e6ff10760cf747a2decd1867741f561b216bd60cc4038c87564713a6da1848"
}
}
}
]
}
7 changes: 7 additions & 0 deletions msipackage/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ foreach(binary ${WINDOWS_BINARIES})
list(APPEND BINARIES_DEPENDENCIES "${PACKAGE_INPUT_DIR}/${binary}")
endforeach()

if (INCLUDE_OPENVMM)
set(WSL_DEVICE_HOST_BINARIES wsldevicehost.dll;openvmm.exe)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wsldevicehost.dll should be included all the time.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe that's an existing issue?

foreach(binary ${WSL_DEVICE_HOST_BINARIES})
list(APPEND BINARIES_DEPENDENCIES "${WSL_DEVICE_HOST_SOURCE_DIR}/bin/${TARGET_PLATFORM}/${binary}")
endforeach()
endif()

set(LINUX_BINARIES init;initrd.img)
foreach(binary ${LINUX_BINARIES})
list(APPEND BINARIES_DEPENDENCIES "${BIN}/${binary}")
Expand Down
1 change: 1 addition & 0 deletions msipackage/package.wix.in
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@
<ServiceControl Id="StopService" Stop="both" Remove="uninstall" Name="WSLService" Wait="yes" />

<File Id="wsldevicehost.dll" Source="${WSL_DEVICE_HOST_SOURCE_DIR}/bin/${TARGET_PLATFORM}/wsldevicehost.dll" />
<File Id="openvmm.exe" Source="${WSL_DEVICE_HOST_SOURCE_DIR}/bin/${TARGET_PLATFORM}/openvmm.exe" />
Comment on lines 243 to +245

<!-- WSLC COM app - activated through WSLService -->
<RegistryKey Root="HKCR" Key="AppID\{E9B79997-57E3-4201-AECC-6A464E530DD2}">
Expand Down
2 changes: 1 addition & 1 deletion packages.config
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<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.2.23-0" />
<package id="Microsoft.WSL.DeviceHost" version="1.2.25-0" />
<package id="Microsoft.WSL.Kernel" version="6.18.26.1-1" targetFramework="native" />
<package id="Microsoft.WSL.LinuxSdk" version="1.20.0" targetFramework="native" />
<package id="Microsoft.WSL.TestData" version="0.4.0" />
Expand Down
90 changes: 89 additions & 1 deletion src/linux/init/WSLCInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,94 @@ void HandleMessageImpl(
Transaction.SendResultMessage(result < 0 ? errno : 0);
}

void HandleMessageImpl(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we probably want to use the existing GNS implementation to do network configuration. it should support all of this stuff.

wsl::shared::SocketChannel& Channel,
wsl::shared::Transaction& Transaction,
const WSLC_CONFIGURE_NETWORKING& Message,
const gsl::span<gsl::byte>& Buffer)
{
int result = -EINVAL;
auto sendResult = wil::scope_exit([&]() { Transaction.SendResultMessage<int32_t>(result); });

const auto* iface = wsl::shared::string::FromSpan(Buffer, Message.InterfaceOffset);
const auto* address = wsl::shared::string::FromSpan(Buffer, Message.AddressOffset);
const auto* gateway = wsl::shared::string::FromSpan(Buffer, Message.GatewayOffset);
const auto* dnsServer = wsl::shared::string::FromSpan(Buffer, Message.DnsServerOffset);

THROW_ERRNO_IF(EINVAL, iface == nullptr || address == nullptr || gateway == nullptr || dnsServer == nullptr);

// Bring up the interface and configure the static address, route, and DNS.
auto configCmd = std::format(
"ip link set {} up && ip addr add {} dev {} && ip route add default via {}",
iface, address, iface, gateway);

// Use a pipe to detect child completion. The child inherits the write end;
// when it exits (via execl or _exit), the write end is closed and read()
// returns 0. This avoids racing with the WSLC_WATCH_PROCESSES handler's
// waitpid(-1) which may reap the child before we can.
int pipeFds[2]{};
THROW_LAST_ERROR_IF(pipe2(pipeFds, O_CLOEXEC) < 0);
wil::unique_fd pipeRead{pipeFds[0]};
wil::unique_fd pipeWrite{pipeFds[1]};

int childPid = UtilCreateChildProcess("ConfigureNetworking", [&configCmd, &pipeWrite]() {
// Clear CLOEXEC on the write end so it stays open across execl.
// When the shell exits, the fd is closed and the parent's read returns.
fcntl(pipeWrite.get(), F_SETFD, 0);
execl("/bin/sh", "/bin/sh", "-c", configCmd.c_str(), nullptr);
LOG_ERROR("execl(/bin/sh) failed, {}", errno);
});

// Close the write end in the parent — only the child holds it now.
pipeWrite.reset();

if (childPid < 0)
{
result = -errno;
return;
}

// Wait for the child to exit by reading from the pipe. When the child
// (and the shell it exec'd) exits, all write ends are closed and read
// returns 0.
char dummy{};
TEMP_FAILURE_RETRY(read(pipeRead.get(), &dummy, sizeof(dummy)));

// Try to reap the child. If WSLC_WATCH_PROCESSES already reaped it, we
// get ECHILD which is fine — the pipe close confirms the child exited.
int status = -1;
if (TEMP_FAILURE_RETRY(waitpid(childPid, &status, 0)) < 0)
{
if (errno == ECHILD)
{
// Child was already reaped by the WatchProcesses handler.
// The pipe confirmed it exited, so treat as success.
status = 0;
}
else
Comment on lines +726 to +737
{
result = -errno;
return;
}
}

result = UtilProcessChildExitCode(status, "ConfigureNetworking");
if (result != 0)
{
return;
}

// Write DNS configuration.
auto resolv = std::format("nameserver {}\n", dnsServer);
if (WriteToFile("/etc/resolv.conf", resolv.c_str()) < 0)
{
result = -errno;
return;
}

result = 0;
}

void HandleMessageImpl(wsl::shared::SocketChannel& Channel, wsl::shared::Transaction& Transaction, const WSLC_UNMOUNT&, const gsl::span<gsl::byte>& Buffer)
{
auto* path = wsl::shared::string::FromMessageBuffer<WSLC_UNMOUNT>(Buffer);
Expand Down Expand Up @@ -831,7 +919,7 @@ void ProcessMessage(wsl::shared::SocketChannel& Channel, wsl::shared::Transactio
{
try
{
HandleMessage<WSLC_GET_DISK, WSLC_MOUNT, WSLC_EXEC, WSLC_FORK, WSLC_CONNECT, WSLC_SIGNAL, WSLC_TTY_RELAY, WSLC_PORT_RELAY, WSLC_UNMOUNT, WSLC_DETACH, WSLC_ACCEPT, WSLC_WATCH_PROCESSES, WSLC_UNIX_CONNECT>(
HandleMessage<WSLC_GET_DISK, WSLC_MOUNT, WSLC_EXEC, WSLC_FORK, WSLC_CONNECT, WSLC_SIGNAL, WSLC_TTY_RELAY, WSLC_PORT_RELAY, WSLC_UNMOUNT, WSLC_DETACH, WSLC_ACCEPT, WSLC_WATCH_PROCESSES, WSLC_UNIX_CONNECT, WSLC_CONFIGURE_NETWORKING>(
Channel, Transaction, Type, Buffer);
}
catch (...)
Expand Down
Loading
Loading