Kernel UBSAN Reports: Classify the Undefined Operation Before Blaming Hardware
Read the UBSAN check category, source location and operand conditions before treating a kernel warning as evidence of defective hardware. The report says that an instrumented operation violated a condition checked by that build. The next step is to reconstruct the operation’s types and inputs, then test the boundary that should have rejected or safely represented them.
This article uses upstream Linux v6.12. Kernel UBSAN is not identical to enabling every sanitizer switch in a standalone C program. Architecture, compiler probes, selected subchecks and per-file exclusions determine coverage. The examples below are hypothetical analysis fixtures; no kernel build, deliberate undefined operation or target test was executed.
Identify the reporting mode and actual checker
The v6.12 UBSAN guide describes compiler-inserted checks and source-level reporting. Preserve the first complete message, including the check name, file and line, type description, available operands and caller stack. Resolve it with the exact source and binaries rather than a nearby release.
Inspect the tagged UBSAN Kconfig alongside the final configuration. Bounds, shifts, alignment and other checks have distinct dependencies. Trap mode can replace a detailed report with an exception and less diagnostic information; its Kconfig help explicitly warns about aborting kernel code in contexts where locks or other state may be held. A trap is not a safe continuation policy.
Do not infer that a check was active because CONFIG_UBSAN alone appears enabled. A driver can exclude a translation unit from instrumentation, and the selected compiler may not provide a requested subcheck. Record final options and compilation settings for the affected object.
Build an operation worksheet
| Report category | Source questions | Boundary to exercise |
|---|---|---|
| Shift | What is the promoted left operand’s width and signedness? How was the shift count obtained? | Last valid count, first invalid count and negative input if accepted by the interface |
| Array index | Which array size is known to the compiler? Which index was used after conversions? | First and last elements, one-past-end and invalid negative index |
| Alignment | What alignment does the dereferenced type require? Where did the pointer originate? | Validly aligned input and each relevant offset of the external layout |
| Arithmetic or conversion-related symptom | Which exact checker exists in this build, and what expression actually triggered it? | Inputs at the checked operation’s representable boundary, before any narrowing |
The worksheet is a review tool, not a promise that every listed condition is detectable on every build. For example, v6.12’s signed-wrap option explains that the kernel’s -fno-strict-overflow setting leaves nearly no instrumentation for that check with the described compiler behavior. A quiet run therefore cannot establish that signed arithmetic is mathematically in range.

Follow values through promotions and validation
Suppose a hypothetical channel-mask operation evaluates 1U << channel in a build where the promoted unsigned left operand has 32 bits. Counts from zero through 31 are representable shift positions; 32 is outside that width. If the interface accepts a signed channel number, reject negative values too. These are conditions for this example, not assumptions about every type named “unsigned.”
Trace the count from external input to the actual expression. A length check on the original packet does not necessarily constrain a derived index. A cast after the shift cannot repair a shift already performed at the wrong width. A wider operand may be part of a valid redesign, but only if the result type, hardware mask width and every consumer agree with that redesign.
For a bounds report, locate the actual array and how its extent is represented to the compiler. Check whether the driver intentionally uses a flexible array and whether allocation size and declarations agree. Do not silence a report by changing an array declaration while retaining an incorrect allocation or lifetime assumption.
Separate machine tolerance from the language contract
An architecture may execute some unaligned accesses without a hardware exception while the C expression still carries an alignment assumption. Conversely, an alignment warning can need careful review on an architecture that deliberately supports unaligned access patterns. v6.12 exposes alignment checking separately and warns that enabling it on efficient-unaligned-access architectures can produce many reports.
The investigation should identify the origin and required layout of the data. If a packed external byte sequence is being treated as a naturally aligned structure, review the accessor and decoding design against the exact architecture and interface. Avoid inserting a broad cast or globally disabling alignment checks before establishing why the access is valid.
Hardware corruption remains a possible cause of an impossible input, but the UBSAN report alone does not prove it. First ask whether normal parsing, sign extension, stale state, integer narrowing or concurrent updates can produce that input. Escalate to a hardware hypothesis when evidence predicts a specific corrupted value or path that software tests cannot explain.
Design the boundary reproducer without executing UB as a normal test
- Capture the smallest valid interface input that reaches the operation and the smallest rejected input that should stop before it.
- Test the validation function’s expected result at the boundary. Invalid input should produce a defined error without reaching the unsafe expression.
- In an isolated diagnostic campaign, replay the original problematic input against the affected kernel with a prepared recovery and logging path.
- Apply the correction and verify both rejection and neighboring valid cases. Keep the intended operation reachable so a blanket early return does not masquerade as a fix.
- Repeat the target workload without extra instrumentation to check functional behavior and timing separately.
A normal unit test should assert that validation rejects an invalid shift count, not compute the invalid shift and hope for a particular value. If a deliberate sanitizer self-test is used, isolate it and review its configured failure policy first. Do not load a fault-generating module onto a deployed controller.
Interpret a disappearing report carefully
Three outcomes need different decisions. A corrected input check with preserved valid behavior supports the proposed fix. A report that disappears only after a checker is disabled says nothing about the operation. A report that disappears because the input path was no longer exercised requires a new reproduction.
UBSAN bounds checking is not a universal memory-access detector. The v6.12 configuration describes direct array indexing with known bounds and explicitly distinguishes copy-family overflows. A clean UBSAN run cannot replace a lifetime investigation, race analysis or review of writes performed by a device.
Record the source-level explanation
Deliver the original report, exact checker configuration, expression with effective operand types, input provenance and accepted/rejected boundary cases. State whether the source correction changes the external interface or merely enforces its existing contract. Keep any unresolved input corruption as a separate open question.
The useful conclusion is specific: this operation now receives a valid count, index or alignment under the tested conditions. It is stronger than blaming the board from a sanitizer label, and narrower than declaring the entire driver free of undefined behavior.