| // Copyright The Prometheus Authors |
| // 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 sysfs |
| |
| import ( |
| "os" |
| "path/filepath" |
| "strings" |
| ) |
| |
| const ( |
| notAffected = "not affected" // based on: https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-devices-system-cpu |
| vulnerable = "vulnerable" |
| mitigation = "mitigation" |
| unknown = "unknown" |
| ) |
| |
| const ( |
| VulnerabilityStateNotAffected = iota |
| VulnerabilityStateVulnerable |
| VulnerabilityStateMitigation |
| VulnerabilityStateUnknown |
| ) |
| |
| var ( |
| // VulnerabilityHumanEncoding allows mapping the vulnerability state (encoded as an int) onto a human friendly |
| // string. It can be used by consumers of this library to expose to the user the state of the vulnerability. |
| VulnerabilityHumanEncoding = map[int]string{ |
| VulnerabilityStateNotAffected: notAffected, |
| VulnerabilityStateVulnerable: vulnerable, |
| VulnerabilityStateMitigation: mitigation, |
| VulnerabilityStateUnknown: unknown, |
| } |
| ) |
| |
| // CPUVulnerabilities retrieves a map of vulnerability names to their mitigations. |
| func (fs FS) CPUVulnerabilities() (map[string]*Vulnerability, error) { |
| matchingFilepaths, err := filepath.Glob(fs.sys.Path("devices/system/cpu/vulnerabilities/*")) |
| if err != nil { |
| return nil, err |
| } |
| |
| vulnerabilities := make(map[string]*Vulnerability, len(matchingFilepaths)) |
| for _, path := range matchingFilepaths { |
| filename := filepath.Base(path) |
| |
| rawContent, err := os.ReadFile(path) |
| if err != nil { |
| return nil, err |
| } |
| |
| v, err := parseVulnerability(filename, string(rawContent)) |
| if err != nil { |
| return nil, err |
| } |
| |
| vulnerabilities[filename] = v |
| } |
| |
| return vulnerabilities, nil |
| } |
| |
| // Vulnerability represents a single vulnerability extracted from /sys/devices/system/cpu/vulnerabilities/. |
| type Vulnerability struct { |
| CodeName string |
| State int |
| Mitigation string |
| } |
| |
| func parseVulnerability(name, rawContent string) (*Vulnerability, error) { |
| v := &Vulnerability{CodeName: name} |
| rawContent = strings.TrimSpace(rawContent) |
| rawContentLower := strings.ToLower(rawContent) |
| switch { |
| case strings.HasPrefix(rawContentLower, notAffected): |
| v.State = VulnerabilityStateNotAffected |
| case strings.HasPrefix(rawContentLower, vulnerable): |
| v.State = VulnerabilityStateVulnerable |
| m := strings.Fields(rawContent) |
| if len(m) > 1 { |
| v.Mitigation = strings.Join(m[1:], " ") |
| } |
| case strings.HasPrefix(rawContentLower, mitigation): |
| v.State = VulnerabilityStateMitigation |
| m := strings.Fields(rawContent) |
| if len(m) > 1 { |
| v.Mitigation = strings.Join(m[1:], " ") |
| } |
| case strings.HasPrefix(rawContentLower, unknown): |
| v.State = VulnerabilityStateUnknown |
| m := strings.Fields(rawContent) |
| if len(m) > 1 { |
| v.Mitigation = strings.Join(m[1:], " ") |
| } |
| default: |
| // Output the raw data obtained from the vulnerability, with state |
| // unknown, rather than erroring out |
| v.State = VulnerabilityStateUnknown |
| v.Mitigation = rawContent |
| } |
| return v, nil |
| } |