We spend our careers on NTFS and then get handed a Linux image. The letters look familiar, the tooling prints four timestamps, and the temptation is to read them the way we read an $SI triple. That is where the findings go wrong.
This one is different from most of what I write here in one important way. The behaviour I describe here is not mine. It comes from a paper I think every DFIR consultant working outside Windows should read, and I want to be explicit about that up front rather than absorb someone else’s work into a blog post. What I am adding is the part a paper does not do: which of these facts change a conclusion in a report, and which benign explanation will be waiting for you when you write it down.
Technical assumptions
Linux on ext4, 256 byte inodes, which is the default for a normal desktop or server install. Where I say something is standard behaviour rather than Linux behaviour, I mean POSIX.
The behavioural findings, including the mount option rules, the interface limits and the editor patterns, are from Thierry and Müller, A systematic approach to understanding MACB timestamps on Unix-like systems, DFRWS EU 2022. Their test framework is open source and the paper is open access. Full citation at the end. I have not re-run their test suite, so treat the specifics as theirs and confirm them on your own box with the commands near the end of this article before you put any of it in a report.
I am deliberately not covering macOS or the BSDs. The paper does, but it tested HFS+ and macOS has since moved to APFS, and a stale claim about a file system nobody runs any more is worse than no claim. Where the BSD behaviour makes a Linux point sharper I mention it and say so.
The four letters, and what they mean here
POSIX defines three timestamps. Not four.
M, last data modification
The file’s contents changed. This one behaves roughly the way you expect.
A, last data access
The file’s contents were read. Hold this one loosely. On a default Linux install it is usually not recorded, for reasons in the next section.
C, last status change
This is the one that catches people out. It is not creation. It is the inode metadata changing: permissions, ownership, link count, and also the timestamps themselves. Every standard operation that updates M also updates C.
B, birth
Not in POSIX at all. ext4 stores it as crtime, and the kernel fills it, but for years there was no interface to read it and there is still no interface to set it.
If you take one thing from this article: C is status change, not creation, and B is the field the standard does not know about. Those two facts are the root of most Linux timestamp mistakes I see.
How they are stored
In the ext4 inode each timestamp is a 4 byte signed count of seconds since 1970. With a 256 byte inode there is a second 4 byte field per timestamp, where the low two bits extend the epoch past 2038 and the upper thirty bits carry nanoseconds. Eight bytes per timestamp, the same total an NTFS FILETIME uses, arranged completely differently and giving 1 nanosecond resolution rather than 100.
That extra field is why inode size matters. Format a file system with 128 byte inodes and there is no room for it: you lose the nanoseconds, resolution drops to 1 second, and crtime does not exist at all. If you are staring at a Linux image wondering why every birth time is missing, check the inode size before you build a theory.
Access time is mostly not there
This is the single biggest difference from Windows work, and the one I would put in the first paragraph of a Linux triage note.
Linux mounts file systems with relatime by default. Under that rule the access time is only written if the existing A was already earlier than or equal to M or C, or if it is more than a day old. Read a file twice in an afternoon and the second read leaves nothing. The paper is blunt about the consequence: this makes a default Linux install non-compliant with POSIX, and it is accepted because the performance cost of honest access times is not worth paying.
So on a default system, an unchanged access time is not evidence that a file was not read. It is the expected result.
False positives and false comfort. The mount options are per file system, so check each one rather than assuming. noatime means A is never updated after creation, which makes the field a fossil of when the file appeared. nodiratime does the same for directories only. strictatime restores standard behaviour, and if you find it set deliberately on a server, someone made a choice you should ask about. There is also lazytime, which is about when updates are flushed to disk rather than whether they happen, so a crash can lose recent timestamp writes. That last one is outside the paper’s scope, so check the mount documentation rather than taking it from me.
The asymmetry, and it is the opposite of the BSDs
On NTFS the useful asymmetry is that the same four times are stored twice and only one copy is reachable through the documented API. Linux has an asymmetry too, and it sits somewhere else entirely.
The interface for setting timestamps reaches the access and modification times. That is all. There is no interface that sets the status change time to a value of your choosing, and setting A or M updates C to now as a side effect. On Linux there is also no interface that sets the birth time. The kernel writes crtime when the inode is created and nothing in userspace will move it.
That gives you two fields with useful properties on Linux: C, which an attacker can push forward but never backward or to an arbitrary value, and B, which they cannot touch at all through normal interfaces.
Now the part that matters if you work across platforms. On FreeBSD and macOS the equivalent interfaces do allow the birth time to be set, and the paper notes this is exposed to ordinary users through the standard command line tool. So “the birth time cannot be faked” is a Linux statement, not a Unix statement. Say it about the wrong platform in front of opposing counsel and you have handed them the afternoon.
And the standard caveat applies to all of it: with root and direct writes to the block device, every field is writable. These properties describe what the interfaces allow, not what an attacker with full control of the box is limited to.
The tells, and the benign explanation for each
Same structure as the NTFS article, because the same discipline applies. A tell you cannot argue against is not a finding.
1. C earlier than M
Every standard operation that changes content updates both M and C, and C cannot be set directly. So a status change time earlier than the modification time should not happen through ordinary use, and it is what a naive timestomp leaves behind: the tool sets A and M into the past, C jumps to now, and the pair no longer makes sense together.
False positives. The comparison only holds if you trust the clock. A system time change, an NTP correction, or an image restored from a machine with a wrong clock will produce the same shape across a whole population of files. That population is the discriminator. One file with an odd pair is interesting, ten thousand of them is a clock event.
2. Birth time later than modification time
Superficially damning: the file claims to have been created after it was last written.
False positives. This is the one I would most expect to see misread, because it is the normal result of an entirely innocent operation. Moving a file between two file systems cannot be a rename, so the tooling copies it. Per the paper, on Linux the destination gets a fresh birth time while inheriting the modification time from the source. Every file a user drags from their home partition to a mounted volume comes out looking like this. The same shape appears in restores from archives that preserve M and A but not creation.
3. A brand new birth time on a file that has existed for months
You have the file in an older backup or an older inventory, and its birth time is yesterday.
False positives. This is the best material in the paper for our purposes, and it is entirely benign. Editors do not agree on what saving means. Some write into the existing file, which leaves the inode alone and moves M and C. Others write a new file and rename it over the original, which produces a new inode with all four timestamps updated, a new birth time included. Both are normal. The paper profiles fifteen editors and finds all three patterns represented, and at least one editor changes behaviour depending on a single setting, so “which editor” is not even a stable answer on its own.
The practical consequence: on Linux, a birth time tells you when this inode appeared, not when this file first existed. Treat it as the age of the container, not the age of the content.
4. Sub-second precision that looks wrong
On NTFS, timestamps ending in too many zeros usually mean an archive or a tool with fewer bytes to spend rather than tampering. Linux has its own version of that trap, and it is more useful, because it points at the tool.
ext4 gives you nanoseconds. A plain command line copy preserves that. But the paper found that copies made through the GNOME I/O library, which is what several graphical file managers use, come out with the modification and access times truncated to microseconds, the result of a bug first reported in 2010 and still present when they tested. Other file managers truncate differently.
False positives. Do not run this the other way round. Microsecond precision does not prove a file manager was used, it is consistent with one. Plenty of other software truncates, and anything that has passed through an archive, a container image or a network file system may have lost precision on the way. This is a lead for attribution, not a conclusion.
5. A local move leaves almost nothing
Renaming a file, or moving it within the same file system, keeps the same inode. M, A and B are untouched and only C moves.
False positives. The trap is the reverse inference. Because a local move updates only C, a lone C change is consistent with a rename, with a permission change, with an ownership change and with the side effect of a timestomp. It narrows nothing on its own. You need the journal or another artifact to say which.
What none of it shows
Timestamps tell you that an operation touched a file. They do not tell you who, they do not tell you which process, and on Linux they frequently do not tell you that a read happened at all.
They are also the weakest evidence in the room the moment you have anything better. Journals, audit logs, the shell history, package manager records and the systemd journal all carry attribution that inode metadata never will. I reach for timestamps to build the shape of an incident and to test a hypothesis, not to prove one on their own.
Confirm it on your own machine
Everything above is checkable in about ten minutes on a spare virtual machine, and I would rather you did that than took my word or anyone else’s. Look at the mount options in effect, read all four timestamps including birth, then read the same inode straight from the file system and compare. Set a timestamp into the past with the standard tool and watch the status change time refuse to follow. Save the same file in two different editors and compare the inode numbers before and after.
The commands you want are findmnt or mount for the options actually in effect, stat for the four timestamps, statx if your tooling is old enough that stat will not print birth, debugfs with the stat command against the inode number for the on-disk view, dumpe2fs for the inode size, and touch with an explicit date for the timestomp test. If your stat shows a birth time of dashes, check the inode size before concluding anything.
Putting it together
If I am handed a Linux file system and asked whether the timestamps can be trusted, the order is roughly this. Establish the mount options, because they decide whether access time means anything at all. Establish the inode size, because it decides whether birth time exists. Then treat C and B as the interesting pair, since they are the two an attacker cannot set to a chosen value through ordinary interfaces, and treat M and A as the two that are cheap to fake.
And then, before writing any of it down, ask the question that has saved me more than once: what is the boring explanation. A cross-volume move, an editor that replaces rather than overwrites, a file manager that truncates precision, a clock that was wrong. On Linux the boring explanation is available for almost every tell, which is exactly why the tells are worth knowing properly.
Credit where it belongs
The systematic work here is Thierry and Müller’s, not mine. They built a test framework, ran 187 compliance tests across four operating systems, profiled libraries and fifteen editors, and released the code. If your work touches Unix file systems at all, read the paper rather than my summary of it, and use their reference tables rather than anything I could reproduce here. It is open access under a licence that does not permit derivatives, which is another good reason to send you to the source.
References
- Primary source A. Thierry and T. Müller, A systematic approach to understanding MACB timestamps on Unix-like systems, DFRWS EU 2022, Forensic Science International: Digital Investigation 40 (2022) 301338. Open access, CC BY-NC-ND 4.0 doi.org/10.1016/j.fsidi.2022.301338
- Test framework os_timestamps, the open source profiling and POSIX compliance framework from that paper github.com/QuoSecGmbH/os_timestamps
- Mount options relatime, strictatime, noatime, nodiratime and lazytime, as documented for mount man7.org/linux/man-pages/man8/mount.8.html
- Interfaces utimensat and futimens, the interfaces that set access and modification times and nothing else man7.org/linux/man-pages/man2/utimensat.2.html
- Interfaces statx, and the birth time flag that finally exposed crtime to userspace man7.org/linux/man-pages/man2/statx.2.html
- Timestamp semantics inode(7), on what the three POSIX timestamps mean and when each is updated man7.org/linux/man-pages/man7/inode.7.html
- On-disk layout The ext4 inode, including the extra timestamp fields that carry nanoseconds and the epoch bits kernel.org/doc/html/latest/filesystems/ext4/inodes.html
- Companion piece The Windows half of this problem: what file timestamps mean, and how to catch tampering /field-notes/what-file-timestamps-mean/