seq_file

#kmalloc-32#kmalloc-64#heapspray
Slabkmalloc-32kmalloc-64
Requiresopen-close-syscall-accessexternal-uaf-or-oob-in-target-slab
Givesheap-groomingkaslr-leakcontrol-flow-hijack

The seq_file (Sequence File) is a standard Linux kernel mechanism used to generate large, dynamic, or complex datasets (like process status or network statistics) into a sequential, human-readable text stream without requiring massive pre-allocated buffers.


1. The Structures

seq_file relies on two interdependent structures defined in include/linux/seq_file.h. These are the primary targets when manipulating kernel memory.

struct seq_file (State Tracker)

This structure tracks the current position and buffer state during a read operation.

struct seq_file {
    char *buf;              // The 4KB buffer for output text
    size_t size;            // Total buffer size
    size_t from;            // Current read offset in buffer
    size_t count;           // Data remaining in buffer
    loff_t index;           // Current iterator index
    const struct seq_operations *op; // Link to iteration logic
    void *private;          // Optional driver-specific data
    // ... (additional alignment/locking fields)
};

struct seq_operations (Iteration Logic)

This is a dispatch table containing pointers to the functions that handle the lifecycle of the data traversal.

struct seq_operations {
    void * (*start) (struct seq_file *m, loff_t *pos); // Initialize/Lock
    void (*stop) (struct seq_file *m, void *v);        // Cleanup/Unlock
    void * (*next) (struct seq_file *m, void *v, loff_t *pos); // Advance
    int (*show) (struct seq_file *m, void *v);         // Format to buffer
};

2. The Workflow

When a user-space process opens a virtual file (e.g., /proc/self/stat), the kernel executes a controlled sequence:

  1. Open: The kernel allocates a seq_file structure in the slab cache (kmalloc) and links it to the specific seq_operations table for that file.

  2. Iterate:

    • start(): Prepares the internal data source (e.g., task_struct).
    • show(): Formats the current data into the seq_file->buf.
    • next(): Moves to the next data element.
  3. Read/Copy: The formatted text is copied from the kernel’s buf to the user-space buffer requested by the read() syscall.

  4. Close: Resources are freed.

Note seq_file is the generic struct that moves data from userspace. However, seq_operatioins is the specific struct for reading /proc/self/stat For More details : https://www.kernel.org/doc/html/latest/filesystems/seq_file.html


3. Exploitation Context: Why we Spray seq_file

In a kernel exploitation scenario, seq_file is useful for heap manipulation for three reasons:

  • Heap Grooming: Because seq_file objects are kmalloc‘d in direct response to open() syscalls, an attacker can precisely fill kmalloc-32 or kmalloc-64 slab slots. This allows the attacker to create a “predictable heap layout,” placing their own controlled data adjacent to vulnerable structures.

  • KASLR Bypass : The seq_file->op pointer is a constant address pointing to the kernel’s read-only data segment. By using an read primitive to leak this pointer, an attacker can leak kernel mapped address.

  • Control Flow Hijack: If an attacker gains an arbitrary write primitive, they can overwrite the seq_file->op pointer to point to a “fake” seq_operations table created in controlled memory. When the kernel next attempts to iterate (e.g., via a read or close on the file), it will jump to the attacker-supplied function pointers.


4. How to ?

 #define SPRAY_COUNT 0x200
 static int spray[0x200];

 for (int i = 0; i < SPRAY_COUNT; i++) {
    spray[i] = open("/proc/self/stat", O_RDONLY);
    if (spray[i] == -1) {
      perror("/proc/self/stat");
    }
  }