From bacc69061152115965f5b17fa59dc4e051ba8dc3 Mon Sep 17 00:00:00 2001 From: zylxjtu Date: Mon, 27 Apr 2026 17:19:58 +0000 Subject: [PATCH] Fix WS2022 compat on hosts past the latest LTSC The compat-range floor was computed by finding the latest LTSC strictly less than host.Build. That works for an exact LTSC host but breaks for any host past the latest LTSC: a WS2025-generation build like 26200 picks 26100 as the floor, excluding WS2022 (20348) containers even though the stable ABI policy permits them. Find the largest LTSC <= host.Build and step one entry back for the floor (or stay put if it is already the first entry). This keeps the floor at the previous LTSC across an entire host generation. Signed-off-by: yuanliang --- platform_windows_compat.go | 25 ++++++++++++++--------- platform_windows_compat_test.go | 35 +++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 9 deletions(-) diff --git a/platform_windows_compat.go b/platform_windows_compat.go index ef21a29..4aa162a 100644 --- a/platform_windows_compat.go +++ b/platform_windows_compat.go @@ -87,19 +87,26 @@ func checkWindowsHostAndContainerCompat(host, ctr windowsOSVersion) bool { return host.Build == ctr.Build } - // Find the latest LTSC version that is earlier than the host version. - // This is the earliest version of container that the host can run. + // Find the floor of the compatible container range. Per the Windows stable + // ABI policy, every host from LTSC N up to (but not including) LTSC N+1 can + // run containers from LTSC N-1 up to the host build. // - // If the host version is an LTSC, then it supports compatibility with - // everything from the previous LTSC up to itself, so we want supportedLTSCRelease - // to be the previous entry. + // So we find the largest LTSC <= host.Build, then step one entry back to + // get the floor. If host.Build is past the latest LTSC in the list + // (e.g. a 26200 host, which is in the WS2025 generation), the floor is + // still the previous LTSC (20348), not the latest LTSC itself. // - // If no match is found, then we know that the host is LTSC2022 exactly, - // since we already checked that it's not less than LTSC2022. + // If host is the very first LTSC (or no entry matches, which is impossible + // here since we already checked host.Build >= ltsc2022), use that LTSC as + // the floor. var supportedLTSCRelease uint16 = ltsc2022 for i := len(compatLTSCReleases) - 1; i >= 0; i-- { - if host.Build > compatLTSCReleases[i] { - supportedLTSCRelease = compatLTSCReleases[i] + if host.Build >= compatLTSCReleases[i] { + if i == 0 { + supportedLTSCRelease = compatLTSCReleases[i] + } else { + supportedLTSCRelease = compatLTSCReleases[i-1] + } break } } diff --git a/platform_windows_compat_test.go b/platform_windows_compat_test.go index 1a05075..94b2e17 100644 --- a/platform_windows_compat_test.go +++ b/platform_windows_compat_test.go @@ -91,6 +91,28 @@ func Test_PlatformCompat(t *testing.T) { ctrOS: v22H2Win11, shouldRun: true, }, + // A WS2025-generation host with a build past the latest LTSC (e.g. + // 26200) must still accept WS2022 containers per the stable ABI policy. + { + hostOS: 26200, + ctrOS: ltsc2022, + shouldRun: true, + }, + { + hostOS: 26200, + ctrOS: ltsc2025, + shouldRun: true, + }, + { + hostOS: 26200, + ctrOS: v22H2Win11, + shouldRun: true, + }, + { + hostOS: 26200, + ctrOS: ltsc2019, + shouldRun: false, + }, } { t.Run(fmt.Sprintf("Host_%d_Ctr_%d", tc.hostOS, tc.ctrOS), func(t *testing.T) { hostOSVersion := windowsOSVersion{ @@ -143,6 +165,13 @@ func Test_PlatformOrder(t *testing.T) { OSFeatures: nil, Variant: "", } + ws2025PatchedPlatform := specs.Platform{ + Architecture: "amd64", + OS: "windows", + OSVersion: "10.0.26200.0", + OSFeatures: nil, + Variant: "", + } tt := []struct { name string @@ -168,6 +197,12 @@ func Test_PlatformOrder(t *testing.T) { platforms: []specs.Platform{linuxPlatform, ws2022Platform, ws2025Rev3000Platform}, wantPlatform: ws2025Rev3000Platform, }, + { + name: "Windows Server 2025 host past latest LTSC should still accept 2022", + hostPlatform: ws2025PatchedPlatform, + platforms: []specs.Platform{linuxPlatform, ws2022Platform}, + wantPlatform: ws2022Platform, + }, } for _, tc := range tt {