The File System Dirty Bit

May 18th, 2021 by Vladimir Katalov
Category: «Mobile», «Tips & Tricks»

In older iPhones, the ‘file system dirty’ flag indicates unclean device shutdown, which affects the ability to perform bootloader-level extractions of Apple devices running legacy versions of iOS (prior to iOS 10.3 released in March 2017). As such, the “file system dirty” flag must be cleared before the extraction. In this article we discuss the very different forensic implications of this flag if it is set on the Data or System partitions.

This article comes from our research department.

What is a file system?

A file system is a concept of storing files and directories on a (usually block based) storage medium. It provides an abstraction for creating, reading, writing and deleting files. These events can occur randomly and even concurrently. It’s the operating systems task to serialize those operations and, with the file system as a strategy, write data to a storage medium.

What are atomic file operations?

Generally speaking, storing files is trivial as long as everything follows the protocol and no unexpected events happen. However what happens when the system crashes or loses power in the middle of a write? In these cases the file system can get corrupted. For example, the metadata of a file says it is of a certain size, but the actual data write aborted mid-way.

In order to prevent having half-written-files or other types of corruption, modern file systems introduce the concept of atomic file operations. This means that an operation always either completely succeeds, or it never happened. Thus there are no longer half-written files.

But how is this implemented in practice?

Since the possibility of a crash or a sudden power loss always exists and isn’t even rare, this has to be somehow dealt with. One possible solution is a concept called journaling, which, as the name suggests, keeps a journal of file operations that are to be performed, that are in progress and that were already completed. The general idea to achieve atomicity when writing files is:

  • First, create a journal entry saying “i am now going to write a file of size X”.
  • Then, perform the actual file write.
  • Finally, update the journal entry saying “I am done performing this file write”.

If at any point in time the system shuts down and thus any of these operations are interrupted, it is possible to either finish the (so called) transaction, or to revert the write altogether. Thus, we achieve atomic file operations

What is the “file system dirty” bit?

In case of a journaling file system, how do we tell whether there was a crash or not? Sure, we could check the journal and verify whether the files are written as they were intended, but what if the shutdown happened while updating the journal itself? Furthermore, checking the journal on every mount can be slow. Ideally we’d want to check it only if something went wrong.

To solve this, some file systems like Apples HFS use a so called “dirty bit” in the file system header. When the file system is mounted, this bit is set to 1, thus indicating that “this file system is in use and it will potentially be modified”.

Once all modifications are done and the file system is unmounted (eg. when performing a clean system shutdown), the dirty bit is cleared (set back to 0) indicating that “everything went fine, there were no issues here”.

Now what happens in case of an unclean shutdown (like a system crash)? Well, the dirty bit is still set, because since the system crashed, the bit never got cleared. This serves as an indicator that the file system may be in a corrupt state and needs fixing. If that happens, it is required to check the journal and either finish the writes (if possible), or revert to the state where the file wasn’t created at all (thus achieving atomicity).

How do I clear the HFS dirty bit?

The file system implementation usually takes care of that on its own, without the user having to perform any action at all. For example, when an HFS file system is mounted and the system crashes and reboots, the system automatically performs a check, repairs the journal and continues to use the file system.

Another method is to manually run a file system check (fsck). In case the dirty bit is clear, there is nothing to do since the file system is in a clean state. On the other hand, if the bit is set, checks are performed, journal and files are fixed up and finally the dirty bit gets cleared indicating that the file system is in a clean state again.

What does my iPhone have to do with all of this?

The iOS operating system used HFS as a file system up to iOS 10.3 (and then switched to APFS on 64bit devices). HFS uses journaling and the concept of the dirty bit, thus the previously explained concepts apply.

On iOS there are at least two partitions, namely the “System” partition and the “Data” partition. As the name suggests, the “Data” partition stores all user data like apps, messages, photos and much more. Therefore the partition is mounted readable and writable. In the case the system crashes a check is performed on the next boot and the file system is repaired.

Why does EIFT need to clear the dirty bit?

As already explained, the dirty bit is set (or rather remains set) when the system has had an unclean shutdown. This can be caused by a kernel panic or a hard reset. For example, when putting the device into DFU mode, you are instructed to hold the power + home button for 10 seconds, then release the power button and keep holding the home button for additional 15 seconds. When taking a closer look on what is happening under the hood, we notice that after the first 7 seconds of holding the power+home combination the system performs a “hard reset”, i.e. the device is instantly reset without the system getting a chance to properly finish remaining work and flush the file system. This is equivalent to pulling the power cord on a desktop computer. Thus, when then booting into EIFT the dirty bit is still set so that the file system needs to be checked first.

Now in the case of HFS the need of manually running fsck only arises because EIFT mounts the file system read-only (since we want to be forensically sound and don’t want to introduce any modifications to the file system like accidentally modifying file access dates). The iOS HFS implementation disallows mounting a file system read-only if the dirty bit set. This is because read-only implies that we cannot do any modifications to the file system, but it also means that files might be corrupted and cannot be fixed (due to it being a read-only mount).

Note that when mounting the file system writable, the system automatically checks and recovers corrupted state before allowing programs to access files.

What exactly does EIFT do to the file system?

If the dirty bit is not set, the file system is mounted read-only straight away. In that case absolutely no modifications are performed.

If the dirty bit is set, then EIFT first runs Apple’s own tool fsck_hfs (file system checking utility), which checks the filesystems state, recovers corruption, replays interrupted journal, fixes up broken files and finally unsets the dirty bit. Afterwards the file system can be mounted read-only and no further modifications are performed.

Does this mean we’re not forensically sound anymore?

Well, no.

It is true that, technically, we do some modifications to the file system, so we can’t say it’s untouched at all. However, the modifications are so minimal that they do not have any impact at all to the data analysis. Furthermore, the fact that the “dirty” bit is set has no practical information in first place, since it could have been introduced by an expert when resetting the device in order to access DFU mode to begin with.

Thus, even when performing a file system check we can say that we don’t (reasonably) impact the soundness of the extraction. Userdata itself (which wasn’t corrupt in first place) isn’t altered during this process.

Can we avoid manually running fsck?

Yes!

In order to let the system handle everything without the need of interfering manually, all we need to do is to perform a clean shutdown. Even clearing a previously dirty bit can be left entirely up to the system. In order to do so, simply power on the device. Then, hold the power button until the “power off” option appears and proceed with powering off the device by sliding the UI element. At this point the device was powered off cleanly and the dirty bit is clear. Now, we only need to make sure we don’t accidentally set it again.

If your device is connected to your computer, you should disconnect it now. Now we proceed by holding the home button while powering on the device (either press the power button once, or plug in a cable).

Important: Make sure to keep holding the home button while powering on the device.

The device will boot into recovery mode and you should see the “connect to iTunes/computer” logo on screen. Since the operating system wasn’t booted yet, the file system wasn’t mounted either. Thus, the dirty bit is still clean and also will remain clean. From recovery mode we can proceed to put the device into DFU mode. Even if we hard reset the device from recovery mode (in order to get into DFU mode), the dirty bit remains untouched since the file system isn’t mounted in first place. When we now boot to EIFT ramdisk, the dirty bit is still clear and there is no need to manually perform file system checks and thus, EIFT does not modify the device at all.

How relevant is this in practice?

First and foremost, even theoretically, this only affects devices that run systems released before iOS 10.3, which was pushed by Apple some four years ago.

I would say the “dirty” bit of the Data partition isn’t relevant at all, since it gets set and unset during normal operation and may remain set in case of a user induced hard reset. This really doesn’t tell you anything useful.

Does that mean I can learn nothing from dirty bits?

For Data partition: yes, this doesn’t really tell you anything.

For System partition, on the other hand, this is a whole different story.

In iOS, the System partition is never mounted writable and thus during normal operation the dirty bit gets never set in the first place. Even in the case of an unclean shutdown (like hard reset or system crash) the dirty bit is never set, since the System partition is never mounted writable. It makes sense that if you never modify a file system, then even a crash can’t corrupt any files, since, well, you’re never writing any files. In fact, starting with iOS 6, the kernel checks for the System partition and even prevents mounting it writable.

Yet still, we can sometimes observe a set dirty bit on the System partition. How is that possible? The answer is Jailbreaks or (more generally) tampering with the device security. Jailbreaks usually patch the kernel, then remount the System partition and deploy files on it. However, as soon as the System partition is re-mounted readable and writable, the dirty bit gets set!

Now here is the interesting part: When the system shuts down uncleanly, the dirty bit remains set. But due to the fact that on the next boot the System partition is then mounted read-only (due to signed bootchain unless there an iBoot exploit), the bit remains set. Remember that a file system can’t be mounted read-only when the dirty bit is set? Well, there is one exception! The file system may have the dirty bit set and mounted read-only if it’s the root file system (which makes sense, since otherwise the system wouldn’t boot).

Furthermore, since the System partition is mounted read-only, the dirty bit won’t get cleared during normal system operation. It will survive several reboots! The only way to un-set the System dirty bit is to exploit the kernel again, then remount the System partition writable, then perform a clean shutdown (or to manually run fsck, but nobody does that). Keep in mind that unless the system is jailbroken (or hacked/implanted) in untethered fashion (which means a kernel exploit is automatically executed on every boot), clearing the System dirty bit requires active user interaction (eg. kickstarting a tethered jailbreak by running an app).

What does it mean if the System partition dirty bit is set?

It means the system was tampered with and the System was shutdown uncleanly (either due to a kernel panic or hard reset). It essentially means the device was either jailbroken by the user at some point or (a bit less likely) that some malware was installed that remounted the System partition writable at some point.

How can I check for the dirty bit?

Elcomsoft iOS Forensic Toolkit ships with a utility called diskinfo which (among other things) checks for HFS dirty bit for System and Data partition if they are not currently mounted.

Does this apply to APFS too?

No.

Without going into much detail, the APFS implementation does not use the concept of dirty bits. Atomicity is implemented in a different manner. When mounting APFS read-only, even after an unclean shutdown, it is never required to perform any modifications to the file system.


REFERENCES:

Elcomsoft iOS Forensic Toolkit

Extract critical evidence from Apple iOS devices in real time. Gain access to phone secrets including passwords and encryption keys, and decrypt the file system image with or without the original passcode. Physical and logical acquisition options for all 64-bit devices running all versions of iOS.

Elcomsoft iOS Forensic Toolkit official web page & downloads »