From 842a1538a6b726ba535497d7bea7756dc191f90c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Sat, 26 Jun 2021 16:53:30 +0200 Subject: [PATCH] ext2: fix metadata_csum for inodes the checksum assumes the full inode block. Change-Id: I60ef5d0b769750107b7e104709edff95beee8085 Reviewed-on: https://review.haiku-os.org/c/haiku/+/4118 Tested-by: Commit checker robot Reviewed-by: Adrien Destugues --- .../kernel/file_systems/ext2/Inode.cpp | 61 +++++++++++-------- src/add-ons/kernel/file_systems/ext2/Inode.h | 2 +- src/add-ons/kernel/file_systems/ext2/ext2.h | 1 + 3 files changed, 36 insertions(+), 28 deletions(-) diff --git a/src/add-ons/kernel/file_systems/ext2/Inode.cpp b/src/add-ons/kernel/file_systems/ext2/Inode.cpp index 0c66aa7db7..fe00fd12aa 100644 --- a/src/add-ons/kernel/file_systems/ext2/Inode.cpp +++ b/src/add-ons/kernel/file_systems/ext2/Inode.cpp @@ -32,6 +32,10 @@ #define ERROR(x...) dprintf("\33[34mext2:\33[0m " x) +#define EXT2_EA_CHECKSUM_SIZE (offsetof(ext2_inode, checksum_high) \ + + sizeof(uint16) - EXT2_INODE_NORMAL_SIZE) + + Inode::Inode(Volume* volume, ino_t id) : fVolume(volume), @@ -135,23 +139,23 @@ Inode::WriteBack(Transaction& transaction) if (inodeBlockData == NULL) return B_IO_ERROR; - if (fVolume->HasMetaGroupChecksumFeature()) { - uint32 checksum = _InodeChecksum(); - fNode.checksum = checksum & 0xffff; - if (fNodeSize > EXT2_INODE_NORMAL_SIZE - && fNodeSize >= offsetof(ext2_inode, change_time_extra)) { - fNode.checksum_high = checksum >> 16; - } - } TRACE("Inode::WriteBack(): Inode ID: %" B_PRIdINO ", inode block: %" B_PRIdOFF ", data: %p, index: %" B_PRIu32 ", inode size: %" B_PRIu32 ", node size: %" B_PRIu32 ", this: %p, node: %p\n", fID, blockNum, inodeBlockData, fVolume->InodeBlockIndex(fID), fVolume->InodeSize(), fNodeSize, this, &fNode); - memcpy(inodeBlockData + - fVolume->InodeBlockIndex(fID) * fVolume->InodeSize(), - (uint8*)&fNode, fNodeSize); + ext2_inode* inode = (ext2_inode*)(inodeBlockData + + fVolume->InodeBlockIndex(fID) * fVolume->InodeSize()); + memcpy(inode, (uint8*)&fNode, fNodeSize); + if (fVolume->HasMetaGroupChecksumFeature()) { + uint32 checksum = _InodeChecksum(inode); + inode->checksum = checksum & 0xffff; + if (fNodeSize > EXT2_INODE_NORMAL_SIZE + && fNode.ExtraInodeSize() >= EXT2_EA_CHECKSUM_SIZE) { + inode->checksum_high = checksum >> 16; + } + } TRACE("Inode::WriteBack() finished %" B_PRId32 "\n", Node().stream.direct[0]); return B_OK; @@ -186,11 +190,11 @@ Inode::UpdateNodeFromDisk() memcpy(&fNode, inode, fNodeSize); if (fVolume->HasMetaGroupChecksumFeature()) { - uint32 checksum = _InodeChecksum(); + uint32 checksum = _InodeChecksum(inode); uint32 provided = fNode.checksum; if (fNodeSize > EXT2_INODE_NORMAL_SIZE - && fNodeSize >= offsetof(ext2_inode, change_time_extra)) { - provided |= (fNode.checksum_high << 16); + && fNode.ExtraInodeSize() >= EXT2_EA_CHECKSUM_SIZE) { + provided |= ((uint32)fNode.checksum_high << 16); } else checksum &= 0xffff; if (provided != checksum) { @@ -943,28 +947,31 @@ Inode::IncrementNumLinks(Transaction& transaction) uint32 -Inode::_InodeChecksum() +Inode::_InodeChecksum(ext2_inode* inode) { size_t offset = offsetof(ext2_inode, checksum); - size_t offset2 = offsetof(ext2_inode, reserved); uint32 number = fID; - uint32 checksum = calculate_crc32c(fVolume->ChecksumSeed(), (uint8*)&number, - sizeof(number)); + uint32 checksum = calculate_crc32c(fVolume->ChecksumSeed(), + (uint8*)&number, sizeof(number)); uint32 gen = fNode.generation; checksum = calculate_crc32c(checksum, (uint8*)&gen, sizeof(gen)); - checksum = calculate_crc32c(checksum, (uint8*)&fNode, offset); + checksum = calculate_crc32c(checksum, (uint8*)inode, offset); uint16 dummy = 0; checksum = calculate_crc32c(checksum, (uint8*)&dummy, sizeof(dummy)); - checksum = calculate_crc32c(checksum, (uint8*)&fNode + offset2, - EXT2_INODE_NORMAL_SIZE - offset2); + offset += sizeof(dummy); + checksum = calculate_crc32c(checksum, (uint8*)inode + offset, + EXT2_INODE_NORMAL_SIZE - offset); if (fNodeSize > EXT2_INODE_NORMAL_SIZE) { offset = offsetof(ext2_inode, checksum_high); - offset2 = offsetof(ext2_inode, change_time_extra); - checksum = calculate_crc32c(checksum, (uint8*)&fNode + EXT2_INODE_NORMAL_SIZE, - offset - EXT2_INODE_NORMAL_SIZE); - checksum = calculate_crc32c(checksum, (uint8*)&dummy, sizeof(dummy)); - checksum = calculate_crc32c(checksum, (uint8*)&fNode + offset2, - fNodeSize - offset2); + checksum = calculate_crc32c(checksum, (uint8*)inode + + EXT2_INODE_NORMAL_SIZE, offset - EXT2_INODE_NORMAL_SIZE); + if (fNode.ExtraInodeSize() >= EXT2_EA_CHECKSUM_SIZE) { + checksum = calculate_crc32c(checksum, (uint8*)&dummy, + sizeof(dummy)); + offset += sizeof(dummy); + } + checksum = calculate_crc32c(checksum, (uint8*)inode + offset, + fVolume->InodeSize() - offset); } return checksum; } diff --git a/src/add-ons/kernel/file_systems/ext2/Inode.h b/src/add-ons/kernel/file_systems/ext2/Inode.h index 3d770e9948..c8dcbf257e 100644 --- a/src/add-ons/kernel/file_systems/ext2/Inode.h +++ b/src/add-ons/kernel/file_systems/ext2/Inode.h @@ -145,7 +145,7 @@ private: uint64 _NumBlocks(); status_t _SetNumBlocks(uint64 numBlocks); - uint32 _InodeChecksum(); + uint32 _InodeChecksum(ext2_inode* inode); ext2_dir_entry_tail* _DirEntryTail(uint8* block) const; uint32 _DirEntryChecksum(uint8* block, uint32 id, diff --git a/src/add-ons/kernel/file_systems/ext2/ext2.h b/src/add-ons/kernel/file_systems/ext2/ext2.h index 41b03c5fea..a13bb3bca5 100644 --- a/src/add-ons/kernel/file_systems/ext2/ext2.h +++ b/src/add-ons/kernel/file_systems/ext2/ext2.h @@ -483,6 +483,7 @@ struct ext2_inode { uint32 creation_time; uint32 creation_time_extra; uint32 version_high; + uint32 project_id; uint16 Mode() const { return B_LENDIAN_TO_HOST_INT16(mode); } uint32 Flags() const { return B_LENDIAN_TO_HOST_INT32(flags); }