@samitouri / QOSAMI-WSL / commits / 64233136

Switch `wslinfo --vm-id` to not rely on presence of VM ID environment variable (#13318)

* Switch WSLg to use wslinfo --vm-id instead of relying on environment variable * DO NOT MERGE: bad WSLg nuget * dead code removal * always send response to LxInitMessageQueryVmId message * add back invalid WslInfoMode error * remove unneeded wsl2 check * use temporary workaround until WSLg update is ready * unit test update * Update string compare Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

Ben Hillis committed Aug 5, 2025 at 14:36 UTC 642331364dda7a3d88bf64acb87e7056918a5fc9
9 files changed +113 -33
src/linux/init/WslDistributionConfig.h
+1
@@ -79,6 +79,7 @@ struct WslDistributionConfig
79 bool GuiAppsEnabled = false;
80 std::optional<int> FeatureFlags = 0;
81 std::optional<LX_MINI_INIT_NETWORKING_MODE> NetworkingMode = LxMiniInitNetworkingModeNone;
82 + std::optional<std::string> VmId;
83
84 //
85 // Global state for boot state. The socket is used to delay-start the distro init process
src/linux/init/config.cpp
+12 -11
@@ -436,6 +436,18 @@ try
436 ResponseChannel.SendResultMessage<uint8_t>(static_cast<uint8_t>(Config.NetworkingMode.value()));
437 break;
438
439 + case LxInitMessageQueryVmId:
440 + {
441 + wsl::shared::MessageWriter<LX_INIT_QUERY_VM_ID> Response(LxInitMessageQueryVmId);
442 + if (Config.VmId.has_value())
443 + {
444 + Response.WriteString(Config.VmId.value());
445 + }
446 +
447 + ResponseChannel.SendMessage<LX_INIT_QUERY_VM_ID>(Response.Span());
448 + break;
449 + }
450 +
451 default:
452 LOG_ERROR("unexpected message {}", Header->MessageType);
453 break;
@@ -1662,17 +1674,6 @@ Return Value:
1674 ConfigAppendNtPath(Environment, Buffer);
1675 }
1676
1665 - //
1666 - // If the VM ID environment variable is present, add it to the environment
1667 - // block.
1668 - //
1669 -
1670 - auto VmId = getenv(LX_WSL2_VM_ID_ENV);
1671 - if (VmId)
1672 - {
1673 - Environment.AddVariable(LX_WSL2_VM_ID_ENV, VmId);
1674 - }
1675 -
1677 return Environment;
1678 }
1679
src/linux/init/init.cpp
+15 -1
@@ -2239,13 +2239,27 @@ Return Value:
2239 unsetenv(LX_WSL2_DISTRO_READ_ONLY_ENV);
2240 }
2241
2242 - const auto Value = getenv(LX_WSL2_NETWORKING_MODE_ENV);
2242 + auto Value = getenv(LX_WSL2_NETWORKING_MODE_ENV);
2243 if (Value != nullptr)
2244 {
2245 Config.NetworkingMode = static_cast<LX_MINI_INIT_NETWORKING_MODE>(std::atoi(Value));
2246 unsetenv(LX_WSL2_NETWORKING_MODE_ENV);
2247 }
2248
2249 + Value = getenv(LX_WSL2_VM_ID_ENV);
2250 + if (Value != nullptr)
2251 + {
2252 + Config.VmId = Value;
2253 +
2254 + // Unset the environment variable for user distros.
2255 + // TODO: this can be removed when WSLg is updated to use `wslinfo --vm-id` instead of the environment variable.
2256 + Value = getenv(LX_WSL2_SYSTEM_DISTRO);
2257 + if (!Value || strcmp(Value, "1") != 0)
2258 + {
2259 + unsetenv(LX_WSL2_VM_ID_ENV);
2260 + }
2261 + }
2262 +
2263 //
2264 // If the boot.systemd option is specified in /etc/wsl.conf, launch the distro init process as pid 1.
2265 // WSL init and session leaders continue as children of the distro init process.
src/linux/init/main.cpp
+5
@@ -1827,6 +1827,11 @@ try
1827 AddEnvironmentVariable(LX_WSL2_USER_PROFILE, UserProfile);
1828 AddEnvironmentVariable(LX_WSL2_NETWORKING_MODE_ENV, std::to_string(static_cast<int>(Config.NetworkingMode)).c_str());
1829
1830 + if (UserProfile)
1831 + {
1832 + AddEnvironmentVariable(LX_WSL2_SYSTEM_DISTRO, "1");
1833 + }
1834 +
1835 if (DistroInitPid.has_value())
1836 {
1837 AddEnvironmentVariable(LX_WSL2_DISTRO_INIT_PID, std::to_string(static_cast<int>(DistroInitPid.value())).c_str());
src/linux/init/util.cpp
+36 -7
@@ -1201,8 +1201,7 @@ std::optional<LX_MINI_INIT_NETWORKING_MODE> UtilGetNetworkingMode(void)
1201
1202 Routine Description:
1203
1204 - This routine gets the feature flags, either directly, from an environment
1205 - variable, or by querying it from the init process.
1204 + This routine queries the networking mode from the init process.
1205
1206 Arguments:
1207
@@ -1210,16 +1209,12 @@ Arguments:
1209
1210 Return Value:
1211
1213 - The feature flags.
1212 + The networking mode if successful, std::nullopt otherwise.
1213
1214 --*/
1215
1216 try
1217 {
1219 - //
1220 - // Query init for the value.
1221 - //
1222 -
1218 wsl::shared::SocketChannel channel{UtilConnectUnix(WSL_INIT_INTEROP_SOCKET), "wslinfo"};
1219 THROW_LAST_ERROR_IF(channel.Socket() < 0);
1220
@@ -1297,6 +1292,40 @@ Return Value:
1292 return Result;
1293 }
1294
1295 +std::string UtilGetVmId(void)
1296 +
1297 +/*++
1298 +
1299 +Routine Description:
1300 +
1301 + This routine queries the VM ID from the init process.
1302 +
1303 +Arguments:
1304 +
1305 + None.
1306 +
1307 +Return Value:
1308 +
1309 + The VM ID if successful, an empty string otherwise.
1310 +
1311 +--*/
1312 +
1313 +try
1314 +{
1315 + wsl::shared::SocketChannel channel{UtilConnectUnix(WSL_INIT_INTEROP_SOCKET), "wslinfo"};
1316 + THROW_LAST_ERROR_IF(channel.Socket() < 0);
1317 +
1318 + wsl::shared::MessageWriter<LX_INIT_QUERY_VM_ID> Message(LxInitMessageQueryVmId);
1319 + channel.SendMessage<LX_INIT_QUERY_VM_ID>(Message.Span());
1320 +
1321 + return channel.ReceiveMessage<LX_INIT_QUERY_VM_ID>().Buffer;
1322 +}
1323 +catch (...)
1324 +{
1325 + LOG_CAUGHT_EXCEPTION();
1326 + return {};
1327 +}
1328 +
1329 void UtilInitGroups(const char* User, gid_t Gid)
1330
1331 /*++
src/linux/init/util.h
+2
@@ -227,6 +227,8 @@ std::optional<LX_MINI_INIT_NETWORKING_MODE> UtilGetNetworkingMode(void);
227
228 pid_t UtilGetPpid(pid_t Pid);
229
230 +std::string UtilGetVmId(void);
231 +
232 void UtilInitGroups(const char* User, gid_t Gid);
233
234 void UtilInitializeMessageBuffer(std::vector<gsl::byte>& Buffer);
src/linux/init/wslinfo.cpp
+13 -6
@@ -149,14 +149,21 @@ Return Value:
149 }
150 else if (Mode.value() == WslInfoMode::VMId)
151 {
152 - auto value = UtilGetEnvironmentVariable(LX_WSL2_VM_ID_ENV);
153 - if (value.empty())
152 + if (UtilIsUtilityVm())
153 {
155 - std::cerr << Localization::MessageNoValueFound() << "\n";
156 - return 1;
157 - }
154 + auto vmId = UtilGetVmId();
155 + if (vmId.empty())
156 + {
157 + std::cerr << Localization::MessageNoValueFound() << "\n";
158 + return 1;
159 + }
160
159 - std::cout << value;
161 + std::cout << vmId;
162 + }
163 + else
164 + {
165 + std::cout << "wsl1";
166 + }
167 }
168 else
169 {
src/shared/inc/lxinitshared.h
+12
@@ -255,6 +255,7 @@ Abstract:
255 #define LX_WSL2_SHARED_MEMORY_OB_DIRECTORY "WSL2_SHARED_MEMORY_OB_DIRECTORY"
256 #define LX_WSL2_INSTALL_PATH "WSL2_INSTALL_PATH"
257 #define LX_WSL2_SAFE_MODE "WSL2_SAFE_MODE"
258 +#define LX_WSL2_SYSTEM_DISTRO "WSL2_SYSTEM_DISTRO"
259 #define LX_WSL2_USER_PROFILE "WSL2_USER_PROFILE"
260 #define LX_WSL2_VM_ID_ENV "WSL2_VM_ID"
261 #define LX_WSL_PID_ENV "WSL2_PID"
@@ -304,6 +305,7 @@ typedef enum _LX_MESSAGE_TYPE
305 LxInitMessageCreateLoginSession,
306 LxInitMessageStopPlan9Server,
307 LxInitMessageQueryNetworkingMode,
308 + LxInitMessageQueryVmId,
309 LxInitCreateProcess,
310 LxInitOobeResult,
311 LxMiniInitMessageLaunchInit,
@@ -1496,6 +1498,16 @@ typedef struct _LX_INIT_OOBE_RESULT
1498 PRETTY_PRINT(FIELD(Header), FIELD(Result), FIELD(DefaultUid));
1499 } LX_INIT_OOBE_RESULT, *PLX_INIT_OOBE_RESULT;
1500
1501 +typedef struct _LX_INIT_QUERY_VM_ID
1502 +{
1503 + static inline auto Type = LxInitMessageQueryVmId;
1504 +
1505 + MESSAGE_HEADER Header;
1506 + char Buffer[];
1507 +
1508 + PRETTY_PRINT(FIELD(Header), FIELD(Buffer));
1509 +} LX_INIT_QUERY_VM_ID, *PLX_INIT_QUERY_VM_ID;
1510 +
1511 template <>
1512 struct std::formatter<LX_MESSAGE_TYPE, char>
1513 {
test/windows/UnitTests.cpp
+17 -8
@@ -843,16 +843,25 @@ class UnitTests
843 L"arguments.\n");
844 }
845
846 - if (LxsstuVmMode())
846 {
848 - // Get the VM ID from the distro and validate that it not null.
849 - auto [vmId, vmIdErr] = LxsstuLaunchWslAndCaptureOutput(L"env | grep 'WSL2_VM_ID' | awk -F= '{print $2}'");
850 - VERIFY_ARE_NOT_EQUAL(vmId, L"");
851 -
852 - // Ensure that the response from wslinfo matches the VM id from the distros environment
853 - auto [out, err] = LxsstuLaunchWslAndCaptureOutput(L"wslinfo --vm-id");
854 - VERIFY_ARE_EQUAL(out, std::format(L"{}", vmId));
847 + auto [out, err] = LxsstuLaunchWslAndCaptureOutput(L"wslinfo --vm-id -n");
848 VERIFY_ARE_EQUAL(err, L"");
849 + if (LxsstuVmMode())
850 + {
851 + // Ensure that the response from wslinfo has the VM ID.
852 + auto guid = wsl::shared::string::ToGuid(out);
853 + VERIFY_IS_TRUE(guid.has_value());
854 + VERIFY_IS_FALSE(IsEqualGUID(guid.value(), GUID_NULL));
855 +
856 + // Validate that the VM ID is not propagated to user commands.
857 + std::tie(out, err) = LxsstuLaunchWslAndCaptureOutput(L"echo -n \"$WSL2_VM_ID\"");
858 + VERIFY_ARE_EQUAL(out, L"");
859 + VERIFY_ARE_EQUAL(err, L"");
860 + }
861 + else
862 + {
863 + VERIFY_ARE_EQUAL(out, L"wsl1");
864 + }
865 }
866 }
867