Modern operating systems provide a way to increase the size of a given file without writing to it.
In Unix-like operating systems, this is achieved through the truncate() and ftruncate() system calls. These calls allow programs to decrease or increase the file size.
If the file size is decreased, data beyond the new end-of-file position is discarded (it can survive as deleted data, but there is no way to bring these bytes back by restoring the original file size).
If the file size is increased, extra data (data after the old end-of-file position) is filled with null bytes. Internally, many modern file systems don’t write those extra null bytes to the drive, they make a sparse data range instead (so, if a program increases the file size by several gigabytes, there is no need to actually write that amount of null bytes to the drive).
Some file systems may reserve sectors to hold that amount of extra data and attach those sectors to the file, but their contents are left intact. This is useful to quickly preallocate some space to avoid fragmentation: a file system driver reserves the requested amount of sectors, but it doesn’t clear them (and an attempt to read from that extra space returns null bytes, despite the fact that these extra sectors may contain something different).
Treating the extra space as containing null bytes is essential for security, there is a POSIX requirement for that:
If the file size is increased, the extended area shall appear as if it were zero-filled.
https://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html
It’s a vulnerability if deleted (or uninitialized) data is returned when reading that extra area (for example, see CVE-2021-4155).
Surprisingly, such vulnerabilities are still discovered in file system drivers.
Continue reading “Bringing unallocated data back: the FAT12/16/32 case”