ext File System Forensics
- ext File System Forensics
The ext file system family (ext2, ext3, ext4) is the default on most Linux distributions and is one of the most commonly encountered file systems in forensic investigations involving Linux servers, workstations, Android devices, and embedded systems. Understanding its on-disk structure is necessary to accurately interpret evidence, recover deleted files, and detect tampering.
Overview and History
| Version | Year | Key Feature |
|---|---|---|
| ext2 | 1993 | No journaling; foundation for the family |
| ext3 | 2001 | Journaling added to ext2 |
| ext4 | 2008 | Extents, large file/volume support, delayed allocation, optional journaling enhancements |
ext4 is backward-compatible with ext3 and ext2 and is the file system most investigators will encounter on modern Linux systems. The forensic principles are largely the same across all three versions; differences are noted where relevant.
On-Disk Layout
An ext file system is divided into fixed-size block groups. Each block group contains a complete, self-contained set of file system structures. This design provides redundancy and reduces head seek times.
[ Boot Block ][ Block Group 0 ][ Block Group 1 ][ ... ][ Block Group N ]
Each block group contains:
| Structure | Purpose |
|---|---|
| Superblock (copy) | File system parameters; copy in group 0 is primary |
| Group Descriptor Table (copy) | Location of structures within each group |
| Block Bitmap | Allocation status of every block in this group |
| Inode Bitmap | Allocation status of every inode in this group |
| Inode Table | Fixed array of inode structures for this group |
| Data Blocks | File content and directory data |
The block size is set at format time (typically 1 KB, 2 KB, or 4 KB) and cannot be changed without reformatting. All addresses in the file system are in units of blocks.
Superblock
The superblock is the most critical structure in the file system. It is always located 1024 bytes from the start of the partition (regardless of block size) in block group 0, and is copied to every (or every other) block group as a backup.
Key fields:
| Field | Forensic Value |
|---|---|
s_inodes_count |
Total inodes; limits maximum number of files |
s_blocks_count |
Total blocks; combined with block size gives volume size |
s_free_inodes_count / s_free_blocks_count |
Inconsistency with actual bitmaps may indicate tampering |
s_mtime |
Time the file system was last mounted |
s_wtime |
Time the superblock was last written |
s_mkfs_time (ext4) |
Time the file system was created |
s_last_mounted |
Path at which the file system was last mounted |
s_uuid |
Universally unique identifier for the file system |
s_volume_name |
Optional label |
s_creator_os |
OS that created the file system |
s_feature_* |
Feature flags indicating ext3/ext4 capabilities in use |
Forensic note: s_mkfs_time records when the file system was created. If a suspect formatted a drive after being notified of an investigation, this timestamp will post-date the notification. Discrepancies between s_mtime (last mount) and s_mkfs_time can also indicate whether the file system has ever been used. Backup superblock copies in other block groups can be compared to the primary superblock to detect tampering with the primary copy.
Inodes
Every file, directory, symlink, device node, and pipe is represented by an inode (index node). An inode stores all metadata about a file except its name.
Key inode fields:
| Field | Contents |
|---|---|
i_mode |
File type and permission bits |
i_uid / i_gid |
Owner user and group IDs |
i_size |
File size in bytes |
i_atime |
Last access time |
i_ctime |
Inode change time (not creation time — see below) |
i_mtime |
Last data modification time |
i_crtime (ext4 only) |
File creation time |
i_dtime |
Deletion time (set when the inode is freed) |
i_links_count |
Number of hard links to this inode |
i_blocks |
Number of 512-byte sectors allocated |
| Block pointers | Locations of data blocks (direct, indirect, double-indirect, triple-indirect in ext2/3; extents in ext4) |
Forensic note — i_ctime is not creation time: A common mistake is treating i_ctime as the file creation time. It is the inode change time — the last time the inode’s metadata was modified (e.g., by a chmod, chown, or link count change). The actual creation time is only available in ext4 via i_crtime. On ext2/3, there is no reliable creation timestamp; i_mtime is often used as a proxy.
Forensic note — i_dtime: When a file is deleted, its inode’s i_dtime field is set to the deletion time and i_links_count is decremented to 0. The inode is then marked free in the inode bitmap, but the inode structure itself may remain on disk until it is reused. If the inode has not been reused, i_dtime gives a precise timestamp for when the file was deleted.
Inode Numbering
Inodes are numbered starting at 1. Several low-numbered inodes are reserved:
| Inode | Purpose |
|---|---|
| 1 | Bad blocks inode (tracks bad sectors) |
| 2 | Root directory |
| 3–10 | Reserved for other kernel structures |
| 11 | First regular (user) inode |
Forensic note: inode 2 (the root directory) is the entry point for all path-based searches. If root directory metadata is intact, the entire directory tree can be traversed from inode 2 regardless of the state of other structures.
Block Allocation
Block Bitmap
Each block group has a block bitmap — one bit per block — stored in a dedicated block. A 1 bit means the block is allocated; a 0 bit means it is free. When a file is deleted, its blocks are marked free in the bitmap, but the data is not overwritten.
Forensic note: free blocks (bit = 0) identified by the block bitmap are the primary targets for data recovery and file carving. The block bitmap from each group must be read to identify which blocks contain potentially recoverable content across the entire volume.
Inode Bitmap
Similarly, each block group has an inode bitmap — one bit per inode. A 0 bit means the inode is unallocated (the corresponding file has been deleted or the inode was never used).
Forensic note: scanning for inode bitmap entries set to 0 where i_dtime is nonzero identifies deleted files whose inodes have not been reused. This is the first step in deleted file recovery.
Directory Entries
Directories in ext are files whose content is a linear list of directory entries (ext2_dir_entry or ext2_dir_entry_2). Each entry contains:
| Field | Contents |
|---|---|
inode |
Inode number of the file (0 = entry is deleted) |
rec_len |
Length of this directory entry record |
name_len |
Length of the filename |
file_type (ext2_dir_entry_2) |
Type hint (regular file, directory, symlink, etc.) |
name |
Filename (not null-terminated in the structure; length given by name_len) |
When a file is deleted from a directory, its entry is not removed from the directory block; instead, the inode field is set to 0 and the rec_len of the preceding entry is increased to skip over it. The filename and original inode number often remain readable in the slack space of the merged entry.
Forensic note: deleted directory entries frequently retain the original filename and inode number. Even if the inode has been reused, the orphaned directory entry can reveal that a file with that name once existed in this directory, potentially linking it to a specific user account or location. Forensic tools like The Sleuth Kit’s fls display both live and deleted directory entries.
htree Directory Indexing (ext3/4)
Large directories in ext3 and ext4 use an HTree (a B-tree variant indexed by filename hash) to speed up lookups. The HTree index is stored in directory data blocks. When entries are deleted, index nodes may become partially stale but are not immediately removed. HTree leaf nodes contain the same dir_entry structures as linear directories and are subject to the same deleted-entry analysis.
Block Addressing
ext2/3: Indirect Blocks
Small files use direct block pointers (12 per inode), pointing directly to data blocks. Larger files use:
- Single indirect block: one block containing an array of block pointers
- Double indirect block: one block containing pointers to single indirect blocks
- Triple indirect block: one block containing pointers to double indirect blocks
Forensic note: if an inode is deleted and its direct pointers are still intact, data recovery is straightforward. If indirect blocks have been reallocated, some or all of the file’s blocks become unlocatable through the inode — falling back to file carving.
ext4: Extents
ext4 replaces the indirect block scheme with extents — a more efficient structure that records a contiguous run of blocks as a single (start block, length) pair. Up to four extents fit directly in the inode; larger files use an extent tree.
Forensic note: extent-based addressing makes deleted file recovery easier when the inode is intact, because a small number of extents describes the file’s entire layout. However, ext4 also introduces delayed allocation (blocks are not assigned until data is flushed to disk), which means very recently created files may not have block assignments recorded even if the data is in the page cache — though this is only relevant on a live system.
Journaling
ext3 and ext4 add a journal — a write-ahead log of pending metadata (and optionally data) changes. The journal allows the file system to recover from power failures or crashes without a full fsck.
The journal is stored as a file (typically inode 8) in the file system itself. Three journaling modes:
| Mode | What is journaled | Forensic implication |
|---|---|---|
writeback |
Metadata only; data may be written before/after | Data blocks may appear inconsistently ordered |
ordered (default) |
Metadata only; data written before metadata committed | Safer consistency; most common |
journal |
Both metadata and data | Data written twice; journal contains full file content |
Forensic note: in journal mode, the journal file itself may contain previous versions of recently overwritten file data. The journal has a fixed circular buffer size (default 128 MB); older entries are overwritten as new transactions are committed. On a live or recently used system, examining the journal can reveal the contents of recently deleted or modified files. Tools like jcat (The Sleuth Kit) can extract journal contents.
File Deletion in ext
When unlink() is called on the last hard link to a file:
- The directory entry’s
inodefield is set to 0;rec_lenof the preceding entry absorbs the freed slot i_links_countin the inode is decremented to 0i_dtimein the inode is set to the current time- The inode is marked free in the inode bitmap
- Each data block is marked free in the block bitmap
The data blocks are not overwritten. The inode structure is not erased — only its allocation status changes. Until the inode and its blocks are reallocated, the complete file (content, timestamps, ownership, permissions, and deletion time) is recoverable.
What ext4 erases on deletion: ext4 by default zeroes the block pointers in the inode when a file is deleted (unlike ext2/3, which left them intact). This was a deliberate change to prevent recovery of orphaned blocks after fsck. The effect on forensics:
- In ext2/3: deleted inode retains its block pointer list → recovery directly follows the pointers
- In ext4: deleted inode has zeroed block pointers → recovery requires scanning the block groups for the file’s content, or relying on journal entries that recorded the original block assignments
Forensic note: on ext4, the journal in ordered mode records which blocks were associated with an inode at transaction commit time. If the transaction that deleted the file is still in the journal, the original block pointers can be reconstructed from it, enabling direct recovery even after ext4’s zeroing behavior.
Deleted File Recovery
When the Inode is Intact (ext2/3)
- Scan the inode bitmap for entries with
i_links_count == 0andi_dtime != 0 - For each such inode, follow the direct and indirect block pointers to recover content
- Recover the filename from orphaned directory entries that still reference the inode number
Tools: The Sleuth Kit (ils, icat, fls), Autopsy, extundelete, ext4magic.
When the Inode is Intact (ext4)
The zeroed block pointers make step 2 impossible via the inode alone. Options:
- Parse the journal for transaction records that include the original block pointer list
- Use
ext4magicorext4undelete, which are specifically designed to reconstruct ext4 deletions from journal data
When the Inode Has Been Reallocated
Fall back to file carving against the free blocks identified by the block bitmap.
Extended Attributes and Symbolic Links
Extended attributes (xattrs) store additional metadata: SELinux security labels, POSIX ACLs, and arbitrary application-defined attributes. They are stored either in a dedicated block (referenced from the inode) or inline within the inode’s extra space (ext4). Their forensic value is limited but can include security context labels that reveal what role a file was meant to play.
Symbolic links whose target path fits within 60 bytes store the path directly in the inode’s block pointer array rather than in a data block. This means symlinks that short leave no data block allocation and are entirely described by the inode. Recovering deleted symlinks is therefore trivial if the inode is intact.
Forensically Significant Locations
| Location | Contents | Forensic Value |
|---|---|---|
| Superblock (group 0 + backups) | File system parameters and timestamps | Creation time, last mount time, UUID |
| Inode table (unallocated entries) | Deleted file metadata | Timestamps, ownership, size, deletion time, block pointers (ext2/3) |
| Directory data blocks | Live and deleted directory entries | Filename-to-inode mapping; deleted entries retain names |
| Journal (inode 8) | Recent metadata (and optionally data) transactions | Reconstructs deleted file block pointers in ext4; may contain previous file versions |
| Block bitmap free regions | Unallocated data blocks | Targets for file carving and slack space analysis |
/lost+found |
Orphaned inodes reconnected by fsck |
Files that existed but had no directory entry; may be evidence of a crash mid-delete or deliberate directory manipulation |
Tools
| Tool | Purpose |
|---|---|
debugfs |
Interactive ext2/3/4 explorer; examine inodes, blocks, superblock; can undelete in ext2/3 |
dumpe2fs |
Print superblock and group descriptor information |
e2fsck -n |
Read-only consistency check; identifies structural anomalies without modifying the image |
The Sleuth Kit (fls, ils, icat, fsstat) |
Forensic file system analysis; displays deleted entries, extracts inode content |
Autopsy |
GUI frontend to The Sleuth Kit |
extundelete |
Recovers deleted files from ext3/4 using journal analysis |
ext4magic |
Advanced deleted file recovery for ext4; reconstructs block lists from journal |
foremost / scalpel |
File carving tools for use against free block regions |
Further Reading
- B. Carrier. (2005). File System Forensic Analysis. Addison-Wesley. (Chapters 11–14 cover ext.)
- The Sleuth Kit documentation
ext4kernel documentationdebugfs(8)man page.