INODES
Now that we have had a little break from theory and had our fun with some scripting, it is time to get back to learning more about the keepers of the metadata, the inodes. For ext2 and ext3 filesystems the inodes are 128 bytes long. As of this writing the ext4 filesystem uses 156 byte inodes, but it allocates 256 bytes on the disk. This extra 100 bytes is for future expansion and may also be used for storage as we will see later in this chapter.
In order to use inodes you must first find them. The block group associated with an inode is easily calculated using the following formula:
block group = (inode number – 1 ) / (inodes per group)
Obviously integer division should be used here as block groups are integers. Once the correct block group has been located, the index within the block groups inode table must be calculated. This is easily done with the modulus operator. Recall that x mod y gives the remainder when performing the integer division x/y. The formula for the index is simply:
index = (inode number – 1) mod (inodes per group) Finally, the offset into the inode table is given by:
offset = index * (inode size on disk)
The inode structure is summarized in Table 7.5. Most of these fields are selfexplanatory. Those that are not will be described in more detail in this section.
There are two operating system dependent unions (OSDs) in the inode. These will vary from what is described here if your filesystem comes from Hurd or BSD. The first OSD for filesystems created by Linux holds the inode version. For extended filesystems created by Linux, the second OSD contains the upper 16 bits of several values.
The block array stores fifteen 32-bit block addresses. If this was used to directly store blocks that make up a file, it would be extremely limiting. For example, if 4-kilobyte blocks are in use, files would be limited to 60 kilobytes! This is not how this array is used, however. The first twelve entries are direct block entries which contain the block numbers for the first twelve data blocks (48 kB when using 4kB blocks) that make up a file. If more space is required, the thirteenth entry has the block number for a singly indirect block. The singly indirect block is a data block that contains a list of data blocks that make up a file. If the block size is 4 kB the singly indirect block can point to 1024 data blocks. The maximum amount that can be stored using singly indirect blocks is then (size of a data block) (number of block addresses that can be stored in a data block) or (4 kB) (1024) which equals 4 megabytes.
For files too large to be stored with direct blocks and singly indirect blocks (48 kB + 4 MB), the fourteenth entry contains the block number for a doubly indirect block. The doubly indirect block points to a block that contains a list of singly indirect blocks. The doubly indirect blocks can store 1024 times as much as singly indirect blocks (again assuming 4 kB blocks) which means that files as large as (48 kB + 4 MB + 4 GB) can be accommodated. If this is still not enough space, the final entry contains a pointer to triply indirect blocks allowing files as large as (48 kB + 4 MB + 4 GB + 4 TB) to be stored. This block system is illustrated in Figure 7.20.
FIGURE 7.20
Data blocks in inode block array.
If you are looking at an ext2 or ext3 filesystem, then the above list of inode fields is complete. For ext4 filesystems the fields in Table 7.6. have been added. Most of these fields are extra time bits.
Table 7.5. Inode structure.
Offset | Size | Name | Description |
---|---|---|---|
0x0 | 2 | File Mode | File mode and type |
0x2 | 2 | UID | Lower 16 bits of owner ID |
0x4 | 4 | Size lo | Lower 32 bits of file size |
0x8 | 4 | Atime | Access time in seconds since epoch |
0xC | 4 | Ctime | Change time in seconds since epoch |
0x10 | 4 | Mtime | Modify time in seconds since epoch |
0x14 | 4 | Dtime | Delete time in seconds since epoch |
---|---|---|---|
0x18 | 2 | GID | Lower 16 bits of group ID |
0x1A | 2 | Hlink count | Hard link count |
0x1C | 4 | Blocks lo | Lower 32 bits of block count |
0x20 | 4 | Flags | Flags |
0x24 | 4 | Union osd1 | Linux : l version |
0x28 | 60 | Block[15] | 15 pointers to data blocks |
0x64 | 4 | Version | File version for NFS |
0x68 | 4 | File ACL low | Lower 32 bits of extended attributes (ACL, etc) |
0x6C | 4 | File size hi | Upper 32 bits of file size (ext4 only) |
0x70 | 4 | Obsolete fragment | An obsoleted fragment address |
0x74 | 12 | Osd 2 | Second operating system dependent union |
0x74 | 2 | Blocks hi | Upper 16 bits of block count |
0x76 | 2 | File ACL hi | Upper 16 bits of extended attributes (ACL, etc.) |
0x78 | 2 | UID hi | Upper 16 bits of owner ID |
0x7A | 2 | GID hi | Upper 16 bits of group ID |
0x7C | 2 | Checksum lo | Lower 16 bits of inode checksum |
Table 7.6. Extra inode fields in ext4 filesystems.
Offset | Size | Name | Description |
---|---|---|---|
0x80 | 2 | Extra size | How many bytes beyond standard 128 are used |
0x82 | 2 | Checksum hi | Upper 16 bits of inode checksum |
0x84 | 4 | Ctime extra | Change time extra bits |
0x88 | 4 | Mtime extra | Modify time extra bits |
0x8C | 4 | Atime extra | Access time extra bits |
0x90 | 4 | Crtime | File create time (seconds since epoch) |
0x94 | 4 | Crtime extra | File create time extra bits |
0x98 | 4 | Version hi | Upper 32 bits of version |
0x9C | Unused | Reserved space for future expansions |
A word about the extra time bits is in order. Linux is facing a serious problem. In the year 2038 the 32-bit timestamps will roll over. While that is over two decades away, a solution is already in place (Hurray for Open Source!). The solution is to expand the 32bit time structure to 64 bits. In order to prevent backward compatibility problems the original 32-bit time structure (stored in first 128 bytes of inodes) remains unchanged; it is still just seconds since the epoch on January 1, 1970. The lower two bits of this extra field are used to extend the 32-bit seconds counter to 34 bits which makes everything good until the year 2446. The upper thirty bits of the extra field are used to store nanoseconds.
This nanosecond accuracy is a dream for forensic investigators. By way of comparison, Windows FAT filesystems provide only a two second resolution and even the latest version of NTFS only provides accuracy to the nearest 100 nanoseconds. This is another reason to use Python and other tools to parse the inodes as standard tools don’t normally display the complete timestamp. This high precision makes timeline analysis easier since you do not have to guess what changed first in a two second interval.
There are a number of special inodes. These are summarized in Table 7.7. Of the inodes listed, the root directory (inode 2) and journal (inode 8) are some of the more important ones for forensic investigators.
Table 7.7. Special purpose inodes.
Inode | Special Purpose |
---|---|
0 | No such inode, numberings starts at 1 |
1 | Defective block list |
2 | Root directory |
3 | User quotas |
4 | Group quotas |
5 | Boot loader |
6 | Undelete directory |
7 | Reserved group descriptors (for resizing filesystem) |
8 | Journal |
9 | Exclude inode (for snapshots) |
10 | Replica inode |
11 | First non-reserved inode (often lost + found) |