Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle CBC padding #521

Closed
wants to merge 14 commits into from
56 changes: 31 additions & 25 deletions encfs/BlockFileIO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,15 @@ static void clearCache(IORequest &req, unsigned int blockSize) {
BlockFileIO::BlockFileIO(unsigned int blockSize, const FSConfigPtr &cfg)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commit message is missing

: _blockSize(blockSize), _allowHoles(cfg->config->allowHoles) {
CHECK(_blockSize > 1);
_cache.data = new unsigned char[_blockSize];
_cache.data = new unsigned char[_blockSize + 16]; // we will need some room for padding
_noCache = cfg->opts->noCache;
/* Even if cache is disabled, we may need to cache some data.
* This is the case in reverse mode, with CBC padding, partially writing the last block.
* If a write request is made with only some of the first bytes of the last block,
* the last bytes of this request won't certainly be properly written to disk (because of CBC mode).
* We must then cache these bytes so that subsequent request, which will certainly complete
* this last block, will properly retrieve them and finally write the full (or correctly padded) block. */
_cachePartialWrite = cfg->reverseEncryption && cfg->config->padding;
}

BlockFileIO::~BlockFileIO() {
Expand All @@ -65,9 +72,9 @@ ssize_t BlockFileIO::cacheReadOneBlock(const IORequest &req) const {
/* we can satisfy the request even if _cache.dataLen is too short, because
* we always request a full block during reads. This just means we are
* in the last block of a file, which may be smaller than the blocksize.
* For reverse encryption, the cache must not be used at all, because
* For reverse encryption, the cache should not be used at all, because
* the lower file may have changed behind our back. */
if ((!_noCache) && (req.offset == _cache.offset) && (_cache.dataLen != 0)) {
if ((_cache.dataLen != 0) && (req.offset == _cache.offset)) {
// satisfy request from cache
size_t len = req.dataLen;
if (_cache.dataLen < len) {
Expand All @@ -76,23 +83,25 @@ ssize_t BlockFileIO::cacheReadOneBlock(const IORequest &req) const {
memcpy(req.data, _cache.data, len);
return len;
}
if (_cache.dataLen > 0) {
clearCache(_cache, _blockSize);
}

// cache results of read -- issue reads for full blocks
IORequest tmp;
tmp.offset = req.offset;
tmp.data = _cache.data;
tmp.dataLen = _blockSize;
ssize_t result = readOneBlock(tmp);
// issue reads for full blocks, and keep result in cache if we're allowed to
_cache.offset = req.offset;
_cache.dataLen = _blockSize;
ssize_t result = readOneBlock(_cache);
if (result > 0) {
_cache.offset = req.offset;
_cache.dataLen = result; // the amount we really have
if ((size_t)result > req.dataLen) {
result = req.dataLen; // only as much as requested
}
memcpy(req.data, _cache.data, result);
if (!_noCache) {
// zero the last bytes of the cache
memset(_cache.data + _cache.dataLen, 0, _blockSize - _cache.dataLen);
} else {
clearCache(_cache, _blockSize);
}
} else {
clearCache(_cache, _blockSize);
}
return result;
}
Expand All @@ -101,19 +110,16 @@ ssize_t BlockFileIO::cacheWriteOneBlock(const IORequest &req) {
// Let's point request buffer to our own buffer, as it may be modified by
// encryption : originating process may not like to have its buffer modified
memcpy(_cache.data, req.data, req.dataLen);
IORequest tmp;
tmp.offset = req.offset;
tmp.data = _cache.data;
tmp.dataLen = req.dataLen;
ssize_t res = writeOneBlock(tmp);
if (res < 0) {
clearCache(_cache, _blockSize);
}
else {
// And now we can cache the write buffer from the request
_cache.offset = req.offset;
_cache.dataLen = req.dataLen;
ssize_t res = writeOneBlock(_cache);
// we cache if we're allowed to or if we are writing the last partial block in CBC reverse mode
if ((res > 0) && (!_noCache || (_cachePartialWrite && (req.dataLen < _blockSize)))) {
memcpy(_cache.data, req.data, req.dataLen);
_cache.offset = req.offset;
_cache.dataLen = req.dataLen;
// zero the last bytes of the cache
memset(_cache.data + req.dataLen, 0, _blockSize - req.dataLen);
} else {
clearCache(_cache, _blockSize);
}
return res;
}
Expand Down
1 change: 1 addition & 0 deletions encfs/BlockFileIO.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class BlockFileIO : public FileIO {
unsigned int _blockSize;
bool _allowHoles;
bool _noCache;
bool _cachePartialWrite;

// cache last block for speed...
mutable IORequest _cache;
Expand Down
Loading