- sb_csum isn't generated properly for 512- or 1024-byte filesystem block sizes.
- Add `--no-sbcrc` option to fsck.erofs to bypass the sb_csum check. Signed-off-by: Gao Xiang <hsiang...@linux.alibaba.com> --- fsck/main.c | 40 ++++++++----------------------- include/erofs/internal.h | 1 + lib/super.c | 51 ++++++++++++++++++++++++++++++---------- man/fsck.erofs.1 | 3 +++ 4 files changed, 52 insertions(+), 43 deletions(-) diff --git a/fsck/main.c b/fsck/main.c index cb4758b..91c193f 100644 --- a/fsck/main.c +++ b/fsck/main.c @@ -41,6 +41,7 @@ struct erofsfsck_cfg { bool preserve_owner; bool preserve_perms; bool dump_xattrs; + bool nosbcrc; }; static struct erofsfsck_cfg fsckcfg; @@ -60,6 +61,7 @@ static struct option long_options[] = { {"offset", required_argument, 0, 12}, {"xattrs", no_argument, 0, 13}, {"no-xattrs", no_argument, 0, 14}, + {"no-sbcrc", no_argument, 0, 512}, {0, 0, 0, 0}, }; @@ -110,6 +112,7 @@ static void usage(int argc, char **argv) " --extract[=X] check if all files are well encoded, optionally\n" " extract to X\n" " --offset=# skip # bytes at the beginning of IMAGE\n" + " --no-sbcrc bypass the superblock checksum verification\n" " --[no-]xattrs whether to dump extended attributes (default off)\n" "\n" " -a, -A, -y no-op, for compatibility with fsck of other filesystems\n" @@ -244,6 +247,9 @@ static int erofsfsck_parse_options_cfg(int argc, char **argv) case 14: fsckcfg.dump_xattrs = false; break; + case 512: + fsckcfg.nosbcrc = true; + break; default: return -EINVAL; } @@ -322,35 +328,6 @@ static void erofsfsck_set_attributes(struct erofs_inode *inode, char *path) } } -static int erofs_check_sb_chksum(void) -{ -#ifndef FUZZING - u8 buf[EROFS_MAX_BLOCK_SIZE]; - u32 crc; - struct erofs_super_block *sb; - int ret; - - ret = erofs_blk_read(&g_sbi, 0, buf, 0, 1); - if (ret) { - erofs_err("failed to read superblock to check checksum: %d", - ret); - return -1; - } - - sb = (struct erofs_super_block *)(buf + EROFS_SUPER_OFFSET); - sb->checksum = 0; - - crc = erofs_crc32c(~0, (u8 *)sb, erofs_blksiz(&g_sbi) - EROFS_SUPER_OFFSET); - if (crc != g_sbi.checksum) { - erofs_err("superblock chksum doesn't match: saved(%08xh) calculated(%08xh)", - g_sbi.checksum, crc); - fsckcfg.corrupted = true; - return -1; - } -#endif - return 0; -} - static int erofs_verify_xattr(struct erofs_inode *inode) { struct erofs_sb_info *sbi = inode->sbi; @@ -1066,6 +1043,7 @@ int main(int argc, char *argv[]) #ifdef FUZZING cfg.c_dbg_lvl = -1; + fsckcfg.nosbcrc = true; #endif err = erofs_dev_open(&g_sbi, cfg.c_img_path, O_RDONLY); @@ -1080,7 +1058,9 @@ int main(int argc, char *argv[]) goto exit_dev_close; } - if (erofs_sb_has_sb_chksum(&g_sbi) && erofs_check_sb_chksum()) { + if (!fsckcfg.nosbcrc && erofs_sb_has_sb_chksum(&g_sbi) && + erofs_superblock_csum_verify(&g_sbi)) { + fsckcfg.corrupted = true; erofs_err("failed to verify superblock checksum"); goto exit_put_super; } diff --git a/include/erofs/internal.h b/include/erofs/internal.h index bf3efb5..d380c45 100644 --- a/include/erofs/internal.h +++ b/include/erofs/internal.h @@ -419,6 +419,7 @@ struct erofs_buffer_head *erofs_reserve_sb(struct erofs_bufmgr *bmgr); int erofs_mkfs_init_devices(struct erofs_sb_info *sbi, unsigned int devices); int erofs_write_device_table(struct erofs_sb_info *sbi); int erofs_enable_sb_chksum(struct erofs_sb_info *sbi, u32 *crc); +int erofs_superblock_csum_verify(struct erofs_sb_info *sbi); /* namei.c */ int erofs_read_inode_from_disk(struct erofs_inode *vi); diff --git a/lib/super.c b/lib/super.c index 8efef50..5b90db5 100644 --- a/lib/super.c +++ b/lib/super.c @@ -259,19 +259,22 @@ int erofs_enable_sb_chksum(struct erofs_sb_info *sbi, u32 *crc) unsigned int len; struct erofs_super_block *sb; - ret = erofs_blk_read(sbi, 0, buf, 0, erofs_blknr(sbi, EROFS_SUPER_END) + 1); + /* + * skip the first 1024 bytes, to allow for the installation + * of x86 boot sectors and other oddities. + */ + if (erofs_blksiz(sbi) > EROFS_SUPER_OFFSET) + len = erofs_blksiz(sbi) - EROFS_SUPER_OFFSET; + else + len = erofs_blksiz(sbi); + ret = erofs_dev_read(sbi, 0, buf, EROFS_SUPER_OFFSET, len); if (ret) { erofs_err("failed to read superblock to set checksum: %s", erofs_strerror(ret)); return ret; } - /* - * skip the first 1024 bytes, to allow for the installation - * of x86 boot sectors and other oddities. - */ - sb = (struct erofs_super_block *)(buf + EROFS_SUPER_OFFSET); - + sb = (struct erofs_super_block *)buf; if (le32_to_cpu(sb->magic) != EROFS_SUPER_MAGIC_V1) { erofs_err("internal error: not an erofs valid image"); return -EFAULT; @@ -280,25 +283,47 @@ int erofs_enable_sb_chksum(struct erofs_sb_info *sbi, u32 *crc) /* turn on checksum feature */ sb->feature_compat = cpu_to_le32(le32_to_cpu(sb->feature_compat) | EROFS_FEATURE_COMPAT_SB_CHKSUM); - if (erofs_blksiz(sbi) > EROFS_SUPER_OFFSET) - len = erofs_blksiz(sbi) - EROFS_SUPER_OFFSET; - else - len = erofs_blksiz(sbi); *crc = erofs_crc32c(~0, (u8 *)sb, len); /* set up checksum field to erofs_super_block */ sb->checksum = cpu_to_le32(*crc); - ret = erofs_blk_write(sbi, buf, 0, 1); + ret = erofs_dev_write(sbi, buf, EROFS_SUPER_OFFSET, len); if (ret) { erofs_err("failed to write checksummed superblock: %s", erofs_strerror(ret)); return ret; } - return 0; } +int erofs_superblock_csum_verify(struct erofs_sb_info *sbi) +{ + u32 len = erofs_blksiz(sbi), crc; + u8 buf[EROFS_MAX_BLOCK_SIZE]; + struct erofs_super_block *sb; + int ret; + + if (len > EROFS_SUPER_OFFSET) + len -= EROFS_SUPER_OFFSET; + ret = erofs_dev_read(sbi, 0, buf, EROFS_SUPER_OFFSET, len); + if (ret) { + erofs_err("failed to read superblock to calculate sbcsum: %d", + ret); + return -1; + } + + sb = (struct erofs_super_block *)buf; + sb->checksum = 0; + + crc = erofs_crc32c(~0, (u8 *)sb, len); + if (crc == sbi->checksum) + return 0; + erofs_err("invalid checksum 0x%08x, 0x%08x expected", + sbi->checksum, crc); + return -EBADMSG; +} + int erofs_mkfs_init_devices(struct erofs_sb_info *sbi, unsigned int devices) { struct erofs_buffer_head *bh; diff --git a/man/fsck.erofs.1 b/man/fsck.erofs.1 index af0e6ab..fb255b4 100644 --- a/man/fsck.erofs.1 +++ b/man/fsck.erofs.1 @@ -34,6 +34,9 @@ take a long time depending on the image size. Optionally extract contents of the \fIIMAGE\fR to \fIdirectory\fR. .TP +.B "--no-sbcrc" +Bypass the on-disk superblock checksum verification. +.TP .BI "--[no-]xattrs" Whether to dump extended attributes during extraction (default off). .TP -- 2.43.5