CVE-2021-47072
Publication date:
01/03/2024
In the Linux kernel, the following vulnerability has been resolved:<br />
<br />
btrfs: fix removed dentries still existing after log is synced<br />
<br />
When we move one inode from one directory to another and both the inode<br />
and its previous parent directory were logged before, we are not supposed<br />
to have the dentry for the old parent if we have a power failure after the<br />
log is synced. Only the new dentry is supposed to exist.<br />
<br />
Generally this works correctly, however there is a scenario where this is<br />
not currently working, because the old parent of the file/directory that<br />
was moved is not authoritative for a range that includes the dir index and<br />
dir item keys of the old dentry. This case is better explained with the<br />
following example and reproducer:<br />
<br />
# The test requires a very specific layout of keys and items in the<br />
# fs/subvolume btree to trigger the bug. So we want to make sure that<br />
# on whatever platform we are, we have the same leaf/node size.<br />
#<br />
# Currently in btrfs the node/leaf size can not be smaller than the page<br />
# size (but it can be greater than the page size). So use the largest<br />
# supported node/leaf size (64K).<br />
<br />
$ mkfs.btrfs -f -n 65536 /dev/sdc<br />
$ mount /dev/sdc /mnt<br />
<br />
# "testdir" is inode 257.<br />
$ mkdir /mnt/testdir<br />
$ chmod 755 /mnt/testdir<br />
<br />
# Create several empty files to have the directory "testdir" with its<br />
# items spread over several leaves (7 in this case).<br />
$ for ((i = 1; i /mnt/testdir/file$i<br />
done<br />
<br />
# Create our test directory "dira", inode number 1458, which gets all<br />
# its items in leaf 7.<br />
#<br />
# The BTRFS_DIR_ITEM_KEY item for inode 257 ("testdir") that points to<br />
# the entry named "dira" is in leaf 2, while the BTRFS_DIR_INDEX_KEY<br />
# item that points to that entry is in leaf 3.<br />
#<br />
# For this particular filesystem node size (64K), file count and file<br />
# names, we endup with the directory entry items from inode 257 in<br />
# leaves 2 and 3, as previously mentioned - what matters for triggering<br />
# the bug exercised by this test case is that those items are not placed<br />
# in leaf 1, they must be placed in a leaf different from the one<br />
# containing the inode item for inode 257.<br />
#<br />
# The corresponding BTRFS_DIR_ITEM_KEY and BTRFS_DIR_INDEX_KEY items for<br />
# the parent inode (257) are the following:<br />
#<br />
# item 460 key (257 DIR_ITEM 3724298081) itemoff 48344 itemsize 34<br />
# location key (1458 INODE_ITEM 0) type DIR<br />
# transid 6 data_len 0 name_len 4<br />
# name: dira<br />
#<br />
# and:<br />
#<br />
# item 771 key (257 DIR_INDEX 1202) itemoff 36673 itemsize 34<br />
# location key (1458 INODE_ITEM 0) type DIR<br />
# transid 6 data_len 0 name_len 4<br />
# name: dira<br />
<br />
$ mkdir /mnt/testdir/dira<br />
<br />
# Make sure everything done so far is durably persisted.<br />
$ sync<br />
<br />
# Now do a change to inode 257 ("testdir") that does not result in<br />
# COWing leaves 2 and 3 - the leaves that contain the directory items<br />
# pointing to inode 1458 (directory "dira").<br />
#<br />
# Changing permissions, the owner/group, updating or adding a xattr,<br />
# etc, will not change (COW) leaves 2 and 3. So for the sake of<br />
# simplicity change the permissions of inode 257, which results in<br />
# updating its inode item and therefore change (COW) only leaf 1.<br />
<br />
$ chmod 700 /mnt/testdir<br />
<br />
# Now fsync directory inode 257.<br />
#<br />
# Since only the first leaf was changed/COWed, we log the inode item of<br />
# inode 257 and only the dentries found in the first leaf, all have a<br />
# key type of BTRFS_DIR_ITEM_KEY, and no keys of type<br />
# BTRFS_DIR_INDEX_KEY, because they sort after the former type and none<br />
# exist in the first leaf.<br />
#<br />
# We also log 3 items that represent ranges for dir items and dir<br />
# indexes for which the log is authoritative:<br />
#<br />
# 1) a key of type BTRFS_DIR_LOG_ITEM_KEY, which indicates the log is<br />
# authoritative for all BTRFS_DIR_ITEM_KEY keys that have an offset<br />
# in the range [0, 2285968570] (the offset here is th<br />
---truncated---
Severity CVSS v4.0: Pending analysis
Last modification:
09/01/2025