From 0dc57dbece497e28b8ab0560ba2eca862ff7c578 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Wed, 12 Mar 2008 22:49:41 +0000 Subject: [PATCH] The log replay code now checks if a super block is valid before the current one gets overwritten; if the log contains invalid data, it will no longer render the whole disk unreadable. This should have helped to prevent bug #1911 (but of course the problem that there is invalid data in the log in the first place remains). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@24381 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../kernel/file_systems/bfs/Journal.cpp | 14 ++++++- .../kernel/file_systems/bfs/Volume.cpp | 41 +++++++++++++------ src/add-ons/kernel/file_systems/bfs/Volume.h | 2 + 3 files changed, 43 insertions(+), 14 deletions(-) diff --git a/src/add-ons/kernel/file_systems/bfs/Journal.cpp b/src/add-ons/kernel/file_systems/bfs/Journal.cpp index ed04b24a4f..b7aaa727d9 100644 --- a/src/add-ons/kernel/file_systems/bfs/Journal.cpp +++ b/src/add-ons/kernel/file_systems/bfs/Journal.cpp @@ -419,12 +419,22 @@ Journal::_ReplayRunArray(int32 *_start) if (data == NULL) RETURN_ERROR(B_IO_ERROR); - ssize_t written = write_pos(fVolume->Device(), - offset + (i * blockSize), data, blockSize); + // TODO: eventually check other well known offsets, like the + // root and index dirs + if (offset == 0) { + // This log entry writes over the super block - check if + // it's valid! + if (Volume::CheckSuperBlock(data) != B_OK) + RETURN_ERROR(B_BAD_DATA); + } + + ssize_t written = write_pos(fVolume->Device(), offset, data, + blockSize); if (written != blockSize) RETURN_ERROR(B_IO_ERROR); blockNumber = (blockNumber + 1) % fLogSize; + offset += blockSize; count++; } } diff --git a/src/add-ons/kernel/file_systems/bfs/Volume.cpp b/src/add-ons/kernel/file_systems/bfs/Volume.cpp index 11ccb0b46c..6e6a57d9d0 100644 --- a/src/add-ons/kernel/file_systems/bfs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/bfs/Volume.cpp @@ -558,25 +558,42 @@ Volume::RemoveQuery(Query *query) // #pragma mark - Disk scanning and initialization -status_t +/*static*/ status_t +Volume::CheckSuperBlock(const uint8* data, uint32* _offset) +{ + disk_super_block* superBlock = (disk_super_block*)(data + 512); + if (superBlock->IsValid()) { + if (_offset != NULL) + *_offset = 512; + return B_OK; + } + +#ifndef BFS_LITTLE_ENDIAN_ONLY + // For PPC, the super block might be located at offset 0 + superBlock = (disk_super_block*)data; + if (superBlock->IsValid()) { + if (_offset != NULL) + *_offset = 0; + return B_OK; + } +#endif + + return B_BAD_VALUE; +} + + +/*static*/ status_t Volume::Identify(int fd, disk_super_block *superBlock) { - char buffer[1024]; + uint8 buffer[1024]; if (read_pos(fd, 0, buffer, sizeof(buffer)) != sizeof(buffer)) return B_IO_ERROR; - memcpy(superBlock, buffer + 512, sizeof(disk_super_block)); - if (!superBlock->IsValid()) { -#ifndef BFS_LITTLE_ENDIAN_ONLY - // For PPC, the super block might be located at offset 0 - memcpy(superBlock, buffer, sizeof(disk_super_block)); - if (!superBlock->IsValid()) - return B_BAD_VALUE; -#else + uint32 offset; + if (CheckSuperBlock(buffer, &offset) != B_OK) return B_BAD_VALUE; -#endif - } + memcpy(superBlock, buffer + offset, sizeof(disk_super_block)); return B_OK; } diff --git a/src/add-ons/kernel/file_systems/bfs/Volume.h b/src/add-ons/kernel/file_systems/bfs/Volume.h index 50a20566f9..79763b522b 100644 --- a/src/add-ons/kernel/file_systems/bfs/Volume.h +++ b/src/add-ons/kernel/file_systems/bfs/Volume.h @@ -102,6 +102,8 @@ class Volume { uint32 GetUniqueID(); + static status_t CheckSuperBlock(const uint8* data, + uint32* _offset = NULL); static status_t Identify(int fd, disk_super_block *superBlock); protected: