From: Krzysztof Jackiewicz Date: Wed, 15 May 2019 09:44:55 +0000 (+0200) Subject: Use libext2fs to read ext4 params and block bitmap X-Git-Tag: submit/tizen/20190607.051013~2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=d067c1b215bcdd4eac0a66d6f14139b047c4fe7b;p=platform%2Fcore%2Fsecurity%2Fode.git Use libext2fs to read ext4 params and block bitmap Until now the ext4 params and the block bitmap was calculated manually. In some cases it could lead to buffer oveflow. This commit replaces manual calculations with libext2fs calls. Change-Id: I54d36a88f1950dd95d0b2a53c3dab605e308250d --- diff --git a/fota/CMakeLists.txt b/fota/CMakeLists.txt index e7d41a0..340f9b3 100755 --- a/fota/CMakeLists.txt +++ b/fota/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved +# Copyright (c) 2017 - 2019 Samsung Electronics Co., Ltd All Rights Reserved # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ SET(PROJECT_NAME "ode-fota") -PKG_CHECK_MODULES(FOTA_DEPS REQUIRED klay-static blkid) +PKG_CHECK_MODULES(FOTA_DEPS REQUIRED klay-static blkid ext2fs com_err) SET(SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/fota.cpp ${ODE_SERVER}/upgrade-support.cpp diff --git a/packaging/ode.spec b/packaging/ode.spec index dde5b9c..fee1d2f 100755 --- a/packaging/ode.spec +++ b/packaging/ode.spec @@ -20,6 +20,8 @@ BuildRequires: pkgconfig(libsmack) BuildRequires: pkgconfig(blkid) BuildRequires: pkgconfig(capi-system-device) BuildRequires: pkgconfig(libsystemd) +BuildRequires: pkgconfig(ext2fs) +BuildRequires: pkgconfig(com_err) Requires: cryptsetup %global key_storage_plugin_dir %{_libdir}/ode-key-storage-plugin/ diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index 395027f..9d35440 100644 --- a/server/CMakeLists.txt +++ b/server/CMakeLists.txt @@ -50,6 +50,8 @@ SET(DEPENDENCY klay libsmack capi-system-device libsystemd + ext2fs + com_err ) SET(SERVER_NAME ${PROJECT_NAME}d) diff --git a/server/engine/encryption/dmcrypt-engine.cpp b/server/engine/encryption/dmcrypt-engine.cpp index c65e9db..358dbe7 100644 --- a/server/engine/encryption/dmcrypt-engine.cpp +++ b/server/engine/encryption/dmcrypt-engine.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2016 - 2019 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -329,12 +329,10 @@ bool DMCryptEngine::isMounted() void DMCryptEngine::encrypt(const BinaryData &key, unsigned int options) { - // Force filesystem check via fcsf might be able to avoid fail situation during encryption. - Ext4Tool ext4Source(source); - for (int retry = 0; retry < 32; retry++) { try { - ext4Source.forceCleanUp(); + // Force filesystem check via fcsf might be able to avoid fail situation during encryption. + Ext4Tool::forceCleanUp(source); } catch (runtime::Exception &e) { continue; } @@ -362,14 +360,12 @@ void DMCryptEngine::decrypt(const BinaryData &key, unsigned int options) // should be encrypted here. auto cryptoBlkDev = createCryptoBlkDev(source, DM_DEFAULT_LABEL_NAME, sanitizeKey(key), DM_DEFAULT_CRYPTO_NAME); - // Force filesystem check via fcsf might be able to avoid fail situation during decryption. - Ext4Tool ext4CryptoBlkDev(cryptoBlkDev); - start = true; for (int retry = 0; retry < 32; retry++) { try { - ext4CryptoBlkDev.forceCleanUp(); + // Force filesystem check via fcsf might be able to avoid fail situation during decryption. + Ext4Tool::forceCleanUp(cryptoBlkDev); } catch (runtime::Exception &e) { continue; } diff --git a/server/ext4-tool.cpp b/server/ext4-tool.cpp index 4dd1780..77d1d3c 100644 --- a/server/ext4-tool.cpp +++ b/server/ext4-tool.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2015 - 2019 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,13 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License */ -#include #include #include -#include -#include +extern "C" { +#include +} + #include #include @@ -28,27 +29,8 @@ namespace ode { -#define ODE_SUPERBLOCK_OFFSET 1024 -#define ODE_SUPERBLOCK_SIZE 1024 -#define ODE_EXT2_MIN_DESC_SIZE 32 -#define ODE_EXT2_MIN_BLOCK_LOG_SIZE 10 /* 1024 */ -#define ODE_EXT2_MIN_BLOCK_SIZE (1 << ODE_EXT2_MIN_BLOCK_LOG_SIZE) - -#define ODE_EXT2_MAGIC 0xEF53 - namespace { -uint32_t divCeilSafely(uint32_t a, uint32_t b) -{ - if (!a) - return 0; - - if (!b) - throw runtime::Exception("Cannot divide by zero"); - - return ((a - 1) / b) + 1; -} - void execAndWait(const std::string &path, std::vector &args) { runtime::Process proc(path, args); @@ -62,180 +44,47 @@ void execAndWait(const std::string &path, std::vector &args) throw runtime::Exception(path + " failed for " + args.back()); } +struct Ext2fsException : public runtime::Exception { + Ext2fsException(const std::string& prefixMsg, errcode_t err) : + runtime::Exception(prefixMsg + error_message(err)) + {} +}; + } // namespace -Ext4Tool::Ext4Tool(const std::string &src) : - source(src), blockSize(0), totalBlockCount(0) +Ext4Tool::Ext4Tool(const std::string &src) { - if (!isExt(src)) - throw runtime::Exception(source + " is not an ext2/3/4 filesystem"); + errcode_t ret; + + ret = ext2fs_open(src.c_str(), 0, 0, 0, unix_io_manager, &fs); + if (ret != 0) + throw Ext2fsException("ext2fs_open() failed: ", ret); - readInfo(); + ret = ext2fs_read_block_bitmap(fs); + if (ret != 0) + throw Ext2fsException("ext2fs_read_block_bitmap() failed: ", ret); } Ext4Tool::~Ext4Tool() { -} - -bool Ext4Tool::isExt(const std::string &src) -{ - unsigned short magic; - runtime::File device(src); - bool ret; - - if (!device.exists()) - throw runtime::Exception(src + " doesn't exist"); - - device.open(O_RDONLY); - - device.lseek(ODE_SUPERBLOCK_OFFSET + 56, SEEK_SET); - device.read(&magic, 2); - - if (magic == ODE_EXT2_MAGIC) - ret = true; - else - ret = false; - - device.close(); - - return ret; -} - -void Ext4Tool::readInfo() -{ - // TODO this function should be rewritten - uint32_t firstDataBlock = 0; - uint32_t blocksPerGroup = 0; - uint32_t clustersPerGroup = 0; - uint16_t descSize = 0; - runtime::File device(source); - - if (!device.exists()) - throw runtime::Exception(source + " doesn't exist"); - - device.open(O_RDONLY); - - // read totalBlockCount - device.lseek(ODE_SUPERBLOCK_OFFSET + 4, SEEK_SET); - device.read(&totalBlockCount, sizeof(totalBlockCount)); - - // read firstDataBlock - device.lseek(ODE_SUPERBLOCK_OFFSET + 20, SEEK_SET); - device.read(&firstDataBlock, sizeof(firstDataBlock)); - - // read blockSize - device.lseek(ODE_SUPERBLOCK_OFFSET + 24, SEEK_SET); - device.read(&blockSize, sizeof(blockSize)); - if ((std::numeric_limits::max() >> blockSize) < ODE_EXT2_MIN_BLOCK_SIZE) - throw runtime::Exception("Block size too big"); // blockSize must be <= 21 - blockSize = (ODE_EXT2_MIN_BLOCK_SIZE << blockSize); - - // read blocksPerGroup - device.lseek(ODE_SUPERBLOCK_OFFSET + 32, SEEK_SET); - device.read(&blocksPerGroup, sizeof(blocksPerGroup)); - - // read clustersPerGroup - device.lseek(ODE_SUPERBLOCK_OFFSET + 36, SEEK_SET); - device.read(&clustersPerGroup, sizeof(clustersPerGroup)); - - // read descSize - device.lseek(ODE_SUPERBLOCK_OFFSET + 0xFE, SEEK_SET); - device.read(&descSize, sizeof(descSize)); - if (descSize < ODE_EXT2_MIN_DESC_SIZE) { - descSize = ODE_EXT2_MIN_DESC_SIZE; - } - - if (firstDataBlock >= totalBlockCount) - throw runtime::Exception("Invalid block info"); - uint32_t groupDescCount = divCeilSafely(totalBlockCount - firstDataBlock, blocksPerGroup); - - // read group_desc - uint32_t descPerBlock = blockSize / descSize; - uint32_t descBlockCount = divCeilSafely(groupDescCount, descPerBlock); - - // read first meta block - if (descBlockCount > std::numeric_limits::max() / blockSize) - throw runtime::Exception("Size too big for BinaryData"); - BinaryData group_desc(descBlockCount * blockSize); - // firstDataBlock < totalBlockCount so no overflow is possible - device.lseek((firstDataBlock + 1) * blockSize, SEEK_SET); - device.read(group_desc.data(), group_desc.size()); - - uint32_t blkItr = firstDataBlock; - - // this structure just is used for easy type-casting. - struct odeExtGroupDesc { - uint32_t blockBitmap; /* Blocks bitmap block */ - /* skip other member */ - }; - - // read bitmap - { - uint32_t start = firstDataBlock; - uint32_t real_end = totalBlockCount - 1; - - uint32_t size = (real_end - start) / 8 + 1; - size = (size + 7) & ~3; - if (std::numeric_limits::max() <= size) - throw runtime::Exception("Bitmap size too big"); - - bitmap.resize(size); - } - - if (groupDescCount >= group_desc.size() / descSize) - throw runtime::Exception("Group descriptors buffer too small"); - - if (clustersPerGroup > std::numeric_limits::max() - 7) - throw runtime::Exception("Too many clusters per group"); - - if (groupDescCount > (std::numeric_limits::max() - blkItr) / clustersPerGroup + 1) - throw runtime::Exception("Block iterator may get too big"); - - if (((blkItr + clustersPerGroup * (groupDescCount - 1)) >> 3) + ((clustersPerGroup + 7) >> 3) > bitmap.size()) - throw runtime::Exception("Bitmap size too small"); - - for (uint32_t i = 0; i < groupDescCount; i++) { - uint32_t blk = reinterpret_cast(group_desc.data() + i * descSize)->blockBitmap; - - try { - BinaryData block_bitmap(blockSize); - - if (blk > std::numeric_limits::max() / blockSize) - throw runtime::Exception("Block bitmap index too big"); - - device.lseek(blk * blockSize, SEEK_SET); - device.read(block_bitmap.data(), blockSize); - - memcpy(bitmap.data() + (blkItr >> 3), block_bitmap.data(), (clustersPerGroup + 7) >> 3); - } catch (runtime::Exception &e) { - WARN(SINK, "Block " + std::to_string(blk) + " is missing"); - memset(bitmap.data() + (blkItr >> 3), 0, (clustersPerGroup + 7) >> 3); - } - blkItr += clustersPerGroup; - } - - device.close(); + errcode_t err = ext2fs_close_free(&fs); + if (err != 0) + ERROR(SINK, "ext2fs_close_free() failed: " + std::string(error_message(err))); } uint32_t Ext4Tool::getBlockSize() { - return blockSize; + return fs->blocksize; } uint32_t Ext4Tool::getTotalBlockCount() { - return totalBlockCount; + return fs->super->s_blocks_count; } bool Ext4Tool::isUsedBlock(uint32_t blockIndex) { - unsigned char *addr = (bitmap.data() + (blockIndex >> 3)); - unsigned char mask = 1 << (blockIndex & 0x07); - - if (mask & *addr) - return true; - - return false; + return ext2fs_test_block_bitmap2(fs->block_map, blockIndex); } void Ext4Tool::mkfs(const std::string &src) @@ -251,14 +100,14 @@ void Ext4Tool::mkfs(const std::string &src) execAndWait(mkfsPath, args); } -void Ext4Tool::forceCleanUp() +void Ext4Tool::forceCleanUp(const std::string &src) { static const char *fsckPath = "/sbin/fsck.ext4"; std::vector args = { fsckPath, "-f", "-y", - source + src }; execAndWait(fsckPath, args); diff --git a/server/ext4-tool.h b/server/ext4-tool.h index 0b0d43c..81cc1fe 100644 --- a/server/ext4-tool.h +++ b/server/ext4-tool.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2016 - 2019 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,9 +21,7 @@ #include -#include - -#include "rmi/common.h" +#include namespace ode { @@ -40,16 +38,12 @@ public: uint32_t getBlockSize(); uint32_t getTotalBlockCount(); bool isUsedBlock(uint32_t blockIndex); - void forceCleanUp(); - static bool isExt(const std::string &src); + static void forceCleanUp(const std::string &src); static void mkfs(const std::string &src); private: - void readInfo(); - std::string source; - uint32_t blockSize, totalBlockCount; - BinaryData bitmap; + ext2_filsys fs; }; } // namespace ode diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f803395..7ca1125 100755 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +# Copyright (c) 2015 - 2019 Samsung Electronics Co., Ltd All Rights Reserved # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -38,6 +38,8 @@ PKG_CHECK_MODULES(TEST_DEPS REQUIRED klay gio-2.0 libcrypto vconf + ext2fs + com_err ) INCLUDE_DIRECTORIES(SYSTEM ${TEST_DEPS_INCLUDE_DIRS} ../server ../)