From 243b80d29235b07f8a26fb51e2af3a949c8fc1fd Mon Sep 17 00:00:00 2001 From: Adam Weiss Date: Wed, 12 Aug 2015 19:32:20 -0400 Subject: Handle leveldb::DestroyDB() errors on wipe failure Add error checking to CLevelDBWrapper for errors from leveldb::DestroyDB(). Without it, if unlink() or DeleteFileW() fail to delete files, they will fail silent. If they fail to delete any files, CLevelDBWrapper will silently open and read the existing database. Typically any permissions issues would be caught by leveldb as it churns through many files as part of its compaction process, but it is conceivable that this could cause problems on Windows with anti-virus and indexing software. --- src/leveldbwrapper.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/leveldbwrapper.cpp') diff --git a/src/leveldbwrapper.cpp b/src/leveldbwrapper.cpp index c353dfa6d..26cacf95a 100644 --- a/src/leveldbwrapper.cpp +++ b/src/leveldbwrapper.cpp @@ -58,7 +58,8 @@ CLevelDBWrapper::CLevelDBWrapper(const boost::filesystem::path& path, size_t nCa } else { if (fWipe) { LogPrintf("Wiping LevelDB in %s\n", path.string()); - leveldb::DestroyDB(path.string(), options); + leveldb::Status result = leveldb::DestroyDB(path.string(), options); + HandleError(result); } TryCreateDirectory(path); LogPrintf("Opening LevelDB in %s\n", path.string()); -- cgit v1.2.3 From 42cb388167ef78f47a3a440eb651b6938c10f508 Mon Sep 17 00:00:00 2001 From: James O'Beirne Date: Mon, 7 Sep 2015 15:22:23 -0700 Subject: Add chainstate obfuscation to avoid spurious antivirus detection Adds an `obfuscate` parameter to `CLevelDBWrapper` and makes use of it for all new chainstate stores built via `CCoinsViewDB`. Also adds an `Xor` method to `CDataStream`. Thanks to @sipa @laanwj @pstratem @dexX7 @KyrosKrane @gmaxwell. --- src/leveldbwrapper.cpp | 60 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) (limited to 'src/leveldbwrapper.cpp') diff --git a/src/leveldbwrapper.cpp b/src/leveldbwrapper.cpp index 26cacf95a..ce96b5c8a 100644 --- a/src/leveldbwrapper.cpp +++ b/src/leveldbwrapper.cpp @@ -5,6 +5,7 @@ #include "leveldbwrapper.h" #include "util.h" +#include "random.h" #include @@ -12,6 +13,7 @@ #include #include #include +#include void HandleError(const leveldb::Status& status) throw(leveldb_error) { @@ -43,7 +45,7 @@ static leveldb::Options GetOptions(size_t nCacheSize) return options; } -CLevelDBWrapper::CLevelDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory, bool fWipe) +CLevelDBWrapper::CLevelDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate) { penv = NULL; readoptions.verify_checksums = true; @@ -67,6 +69,25 @@ CLevelDBWrapper::CLevelDBWrapper(const boost::filesystem::path& path, size_t nCa leveldb::Status status = leveldb::DB::Open(options, path.string(), &pdb); HandleError(status); LogPrintf("Opened LevelDB successfully\n"); + + // The base-case obfuscation key, which is a noop. + obfuscate_key = std::vector(OBFUSCATE_KEY_NUM_BYTES, '\000'); + + bool key_exists = Read(OBFUSCATE_KEY_KEY, obfuscate_key); + + if (!key_exists && obfuscate && IsEmpty()) { + // Initialize non-degenerate obfuscation if it won't upset + // existing, non-obfuscated data. + std::vector new_key = CreateObfuscateKey(); + + // Write `new_key` so we don't obfuscate the key with itself + Write(OBFUSCATE_KEY_KEY, new_key); + obfuscate_key = new_key; + + LogPrintf("Wrote new obfuscate key for %s: %s\n", path.string(), GetObfuscateKeyHex()); + } + + LogPrintf("Using obfuscation key for %s: %s\n", path.string(), GetObfuscateKeyHex()); } CLevelDBWrapper::~CLevelDBWrapper() @@ -87,3 +108,40 @@ bool CLevelDBWrapper::WriteBatch(CLevelDBBatch& batch, bool fSync) throw(leveldb HandleError(status); return true; } + +// Prefixed with null character to avoid collisions with other keys +// +// We must use a string constructor which specifies length so that we copy +// past the null-terminator. +const std::string CLevelDBWrapper::OBFUSCATE_KEY_KEY("\000obfuscate_key", 14); + +const unsigned int CLevelDBWrapper::OBFUSCATE_KEY_NUM_BYTES = 8; + +/** + * Returns a string (consisting of 8 random bytes) suitable for use as an + * obfuscating XOR key. + */ +std::vector CLevelDBWrapper::CreateObfuscateKey() const +{ + unsigned char buff[OBFUSCATE_KEY_NUM_BYTES]; + GetRandBytes(buff, OBFUSCATE_KEY_NUM_BYTES); + return std::vector(&buff[0], &buff[OBFUSCATE_KEY_NUM_BYTES]); + +} + +bool CLevelDBWrapper::IsEmpty() +{ + boost::scoped_ptr it(NewIterator()); + it->SeekToFirst(); + return !(it->Valid()); +} + +const std::vector& CLevelDBWrapper::GetObfuscateKey() const +{ + return obfuscate_key; +} + +std::string CLevelDBWrapper::GetObfuscateKeyHex() const +{ + return HexStr(obfuscate_key); +} -- cgit v1.2.3 From 3499ce1e1ad87a86598d00b7124072c91ddad833 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 7 Oct 2015 17:12:24 -0700 Subject: Encapsulate CLevelDB iterators cleanly Conflicts: src/leveldb.cpp src/leveldb.h src/txdb.cpp --- src/leveldbwrapper.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src/leveldbwrapper.cpp') diff --git a/src/leveldbwrapper.cpp b/src/leveldbwrapper.cpp index ce96b5c8a..a94cfd8a3 100644 --- a/src/leveldbwrapper.cpp +++ b/src/leveldbwrapper.cpp @@ -131,7 +131,7 @@ std::vector CLevelDBWrapper::CreateObfuscateKey() const bool CLevelDBWrapper::IsEmpty() { - boost::scoped_ptr it(NewIterator()); + boost::scoped_ptr it(NewIterator()); it->SeekToFirst(); return !(it->Valid()); } @@ -145,3 +145,10 @@ std::string CLevelDBWrapper::GetObfuscateKeyHex() const { return HexStr(obfuscate_key); } + +CLevelDBIterator::~CLevelDBIterator() { delete piter; } +bool CLevelDBIterator::Valid() { return piter->Valid(); } +void CLevelDBIterator::SeekToFirst() { piter->SeekToFirst(); } +void CLevelDBIterator::SeekToLast() { piter->SeekToLast(); } +void CLevelDBIterator::Next() { piter->Next(); } +void CLevelDBIterator::Prev() { piter->Prev(); } -- cgit v1.2.3 From 0fdf8c80ee322ab747321d61faf9c72af4a51445 Mon Sep 17 00:00:00 2001 From: James O'Beirne Date: Thu, 8 Oct 2015 00:44:10 -0700 Subject: Handle obfuscation in CLevelDBIterator --- src/leveldbwrapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/leveldbwrapper.cpp') diff --git a/src/leveldbwrapper.cpp b/src/leveldbwrapper.cpp index a94cfd8a3..32c9345be 100644 --- a/src/leveldbwrapper.cpp +++ b/src/leveldbwrapper.cpp @@ -145,7 +145,7 @@ std::string CLevelDBWrapper::GetObfuscateKeyHex() const { return HexStr(obfuscate_key); } - + CLevelDBIterator::~CLevelDBIterator() { delete piter; } bool CLevelDBIterator::Valid() { return piter->Valid(); } void CLevelDBIterator::SeekToFirst() { piter->SeekToFirst(); } -- cgit v1.2.3 From 6ec4b7eb20abf05dd6e3c0885644616a2c2acfd7 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 22 Oct 2015 20:49:02 -0400 Subject: leveldbwrapper: Remove unused .Prev(), .SeekToLast() methods Also, trim trailing whitespace. --- src/leveldbwrapper.cpp | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'src/leveldbwrapper.cpp') diff --git a/src/leveldbwrapper.cpp b/src/leveldbwrapper.cpp index 32c9345be..641d25152 100644 --- a/src/leveldbwrapper.cpp +++ b/src/leveldbwrapper.cpp @@ -76,7 +76,7 @@ CLevelDBWrapper::CLevelDBWrapper(const boost::filesystem::path& path, size_t nCa bool key_exists = Read(OBFUSCATE_KEY_KEY, obfuscate_key); if (!key_exists && obfuscate && IsEmpty()) { - // Initialize non-degenerate obfuscation if it won't upset + // Initialize non-degenerate obfuscation if it won't upset // existing, non-obfuscated data. std::vector new_key = CreateObfuscateKey(); @@ -118,10 +118,10 @@ const std::string CLevelDBWrapper::OBFUSCATE_KEY_KEY("\000obfuscate_key", 14); const unsigned int CLevelDBWrapper::OBFUSCATE_KEY_NUM_BYTES = 8; /** - * Returns a string (consisting of 8 random bytes) suitable for use as an - * obfuscating XOR key. + * Returns a string (consisting of 8 random bytes) suitable for use as an + * obfuscating XOR key. */ -std::vector CLevelDBWrapper::CreateObfuscateKey() const +std::vector CLevelDBWrapper::CreateObfuscateKey() const { unsigned char buff[OBFUSCATE_KEY_NUM_BYTES]; GetRandBytes(buff, OBFUSCATE_KEY_NUM_BYTES); @@ -136,19 +136,17 @@ bool CLevelDBWrapper::IsEmpty() return !(it->Valid()); } -const std::vector& CLevelDBWrapper::GetObfuscateKey() const -{ - return obfuscate_key; +const std::vector& CLevelDBWrapper::GetObfuscateKey() const +{ + return obfuscate_key; } std::string CLevelDBWrapper::GetObfuscateKeyHex() const -{ - return HexStr(obfuscate_key); +{ + return HexStr(obfuscate_key); } CLevelDBIterator::~CLevelDBIterator() { delete piter; } bool CLevelDBIterator::Valid() { return piter->Valid(); } void CLevelDBIterator::SeekToFirst() { piter->SeekToFirst(); } -void CLevelDBIterator::SeekToLast() { piter->SeekToLast(); } void CLevelDBIterator::Next() { piter->Next(); } -void CLevelDBIterator::Prev() { piter->Prev(); } -- cgit v1.2.3 From 8587b23038b88340ec64253ea4282afe90187a69 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 22 Oct 2015 21:02:20 -0400 Subject: leveldbwrapper symbol rename: Remove "Level" from class, etc. names --- src/leveldbwrapper.cpp | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'src/leveldbwrapper.cpp') diff --git a/src/leveldbwrapper.cpp b/src/leveldbwrapper.cpp index 641d25152..6ecf7c7f0 100644 --- a/src/leveldbwrapper.cpp +++ b/src/leveldbwrapper.cpp @@ -15,18 +15,18 @@ #include #include -void HandleError(const leveldb::Status& status) throw(leveldb_error) +void HandleError(const leveldb::Status& status) throw(dbwrapper_error) { if (status.ok()) return; LogPrintf("%s\n", status.ToString()); if (status.IsCorruption()) - throw leveldb_error("Database corrupted"); + throw dbwrapper_error("Database corrupted"); if (status.IsIOError()) - throw leveldb_error("Database I/O error"); + throw dbwrapper_error("Database I/O error"); if (status.IsNotFound()) - throw leveldb_error("Database entry missing"); - throw leveldb_error("Unknown database error"); + throw dbwrapper_error("Database entry missing"); + throw dbwrapper_error("Unknown database error"); } static leveldb::Options GetOptions(size_t nCacheSize) @@ -45,7 +45,7 @@ static leveldb::Options GetOptions(size_t nCacheSize) return options; } -CLevelDBWrapper::CLevelDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate) +CDBWrapper::CDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate) { penv = NULL; readoptions.verify_checksums = true; @@ -90,7 +90,7 @@ CLevelDBWrapper::CLevelDBWrapper(const boost::filesystem::path& path, size_t nCa LogPrintf("Using obfuscation key for %s: %s\n", path.string(), GetObfuscateKeyHex()); } -CLevelDBWrapper::~CLevelDBWrapper() +CDBWrapper::~CDBWrapper() { delete pdb; pdb = NULL; @@ -102,7 +102,7 @@ CLevelDBWrapper::~CLevelDBWrapper() options.env = NULL; } -bool CLevelDBWrapper::WriteBatch(CLevelDBBatch& batch, bool fSync) throw(leveldb_error) +bool CDBWrapper::WriteBatch(CDBBatch& batch, bool fSync) throw(dbwrapper_error) { leveldb::Status status = pdb->Write(fSync ? syncoptions : writeoptions, &batch.batch); HandleError(status); @@ -113,15 +113,15 @@ bool CLevelDBWrapper::WriteBatch(CLevelDBBatch& batch, bool fSync) throw(leveldb // // We must use a string constructor which specifies length so that we copy // past the null-terminator. -const std::string CLevelDBWrapper::OBFUSCATE_KEY_KEY("\000obfuscate_key", 14); +const std::string CDBWrapper::OBFUSCATE_KEY_KEY("\000obfuscate_key", 14); -const unsigned int CLevelDBWrapper::OBFUSCATE_KEY_NUM_BYTES = 8; +const unsigned int CDBWrapper::OBFUSCATE_KEY_NUM_BYTES = 8; /** * Returns a string (consisting of 8 random bytes) suitable for use as an * obfuscating XOR key. */ -std::vector CLevelDBWrapper::CreateObfuscateKey() const +std::vector CDBWrapper::CreateObfuscateKey() const { unsigned char buff[OBFUSCATE_KEY_NUM_BYTES]; GetRandBytes(buff, OBFUSCATE_KEY_NUM_BYTES); @@ -129,24 +129,24 @@ std::vector CLevelDBWrapper::CreateObfuscateKey() const } -bool CLevelDBWrapper::IsEmpty() +bool CDBWrapper::IsEmpty() { - boost::scoped_ptr it(NewIterator()); + boost::scoped_ptr it(NewIterator()); it->SeekToFirst(); return !(it->Valid()); } -const std::vector& CLevelDBWrapper::GetObfuscateKey() const +const std::vector& CDBWrapper::GetObfuscateKey() const { return obfuscate_key; } -std::string CLevelDBWrapper::GetObfuscateKeyHex() const +std::string CDBWrapper::GetObfuscateKeyHex() const { return HexStr(obfuscate_key); } -CLevelDBIterator::~CLevelDBIterator() { delete piter; } -bool CLevelDBIterator::Valid() { return piter->Valid(); } -void CLevelDBIterator::SeekToFirst() { piter->SeekToFirst(); } -void CLevelDBIterator::Next() { piter->Next(); } +CDBIterator::~CDBIterator() { delete piter; } +bool CDBIterator::Valid() { return piter->Valid(); } +void CDBIterator::SeekToFirst() { piter->SeekToFirst(); } +void CDBIterator::Next() { piter->Next(); } -- cgit v1.2.3 From 3795e8152b678b9f805a395b144190a9f2fa2af4 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 22 Oct 2015 21:33:06 -0400 Subject: leveldbwrapper file rename to dbwrapper.* --- src/leveldbwrapper.cpp | 152 ------------------------------------------------- 1 file changed, 152 deletions(-) delete mode 100644 src/leveldbwrapper.cpp (limited to 'src/leveldbwrapper.cpp') diff --git a/src/leveldbwrapper.cpp b/src/leveldbwrapper.cpp deleted file mode 100644 index 6ecf7c7f0..000000000 --- a/src/leveldbwrapper.cpp +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright (c) 2012-2014 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "leveldbwrapper.h" - -#include "util.h" -#include "random.h" - -#include - -#include -#include -#include -#include -#include - -void HandleError(const leveldb::Status& status) throw(dbwrapper_error) -{ - if (status.ok()) - return; - LogPrintf("%s\n", status.ToString()); - if (status.IsCorruption()) - throw dbwrapper_error("Database corrupted"); - if (status.IsIOError()) - throw dbwrapper_error("Database I/O error"); - if (status.IsNotFound()) - throw dbwrapper_error("Database entry missing"); - throw dbwrapper_error("Unknown database error"); -} - -static leveldb::Options GetOptions(size_t nCacheSize) -{ - leveldb::Options options; - options.block_cache = leveldb::NewLRUCache(nCacheSize / 2); - options.write_buffer_size = nCacheSize / 4; // up to two write buffers may be held in memory simultaneously - options.filter_policy = leveldb::NewBloomFilterPolicy(10); - options.compression = leveldb::kNoCompression; - options.max_open_files = 64; - if (leveldb::kMajorVersion > 1 || (leveldb::kMajorVersion == 1 && leveldb::kMinorVersion >= 16)) { - // LevelDB versions before 1.16 consider short writes to be corruption. Only trigger error - // on corruption in later versions. - options.paranoid_checks = true; - } - return options; -} - -CDBWrapper::CDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate) -{ - penv = NULL; - readoptions.verify_checksums = true; - iteroptions.verify_checksums = true; - iteroptions.fill_cache = false; - syncoptions.sync = true; - options = GetOptions(nCacheSize); - options.create_if_missing = true; - if (fMemory) { - penv = leveldb::NewMemEnv(leveldb::Env::Default()); - options.env = penv; - } else { - if (fWipe) { - LogPrintf("Wiping LevelDB in %s\n", path.string()); - leveldb::Status result = leveldb::DestroyDB(path.string(), options); - HandleError(result); - } - TryCreateDirectory(path); - LogPrintf("Opening LevelDB in %s\n", path.string()); - } - leveldb::Status status = leveldb::DB::Open(options, path.string(), &pdb); - HandleError(status); - LogPrintf("Opened LevelDB successfully\n"); - - // The base-case obfuscation key, which is a noop. - obfuscate_key = std::vector(OBFUSCATE_KEY_NUM_BYTES, '\000'); - - bool key_exists = Read(OBFUSCATE_KEY_KEY, obfuscate_key); - - if (!key_exists && obfuscate && IsEmpty()) { - // Initialize non-degenerate obfuscation if it won't upset - // existing, non-obfuscated data. - std::vector new_key = CreateObfuscateKey(); - - // Write `new_key` so we don't obfuscate the key with itself - Write(OBFUSCATE_KEY_KEY, new_key); - obfuscate_key = new_key; - - LogPrintf("Wrote new obfuscate key for %s: %s\n", path.string(), GetObfuscateKeyHex()); - } - - LogPrintf("Using obfuscation key for %s: %s\n", path.string(), GetObfuscateKeyHex()); -} - -CDBWrapper::~CDBWrapper() -{ - delete pdb; - pdb = NULL; - delete options.filter_policy; - options.filter_policy = NULL; - delete options.block_cache; - options.block_cache = NULL; - delete penv; - options.env = NULL; -} - -bool CDBWrapper::WriteBatch(CDBBatch& batch, bool fSync) throw(dbwrapper_error) -{ - leveldb::Status status = pdb->Write(fSync ? syncoptions : writeoptions, &batch.batch); - HandleError(status); - return true; -} - -// Prefixed with null character to avoid collisions with other keys -// -// We must use a string constructor which specifies length so that we copy -// past the null-terminator. -const std::string CDBWrapper::OBFUSCATE_KEY_KEY("\000obfuscate_key", 14); - -const unsigned int CDBWrapper::OBFUSCATE_KEY_NUM_BYTES = 8; - -/** - * Returns a string (consisting of 8 random bytes) suitable for use as an - * obfuscating XOR key. - */ -std::vector CDBWrapper::CreateObfuscateKey() const -{ - unsigned char buff[OBFUSCATE_KEY_NUM_BYTES]; - GetRandBytes(buff, OBFUSCATE_KEY_NUM_BYTES); - return std::vector(&buff[0], &buff[OBFUSCATE_KEY_NUM_BYTES]); - -} - -bool CDBWrapper::IsEmpty() -{ - boost::scoped_ptr it(NewIterator()); - it->SeekToFirst(); - return !(it->Valid()); -} - -const std::vector& CDBWrapper::GetObfuscateKey() const -{ - return obfuscate_key; -} - -std::string CDBWrapper::GetObfuscateKeyHex() const -{ - return HexStr(obfuscate_key); -} - -CDBIterator::~CDBIterator() { delete piter; } -bool CDBIterator::Valid() { return piter->Valid(); } -void CDBIterator::SeekToFirst() { piter->SeekToFirst(); } -void CDBIterator::Next() { piter->Next(); } -- cgit v1.2.3