Harden the COM service API (#40749)

* Harden the COM service API * Apply PR feedback

Blue committed Jun 8, 2026 at 18:02 UTC 1309fd1c26628673e258357bcff52b6672baa19f
8 files changed +181 -1
src/windows/service/exe/HcsVirtualMachine.cpp
+6
@@ -375,6 +375,8 @@ bool HcsVirtualMachine::FeatureEnabled(WSLCFeatureFlags Value) const
375 HRESULT HcsVirtualMachine::GetId(_Out_ GUID* VmId)
376 try
377 {
378 + RETURN_HR_IF_NULL(E_POINTER, VmId);
379 +
380 *VmId = m_vmId;
381 return S_OK;
382 }
@@ -383,6 +385,8 @@ CATCH_RETURN()
385 HRESULT HcsVirtualMachine::AcceptConnection(_Out_ HANDLE* Socket)
386 try
387 {
388 + RETURN_HR_IF_NULL(E_POINTER, Socket);
389 +
390 auto socket = wsl::windows::common::hvsocket::CancellableAccept(m_listenSocket.get(), m_bootTimeoutMs, m_vmExitEvent.get());
391 THROW_HR_IF(E_ABORT, !socket.has_value());
392
@@ -658,6 +662,8 @@ CATCH_RETURN()
662 HRESULT HcsVirtualMachine::GetTerminationEvent(_Out_ HANDLE* Event)
663 try
664 {
665 + RETURN_HR_IF_NULL(E_POINTER, Event);
666 +
667 *Event = wslutil::DuplicateHandle(m_vmExitEvent.get());
668
669 return S_OK;
src/windows/service/exe/WSLCSessionManager.cpp
+12
@@ -167,6 +167,8 @@ CATCH_LOG()
167 void WSLCSessionManagerImpl::CreateSession(
168 _In_ const WSLCSessionSettings* Settings, _In_ WSLCSessionFlags Flags, _In_opt_ IWarningCallback* WarningCallback, _Out_ IWSLCSession** WslcSession)
169 {
170 + THROW_HR_IF_NULL(E_POINTER, WslcSession);
171 +
172 auto tokenInfo = GetCallingProcessTokenInfo();
173 const auto callerToken = wsl::windows::common::security::GetUserToken(TokenImpersonation);
174
@@ -183,6 +185,9 @@ void WSLCSessionManagerImpl::CreateSession(
185 THROW_HR_IF(WSLC_E_INVALID_SESSION_NAME, Settings->DisplayName == nullptr || wcslen(Settings->DisplayName) == 0);
186 THROW_HR_IF(E_INVALIDARG, Settings->StoragePath != nullptr && wcslen(Settings->StoragePath) == 0);
187 THROW_HR_IF(WSLC_E_INVALID_SESSION_NAME, wcslen(Settings->DisplayName) >= std::size(WSLCSessionListEntry{}.DisplayName));
188 + THROW_HR_IF_MSG(E_INVALIDARG, WI_IsAnyFlagSet(Flags, ~WSLCSessionFlagsValid), "Invalid session flags: 0x%x", Flags);
189 + THROW_HR_IF_MSG(
190 + E_INVALIDARG, WI_IsAnyFlagSet(Settings->FeatureFlags, ~WSLCFeatureFlagsValid), "Invalid feature flags: 0x%x", Settings->FeatureFlags);
191 THROW_HR_IF_MSG(
192 E_INVALIDARG,
193 WI_IsAnyFlagSet(Settings->StorageFlags, ~WSLCSessionStorageFlagsValid),
@@ -334,6 +339,8 @@ void WSLCSessionManagerImpl::CreateSession(
339
340 void WSLCSessionManagerImpl::OpenSession(ULONG Id, IWSLCSession** Session)
341 {
342 + THROW_HR_IF_NULL(E_POINTER, Session);
343 +
344 auto tokenInfo = GetCallingProcessTokenInfo();
345 auto result = ForEachSession<HRESULT>([&](auto& entry, const wil::com_ptr<IWSLCSession>& session) noexcept -> std::optional<HRESULT> {
346 if (entry.SessionId != Id)
@@ -353,6 +360,8 @@ void WSLCSessionManagerImpl::OpenSession(ULONG Id, IWSLCSession** Session)
360
361 void WSLCSessionManagerImpl::OpenSessionByName(LPCWSTR DisplayName, IWSLCSession** Session)
362 {
363 + THROW_HR_IF_NULL(E_POINTER, Session);
364 +
365 auto tokenInfo = GetCallingProcessTokenInfo();
366
367 // Null name = default session, resolved from caller's token + username.
@@ -381,6 +390,9 @@ void WSLCSessionManagerImpl::OpenSessionByName(LPCWSTR DisplayName, IWSLCSession
390
391 void WSLCSessionManagerImpl::ListSessions(_Out_ WSLCSessionListEntry** Sessions, _Out_ ULONG* SessionsCount)
392 {
393 + THROW_HR_IF_NULL(E_POINTER, Sessions);
394 + THROW_HR_IF_NULL(E_POINTER, SessionsCount);
395 +
396 std::vector<WSLCSessionListEntry> sessionInfo;
397
398 ForEachSession<void>([&](auto& entry, const auto&) noexcept {
src/windows/wslcsession/WSLCContainer.cpp
+14
@@ -2054,6 +2054,10 @@ HRESULT WSLCContainer::Attach(LPCSTR DetachKeys, WSLCHandle* Stdin, WSLCHandle*
2054 {
2055 WSLCExecutionContext context(&m_session);
2056
2057 + RETURN_HR_IF_NULL(E_POINTER, Stdin);
2058 + RETURN_HR_IF_NULL(E_POINTER, Stdout);
2059 + RETURN_HR_IF_NULL(E_POINTER, Stderr);
2060 +
2061 *Stdin = {};
2062 *Stdout = {};
2063 *Stderr = {};
@@ -2092,6 +2096,8 @@ HRESULT WSLCContainer::GetInitProcess(IWSLCProcess** Process)
2096 {
2097 WSLCExecutionContext context(&m_session);
2098
2099 + RETURN_HR_IF_NULL(E_POINTER, Process);
2100 +
2101 *Process = nullptr;
2102
2103 HRESULT hr = CallImpl(&WSLCContainerImpl::GetInitProcess, Process);
@@ -2118,6 +2124,10 @@ HRESULT WSLCContainer::Exec(const WSLCProcessOptions* Options, LPCSTR DetachKeys
2124 {
2125 WSLCExecutionContext context(&m_session);
2126
2127 + RETURN_HR_IF_NULL(E_POINTER, Options);
2128 + RETURN_HR_IF_NULL(E_POINTER, Process);
2129 + RETURN_HR_IF_MSG(E_INVALIDARG, WI_IsAnyFlagSet(Options->Flags, ~WSLCProcessFlagsValid), "Invalid flags: 0x%x", Options->Flags);
2130 +
2131 *Process = nullptr;
2132 return CallImpl(&WSLCContainerImpl::Exec, Options, DetachKeys, Process);
2133 }
@@ -2151,6 +2161,8 @@ HRESULT WSLCContainer::Inspect(LPSTR* Output)
2161 {
2162 WSLCExecutionContext context(&m_session);
2163
2164 + RETURN_HR_IF_NULL(E_POINTER, Output);
2165 +
2166 *Output = nullptr;
2167
2168 return CallImpl(&WSLCContainerImpl::Inspect, Output);
@@ -2227,6 +2239,8 @@ try
2239 {
2240 WSLCExecutionContext context(&m_session);
2241
2242 + RETURN_HR_IF_NULL(E_POINTER, Id);
2243 +
2244 const auto hr = wil::ResultFromException([&] {
2245 auto [lock, impl] = LockImpl();
2246 WI_VERIFY(strcpy_s(Id, std::size<char>(WSLCContainerId{}), impl->ID().c_str()) == 0);
src/windows/wslcsession/WSLCProcess.cpp
+10
@@ -34,6 +34,8 @@ CATCH_RETURN();
34 HRESULT WSLCProcess::GetExitEvent(HANDLE* Event)
35 try
36 {
37 + RETURN_HR_IF_NULL(E_POINTER, Event);
38 +
39 *Event = wsl::windows::common::wslutil::DuplicateHandle(m_control->GetExitEvent().get(), SYNCHRONIZE, FALSE);
40 return S_OK;
41 }
@@ -42,6 +44,7 @@ CATCH_RETURN();
44 HRESULT WSLCProcess::GetStdHandle(WSLCFD Fd, WSLCHandle* Handle)
45 try
46 {
47 + RETURN_HR_IF_NULL(E_POINTER, Handle);
48 RETURN_HR_IF_MSG(HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED), !m_io, "Process IO not attached");
49
50 auto typedHandle = m_io->OpenFd(Fd);
@@ -68,6 +71,8 @@ CATCH_RETURN();
71 HRESULT WSLCProcess::GetFlags(WSLCProcessFlags* Flags)
72 try
73 {
74 + RETURN_HR_IF_NULL(E_POINTER, Flags);
75 +
76 *Flags = m_flags;
77 return S_OK;
78 }
@@ -88,6 +93,8 @@ HANDLE WSLCProcess::GetExitEvent()
93 HRESULT WSLCProcess::GetPid(int* Pid)
94 try
95 {
96 + RETURN_HR_IF_NULL(E_POINTER, Pid);
97 +
98 *Pid = m_control->GetPid();
99 return S_OK;
100 }
@@ -101,6 +108,9 @@ int WSLCProcess::GetPid() const
108 HRESULT WSLCProcess::GetState(WSLCProcessState* State, int* Code)
109 try
110 {
111 + RETURN_HR_IF_NULL(E_POINTER, State);
112 + RETURN_HR_IF_NULL(E_POINTER, Code);
113 +
114 std::tie(*State, *Code) = m_control->GetState();
115 return S_OK;
116 }
src/windows/wslcsession/WSLCSession.cpp
+36 -1
@@ -266,6 +266,14 @@ try
266 RETURN_HR_IF(E_POINTER, Settings == nullptr || Vm == nullptr);
267 RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_ALREADY_INITIALIZED), m_virtualMachine.has_value());
268
269 + THROW_HR_IF_MSG(
270 + E_INVALIDARG, WI_IsAnyFlagSet(Settings->FeatureFlags, ~WSLCFeatureFlagsValid), "Invalid feature flags: 0x%x", Settings->FeatureFlags);
271 + THROW_HR_IF_MSG(
272 + E_INVALIDARG,
273 + WI_IsAnyFlagSet(Settings->StorageFlags, ~WSLCSessionStorageFlagsValid),
274 + "Invalid storage flags: 0x%x",
275 + Settings->StorageFlags);
276 +
277 // Set up a warning context for the duration of initialization so that non-fatal
278 // failures (e.g., container/volume/network recovery) are streamed to the CLI.
279 WSLCExecutionContext warningContext(this, WarningCallback);
@@ -439,6 +447,8 @@ void WSLCSession::ConfigureStorage(const WSLCSessionInitSettings& Settings, PSID
447
448 HRESULT WSLCSession::GetId(ULONG* Id)
449 {
450 + RETURN_HR_IF_NULL(E_POINTER, Id);
451 +
452 *Id = m_id;
453
454 return S_OK;
@@ -1672,7 +1682,17 @@ try
1682 WSLCExecutionContext context(this, WarningCallback);
1683 THROW_HR_IF_NULL(E_POINTER, containerOptions);
1684 THROW_HR_IF_NULL(E_POINTER, Container);
1675 - THROW_HR_IF(E_POINTER, containerOptions->Image == nullptr);
1685 + THROW_HR_IF_NULL(E_POINTER, containerOptions->Image);
1686 + THROW_HR_IF_MSG(
1687 + E_INVALIDARG,
1688 + WI_IsAnyFlagSet(containerOptions->Flags, ~WSLCContainerFlagsValid),
1689 + "Invalid container flags: 0x%x",
1690 + containerOptions->Flags);
1691 + THROW_HR_IF_MSG(
1692 + E_INVALIDARG,
1693 + WI_IsAnyFlagSet(containerOptions->InitProcessOptions.Flags, ~WSLCProcessFlagsValid),
1694 + "Invalid process flags: 0x%x",
1695 + containerOptions->InitProcessOptions.Flags);
1696
1697 auto lock = m_lock.lock_shared();
1698
@@ -1776,6 +1796,9 @@ try
1796 {
1797 WSLCExecutionContext context(this);
1798
1799 + RETURN_HR_IF_NULL(E_POINTER, Id);
1800 + RETURN_HR_IF_NULL(E_POINTER, Container);
1801 +
1802 ValidateName(Id, WSLC_MAX_CONTAINER_NAME_LENGTH);
1803
1804 // Look for an exact ID match first.
@@ -1991,6 +2014,11 @@ try
2014 {
2015 WSLCExecutionContext context(this);
2016
2017 + THROW_HR_IF_NULL(E_POINTER, Executable);
2018 + THROW_HR_IF_NULL(E_POINTER, Options);
2019 + THROW_HR_IF_NULL(E_POINTER, Process);
2020 + THROW_HR_IF_MSG(E_INVALIDARG, WI_IsAnyFlagSet(Options->Flags, ~WSLCProcessFlagsValid), "Invalid flags: 0x%x", Options->Flags);
2021 +
2022 if (Errno != nullptr)
2023 {
2024 *Errno = -1; // Make sure not to return 0 if something fails.
@@ -2600,6 +2628,9 @@ try
2628 {
2629 WSLCExecutionContext context(this);
2630
2631 + RETURN_HR_IF_NULL(E_POINTER, WindowsPath);
2632 + RETURN_HR_IF_NULL(E_POINTER, LinuxPath);
2633 +
2634 auto lock = m_lock.lock_shared();
2635 THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_STATE), !m_virtualMachine);
2636
@@ -2612,6 +2643,8 @@ try
2643 {
2644 WSLCExecutionContext context(this);
2645
2646 + RETURN_HR_IF_NULL(E_POINTER, LinuxPath);
2647 +
2648 auto lock = m_lock.lock_shared();
2649 THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_STATE), !m_virtualMachine);
2650
@@ -2826,6 +2859,8 @@ void WSLCSession::OnContainerDeleted(const WSLCContainerImpl* Container)
2859
2860 HRESULT WSLCSession::GetState(_Out_ WSLCSessionState* State)
2861 {
2862 + RETURN_HR_IF_NULL(E_POINTER, State);
2863 +
2864 *State = m_terminated ? WSLCSessionStateTerminated : WSLCSessionStateRunning;
2865 return S_OK;
2866 }
src/windows/wslcsession/WSLCSessionFactory.cpp
+5
@@ -38,6 +38,9 @@ HRESULT wslc::WSLCSessionFactory::CreateSession(
38 _Out_ IWSLCSessionReference** ServiceRef)
39 try
40 {
41 + RETURN_HR_IF_NULL(E_POINTER, Session);
42 + RETURN_HR_IF_NULL(E_POINTER, ServiceRef);
43 +
44 *Session = nullptr;
45 *ServiceRef = nullptr;
46
@@ -71,6 +74,8 @@ CATCH_RETURN()
74 HRESULT wslc::WSLCSessionFactory::GetProcessHandle(_Out_ HANDLE* ProcessHandle)
75 try
76 {
77 + RETURN_HR_IF_NULL(E_POINTER, ProcessHandle);
78 +
79 wil::unique_handle process{OpenProcess(PROCESS_SET_QUOTA | PROCESS_TERMINATE, FALSE, GetCurrentProcessId())};
80 RETURN_LAST_ERROR_IF(!process);
81
src/windows/wslcsession/WSLCSessionReference.cpp
+2
@@ -33,6 +33,8 @@ wslc::WSLCSessionReference::~WSLCSessionReference() = default;
33
34 HRESULT wslc::WSLCSessionReference::OpenSession(_Out_ IWSLCSession** Session)
35 {
36 + RETURN_HR_IF_NULL(E_POINTER, Session);
37 +
38 *Session = nullptr;
39
40 Microsoft::WRL::ComPtr<IWSLCSession> lockedSession;
test/windows/WSLCTests.cpp
+96
@@ -451,6 +451,39 @@ class WSLCTests
451 wil::com_ptr<IWSLCSession> session;
452 VERIFY_ARE_EQUAL(sessionManager->CreateSession(&settings, WSLCSessionFlagsNone, nullptr, &session), E_INVALIDARG);
453 }
454 +
455 + // Reject invalid session flags.
456 + {
457 + auto settings = GetDefaultSessionSettings(L"invalid-session-flags");
458 + wil::com_ptr<IWSLCSession> session;
459 + VERIFY_ARE_EQUAL(E_INVALIDARG, sessionManager->CreateSession(&settings, static_cast<WSLCSessionFlags>(0x4), nullptr, &session));
460 + }
461 +
462 + // Reject invalid feature flags.
463 + {
464 + auto settings = GetDefaultSessionSettings(L"invalid-feature-flags");
465 + settings.FeatureFlags = static_cast<WSLCFeatureFlags>(0x20);
466 + wil::com_ptr<IWSLCSession> session;
467 + VERIFY_ARE_EQUAL(E_INVALIDARG, sessionManager->CreateSession(&settings, WSLCSessionFlagsNone, nullptr, &session));
468 + }
469 +
470 + // Reject NULL output pointers across the session manager API.
471 + {
472 + auto settings = GetDefaultSessionSettings(L"null-out-session");
473 + VERIFY_ARE_EQUAL(
474 + HRESULT_FROM_WIN32(RPC_X_NULL_REF_POINTER), sessionManager->CreateSession(&settings, WSLCSessionFlagsNone, nullptr, nullptr));
475 + VERIFY_ARE_EQUAL(HRESULT_FROM_WIN32(RPC_X_NULL_REF_POINTER), sessionManager->OpenSession(0, nullptr));
476 + VERIFY_ARE_EQUAL(HRESULT_FROM_WIN32(RPC_X_NULL_REF_POINTER), sessionManager->OpenSessionByName(c_testSessionName, nullptr));
477 +
478 + WSLCSessionListEntry* entries = nullptr;
479 + ULONG count = 0;
480 + VERIFY_ARE_EQUAL(HRESULT_FROM_WIN32(RPC_X_NULL_REF_POINTER), sessionManager->ListSessions(nullptr, &count));
481 + VERIFY_ARE_EQUAL(HRESULT_FROM_WIN32(RPC_X_NULL_REF_POINTER), sessionManager->ListSessions(&entries, nullptr));
482 + }
483 +
484 + // The session object must reject NULL output pointers.
485 + VERIFY_ARE_EQUAL(HRESULT_FROM_WIN32(RPC_X_NULL_REF_POINTER), m_defaultSession->GetId(nullptr));
486 + VERIFY_ARE_EQUAL(HRESULT_FROM_WIN32(RPC_X_NULL_REF_POINTER), m_defaultSession->GetState(nullptr));
487 }
488
489 struct VmInfo
@@ -3585,6 +3618,15 @@ class WSLCTests
3618
3619 WSLC_TEST_METHOD(CreateRootNamespaceProcess)
3620 {
3621 + // Reject invalid process flags.
3622 + {
3623 + WSLCProcessOptions options{};
3624 + options.Flags = static_cast<WSLCProcessFlags>(0x4);
3625 + wil::com_ptr<IWSLCProcess> process;
3626 + int err = 0;
3627 + VERIFY_ARE_EQUAL(E_INVALIDARG, m_defaultSession->CreateRootNamespaceProcess("/bin/true", &options, &process, &err));
3628 + }
3629 +
3630 // Simple case
3631 {
3632 auto result = ExpectCommandResult(m_defaultSession.get(), {"/bin/sh", "-c", "echo OK"}, 0);
@@ -3626,6 +3668,17 @@ class WSLCTests
3668 // Validate that a null out handle is rejected.
3669
3670 VERIFY_ARE_EQUAL(process.Get().GetStdHandle(WSLCFDStdout, nullptr), HRESULT_FROM_WIN32(RPC_X_NULL_REF_POINTER));
3671 +
3672 + // Validate that every IWSLCProcess output pointer is rejected when null.
3673 + VERIFY_ARE_EQUAL(HRESULT_FROM_WIN32(RPC_X_NULL_REF_POINTER), process.Get().GetExitEvent(nullptr));
3674 + VERIFY_ARE_EQUAL(HRESULT_FROM_WIN32(RPC_X_NULL_REF_POINTER), process.Get().GetPid(nullptr));
3675 + VERIFY_ARE_EQUAL(HRESULT_FROM_WIN32(RPC_X_NULL_REF_POINTER), process.Get().GetState(nullptr, nullptr));
3676 + VERIFY_ARE_EQUAL(HRESULT_FROM_WIN32(RPC_X_NULL_REF_POINTER), process.Get().GetFlags(nullptr));
3677 +
3678 + // GetFlags succeeds with a valid pointer and reports the launched flags.
3679 + WSLCProcessFlags flags{};
3680 + VERIFY_SUCCEEDED(process.Get().GetFlags(&flags));
3681 + VERIFY_IS_TRUE(WI_IsFlagSet(flags, WSLCProcessFlagsStdin));
3682 }
3683
3684 // Create a stuck process and kill it.
@@ -5108,6 +5161,25 @@ class WSLCTests
5161 VERIFY_ARE_EQUAL(HRESULT_FROM_WIN32(RPC_X_NULL_REF_POINTER), container.Get().GetInitProcess(nullptr));
5162 }
5163
5164 + // Validate that CreateContainer rejects a null image and invalid flags.
5165 + {
5166 + WSLCContainerOptions options{};
5167 + wil::com_ptr<IWSLCContainer> container;
5168 +
5169 + // A null Image field is rejected with E_POINTER.
5170 + VERIFY_ARE_EQUAL(E_POINTER, m_defaultSession->CreateContainer(&options, nullptr, &container));
5171 +
5172 + // Invalid container flags are rejected with E_INVALIDARG.
5173 + options.Image = "debian:latest";
5174 + options.Flags = static_cast<WSLCContainerFlags>(0x10);
5175 + VERIFY_ARE_EQUAL(E_INVALIDARG, m_defaultSession->CreateContainer(&options, nullptr, &container));
5176 +
5177 + // Invalid init process flags are rejected with E_INVALIDARG.
5178 + options.Flags = WSLCContainerFlagsNone;
5179 + options.InitProcessOptions.Flags = static_cast<WSLCProcessFlags>(0x4);
5180 + VERIFY_ARE_EQUAL(E_INVALIDARG, m_defaultSession->CreateContainer(&options, nullptr, &container));
5181 + }
5182 +
5183 // Validate that env is correctly wired.
5184 {
5185 WSLCContainerLauncher launcher("debian:latest", "test-env", {"/bin/sh", "-c", "echo $testenv"}, {{"testenv=testvalue"}});
@@ -5600,6 +5672,13 @@ class WSLCTests
5672
5673 // Test error paths
5674 {
5675 + // A null id and a null output pointer are rejected by the marshaller.
5676 + {
5677 + wil::com_ptr<IWSLCContainer> container;
5678 + VERIFY_ARE_EQUAL(HRESULT_FROM_WIN32(RPC_X_NULL_REF_POINTER), m_defaultSession->OpenContainer(nullptr, &container));
5679 + VERIFY_ARE_EQUAL(HRESULT_FROM_WIN32(RPC_X_NULL_REF_POINTER), m_defaultSession->OpenContainer("named-container", nullptr));
5680 + }
5681 +
5682 expectOpen("", E_INVALIDARG);
5683 ValidateCOMErrorMessage(L"Invalid name: ''");
5684
@@ -6854,6 +6933,10 @@ class WSLCTests
6933 launcher.AddTmpfs("/mnt/wslc-tmpfs-inspect", "");
6934
6935 auto container = launcher.Launch(*m_defaultSession);
6936 +
6937 + // Validate that inspect fails with a null pointer.
6938 + VERIFY_ARE_EQUAL(HRESULT_FROM_WIN32(RPC_X_NULL_REF_POINTER), container.Get().Inspect(nullptr));
6939 +
6940 auto details = container.Inspect();
6941
6942 // Verify basic container metadata.
@@ -6956,6 +7039,19 @@ class WSLCTests
7039 ValidateProcessOutput(process, {{1, "OK\n"}});
7040 }
7041
7042 + // Validate that Exec rejects invalid flags and a null output pointer.
7043 + {
7044 + WSLCProcessOptions options{};
7045 + wil::com_ptr<IWSLCProcess> process;
7046 +
7047 + // A null output pointer is rejected by the marshaller.
7048 + VERIFY_ARE_EQUAL(HRESULT_FROM_WIN32(RPC_X_NULL_REF_POINTER), container.Get().Exec(&options, nullptr, nullptr));
7049 +
7050 + // Invalid process flags are rejected with E_INVALIDARG.
7051 + options.Flags = static_cast<WSLCProcessFlags>(0x4);
7052 + VERIFY_ARE_EQUAL(E_INVALIDARG, container.Get().Exec(&options, nullptr, &process));
7053 + }
7054 +
7055 // Validate that the working directory is correctly wired.
7056 {
7057 WSLCProcessLauncher launcher({}, {"pwd"});