From 3b0706b968461abebf1e7f81aa24e437ad2f6a78 Mon Sep 17 00:00:00 2001 From: Arun S Date: Wed, 15 Jul 2026 12:57:59 +0530 Subject: [PATCH] procfs: add KernelTainted() to parse /proc/sys/kernel/tainted Signed-off-by: Arun S --- kernel_tainted.go | 115 +++++++++++++++++++++++++++++++++++++++++ kernel_tainted_test.go | 89 +++++++++++++++++++++++++++++++ testdata/fixtures.ttar | 5 ++ 3 files changed, 209 insertions(+) create mode 100644 kernel_tainted.go create mode 100644 kernel_tainted_test.go diff --git a/kernel_tainted.go b/kernel_tainted.go new file mode 100644 index 00000000..46a48732 --- /dev/null +++ b/kernel_tainted.go @@ -0,0 +1,115 @@ +// 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 !windows + +package procfs + +import ( + "bytes" + "fmt" + "io" + "strconv" + "strings" + + "github.com/prometheus/procfs/internal/util" +) + +// KernelTaintBit represents a single kernel taint flag. +type KernelTaintBit struct { + // Index is the zero-based bit position in the tainted bitmask. + Index int + // Flag is the letter code identifying this taint (e.g. "L" for soft lockup). + // See https://www.kernel.org/doc/html/latest/admin-guide/tainted-kernels.html + Flag string + // Description is a human-readable explanation of what this taint means. + Description string + // Set indicates whether this taint flag is currently active. + Set bool +} + +// KernelTainted holds the kernel taint state read from /proc/sys/kernel/tainted. +type KernelTainted struct { + // Value is the raw integer from /proc/sys/kernel/tainted. + Value uint64 + // Bits contains each known taint flag and whether it is currently set. + // Flags are listed in bit-position order (bit 0 first). + Bits []KernelTaintBit +} + +// kernelTaintBitDefs lists all known kernel taint flags in bit-position order. +// Reference: https://www.kernel.org/doc/html/latest/admin-guide/tainted-kernels.html +var kernelTaintBitDefs = []struct { + flag string + description string +}{ + {"P", "Proprietary module was loaded."}, + {"F", "Module was force loaded."}, + {"S", "SMP kernel oops on an officially SMP incapable processor."}, + {"R", "Module was force unloaded."}, + {"M", "Processor reported a Machine Check Exception (MCE)."}, + {"B", "Bad page referenced or some unexpected page flags."}, + {"U", "Taint requested by userspace application."}, + {"D", "Kernel died recently, i.e. there was an OOPS or BUG."}, + {"A", "An ACPI table was overridden by user."}, + {"W", "Kernel issued warning."}, + {"C", "Staging driver was loaded."}, + {"I", "Workaround for bug in platform firmware applied."}, + {"O", "Externally-built (out-of-tree) module was loaded."}, + {"E", "Unsigned module was loaded."}, + {"L", "Soft lockup occurred."}, + {"K", "Kernel has been live patched."}, + {"X", "Auxiliary taint, defined and used by distros."}, + {"T", "The kernel was built with the struct randomization plugin."}, + {"N", "An in-kernel test such as a KUnit test has been run."}, + {"J", "Userspace used a mutating debug operation in fwctl."}, +} + +// KernelTainted reads /proc/sys/kernel/tainted and returns the raw taint value +// along with each known flag parsed into a KernelTainted struct. +// See https://www.kernel.org/doc/html/latest/admin-guide/tainted-kernels.html +func (fs FS) KernelTainted() (KernelTainted, error) { + data, err := util.ReadFileNoStat(fs.proc.Path("sys", "kernel", "tainted")) + if err != nil { + return KernelTainted{}, err + } + return parseTainted(bytes.NewReader(data)) +} + +// parseTainted parses the content of /proc/sys/kernel/tainted. +func parseTainted(r io.Reader) (KernelTainted, error) { + data, err := io.ReadAll(r) + if err != nil { + return KernelTainted{}, err + } + + value, err := strconv.ParseUint(strings.TrimSpace(string(data)), 10, 64) + if err != nil { + return KernelTainted{}, fmt.Errorf("couldn't parse tainted value: %w", err) + } + + bits := make([]KernelTaintBit, len(kernelTaintBitDefs)) + for i, def := range kernelTaintBitDefs { + bits[i] = KernelTaintBit{ + Index: i, + Flag: def.flag, + Description: def.description, + Set: value&(1<