Full Report
Type confusions are a bug class that operates in both memory safe and memory unsafe languages. In C, type confusions typically lead to bad memory corruption bugs. The main part of this paper that I enjoyed was around C class and type hierarchies. C doesn't technically have type hierarchies but it's possible to create a similar effect using structure embedding. For instance, you can have a type and then a child field at the end of that type. To go between the parent and child parts of the object you can just do some pointer math. The Linux kernel uses the container_of macro to do this a lot. According to the author, this technically violates the C language standard and is always an unsafe cast. The goal was to find cases where the casting into the container (child) type is incorrect, leading to a type confusion bug they call container confusion. In LLVM, they created a custom compiler pass to spot uses of container_of in the source code to create a type system. This tracks all casts up and down. From there, they built a custom sanitizer called uncontained in order to detect casts up then back down to the wrong type. An interesting design decision was checking at the time of use vs. the time of the incorrect downcast. They found several scenarios where the downcast was safe through only accessing the parent field on the downcast. In the Linux kernel, they found 37 cases of container confusion. Of these, 16 were false positives, 11 were unique bugs and 10 of them were anti-patterns of checking the container confusion later in the small section of code they looked at. Besides simply downcasting to a static container, they found a few other types of bugs: Empty List Confusion: In cases of list being used but empty, both the next and prev fields will point to the object itself. Mismatch on Data Structure Operators: Different locations in good may treat a pointer as a different type depending on the needs. Of course, offsets must be correct in this case. Past-the-end Iterator: Break-like logic is often used by searching for an element in a data structure until the end. It's possible to use the iterator without checking for its validity. Containers with Contracts: An object may come with additional metadata that program semantics use to control what operations can be done on it, such as the sysfs kernel subsystem. If these invariants are not kept, it leads to a mis-use of the pointer. The sanitizier is not meant to have a 100% positive rate. Instead, it's meant to point out potential locations and types of the bug. To me, this is completely reasonable as long as the false positive rate isn't too high. They added all 5 locations to find a total of 80 bugs, 179 anti-patterns and 107 false positives. Most of the false positives came from the first pattern that had explicit tag type checks within the code. Overall, a real bug 30% of the time is pretty amazing! To me, this is absolutely amazing work. Taking a known bug class in the Linux kernel (and some other code) and writing a fairly accurate static analysis tool is awesome. 80+ in the Linux kernel at a time is unheard of in modern days.
Analysis Summary
# Vulnerability: Container Confusion in the Linux Kernel
## CVE Details
- **CVE ID:** Not explicitly provided (Research paper identifies 80+ unique bugs)
- **CVSS Score:** N/A (General bug class research)
- **CWE:** CWE-843 (Access of Resource Using Incompatible Type / Type Confusion)
## Affected Systems
- **Products:** Linux Kernel
- **Versions:** Multiple versions (Subsystems mentioned include `sysfs`)
- **Configurations:** Systems utilizing C-style structure embedding and the `container_of` macro for type casting.
## Vulnerability Description
This research identifies a specific class of type confusion dubbed **"Container Confusion."** While the C language does not have formal type hierarchies, the Linux kernel simulates them by embedding structures within one another. Developers use the `container_of` macro to perform pointer arithmetic to navigate between parent and child structures.
The vulnerability occurs when a pointer is cast back to a "container" (child) type that does not match the original object type. The researchers identified five primary patterns:
1. **Static Downcasting:** Incorrectly casting a parent field to the wrong child container type.
2. **Empty List Confusion:** In `list_head` implementations, empty lists have `next` and `prev` pointers pointing to the list head itself. Treating the head as a data-containing node leads to confusion.
3. **Data Structure Operator Mismatch:** Treating a pointer as different types across different code locations without correcting offsets.
4. **Past-the-end Iterator:** Using an iterator after a loop finishes without verifying if it points to a valid entry or the list head.
5. **Containers with Contracts:** Violating metadata invariants (e.g., in `sysfs`) that dictate which operations are valid for a specific pointer.
## Exploitation
- **Status:** Research/PoC status. 80 unique bugs and 179 anti-patterns were identified.
- **Complexity:** Medium to High (Requires specific knowledge of kernel memory layout).
- **Attack Vector:** Local (Typically requires the ability to trigger specific kernel syscalls or subsystem interactions).
## Impact
- **Confidentiality:** High (Potential for out-of-bounds reads).
- **Integrity:** High (Potential for memory corruption and unauthorized data modification).
- **Availability:** High (Kernel panic/System crash).
## Remediation
### Patches
- The research resulted in the identification of 80 bugs; specific patches are upstreamed to the Linux kernel project on a case-by-case basis.
### Workarounds
- **Code Refactoring:** Avoid using `container_of` without explicit type validation.
- **Strict Tag Checking:** Implementing manual tag/type checks before performing downcasts (though this currently causes false positives in analysis tools).
## Detection
- **Indicators of Compromise:** Kernel oops, unexpected memory corruption, or system instability when interacting with specific subsystems like `sysfs`.
- **Detection Methods and Tools:**
- **UNCONTAINED Sanitizer:** A custom LLVM-based sanitizer developed by the researchers to detect incorrect downcasts at the time of use.
- **Static Analysis:** Custom compiler passes to track pointer casts up and down the structure hierarchy.
## References
- Linux Kernel Source: hxxps[://]github[.]com/torvalds/linux
- Research Paper: (Context refers to the "Uncontained" paper/sanitizer)
- Macro Documentation: hxxps[://]elixir[.]bootlin[.]com/linux/latest/source/include/linux/container_of[.]h