Remove the wmic.exe dependency in mdm_bridge table (#49296)

Resolves #34311.

It's not urgent because:
- Orbit uses a fallback mechanism to fetch the device UUID (using
SMBIOS):

https://github.com/fleetdm/fleet/blob/d3092bbc640ebd8e92c13476f0ca8772b98d425e/orbit/pkg/platform/platform_windows.go#L354-L359
- Only used by the `mdm_bridge` table implementation. Which is only used
by CIS policies (not for critical MDM functionality).

- [X] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.

## Testing

- [X] QA'd all new/changed functionality manually

Tested on both a Windows 11 VM with 25H2 and real Windows 11 device with
23H2. The extracted UUID matches the UUID reported by osquery.

## fleetd/orbit/Fleet Desktop

- [X] Verified compatibility with the latest released version of Fleet
(see [Must
rule](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/workflows/fleetd-development-and-release-strategy.md))
- [X] If the change applies to only one platform, confirmed that
`runtime.GOOS` is used as needed to isolate changes
- [X] Verified that fleetd runs on macOS, Linux and Windows
- [X] Verified auto-update works from the released version of component
to the new version (see [tools/tuf/test](../tools/tuf/test/README.md))


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **Bug Fixes**
- Updated Windows device identification to obtain the system UUID using
COM-based WMI querying instead of relying on the deprecated WMIC
utility.
- Removed the WMIC dependency from the MDM bridge table implementation.
- Improved cross-platform UUID handling by removing unused non-Windows
UUID placeholder logic and related constants.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Lucas Manuel Rodriguez
2026-07-16 11:42:28 -03:00
committed by GitHub
parent 621ede7584
commit 9aa4a3375b
4 changed files with 94 additions and 16 deletions
@@ -0,0 +1 @@
* Removed the wmic.exe dependency in the `mdm_bridge` table implementation.
-1
View File
@@ -16,7 +16,6 @@ var (
type UUIDSource string
const (
UUIDSourceInvalid = "UUID_Source_Invalid"
UUIDSourceWMI = "UUID_Source_WMI"
UUIDSourceHardware = "UUID_Source_Hardware"
)
@@ -87,10 +87,6 @@ func GetProcessesByName(name string) ([]*gopsutil_process.Process, error) {
return foundProcesses, nil
}
func GetSMBiosUUID() (string, UUIDSource, error) {
return "", UUIDSourceInvalid, errors.New("not implemented.")
}
// RunUpdateQuirks is a no-op on non-windows platforms
func PreUpdateQuirks() {
}
+93 -11
View File
@@ -10,6 +10,7 @@ import (
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"syscall"
"time"
@@ -17,6 +18,8 @@ import (
"github.com/digitalocean/go-smbios/smbios"
"github.com/fleetdm/fleet/v4/orbit/pkg/constant"
"github.com/go-ole/go-ole"
"github.com/go-ole/go-ole/oleutil"
"github.com/google/uuid"
"github.com/hectane/go-acl"
"github.com/rs/zerolog/log"
@@ -224,22 +227,101 @@ func GetProcessesByName(name string) ([]*gopsutil_process.Process, error) {
return processes, nil
}
// It obtains the BIOS UUID by calling "cmd.exe /c wmic csproduct get UUID" and parsing the results
// wmiGetSMBiosUUID obtains the BIOS/hardware UUID by querying the WMI
// Win32_ComputerSystemProduct class directly over COM.
//
// This replaces the previous implementation that shelled out to
// "wmic csproduct get UUID". The wmic.exe CLI is removed as of Windows 11 25H2
// (https://github.com/fleetdm/fleet/issues/34311), but the underlying WMI
// service and Win32_ComputerSystemProduct class remain available. Querying WMI
// over COM returns the exact same UUID string wmic did, so an existing host's
// UUID — and the SHA256 hash derived from it for Windows MDM local management
// registration — is unchanged.
func wmiGetSMBiosUUID() (string, error) {
args := []string{"/C", "wmic csproduct get UUID"}
out, err := exec.Command("cmd", args...).Output()
// COM calls must be issued from a thread that has been initialized with
// CoInitializeEx, so pin this goroutine to its OS thread for the duration.
runtime.LockOSThread()
defer runtime.UnlockOSThread()
if err := ole.CoInitializeEx(0, ole.COINIT_MULTITHREADED); err != nil {
var code uintptr
if oleErr, ok := errors.AsType[*ole.OleError](err); ok {
code = oleErr.Code()
}
switch code {
case uintptr(windows.S_FALSE):
// COM was already initialized on this thread with the same model;
// our call still counts as a reference that must be balanced.
defer ole.CoUninitialize()
case uintptr(windows.RPC_E_CHANGED_MODE):
// COM was already initialized with a different concurrency model.
// We can still make calls, but must not uninitialize it.
default:
return "", fmt.Errorf("CoInitializeEx: %w", err)
}
} else {
defer ole.CoUninitialize()
}
unknown, err := oleutil.CreateObject("WbemScripting.SWbemLocator")
if err != nil {
return "", err
return "", fmt.Errorf("create SWbemLocator: %w", err)
}
uuidOutputStr := string(out)
if len(uuidOutputStr) == 0 {
return "", errors.New("get UUID: output from wmi is empty")
defer unknown.Release()
locator, err := unknown.QueryInterface(ole.IID_IDispatch)
if err != nil {
return "", fmt.Errorf("query IDispatch: %w", err)
}
outputByLines := strings.Split(strings.TrimRight(uuidOutputStr, "\n"), "\n")
if len(outputByLines) < 2 {
return "", errors.New("get UUID: unexpected output")
defer locator.Release()
serviceRaw, err := oleutil.CallMethod(locator, "ConnectServer", nil, `\\.\ROOT\CIMV2`)
if err != nil {
return "", fmt.Errorf("connect to WMI: %w", err)
}
return strings.TrimSpace(outputByLines[1]), nil
service := serviceRaw.ToIDispatch()
defer service.Release()
resultRaw, err := oleutil.CallMethod(service, "ExecQuery", "SELECT UUID FROM Win32_ComputerSystemProduct")
if err != nil {
return "", fmt.Errorf("execute WMI query: %w", err)
}
result := resultRaw.ToIDispatch()
defer result.Release()
itemRaw, err := oleutil.CallMethod(result, "ItemIndex", 0)
if err != nil {
return "", fmt.Errorf("fetch WMI result row: %w", err)
}
item := itemRaw.ToIDispatch()
defer item.Release()
uuidVariant, err := oleutil.GetProperty(item, "UUID")
if err != nil {
return "", fmt.Errorf("read UUID property: %w", err)
}
defer func() { _ = uuidVariant.Clear() }()
uuidStr := strings.TrimSpace(uuidVariant.ToString())
if uuidStr == "" {
return "", errors.New("get UUID: WMI returned an empty UUID")
}
// Reject documented placeholder/filler UUIDs (all-zero, all-0xFF) that some
// firmware reports. WMI sources the UUID from the same SMBIOS System
// Information structure as the hardware fallback, so returning a sentinel
// value here would let it be used as the device UUID instead of falling
// through to hardwareGetSMBiosUUID (which already rejects these). Reuse the
// same sentinel check for parity between both paths.
parsedUUID, err := uuid.Parse(uuidStr)
if err != nil {
return "", fmt.Errorf("parse WMI UUID: %w", err)
}
if valid, err := isValidUUID(parsedUUID[:]); !valid {
return "", fmt.Errorf("get UUID: WMI returned an unusable UUID: %w", err)
}
return uuidStr, nil
}
// It performs a UUID sanity check on a given byte array