forked from google/osv-scalibr
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Extract the full version of Windows from the registry.
PiperOrigin-RevId: 640616891
- Loading branch information
1 parent
58c1eff
commit c45fdee
Showing
3 changed files
with
185 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
53 changes: 53 additions & 0 deletions
53
extractor/standalone/windows/regosversion/extractor_linux.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
// Copyright 2024 Google LLC | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
//go:build linux | ||
|
||
package regosversion | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"github.com/google/osv-scalibr/extractor" | ||
"github.com/google/osv-scalibr/extractor/standalone" | ||
"github.com/google/osv-scalibr/purl" | ||
) | ||
|
||
// Name of the Windows version extractor | ||
const Name = "windows/regosversion" | ||
|
||
// Extractor provides a metadata extractor for the version of Windows. | ||
type Extractor struct{} | ||
|
||
// Name of the extractor. | ||
func (e Extractor) Name() string { return Name } | ||
|
||
// Version of the extractor. | ||
func (e Extractor) Version() int { return 0 } | ||
|
||
// Extract is a no-op for non-Windows platforms. | ||
func (e *Extractor) Extract(ctx context.Context, input *standalone.ScanInput) ([]*extractor.Inventory, error) { | ||
return nil, fmt.Errorf("only supported on Windows") | ||
} | ||
|
||
// ToPURL converts an inventory created by this extractor into a PURL. | ||
func (e *Extractor) ToPURL(i *extractor.Inventory) (*purl.PackageURL, error) { | ||
return nil, fmt.Errorf("only supported on Windows") | ||
} | ||
|
||
// ToCPEs converts an inventory created by this extractor into CPEs, if supported. | ||
func (e *Extractor) ToCPEs(i *extractor.Inventory) ([]string, error) { | ||
return nil, fmt.Errorf("only supported on Windows") | ||
} |
130 changes: 130 additions & 0 deletions
130
extractor/standalone/windows/regosversion/extractor_windows.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
// Copyright 2024 Google LLC | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
//go:build windows | ||
|
||
// Package regosversion extracts the OS version (build, major, minor release) from the registry. | ||
package regosversion | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"strconv" | ||
"strings" | ||
|
||
"golang.org/x/sys/windows/registry" | ||
"github.com/google/osv-scalibr/extractor" | ||
"github.com/google/osv-scalibr/extractor/standalone" | ||
"github.com/google/osv-scalibr/extractor/standalone/windows/common/winproducts" | ||
"github.com/google/osv-scalibr/purl" | ||
) | ||
|
||
const ( | ||
// Name of the DISM patch level extractor | ||
Name = "windows/regosversion" | ||
regVersionPath = `SOFTWARE\Microsoft\Windows NT\CurrentVersion` | ||
) | ||
|
||
// Extractor provides a metadata extractor for the DISM patch level on Windows. | ||
type Extractor struct{} | ||
|
||
// Name of the extractor. | ||
func (e Extractor) Name() string { return Name } | ||
|
||
// Version of the extractor. | ||
func (e Extractor) Version() int { return 0 } | ||
|
||
// Extract the DISM patch level on Windows. | ||
func (e *Extractor) Extract(ctx context.Context, input *standalone.ScanInput) ([]*extractor.Inventory, error) { | ||
key, err := registry.OpenKey(registry.LOCAL_MACHINE, regVersionPath, registry.QUERY_VALUE) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer key.Close() | ||
|
||
currentVersion, err := e.windowsVersion(key) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// CurrentBuildNumber should be available on a large range of Windows versions. | ||
buildNumber, _, err := key.GetStringValue("CurrentBuildNumber") | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
revision, err := e.windowsRevision(key) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
flavor := winproducts.WindowsFlavorFromRegistry() | ||
fullVersion := fmt.Sprintf("%s.%s.%d", currentVersion, buildNumber, revision) | ||
winproduct := winproducts.WindowsProductFromVersion(flavor, fullVersion) | ||
return []*extractor.Inventory{ | ||
&extractor.Inventory{ | ||
Name: winproduct, | ||
Version: fullVersion, | ||
Locations: []string{"registry"}, | ||
}, | ||
}, nil | ||
} | ||
|
||
// windowsVersion extracts the version of Windows (major and minor, e.g. 6.3 or 10.0) | ||
func (e Extractor) windowsVersion(key registry.Key) (string, error) { | ||
// recent version of Windows | ||
majorVersion, _, majorErr := key.GetIntegerValue("CurrentMajorVersionNumber") | ||
minorVersion, _, minorErr := key.GetIntegerValue("CurrentMinorVersionNumber") | ||
|
||
if majorErr == nil && minorErr == nil { | ||
return fmt.Sprintf("%d.%d", majorVersion, minorVersion), nil | ||
} | ||
|
||
// older versions of Windows | ||
version, _, err := key.GetStringValue("CurrentVersion") | ||
return version, err | ||
} | ||
|
||
// windowsRevision extracts the revision within the current build. | ||
func (e Extractor) windowsRevision(key registry.Key) (uint64, error) { | ||
// recent version of Windows | ||
if revision, _, err := key.GetIntegerValue("UBR"); err == nil { | ||
return revision, nil | ||
} | ||
|
||
// on older version, we have to parse the BuildLabEx key | ||
buildLabEx, _, err := key.GetStringValue("BuildLabEx") | ||
if err != nil { | ||
return 0, err | ||
} | ||
|
||
buildLabParts := strings.Split(buildLabEx, ".") | ||
if len(buildLabParts) < 2 { | ||
return 0, fmt.Errorf("could not parse BuildLabEx: %q", buildLabEx) | ||
} | ||
|
||
return strconv.ParseUint(buildLabParts[1], 10, 64) | ||
} | ||
|
||
// ToPURL converts an inventory created by this extractor into a PURL. | ||
func (e Extractor) ToPURL(i *extractor.Inventory) (*purl.PackageURL, error) { | ||
return &purl.PackageURL{ | ||
Type: purl.TypeMicrosoft, | ||
Name: i.Name, | ||
Version: i.Version, | ||
}, nil | ||
} | ||
|
||
// ToCPEs is not applicable as this extractor does not infer CPEs from the Inventory. | ||
func (e Extractor) ToCPEs(i *extractor.Inventory) ([]string, error) { return []string{}, nil } |