aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Biggers <ebiggers@google.com>2020-05-29 13:47:38 -0700
committerJaegeuk Kim <jaegeuk@kernel.org>2020-05-30 08:18:51 -0700
commite65d9c7adf52aae7d7e2eb132961c8373072c8c9 (patch)
treec80dedc80bd7282fe154798207014ffe6411d69b
parentb23b2b97a662168ee364bc67965de08ffc1455bc (diff)
downloadf2fs-tools-e65d9c7adf52aae7d7e2eb132961c8373072c8c9.tar.gz
fsck.f2fs: fix dirent position check for encrypted+casefolded dentries
fsck.f2fs reports corruption if the filesystem contains any encrypted + casefolded directories with any substantial number of dentries: [ASSERT] (f2fs_check_dirent_position:1374) --> Wrong position of dirent pino:8, name:۟�[I�^*�(�5~�}�D��#]7�8�ˎ�, level:1, dir_level:0, pgofs:4, correct range:[2, 3] The problem is that f2fs_check_dirent_position() computes the wrong hash for encrypted+casefolded dentries. It's not actually possible for it to compute the correct hash, because it would need the encryption key. However, the on-disk dentry already contains the hash code, and its correctness was already verified by f2fs_check_hash_code() if possible. So, make f2fs_check_dirent_position() use the hash code from disk rather than recompute it. Also fix it to print the filename in human-readable form. This bug was causing 'kvm-xfstests -c f2fs/encrypt -g casefold' to fail with the test_dummy_encryption_v2 and encryption+casefolding kernel patches applied. Fixes: 7f3767ee8dc5 ("f2fs-tools: Casefolded Encryption support") Cc: Daniel Rosenberg <drosen@google.com> Signed-off-by: Eric Biggers <ebiggers@google.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
-rw-r--r--fsck/fsck.c21
1 files changed, 11 insertions, 10 deletions
diff --git a/fsck/fsck.c b/fsck/fsck.c
index 0389146..c249dfa 100644
--- a/fsck/fsck.c
+++ b/fsck/fsck.c
@@ -1348,11 +1348,10 @@ static int __get_current_level(int dir_level, u32 pgofs)
return i;
}
-static int f2fs_check_dirent_position(int encoding, int casefolded,
- u8 *name, u16 name_len, u32 pgofs,
- u8 dir_level, u32 pino)
+static int f2fs_check_dirent_position(const struct f2fs_dir_entry *dentry,
+ const char *printable_name,
+ u32 pgofs, u8 dir_level, u32 pino)
{
- f2fs_hash_t namehash = f2fs_dentry_hash(encoding, casefolded, name, name_len);
unsigned int nbucket, nblock;
unsigned int bidx, end_block;
int level;
@@ -1363,7 +1362,7 @@ static int f2fs_check_dirent_position(int encoding, int casefolded,
nblock = bucket_blocks(level);
bidx = dir_block_index(level, dir_level,
- le32_to_cpu(namehash) % nbucket);
+ le32_to_cpu(dentry->hash_code) % nbucket);
end_block = bidx + nblock;
if (pgofs >= bidx && pgofs < end_block)
@@ -1371,7 +1370,8 @@ static int f2fs_check_dirent_position(int encoding, int casefolded,
ASSERT_MSG("Wrong position of dirent pino:%u, name:%s, level:%d, "
"dir_level:%d, pgofs:%u, correct range:[%u, %u]\n",
- pino, name, level, dir_level, pgofs, bidx, end_block - 1);
+ pino, printable_name, level, dir_level, pgofs, bidx,
+ end_block - 1);
return 1;
}
@@ -1552,10 +1552,12 @@ static int __chk_dentries(struct f2fs_sb_info *sbi, int casefolded,
if (f2fs_check_hash_code(get_encoding(sbi), casefolded, dentry + i, name, name_len, enc_name))
fixed = 1;
+ pretty_print_filename(name, name_len, en, enc_name);
+
if (max == NR_DENTRY_IN_BLOCK) {
- ret = f2fs_check_dirent_position(get_encoding(sbi), casefolded,
- name, name_len, child->pgofs,
- child->dir_level, child->p_ino);
+ ret = f2fs_check_dirent_position(dentry + i, en,
+ child->pgofs, child->dir_level,
+ child->p_ino);
if (ret) {
if (c.fix_on) {
FIX_MSG("Clear bad dentry 0x%x", i);
@@ -1568,7 +1570,6 @@ static int __chk_dentries(struct f2fs_sb_info *sbi, int casefolded,
}
}
- pretty_print_filename(name, name_len, en, enc_name);
DBG(1, "[%3u]-[0x%x] name[%s] len[0x%x] ino[0x%x] type[0x%x]\n",
fsck->dentry_depth, i, en, name_len,
le32_to_cpu(dentry[i].ino),