Kernel Bug Tracker – Bug 5079
Possible file date underflow on ext2/3 filesystems on amd64 systems
Last modified: 2009-01-17 19:44:55 UTC
Hardware Environment: 64 bit machine
A user at gentoo buzilla(1) reported that some files that he change the date to
1 Jan 1970 for archiving purposes, after umount and re-mounting the partition,
the files would have the date changed to 7 Feb 2106. On the report, he only test
this on ext3 filesystem but i also reproduce it in ext2 filesystems. If any mor
info is needed just ask.
Steps to reproduce:
1. Compile and install a kernel with ext2/3 support
2. mount <ext2/3_partition>
3. cd <ext2/3_partition>
4. touch -d 01/01/1907 test_file
5. cd ..
6. umount <ext2/3_partition>
7. mount <ext2/3_partition>
8. ls -l <ext2/3_partition>/test_file
The file will report 7 Feb 2106.
This was also confirmed in plain vanilla kernel 2.6.13-rc6.
btw, forgot to mention that this was only reproduced on 64bit machines (intel
and amd) and that this bug doesn't happen on reiserfs nor xfs, just ext2/3. Also
this is not new to the 2.6.13 kernel since it is reproducible on 2.6.12 kernel's.
Downstream bug report: http://bugs.gentoo.org/show_bug.cgi?id=101723
I cannot reproduce this with 2.6.16-rc1. I tried setting localtime to Japan too.
Can you guys please retest?
If it still happens, then we need to work out what's different between your
setups and mine.
Also, use /usr/bin/stat to read the inode timestamps - that'll help us separate
kernel problems from userspace ones.
I am now on x86_64 and interestingly enough I was looking into this just a
I can reproduce the bug on my x86_64 but *not* on my x86. Note that the
partition must be remounted before the "future" date appears.
I didn't get much time to work on this, but I ended up confusing myself how it
can possibly work on x86. In ext2_update_inode(), the inode->i_mtime.tv_sec
value seems to be represented as 64 bits, but the raw_inode->i_mtime as 32.
The inode value was reading something like 0xffffff831212 (made up number, it
was similar to that though: first 32 bits as ff), and the raw_inode value was
being truncated to 0x831212.
You can probably discount these results as they were quite rushed. However I can
definately confirm the bug, and I'll come up with a detailed description of the
problem (and maybe even fix it :) when I next have some time (maybe this weekend).
Found the numbers I was testing with in my logs.
When inode->i_mtime.tv_sec read 0xffffffff89808d00, 0x89808d00 was being written
Ok I just gave it some thought and the bug is obvious. The function I've been
talking about is ext2_update_inode() by the way, which deals with copying
values from an inode struct (inode) to an ext2_inode struct (raw_inode).
inode->i_mtime.tv_sec is a time_t which is a "long" for both x86 and x86_64. On
x86 this is 32 bits and on x86_64 it is 64 bits.
raw_inode->i_mtime is __le32.
This explains why it works on x86: cpu_to_le32() on a 32 bit value isn't gonna
However, cpu_to_le32() on a 64 bit signed number (apparently) doesn't consider
its numerical value (in this case, negative, since we are talking about dates
before the epoch), it just chops off the upper bits which it doesn't care about.
Yes, something like that. Or the bug's in ext2_read_inode():
sign-extending a 32-bit field to 64.
But how are you setting an inode's time to before-epoch anyway?
If I try that, /bin/date complains.
touch -d 01/01/1907 somefile
oh, I thought 1907 was a typo in the bug report.
ext2 and ext3 cannot represent dates prior to epoch, and FC1's `touch'
command refuses to let you try.
But a newer version of `date' _does_ permit it. As one would expect, a
negative time like this will turn into a large positive time after it's
been written to a 32-bit inode field and read back.
I guess the filesystem should be returning error on this, but it cannot
distinguish a negative time from a large positive one.
That being said, 2106 is the wrong year. Setting the time to epoch-63
years _should_ result in epoch+73, but that's 2043.
I think the 2106 is epoch+0xffffffff, which is odd.
Oh, it probably was a typo, as the description talks about 1 Jan 1970. I'll
retest for 1970 later, since that shouldn't suffer from this weird pre-epoch
With the advent of large inodes, we gain the ability to have more space for the
inode timestamps. This has repeatedly been considered only for adding
nanosecond timestamps (consuming 30 bits per), but little consideration has been
given to also increasing the maximum values using some of those bits.
I also thought that unix timestamps are considered signed values, which is why
there is a unix "y2k" problem in 2038 (68 years = 2^31 seconds), so in theory
negative timestamps should get us to 1902 or so. Whether we care about the
signedness for ext3 files is a completely different issue.
Has anyone looked into this problem? I am interested in the timestamp bug. Where
in the kernel source should I look into to fix the bug? Are there documents
about ext3 filesystem for developers?
Created attachment 10317 [details]
signed/unsigned inode fix
The previous attachment is an approach to fix the date problem.
I tested this fix on an amd64 machine:
unsigned long ranges from -2.147.483.648
10000011110110100100111110111101 .. -2.082.844.739
10000011110110100100111110111101 .. 18.104.22.1687 <- this would be stored in
long(64bit) which overflows the 32bit range/date
signed long ranges from -2.147.483.648 to 2.147.483.647 on x86 32bit
10000011110110100100111110111101 .. -2.082.844.739
10000011110110100100111110111101 .. 22.214.171.1247 <- this currently gets
stored on the disk but when converting it to a 64bit signed long value it loses
its sign and becomes positive.
merged Markus's fix into -mm.
Btw: after time val becomes interpreted as signed value we have to make
according changes in e2fsprogs.
*** Bug 8643 has been marked as a duplicate of this bug. ***
Committed into mainline as commit: 4d7bf11d649c72621ca31b8ea12b9c94af380e63