From 68614a9608f5d70a247cdcc4621a150141cfe72f Mon Sep 17 00:00:00 2001 From: Sagar Vemuri Date: Wed, 19 Jun 2019 16:42:59 -0700 Subject: [PATCH] Fix AlignedBuffer's usage in Encryption Env (#5396) Summary: The usage of `AlignedBuffer` in env_encryption.cc writes and reads to/from the AlignedBuffer's internal buffer directly without going through AlignedBuffer's APIs (like `Append` and `Read`), causing encapsulation to break in some cases. The writes are especially problematic as after the data is written to the buffer (directly using either memmove or memcpy), the size of the buffer is not updated ... causing the AlignedBuffer to lose track of the encapsulated buffer's current size. Fixed this by updating the buffer size after every write. Todo for later: Add an overloaded method to AlignedBuffer to support a memmove in addition to a memcopy. Encryption env does a memmove, and hence I couldn't switch to using `AlignedBuffer.Append()`. Pull Request resolved: https://github.com/facebook/rocksdb/pull/5396 Test Plan: `make check` Differential Revision: D15764756 Pulled By: sagar0 fbshipit-source-id: 2e24b52bd3b4b5056c5c1da157f91ddf89370183 --- env/env_encryption.cc | 87 ++++++++++++++++++++++++------------------- 1 file changed, 49 insertions(+), 38 deletions(-) diff --git a/env/env_encryption.cc b/env/env_encryption.cc index df1b0011a..6be2137ed 100644 --- a/env/env_encryption.cc +++ b/env/env_encryption.cc @@ -195,23 +195,26 @@ class EncryptedWritableFile : public WritableFileWrapper { EncryptedWritableFile(WritableFile* f, BlockAccessCipherStream* s, size_t prefixLength) : WritableFileWrapper(f), file_(f), stream_(s), prefixLength_(prefixLength) { } - Status Append(const Slice& data) override { + Status Append(const Slice& data) override { AlignedBuffer buf; Status status; - Slice dataToAppend(data); + Slice dataToAppend(data); if (data.size() > 0) { auto offset = file_->GetFileSize(); // size including prefix // Encrypt in cloned buffer buf.Alignment(GetRequiredBufferAlignment()); buf.AllocateNewBuffer(data.size()); + // TODO (sagar0): Modify AlignedBuffer.Append to allow doing a memmove + // so that the next two lines can be replaced with buf.Append(). memmove(buf.BufferStart(), data.data(), data.size()); - status = stream_->Encrypt(offset, buf.BufferStart(), data.size()); + buf.Size(data.size()); + status = stream_->Encrypt(offset, buf.BufferStart(), buf.CurrentSize()); if (!status.ok()) { return status; } - dataToAppend = Slice(buf.BufferStart(), data.size()); + dataToAppend = Slice(buf.BufferStart(), buf.CurrentSize()); } - status = file_->Append(dataToAppend); + status = file_->Append(dataToAppend); if (!status.ok()) { return status; } @@ -221,18 +224,19 @@ class EncryptedWritableFile : public WritableFileWrapper { Status PositionedAppend(const Slice& data, uint64_t offset) override { AlignedBuffer buf; Status status; - Slice dataToAppend(data); + Slice dataToAppend(data); offset += prefixLength_; if (data.size() > 0) { // Encrypt in cloned buffer buf.Alignment(GetRequiredBufferAlignment()); buf.AllocateNewBuffer(data.size()); memmove(buf.BufferStart(), data.data(), data.size()); - status = stream_->Encrypt(offset, buf.BufferStart(), data.size()); + buf.Size(data.size()); + status = stream_->Encrypt(offset, buf.BufferStart(), buf.CurrentSize()); if (!status.ok()) { return status; } - dataToAppend = Slice(buf.BufferStart(), data.size()); + dataToAppend = Slice(buf.BufferStart(), buf.CurrentSize()); } status = file_->PositionedAppend(dataToAppend, offset); if (!status.ok()) { @@ -325,18 +329,19 @@ class EncryptedRandomRWFile : public RandomRWFile { Status Write(uint64_t offset, const Slice& data) override { AlignedBuffer buf; Status status; - Slice dataToWrite(data); + Slice dataToWrite(data); offset += prefixLength_; if (data.size() > 0) { // Encrypt in cloned buffer buf.Alignment(GetRequiredBufferAlignment()); buf.AllocateNewBuffer(data.size()); memmove(buf.BufferStart(), data.data(), data.size()); - status = stream_->Encrypt(offset, buf.BufferStart(), data.size()); + buf.Size(data.size()); + status = stream_->Encrypt(offset, buf.BufferStart(), buf.CurrentSize()); if (!status.ok()) { return status; } - dataToWrite = Slice(buf.BufferStart(), data.size()); + dataToWrite = Slice(buf.BufferStart(), buf.CurrentSize()); } status = file_->Write(offset, dataToWrite); return status; @@ -393,13 +398,14 @@ class EncryptedEnv : public EnvWrapper { Slice prefixSlice; size_t prefixLength = provider_->GetPrefixLength(); if (prefixLength > 0) { - // Read prefix + // Read prefix prefixBuf.Alignment(underlying->GetRequiredBufferAlignment()); prefixBuf.AllocateNewBuffer(prefixLength); status = underlying->Read(prefixLength, &prefixSlice, prefixBuf.BufferStart()); if (!status.ok()) { return status; } + prefixBuf.Size(prefixLength); } // Create cipher stream std::unique_ptr stream; @@ -430,13 +436,14 @@ class EncryptedEnv : public EnvWrapper { Slice prefixSlice; size_t prefixLength = provider_->GetPrefixLength(); if (prefixLength > 0) { - // Read prefix + // Read prefix prefixBuf.Alignment(underlying->GetRequiredBufferAlignment()); prefixBuf.AllocateNewBuffer(prefixLength); status = underlying->Read(0, prefixLength, &prefixSlice, prefixBuf.BufferStart()); if (!status.ok()) { return status; } + prefixBuf.Size(prefixLength); } // Create cipher stream std::unique_ptr stream; @@ -467,12 +474,13 @@ class EncryptedEnv : public EnvWrapper { Slice prefixSlice; size_t prefixLength = provider_->GetPrefixLength(); if (prefixLength > 0) { - // Initialize prefix + // Initialize prefix prefixBuf.Alignment(underlying->GetRequiredBufferAlignment()); prefixBuf.AllocateNewBuffer(prefixLength); provider_->CreateNewPrefix(fname, prefixBuf.BufferStart(), prefixLength); - prefixSlice = Slice(prefixBuf.BufferStart(), prefixLength); - // Write prefix + prefixBuf.Size(prefixLength); + prefixSlice = Slice(prefixBuf.BufferStart(), prefixBuf.CurrentSize()); + // Write prefix status = underlying->Append(prefixSlice); if (!status.ok()) { return status; @@ -513,12 +521,13 @@ class EncryptedEnv : public EnvWrapper { Slice prefixSlice; size_t prefixLength = provider_->GetPrefixLength(); if (prefixLength > 0) { - // Initialize prefix + // Initialize prefix prefixBuf.Alignment(underlying->GetRequiredBufferAlignment()); prefixBuf.AllocateNewBuffer(prefixLength); provider_->CreateNewPrefix(fname, prefixBuf.BufferStart(), prefixLength); - prefixSlice = Slice(prefixBuf.BufferStart(), prefixLength); - // Write prefix + prefixBuf.Size(prefixLength); + prefixSlice = Slice(prefixBuf.BufferStart(), prefixBuf.CurrentSize()); + // Write prefix status = underlying->Append(prefixSlice); if (!status.ok()) { return status; @@ -554,12 +563,13 @@ class EncryptedEnv : public EnvWrapper { Slice prefixSlice; size_t prefixLength = provider_->GetPrefixLength(); if (prefixLength > 0) { - // Initialize prefix + // Initialize prefix prefixBuf.Alignment(underlying->GetRequiredBufferAlignment()); prefixBuf.AllocateNewBuffer(prefixLength); provider_->CreateNewPrefix(fname, prefixBuf.BufferStart(), prefixLength); - prefixSlice = Slice(prefixBuf.BufferStart(), prefixLength); - // Write prefix + prefixBuf.Size(prefixLength); + prefixSlice = Slice(prefixBuf.BufferStart(), prefixBuf.CurrentSize()); + // Write prefix status = underlying->Append(prefixSlice); if (!status.ok()) { return status; @@ -609,11 +619,13 @@ class EncryptedEnv : public EnvWrapper { if (!status.ok()) { return status; } + prefixBuf.Size(prefixLength); } else { - // File is new, initialize & write prefix + // File is new, initialize & write prefix provider_->CreateNewPrefix(fname, prefixBuf.BufferStart(), prefixLength); - prefixSlice = Slice(prefixBuf.BufferStart(), prefixLength); - // Write prefix + prefixBuf.Size(prefixLength); + prefixSlice = Slice(prefixBuf.BufferStart(), prefixBuf.CurrentSize()); + // Write prefix status = underlying->Write(0, prefixSlice); if (!status.ok()) { return status; @@ -630,7 +642,7 @@ class EncryptedEnv : public EnvWrapper { return Status::OK(); } - // Store in *result the attributes of the children of the specified directory. + // Store in *result the attributes of the children of the specified directory. // In case the implementation lists the directory prior to iterating the files // and files are concurrently deleted, the deleted files will be omitted from // result. @@ -670,8 +682,7 @@ class EncryptedEnv : public EnvWrapper { EncryptionProvider *provider_; }; - -// Returns an Env that encrypts data when stored on disk and decrypts data when +// Returns an Env that encrypts data when stored on disk and decrypts data when // read from disk. Env* NewEncryptedEnv(Env* base_env, EncryptionProvider* provider) { return new EncryptedEnv(base_env, provider); @@ -694,14 +705,14 @@ Status BlockAccessCipherStream::Encrypt(uint64_t fileOffset, char *data, size_t char *block = data; size_t n = std::min(dataSize, blockSize - blockOffset); if (n != blockSize) { - // We're not encrypting a full block. + // We're not encrypting a full block. // Copy data to blockBuffer if (!blockBuffer.get()) { // Allocate buffer blockBuffer = std::unique_ptr(new char[blockSize]); } block = blockBuffer.get(); - // Copy plain data to block buffer + // Copy plain data to block buffer memmove(block + blockOffset, data, n); } auto status = EncryptBlock(blockIndex, block, (char*)scratch.data()); @@ -741,14 +752,14 @@ Status BlockAccessCipherStream::Decrypt(uint64_t fileOffset, char *data, size_t char *block = data; size_t n = std::min(dataSize, blockSize - blockOffset); if (n != blockSize) { - // We're not decrypting a full block. + // We're not decrypting a full block. // Copy data to blockBuffer if (!blockBuffer.get()) { // Allocate buffer blockBuffer = std::unique_ptr(new char[blockSize]); } block = blockBuffer.get(); - // Copy encrypted data to block buffer + // Copy encrypted data to block buffer memmove(block + blockOffset, data, n); } auto status = DecryptBlock(blockIndex, block, (char*)scratch.data()); @@ -807,7 +818,7 @@ Status CTRCipherStream::EncryptBlock(uint64_t blockIndex, char *data, char* scra memmove(scratch, iv_.data(), blockSize); EncodeFixed64(scratch, blockIndex + initialCounter_); - // Encrypt nonce+counter + // Encrypt nonce+counter auto status = cipher_.Encrypt(scratch); if (!status.ok()) { return status; @@ -823,13 +834,13 @@ Status CTRCipherStream::EncryptBlock(uint64_t blockIndex, char *data, char* scra // Decrypt a block of data at the given block index. // Length of data is equal to BlockSize(); Status CTRCipherStream::DecryptBlock(uint64_t blockIndex, char *data, char* scratch) { - // For CTR decryption & encryption are the same + // For CTR decryption & encryption are the same return EncryptBlock(blockIndex, data, scratch); } // GetPrefixLength returns the length of the prefix that is added to every file // and used for storing encryption options. -// For optimal performance, the prefix length should be a multiple of +// For optimal performance, the prefix length should be a multiple of // the page size. size_t CTREncryptionProvider::GetPrefixLength() { return defaultPrefixLength; @@ -844,7 +855,7 @@ static void decodeCTRParameters(const char *prefix, size_t blockSize, uint64_t & iv = Slice(prefix + blockSize, blockSize); } -// CreateNewPrefix initialized an allocated block of prefix memory +// CreateNewPrefix initialized an allocated block of prefix memory // for a new file. Status CTREncryptionProvider::CreateNewPrefix(const std::string& /*fname*/, char* prefix, @@ -873,7 +884,7 @@ Status CTREncryptionProvider::CreateNewPrefix(const std::string& /*fname*/, return Status::OK(); } -// PopulateSecretPrefixPart initializes the data into a new prefix block +// PopulateSecretPrefixPart initializes the data into a new prefix block // in plain text. // Returns the amount of space (starting from the start of the prefix) // that has been initialized. @@ -908,7 +919,7 @@ Status CTREncryptionProvider::CreateCipherStream( return status; } - // Create cipher stream + // Create cipher stream return CreateCipherStreamFromPrefix(fname, options, initialCounter, iv, prefix, result); }