elastic / elastic/go-sysinfo

[windows] `KernelVersion()` reports the file version of `ntoskrnl.exe`, not the running OS build number

Open Beginner friendly
#294 0 comments 2 reactions 0 assignees View on GitHub
bug Team:Elastic-Agent
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.