[windows] `KernelVersion()` reports the file version of `ntoskrnl.exe`, not the running OS build number
- Dominant language
- Go
- Stars
- 405
- Forks
- 91
- PR merge metrics
- No merged PRs in 30d
Description
On recent versions of Windows, Microsoft has begun shipping feature updates (e.g. the 22H2 -> 23H2 upgrade) as "enablement packages". These packages change only the OS build number in the registry; they do not replace `ntoskrnl.exe`. The kernel binary that ships with 22H2 (`10.0.22621.x`) continues to run, unmodified, on the same machine after it is upgraded to 23H2 (`10.0.22631.x`).
[`KernelVersion()`](https://github.com/elastic/go-sysinfo/blob/main/providers/windows/kernel_windows.go) currently reads the `FileVersion` string resource of `ntoskrnl.exe`. Because the binary itself did not change, it returns the 22H2 file version (`10.0.22621.x`) even after the host has been upgraded to 23H2 and its registry reports build `22631.x`.
A concrete example from [winbindex](https://winbindex.m417z.com/?file=ntoskrnl.exe): the `ntoskrnl.exe` shipping with KB5120240 has `fileInfo.version = "10.0.22621.7517"` but `updateInfo.releaseVersion = "22631.7517"` - the same binary file is indexed under the Windows 11 23H2 update.
This was surfaced in practice when comparing the `os.kernel` field reported by Elastic Agent (via `go-sysinfo`) against OS version data from endpoint: the agent consistently reported a build number corresponding to the previous feature release (`22621.x`) while the host's actual build was `22631.x`.
### Affected code
[`providers/windows/kernel_windows.go` - `KernelVersion()`](https://github.com/elastic/go-sysinfo/blob/main/providers/windows/kernel_windows.go)
```go
func KernelVersion() (string, error) {
versionData, err := windows.GetFileVersionInfo(kernelExePath())
// ...
fileVersion, err := versionData.QueryValue("FileVersion")
if err == nil {
return fileVersion, nil // ← returns 10.0.22621.x on a 23H2 host
}
// ...
}
```
### Proposed fix
Read the kernel version from the registry instead of from `ntoskrnl.exe`. The registry values under `HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion` always reflect the running OS build, regardless of which enablement packages have been applied:
| Value | Type | Example |
|---|---|---|
| `CurrentMajorVersionNumber` | `REG_DWORD` | `10` |
| `CurrentMinorVersionNumber` | `REG_DWORD` | `0` |
| `CurrentBuildNumber` | `REG_SZ` | `22631` |
| `UBR` | `REG_DWORD` | `7376` |
`KernelVersion()` should open the same registry key that [`OperatingSystem()`](https://github.com/elastic/go-sysinfo/blob/main/providers/windows/os_windows.go) already opens, and compose the result as `...` - for example `10.0.22631.7376`. This is the format that unambiguously identifies the running OS build and matches the version string surfaced by other Windows tooling.
The existing `ntoskrnl.exe` path resolution logic (`kernelExePath`, `systemRootFromRegistry`) can be removed from the kernel version path entirely once this change is made, unless it is still needed for another purpose.
### Additional context
The `(WinBuild.160101.0800)` suffix currently appended to the `FileVersion` string resource (e.g. `10.0.22621.7376 (WinBuild.160101.0800)`) is an artifact of the string table embedded in the PE, not a meaningful runtime identifier. The registry-based approach avoids this noise as well.
Contributor guide
Research direction
Start with KernelVersion() in providers/windows/kernel_windows.go and compare its current version source with the registry access used by OperatingSystem() in providers/windows/os_windows.go. Verify that the resulting version reflects CurrentMajorVersionNumber, CurrentMinorVersionNumber, CurrentBuildNumber, and UBR, including the 23H2 example, and that the obsolete file-version suffix is absent.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- operating-systems
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100