Building a Simple Linux Kernel Object Cache with the SLAB Allocator: From Module Signing to Cleanup

Building a Simple Linux Kernel Object Cache Using SLAB Allocator
Linux kernel development is very different from user-space programming.
In user space, developers typically use:
malloc();
free();
Inside the kernel, memory allocation is handled using specialized allocators such as:
kmalloc();
kfree();
and for frequently created kernel objects:
kmem_cache_alloc();
kmem_cache_free();
In this article we build and load a simple kernel module that implements a tiny caching layer using the Linux SLAB allocator and then walk through module signing, loading, debugging, and cleanup.
Source Repository:
Why Object Caches Exist
Many kernel subsystems repeatedly allocate and destroy the same type of object.
Examples include:
- Inodes
- Dentries
- Socket buffers
- Process-related structures
Allocating these structures from a dedicated cache is usually faster than repeatedly requesting generic memory blocks.
The SLAB allocator provides:
- Object reuse
- Better cache locality
- Reduced fragmentation
- Optional constructors
- Faster allocation for hot objects
High-Level Architecture
Our module creates a cache of objects and maintains them in a linked list.
Architecture Diagram
+------------------+
| SLAB CACHE |
| kmem_cache |
+--------+---------+
|
+---------------+--------------+
| |
v v
cache_obj cache_obj
+---------+ +---------+
| id = 1 |----next---------> | id = 2 |
| alpha | | beta |
+---------+ +---------+
Linked List of Objects
The Cache Object
Each object stored inside the cache contains:
struct cache_obj {
int id;
char name[32];
unsigned long created;
struct list_head list;
};
Each object stores:
| Field | Purpose |
|---|---|
| id | Unique identifier |
| name | Human readable label |
| created | Creation timestamp |
| list | Kernel linked-list node |
Why Not Use kmalloc()
A beginner may wonder:
obj = kmalloc(sizeof(*obj), GFP_KERNEL);
Why create a cache at all?
Because the allocator only sees:
Allocate 64 bytes
Allocate 64 bytes
Allocate 64 bytes
It does not know these are identical objects.
SLAB caches know exactly what object type is being allocated.
Give me cache_obj
Give me cache_obj
Give me cache_obj
This enables object reuse.
kmalloc() vs kmem_cache_alloc()
| Feature | kmalloc() | kmem_cache_alloc() |
|---|---|---|
| Generic allocator | Yes | No |
| Object aware | No | Yes |
| Reuse objects | Limited | Yes |
| Constructor support | No | Yes |
| Best for buffers | Yes | No |
| Best for kernel objects | No | Yes |
Memory Allocation Flow
kmalloc()
Request
|
v
Allocate N Bytes
|
v
Return Pointer
kmem_cache_alloc()
Request Object
|
v
+------------------+
| SLAB CACHE |
| |
| free object |
| free object |
| free object |
+---------+--------+
|
v
Return Prepared Object
Creating a Cache
A cache is created during module initialization.
Example:
cachep = kmem_cache_create(
"cache_obj",
sizeof(struct cache_obj),
0,
0,
NULL);
Parameters:
Name : cache_obj
Object Size : sizeof(cache_obj)
Alignment : default
Flags : none
Constructor : NULL
After creation the cache can hand out objects very quickly.
Allocating Objects
Objects are allocated from the cache.
obj = kmem_cache_alloc(cachep, GFP_KERNEL);
if (!obj)
return -ENOMEM;
The NULL check is mandatory.
Without it:
obj->id = 1;
could become:
NULL->id = 1;
leading to:
BUG: kernel NULL pointer dereference
Understanding -ENOMEM
if (!obj)
return -ENOMEM;
Meaning:
Memory allocation failed.
Stop execution and notify caller that
the system is out of memory.
Common kernel error codes:
-ENOMEM // Out of memory
-EINVAL // Invalid argument
-EFAULT // Invalid address
-EBUSY // Resource busy
Linking Objects Together
The kernel provides a generic linked-list implementation.
Example:
alpha --> beta --> gamma
Visualization:
+-------+ +-------+ +-------+
| alpha | ---> | beta | ---> | gamma |
+-------+ +-------+ +-------+
This avoids writing custom linked-list code.
Building the Module
Compile:
make
Expected output:
CC [M] simple_cache.o
LD [M] simple_cache.ko
The generated file:
simple_cache.ko
is a loadable kernel module.
Why Module Signing Matters
Modern Linux distributions often enable Secure Boot.
Unsigned modules may fail to load.
Flow:
Kernel Module
|
v
Module Signature
|
v
Secure Boot Validation
|
v
Load or Reject
Signing the Kernel Module
Sign the module using the kernel's signing utility.
sudo /usr/src/linux-headers-$(uname -r)/scripts/sign-file \
sha256 \
~/kernel_keys/MOK.key \
~/kernel_keys/MOK.crt \
simple_cache.ko
Explanation:
| Component | Purpose |
|---|---|
| sign-file | Kernel signing utility |
| sha256 | Digest algorithm |
| MOK.key | Private key |
| MOK.crt | Public certificate |
| simple_cache.ko | Module being signed |
Loading the Module
Insert the module:
sudo insmod simple_cache.ko
Initialization sequence:
Module Load
|
v
Create SLAB Cache
|
v
Allocate Objects
|
v
Insert Into Linked List
|
v
Print Kernel Logs
Monitoring Kernel Messages
Open a live kernel log viewer.
dmesg -w
Expected output:
CACHE: created 1 alpha
CACHE: created 2 beta
Architecture:
Kernel Module
|
v
printk()
|
v
Kernel Ring Buffer
|
v
dmesg
Cleaning Up
Remove the module.
sudo rmmod simple_cache
Cleanup sequence:
Delete Objects
|
v
Free Objects
|
v
Destroy Cache
|
v
Module Exit
Correct Memory Pairing
Always pair allocation and free APIs correctly.
Correct:
ptr = kmalloc(size, GFP_KERNEL);
kfree(ptr);
Correct:
obj = kmem_cache_alloc(cachep, GFP_KERNEL);
kmem_cache_free(cachep, obj);
Incorrect:
obj = kmem_cache_alloc(cachep, GFP_KERNEL);
kfree(obj);
Incorrect:
ptr = kmalloc(size, GFP_KERNEL);
kmem_cache_free(cachep, ptr);
Mixing allocators can corrupt kernel memory.
Real Kernel Components Using SLAB
Many core Linux subsystems depend heavily on slab caches.
Examples:
inode cache
dentry cache
socket buffers
VFS metadata
network objects
task structures
Our module is a miniature version of the same concept.
Complete Execution Flow
make
|
v
simple_cache.ko
|
v
sign-file
|
v
Signed Module
|
v
insmod
|
v
Create SLAB Cache
|
v
Allocate Objects
|
v
Store in Linked List
|
v
Observe via dmesg
|
v
rmmod
|
v
Free Objects
|
v
Destroy Cache
Key Takeaways
kmalloc()is a generic kernel allocator.kmem_cache_alloc()is optimized for repeatedly used object types.- SLAB caches improve performance and memory locality.
- Always check allocation failures.
- Pair allocation and deallocation APIs correctly.
- Module signing is required on many Secure Boot systems.
dmesg -wis invaluable when debugging kernel modules.- Proper cleanup is mandatory inside kernel code.
References
Linux Kernel Documentation
- Memory Management
- SLAB Allocator
- Loadable Kernel Modules
Repository:
https://github.com/aj333git/linux_kernel_kobjex2
Footer
Source code and experiments are available in the repository: https://github.com/aj333git/linux\_kernel\_kobjex2
Based on the kernel object cache concepts and notes provided in your source material.



