by: Antonius
Country: Indonesia
https://www.bluedragonsec.com – https://github.com/bluedragonsecurity
Linux kernel 7.0-rc7 & linux kernel 7.0 mainline uses the SLUB Sheaves architecture, replacing the legacy kmem_cache_cpu structure. In this new architecture, each sheaf is represented by struct slab_sheaf, declared at mm/slub.c line 404 in Linux kernel 7.0-rc7.
From source code analysis of Linux kernel 7.0-rc7, one of the most interesting design characteristics of struct slab_sheaf is the use of a union at the beginning of the struct. This union allows the same block of memory to be used for three different purposes depending on context. The Linux kernel use-after-free exploitation technique using slab_sheaf Union State Confusion is directly related to the ambiguity that arises from the use of this union.
Below is the complete declaration of the union portion of struct slab_sheaf, verified directly from the linux-7.0-rc7 & linux-7.0 Mainline source tree (both at the same line number):

This union does not add alias names — all three variants are directly accessible through their respective field names (rcu_head, barn_list, capacity, pfmemalloc).
Press enter or click to view image in full size

Press enter or click to view image in full size

Press enter or click to view image in full size

Although the three union variants are declared separately, in memory they all occupy the exact same byte range, starting from offset +0x00 of struct slab_sheaf.
Press enter or click to view image in full size

The first column shows that rcu_head.next and barn_list.next are at an identical offset (+0x00).
Likewise rcu_head.func and barn_list.prev are both at +0x08. This is a direct consequence of how unions work in C: all union members share the same starting address.
This is a direct consequence of how unions work in C: all members of a union share the same starting address. There is no memory separation between them.
Understanding the type of each field is important for grasping the meaning of this overlap.
Below are the actual definitions of the two structs involved:
Press enter or click to view image in full size

The most critical difference is at offset +0x08: in the rcu_head context, the byte at this position is a pointer to a callback function. In the barn_list context, the same byte is a pointer to the previous element in the barn’s doubly-linked list. A single 8-byte block of memory is interpreted
as two different things depending on which code path reads it.
To avoid confusion about this union, we first need to understand the life cycle of a slab_sheaf in kernel 7.0-rc7.
At any given time, a slab_sheaf may be in one of the following states:
Press enter or click to view image in full size

The critical transitions are between the IN_BARN and RCU_PENDING states. When a sheaf is moved from the barn to the RCU path:
1. list_del(&sheaf->barn_list) is called when the sheaf is removed from the barn (mm/slub.c:3103, 3155, 3192). After this, barn_list.next (+0x00) and barn_list.prev (+0x08) contain LIST_POISON1 and LIST_POISON2 respectively, set unconditionally by list_del().
2. The sheaf is placed into pcs->rcu_free: the union still contains the LIST_POISON values from list_del().
3. When the sheaf is full: call_rcu(&sheaf->rcu_head, rcu_free_sheaf) is called (mm/slub.c:5949). The RCU infrastructure writes rcu_head.next (+0x00) as RCU internal linkage, and rcu_head.func (+0x08) as &rcu_free_sheaf — overwriting the previous values.
The reverse direction also applies. In rcu_free_sheaf() (mm/slub.c:5789), after the RCU grace period completes, if the barn has free slots, the sheaf is returned to the barn:

Press enter or click to view image in full size

This technique centers on one question: is there a moment where the kernel reads or writes the slab_sheaf union with an interpretation inconsistent with the sheaf’s actual state?
struct slab_sheaf has no explicit field recording which state is currently active. There is no enum state, no BARN_OR_RCU flag. The kernel determines the correct interpretation solely from program flow context. This is common in C-based kernel code and is not inherently flawed, but it
creates a dependency on the validity of operation ordering.
Consider the following flow in __kfree_rcu_sheaf() (mm/slub.c around line 5862):
/* linux-7.0-rc7 /mm/slub.c:5862 — __kfree_rcu_sheaf() */
bool __kfree_rcu_sheaf(struct kmem_cache *s, void *obj)
{
/* Step 1: rcu_free sheaf obtained from spare or barn */
do_free:
rcu_sheaf = pcs->rcu_free;
/* Step 2: objects are collected into objects[] */
rcu_sheaf->objects[rcu_sheaf->size++] = obj;
/* Step 3: when sheaf is full, call_rcu is invoked */
if (likely(rcu_sheaf->size < s->sheaf_capacity)) {
rcu_sheaf = NULL;
} else {
pcs->rcu_free = NULL;
rcu_sheaf->node = numa_mem_id();
}
if (rcu_sheaf)
call_rcu(&rcu_sheaf->rcu_head, rcu_free_sheaf);
/* call_rcu writes:
* rcu_head.next (+0x00) = RCU internal linkage
* rcu_head.func (+0x08) = &rcu_free_sheaf */
}
After the RCU grace period completes and the callback is invoked in rcu_free_sheaf() (mm/slub.c:5789), if the barn has free slots, barn_put_full_sheaf() calls list_add(&sheaf->barn_list, …). This writes to barn_list.next (+0x00) and barn_list.prev (+0x08), overwriting rcu_head.next and rcu_head.func respectively.
If there is a write primitive that can modify the slab_sheaf union while in the RCU_PENDING state, the value written to offset +0x08 will be interpreted by the RCU infrastructure as a pointer to a callback function. Symmetrically, modification in the IN_BARN state to offset +0x08 will carry over as rcu_head.func when the sheaf transitions to the RCU path.
Modification at offset +0x08 is the most interesting point for exploitation because it touches rcu_head.func, a function pointer called by the RCU mechanism after the grace period.
To understand this exploitation technique more completely, below is a full slab_sheaf life-cycle diagram with the relevant union transition points:
Press enter or click to view image in full size

It is important to stress that this technique is not a vulnerability that can be exploited directly from scratch. It is a design property that amplifies the impact when some other bug already exists.
Initial access primitive: there must be another vulnerability (UAF, buffer overflow, race condition) that provides ability to read or write memory overlapping with a slab_sheaf.
Correct timing: (a) For poisoning via IN_BARN: write to offset +0x08 while sheaf is in barn. (b) For direct overwrite: write to offset +0x08 after call_rcu() but before grace period completes (window of hundreds of microseconds to milliseconds).
Sheaf location knowledge: the attacker must know the target slab_sheaf address, generally requiring a separate information leak.
In other terms: this technique is an amplifier, not an initial vector.
In other words, this technique is an amplifier, not an initial vector. It turns a limited memory access primitive into something potentially more significant because the manipulated value carries special meaning for kernel infrastructure (the RCU machinery or barn list management).
The slab_sheaf Union State Confusion technique centers on one architectural fact: struct slab_sheaf uses a union to overlay rcu_head and barn_list at the same memory offsets, without an explicit state marker.
The critical point is offset +0x08, where barn_list.prev and rcu_head.func overwrite each other. In the RCU context, this is a function pointer called after the grace period. In the barn context, it is a list pointer. This technique can be adapted for linux kernel 7.0 mainline.
The core idea is simple: one write, two interpretations. The attacker writes as ordinary data, the kernel reads it as a function address and jumps to it. That is “state confusion” — confusion between two contexts that share the same memory.
This is the personal web of Antonius Wisdom, a security researcher based in Indonesia. I do low level vulnerability research & hardware hacking.
Hobbies