Fix: Update plan9 registration with the new default uid after OOBE (#40977)
Currently, after a fresh distro installation, operations in the linux plan9 share will use the uid 0. Because the uid was cached before the OOBE is complete. And this only recovers after a distro termination. This PR updates the plan9 registration after the OOBE completes with the new default uid.
Feng Wang committed
Aug 7, 2026 at 11:36 UTC
70f6890c83bb5e56b8ea17abdbb834b55e92dc80
5 files changed
+55
-9
src/windows/common/Redirector.cpp
+29
-8
@@ -226,14 +226,14 @@ void ConnectionTargetManager::AddConnectionTarget(
226
if (!Contains(security.LogonId))
227
{
228
redirector::AddConnectionTarget(m_name, security.LogonId, aname, uid, unixSocketPath, instanceId, port);
229
- m_logonIds.push_back(security.LogonId);
229
+ m_targets.emplace_back(security.LogonId, std::string(aname), uid, std::wstring(unixSocketPath), instanceId, port);
230
}
231
232
// Checking the list also catches the case where the logon ID and linked logon ID are equal.
233
if (!Contains(security.LinkedLogonId))
234
{
235
redirector::AddConnectionTarget(m_name, security.LinkedLogonId, aname, uid, unixSocketPath, instanceId, port);
236
- m_logonIds.push_back(security.LinkedLogonId);
236
+ m_targets.emplace_back(security.LinkedLogonId, std::string(aname), uid, std::wstring(unixSocketPath), instanceId, port);
237
}
238
}
239
@@ -241,20 +241,41 @@ void ConnectionTargetManager::AddConnectionTarget(
241
void ConnectionTargetManager::RemoveAll()
242
{
243
auto lock = m_lock.lock_exclusive();
244
- for (const auto logonId : m_logonIds)
244
+ for (const auto& target : m_targets)
245
{
246
- RemoveConnectionTarget(m_name, logonId);
246
+ RemoveConnectionTarget(m_name, target.logonId);
247
}
248
249
- m_logonIds.clear();
249
+ m_targets.clear();
250
}
251
252
-// Checks whether the list of logon IDs contains the specified ID.
252
+// Checks whether the list of targets contains the specified ID.
253
bool ConnectionTargetManager::Contains(LUID luid) const
254
{
255
- const auto it = std::find_if(m_logonIds.begin(), m_logonIds.end(), [&luid](auto& item) { return RtlEqualLuid(&luid, &item); });
255
+ const auto it =
256
+ std::find_if(m_targets.begin(), m_targets.end(), [&luid](auto& item) { return RtlEqualLuid(&luid, &item.logonId); });
257
257
- return it != m_logonIds.end();
258
+ return it != m_targets.end();
259
+}
260
+
261
+// Re-add all connection targets with the new UID.
262
+void ConnectionTargetManager::UpdateUid(LX_UID_T uid)
263
+{
264
+ auto lock = m_lock.lock_exclusive();
265
+
266
+ for (auto& target : m_targets)
267
+ {
268
+ if (target.uid == uid)
269
+ {
270
+ continue;
271
+ }
272
+
273
+ redirector::RemoveConnectionTarget(m_name, target.logonId);
274
+ redirector::AddConnectionTarget(
275
+ m_name, target.logonId, target.aname, uid, target.unixSocketPath, target.instanceId, target.port);
276
+
277
+ target.uid = uid;
278
+ }
279
}
280
281
} // namespace wsl::windows::common::redirector
src/windows/common/Redirector.h
+13
-1
@@ -26,11 +26,23 @@ public:
26
27
void RemoveAll();
28
29
+ void UpdateUid(LX_UID_T uid);
30
+
31
private:
32
+ struct ConnectionTarget
33
+ {
34
+ LUID logonId;
35
+ std::string aname;
36
+ LX_UID_T uid;
37
+ std::wstring unixSocketPath;
38
+ GUID instanceId;
39
+ ULONG port;
40
+ };
41
+
42
bool Contains(LUID luid) const;
43
44
std::wstring_view m_name;
33
- std::vector<LUID> m_logonIds;
45
+ std::vector<ConnectionTarget> m_targets;
46
wil::srwlock m_lock;
47
};
48
src/windows/service/exe/LxssInstance.cpp
+2
@@ -577,6 +577,8 @@ wil::unique_handle LxssInstance::_CreateLxProcess(
577
registration.Write(wsl::windows::service::Property::DefaultUid, static_cast<int>(OobeResult->DefaultUid));
578
m_defaultUid = static_cast<int>(OobeResult->DefaultUid);
579
}
580
+
581
+ m_redirectorConnectionTargets.UpdateUid(m_defaultUid);
582
}
583
}
584
CATCH_LOG()
src/windows/service/exe/WslCoreInstance.cpp
+2
@@ -309,6 +309,8 @@ void WslCoreInstance::ReadOOBEResult(wil::unique_socket&& Socket, wsl::windows::
309
registration.Write(wsl::windows::service::Property::DefaultUid, static_cast<int>(oobeResult->DefaultUid));
310
m_defaultUid = static_cast<int>(oobeResult->DefaultUid);
311
}
312
+
313
+ m_redirectorConnectionTargets.UpdateUid(m_defaultUid);
314
}
315
}
316
test/windows/UnitTests.cpp
+9
@@ -4603,6 +4603,15 @@ VERSION_ID="Invalid|Format"
4603
// Validate that DefaultUid was set
4604
validateOutput(L"id -u", L"1010\n");
4605
VERIFY_ARE_EQUAL(defaultUid.Get(), 1010);
4606
+
4607
+ // New file should be created with the correct uid.
4608
+ const std::wstring testFilePathLinux = L"/tmp/oobe_file_test";
4609
+ const std::wstring testFilePathWindows = L"\\\\wsl.localhost\\" LXSS_DISTRO_NAME_TEST_L L"\\tmp\\oobe_file_test";
4610
+
4611
+ const wil::unique_hfile file(CreateFile(
4612
+ testFilePathWindows.c_str(), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr));
4613
+ VERIFY_IS_TRUE(file.is_valid());
4614
+ validateOutput(std::format(L"stat -c %u {}", testFilePathLinux).c_str(), L"1010\n");
4615
}
4616
4617
// Verify that the default UID isn't changed if it's not present in wsl-distribution.conf.