|
| 1 | +// Copyright The Prometheus Authors |
| 2 | +// Licensed under the Apache License, Version 2.0 (the "License"); |
| 3 | +// you may not use this file except in compliance with the License. |
| 4 | +// You may obtain a copy of the License at |
| 5 | +// |
| 6 | +// http://www.apache.org/licenses/LICENSE-2.0 |
| 7 | +// |
| 8 | +// Unless required by applicable law or agreed to in writing, software |
| 9 | +// distributed under the License is distributed on an "AS IS" BASIS, |
| 10 | +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 11 | +// See the License for the specific language governing permissions and |
| 12 | +// limitations under the License. |
| 13 | + |
| 14 | +//go:build !windows |
| 15 | + |
| 16 | +package procfs |
| 17 | + |
| 18 | +import ( |
| 19 | + "bytes" |
| 20 | + "fmt" |
| 21 | + "io" |
| 22 | + "strconv" |
| 23 | + "strings" |
| 24 | + |
| 25 | + "github.com/prometheus/procfs/internal/util" |
| 26 | +) |
| 27 | + |
| 28 | +// KernelTaintBit represents a single kernel taint flag. |
| 29 | +type KernelTaintBit struct { |
| 30 | + // Index is the zero-based bit position in the tainted bitmask. |
| 31 | + Index int |
| 32 | + // Flag is the letter code identifying this taint (e.g. "L" for soft lockup). |
| 33 | + // See https://www.kernel.org/doc/html/latest/admin-guide/tainted-kernels.html |
| 34 | + Flag string |
| 35 | + // Description is a human-readable explanation of what this taint means. |
| 36 | + Description string |
| 37 | + // Set indicates whether this taint flag is currently active. |
| 38 | + Set bool |
| 39 | +} |
| 40 | + |
| 41 | +// KernelTainted holds the kernel taint state read from /proc/sys/kernel/tainted. |
| 42 | +type KernelTainted struct { |
| 43 | + // Value is the raw integer from /proc/sys/kernel/tainted. |
| 44 | + Value uint64 |
| 45 | + // Bits contains each known taint flag and whether it is currently set. |
| 46 | + // Flags are listed in bit-position order (bit 0 first). |
| 47 | + Bits []KernelTaintBit |
| 48 | +} |
| 49 | + |
| 50 | +// kernelTaintBitDefs lists all known kernel taint flags in bit-position order. |
| 51 | +// Reference: https://www.kernel.org/doc/html/latest/admin-guide/tainted-kernels.html |
| 52 | +var kernelTaintBitDefs = []struct { |
| 53 | + flag string |
| 54 | + description string |
| 55 | +}{ |
| 56 | + {"P", "Proprietary module was loaded."}, |
| 57 | + {"F", "Module was force loaded."}, |
| 58 | + {"S", "SMP kernel oops on an officially SMP incapable processor."}, |
| 59 | + {"R", "Module was force unloaded."}, |
| 60 | + {"M", "Processor reported a Machine Check Exception (MCE)."}, |
| 61 | + {"B", "Bad page referenced or some unexpected page flags."}, |
| 62 | + {"U", "Taint requested by userspace application."}, |
| 63 | + {"D", "Kernel died recently, i.e. there was an OOPS or BUG."}, |
| 64 | + {"A", "An ACPI table was overridden by user."}, |
| 65 | + {"W", "Kernel issued warning."}, |
| 66 | + {"C", "Staging driver was loaded."}, |
| 67 | + {"I", "Workaround for bug in platform firmware applied."}, |
| 68 | + {"O", "Externally-built (out-of-tree) module was loaded."}, |
| 69 | + {"E", "Unsigned module was loaded."}, |
| 70 | + {"L", "Soft lockup occurred."}, |
| 71 | + {"K", "Kernel has been live patched."}, |
| 72 | + {"X", "Auxiliary taint, defined and used by distros."}, |
| 73 | + {"T", "The kernel was built with the struct randomization plugin."}, |
| 74 | + {"N", "An in-kernel test such as a KUnit test has been run."}, |
| 75 | + {"J", "Userspace used a mutating debug operation in fwctl."}, |
| 76 | +} |
| 77 | + |
| 78 | +// KernelTainted reads /proc/sys/kernel/tainted and returns the raw taint value |
| 79 | +// along with each known flag parsed into a KernelTainted struct. |
| 80 | +// See https://www.kernel.org/doc/html/latest/admin-guide/tainted-kernels.html |
| 81 | +func (fs FS) KernelTainted() (KernelTainted, error) { |
| 82 | + data, err := util.ReadFileNoStat(fs.proc.Path("sys", "kernel", "tainted")) |
| 83 | + if err != nil { |
| 84 | + return KernelTainted{}, err |
| 85 | + } |
| 86 | + return parseTainted(bytes.NewReader(data)) |
| 87 | +} |
| 88 | + |
| 89 | +// parseTainted parses the content of /proc/sys/kernel/tainted. |
| 90 | +func parseTainted(r io.Reader) (KernelTainted, error) { |
| 91 | + data, err := io.ReadAll(r) |
| 92 | + if err != nil { |
| 93 | + return KernelTainted{}, err |
| 94 | + } |
| 95 | + |
| 96 | + value, err := strconv.ParseUint(strings.TrimSpace(string(data)), 10, 64) |
| 97 | + if err != nil { |
| 98 | + return KernelTainted{}, fmt.Errorf("couldn't parse tainted value: %w", err) |
| 99 | + } |
| 100 | + |
| 101 | + bits := make([]KernelTaintBit, len(kernelTaintBitDefs)) |
| 102 | + for i, def := range kernelTaintBitDefs { |
| 103 | + bits[i] = KernelTaintBit{ |
| 104 | + Index: i, |
| 105 | + Flag: def.flag, |
| 106 | + Description: def.description, |
| 107 | + Set: value&(1<<uint(i)) != 0, |
| 108 | + } |
| 109 | + } |
| 110 | + |
| 111 | + return KernelTainted{ |
| 112 | + Value: value, |
| 113 | + Bits: bits, |
| 114 | + }, nil |
| 115 | +} |
0 commit comments