HomeFreeBSD

msdosfs: fix directory corruption after rename operation

Description

msdosfs: fix directory corruption after rename operation

The is a bug in MSDOSFS that can be triggered when the target of a
rename operation exists. It is caused by the lack of inodes in the
FAT file system, which are substituted by the location of the DOS 8.3
directory entry in the file system. This causes the "inode" of a file
to change when its directory entry is moved to a different location.

The rename operation wants to re-use the existing directory entry
position of an existing target file name (POS1). But the code does
instead locate the first position in the directory that provides
sufficient free directory slots (POS2) to hold the target file name
and fills it with the directory data.

The rename operation continues and at the end writes directory data to
the initially retrieved location (POS1) of the old target directory.
This leads to 2 directory entries for the target file, but with
inconsistent data in the directory and in the cached file system
state.

The location that should have been re-used (POS1) is marked as deleted
in the directory, and new directory data has been written to a
different location (POS2). But the VFS cache has the newly written
data stored under the inode number that corresponds to the initially
planned position (POS1).

If then a new file is written, it can allocate the deleted directory
entries (POS1) and when it queries the cache, it retrieves data that
is valid for the target of the prior rename operation, leading to a
corrupt directory entry (at POS1) being written (DOS file name of the
earlier rename target combined with the Windows long file name of the
newly written file).

PR: 268005
Reported by: wbe@psr.com
Approved by: kib, mckusick
Fixes: 2c9cbc2d45b94
MFC after: 3 days
Differential Revision: https://reviews.freebsd.org/D43951

Details

Provenance
seAuthored on Feb 17 2024, 9:04 PM
Differential Revision
D43951: Fix MSDOSFS rename (in case target exists)
Parents
rGe368e9b75677: Proactively remove /usr/lib/kgdb file that became a directory
Branches
Unknown
Tags
Unknown