mirror of
https://github.com/vgough/encfs.git
synced 2024-11-29 03:15:07 +01:00
Bugfix: Possible Out of Bounds Write in StreamNameIO and BlockNameIO #15
Issue #15, the encodeName functions fail to verify buffer length can store encoded filenames For good measure and interface consistency, also check decodeName fnc
This commit is contained in:
parent
da03864538
commit
a0e02cb3ea
@ -135,14 +135,17 @@ int BlockNameIO::maxDecodedNameLen(int encodedNameLen) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int BlockNameIO::encodeName(const char *plaintextName, int length, uint64_t *iv,
|
int BlockNameIO::encodeName(const char *plaintextName, int length, uint64_t *iv,
|
||||||
char *encodedName) const {
|
char *encodedName, int bufferLength) const {
|
||||||
|
|
||||||
// copy the data into the encoding buffer..
|
// copy the data into the encoding buffer..
|
||||||
|
rAssert(length <= (bufferLength - 2));
|
||||||
memcpy(encodedName + 2, plaintextName, length);
|
memcpy(encodedName + 2, plaintextName, length);
|
||||||
|
|
||||||
// Pad encryption buffer to block boundary..
|
// Pad encryption buffer to block boundary..
|
||||||
int padding = _bs - length % _bs;
|
int padding = _bs - length % _bs;
|
||||||
if (padding == 0) padding = _bs; // padding a full extra block!
|
if (padding == 0) padding = _bs; // padding a full extra block!
|
||||||
|
|
||||||
|
rAssert(padding <= (bufferLength - length - 2));
|
||||||
memset(encodedName + length + 2, (unsigned char)padding, padding);
|
memset(encodedName + length + 2, (unsigned char)padding, padding);
|
||||||
|
|
||||||
// store the IV before it is modified by the MAC call.
|
// store the IV before it is modified by the MAC call.
|
||||||
@ -182,7 +185,7 @@ int BlockNameIO::encodeName(const char *plaintextName, int length, uint64_t *iv,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int BlockNameIO::decodeName(const char *encodedName, int length, uint64_t *iv,
|
int BlockNameIO::decodeName(const char *encodedName, int length, uint64_t *iv,
|
||||||
char *plaintextName) const {
|
char *plaintextName, int bufferLength) const {
|
||||||
int decLen256 =
|
int decLen256 =
|
||||||
_caseSensitive ? B32ToB256Bytes(length) : B64ToB256Bytes(length);
|
_caseSensitive ? B32ToB256Bytes(length) : B64ToB256Bytes(length);
|
||||||
int decodedStreamLen = decLen256 - 2;
|
int decodedStreamLen = decLen256 - 2;
|
||||||
@ -225,6 +228,7 @@ int BlockNameIO::decodeName(const char *encodedName, int length, uint64_t *iv,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// copy out the result..
|
// copy out the result..
|
||||||
|
rAssert(finalSize < bufferLength);
|
||||||
memcpy(plaintextName, tmpBuf + 2, finalSize);
|
memcpy(plaintextName, tmpBuf + 2, finalSize);
|
||||||
plaintextName[finalSize] = '\0';
|
plaintextName[finalSize] = '\0';
|
||||||
|
|
||||||
|
@ -55,9 +55,9 @@ class BlockNameIO : public NameIO {
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual int encodeName(const char *plaintextName, int length, uint64_t *iv,
|
virtual int encodeName(const char *plaintextName, int length, uint64_t *iv,
|
||||||
char *encodedName) const;
|
char *encodedName, int bufferLength) const;
|
||||||
virtual int decodeName(const char *encodedName, int length, uint64_t *iv,
|
virtual int decodeName(const char *encodedName, int length, uint64_t *iv,
|
||||||
char *plaintextName) const;
|
char *plaintextName, int bufferLength) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int _interface;
|
int _interface;
|
||||||
|
@ -142,7 +142,7 @@ bool NameIO::getReverseEncryption() const { return reverseEncryption; }
|
|||||||
std::string NameIO::recodePath(const char *path,
|
std::string NameIO::recodePath(const char *path,
|
||||||
int (NameIO::*_length)(int) const,
|
int (NameIO::*_length)(int) const,
|
||||||
int (NameIO::*_code)(const char *, int,
|
int (NameIO::*_code)(const char *, int,
|
||||||
uint64_t *, char *) const,
|
uint64_t *, char *, int) const,
|
||||||
uint64_t *iv) const {
|
uint64_t *iv) const {
|
||||||
string output;
|
string output;
|
||||||
|
|
||||||
@ -166,11 +166,12 @@ std::string NameIO::recodePath(const char *path,
|
|||||||
// figure out buffer sizes
|
// figure out buffer sizes
|
||||||
int approxLen = (this->*_length)(len);
|
int approxLen = (this->*_length)(len);
|
||||||
if (approxLen <= 0) throw ERROR("Filename too small to decode");
|
if (approxLen <= 0) throw ERROR("Filename too small to decode");
|
||||||
|
int bufSize = 0;
|
||||||
|
|
||||||
BUFFER_INIT(codeBuf, 32, (unsigned int)approxLen + 1)
|
BUFFER_INIT_S(codeBuf, 32, (unsigned int)approxLen + 1, bufSize)
|
||||||
|
|
||||||
// code the name
|
// code the name
|
||||||
int codedLen = (this->*_code)(path, len, iv, codeBuf);
|
int codedLen = (this->*_code)(path, len, iv, codeBuf, bufSize);
|
||||||
rAssert(codedLen <= approxLen);
|
rAssert(codedLen <= approxLen);
|
||||||
rAssert(codeBuf[codedLen] == '\0');
|
rAssert(codeBuf[codedLen] == '\0');
|
||||||
path += len;
|
path += len;
|
||||||
@ -217,21 +218,22 @@ std::string NameIO::decodePath(const char *path, uint64_t *iv) const {
|
|||||||
return getReverseEncryption() ? _encodePath(path, iv) : _decodePath(path, iv);
|
return getReverseEncryption() ? _encodePath(path, iv) : _decodePath(path, iv);
|
||||||
}
|
}
|
||||||
|
|
||||||
int NameIO::encodeName(const char *input, int length, char *output) const {
|
int NameIO::encodeName(const char *input, int length, char *output, int bufferLength) const {
|
||||||
return encodeName(input, length, (uint64_t *)0, output);
|
return encodeName(input, length, (uint64_t *)0, output, bufferLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
int NameIO::decodeName(const char *input, int length, char *output) const {
|
int NameIO::decodeName(const char *input, int length, char *output, int bufferLength) const {
|
||||||
return decodeName(input, length, (uint64_t *)0, output);
|
return decodeName(input, length, (uint64_t *)0, output, bufferLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string NameIO::_encodeName(const char *plaintextName, int length) const {
|
std::string NameIO::_encodeName(const char *plaintextName, int length) const {
|
||||||
int approxLen = maxEncodedNameLen(length);
|
int approxLen = maxEncodedNameLen(length);
|
||||||
|
int bufSize = 0;
|
||||||
|
|
||||||
BUFFER_INIT(codeBuf, 32, (unsigned int)approxLen + 1)
|
BUFFER_INIT_S(codeBuf, 32, (unsigned int)approxLen + 1, bufSize)
|
||||||
|
|
||||||
// code the name
|
// code the name
|
||||||
int codedLen = encodeName(plaintextName, length, 0, codeBuf);
|
int codedLen = encodeName(plaintextName, length, 0, codeBuf, bufSize);
|
||||||
rAssert(codedLen <= approxLen);
|
rAssert(codedLen <= approxLen);
|
||||||
rAssert(codeBuf[codedLen] == '\0');
|
rAssert(codeBuf[codedLen] == '\0');
|
||||||
|
|
||||||
@ -245,11 +247,12 @@ std::string NameIO::_encodeName(const char *plaintextName, int length) const {
|
|||||||
|
|
||||||
std::string NameIO::_decodeName(const char *encodedName, int length) const {
|
std::string NameIO::_decodeName(const char *encodedName, int length) const {
|
||||||
int approxLen = maxDecodedNameLen(length);
|
int approxLen = maxDecodedNameLen(length);
|
||||||
|
int bufSize = 0;
|
||||||
|
|
||||||
BUFFER_INIT(codeBuf, 32, (unsigned int)approxLen + 1)
|
BUFFER_INIT_S(codeBuf, 32, (unsigned int)approxLen + 1, bufSize)
|
||||||
|
|
||||||
// code the name
|
// code the name
|
||||||
int codedLen = decodeName(encodedName, length, 0, codeBuf);
|
int codedLen = decodeName(encodedName, length, 0, codeBuf, bufSize);
|
||||||
rAssert(codedLen <= approxLen);
|
rAssert(codedLen <= approxLen);
|
||||||
rAssert(codeBuf[codedLen] == '\0');
|
rAssert(codeBuf[codedLen] == '\0');
|
||||||
|
|
||||||
|
@ -83,19 +83,19 @@ class NameIO {
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual int encodeName(const char *plaintextName, int length,
|
virtual int encodeName(const char *plaintextName, int length,
|
||||||
char *encodedName) const;
|
char *encodedName, int bufferLength) const;
|
||||||
virtual int decodeName(const char *encodedName, int length,
|
virtual int decodeName(const char *encodedName, int length,
|
||||||
char *plaintextName) const;
|
char *plaintextName, int bufferLength) const;
|
||||||
|
|
||||||
virtual int encodeName(const char *plaintextName, int length, uint64_t *iv,
|
virtual int encodeName(const char *plaintextName, int length, uint64_t *iv,
|
||||||
char *encodedName) const = 0;
|
char *encodedName, int bufferLength) const = 0;
|
||||||
virtual int decodeName(const char *encodedName, int length, uint64_t *iv,
|
virtual int decodeName(const char *encodedName, int length, uint64_t *iv,
|
||||||
char *plaintextName) const = 0;
|
char *plaintextName, int bufferLength) const = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string recodePath(const char *path, int (NameIO::*codingLen)(int) const,
|
std::string recodePath(const char *path, int (NameIO::*codingLen)(int) const,
|
||||||
int (NameIO::*codingFunc)(const char *, int,
|
int (NameIO::*codingFunc)(const char *, int,
|
||||||
uint64_t *, char *) const,
|
uint64_t *, char *, int) const,
|
||||||
uint64_t *iv) const;
|
uint64_t *iv) const;
|
||||||
|
|
||||||
std::string _encodePath(const char *plaintextPath, uint64_t *iv) const;
|
std::string _encodePath(const char *plaintextPath, uint64_t *iv) const;
|
||||||
@ -108,11 +108,11 @@ class NameIO {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Helper macros for creating temporary buffers with an optimization that
|
Helper macros for creating temporary buffers with an optimization that
|
||||||
below a given size (OptimizedSize) is allocated on the stack, and when a
|
below a given size (OptimizedSize) is allocated on the stack, and when a
|
||||||
larger size is requested it is allocated on the heap.
|
larger size is requested it is allocated on the heap.
|
||||||
|
|
||||||
BUFFER_RESET should be called for the same name as BUFFER_INIT
|
BUFFER_RESET should be called for the same name as BUFFER_INIT
|
||||||
*/
|
*/
|
||||||
#define BUFFER_INIT(Name, OptimizedSize, Size) \
|
#define BUFFER_INIT(Name, OptimizedSize, Size) \
|
||||||
char Name##_Raw[OptimizedSize]; \
|
char Name##_Raw[OptimizedSize]; \
|
||||||
@ -120,6 +120,16 @@ class NameIO {
|
|||||||
if (sizeof(Name##_Raw) < Size) Name = new char[Size]; \
|
if (sizeof(Name##_Raw) < Size) Name = new char[Size]; \
|
||||||
memset(Name, 0, Size);
|
memset(Name, 0, Size);
|
||||||
|
|
||||||
|
#define BUFFER_INIT_S(Name, OptimizedSize, Size, BufSize) \
|
||||||
|
char Name##_Raw[OptimizedSize]; \
|
||||||
|
BufSize = sizeof(Name##_Raw); \
|
||||||
|
char *Name = Name##_Raw; \
|
||||||
|
if (sizeof(Name##_Raw) < Size) { \
|
||||||
|
Name = new char[Size]; \
|
||||||
|
BufSize = Size; \
|
||||||
|
} \
|
||||||
|
memset(Name, 0, Size);
|
||||||
|
|
||||||
#define BUFFER_RESET(Name) \
|
#define BUFFER_RESET(Name) \
|
||||||
do { \
|
do { \
|
||||||
if (Name != Name##_Raw) { \
|
if (Name != Name##_Raw) { \
|
||||||
|
@ -56,16 +56,20 @@ int NullNameIO::maxDecodedNameLen(int encodedNameLen) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int NullNameIO::encodeName(const char *plaintextName, int length, uint64_t *iv,
|
int NullNameIO::encodeName(const char *plaintextName, int length, uint64_t *iv,
|
||||||
char *encodedName) const {
|
char *encodedName, int bufferLength) const {
|
||||||
(void)iv;
|
(void)iv;
|
||||||
|
|
||||||
|
rAssert(length <= bufferLength);
|
||||||
memcpy(encodedName, plaintextName, length);
|
memcpy(encodedName, plaintextName, length);
|
||||||
|
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
int NullNameIO::decodeName(const char *encodedName, int length, uint64_t *iv,
|
int NullNameIO::decodeName(const char *encodedName, int length, uint64_t *iv,
|
||||||
char *plaintextName) const {
|
char *plaintextName, int bufferLength) const {
|
||||||
(void)iv;
|
(void)iv;
|
||||||
|
|
||||||
|
rAssert(length <= bufferLength);
|
||||||
memcpy(plaintextName, encodedName, length);
|
memcpy(plaintextName, encodedName, length);
|
||||||
|
|
||||||
return length;
|
return length;
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "rlog/Error.h"
|
||||||
|
#include "rlog/rlog.h"
|
||||||
#include "Interface.h"
|
#include "Interface.h"
|
||||||
#include "NameIO.h"
|
#include "NameIO.h"
|
||||||
|
|
||||||
@ -44,9 +46,9 @@ class NullNameIO : public NameIO {
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual int encodeName(const char *plaintextName, int length, uint64_t *iv,
|
virtual int encodeName(const char *plaintextName, int length, uint64_t *iv,
|
||||||
char *encodedName) const;
|
char *encodedName, int bufferLength) const;
|
||||||
virtual int decodeName(const char *encodedName, int length, uint64_t *iv,
|
virtual int decodeName(const char *encodedName, int length, uint64_t *iv,
|
||||||
char *plaintextName) const;
|
char *plaintextName, int bufferLength) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
};
|
};
|
||||||
|
@ -90,7 +90,7 @@ int StreamNameIO::maxDecodedNameLen(int encodedStreamLen) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int StreamNameIO::encodeName(const char *plaintextName, int length,
|
int StreamNameIO::encodeName(const char *plaintextName, int length,
|
||||||
uint64_t *iv, char *encodedName) const {
|
uint64_t *iv, char *encodedName, int bufferLength) const {
|
||||||
uint64_t tmpIV = 0;
|
uint64_t tmpIV = 0;
|
||||||
if (iv && _interface >= 2) tmpIV = *iv;
|
if (iv && _interface >= 2) tmpIV = *iv;
|
||||||
|
|
||||||
@ -104,11 +104,13 @@ int StreamNameIO::encodeName(const char *plaintextName, int length,
|
|||||||
encodedName[0] = (mac >> 8) & 0xff;
|
encodedName[0] = (mac >> 8) & 0xff;
|
||||||
encodedName[1] = (mac)&0xff;
|
encodedName[1] = (mac)&0xff;
|
||||||
encodeBegin = (unsigned char *)encodedName + 2;
|
encodeBegin = (unsigned char *)encodedName + 2;
|
||||||
|
rAssert(length <= (bufferLength - 2));
|
||||||
} else {
|
} else {
|
||||||
// encfs 0.x stored checksums at the end.
|
// encfs 0.x stored checksums at the end.
|
||||||
encodedName[length] = (mac >> 8) & 0xff;
|
encodedName[length] = (mac >> 8) & 0xff;
|
||||||
encodedName[length + 1] = (mac)&0xff;
|
encodedName[length + 1] = (mac)&0xff;
|
||||||
encodeBegin = (unsigned char *)encodedName;
|
encodeBegin = (unsigned char *)encodedName;
|
||||||
|
rAssert(length <= bufferLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
// stream encode the plaintext bytes
|
// stream encode the plaintext bytes
|
||||||
@ -126,10 +128,11 @@ int StreamNameIO::encodeName(const char *plaintextName, int length,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int StreamNameIO::decodeName(const char *encodedName, int length, uint64_t *iv,
|
int StreamNameIO::decodeName(const char *encodedName, int length, uint64_t *iv,
|
||||||
char *plaintextName) const {
|
char *plaintextName, int bufferLength) const {
|
||||||
rAssert(length > 2);
|
rAssert(length > 2);
|
||||||
int decLen256 = B64ToB256Bytes(length);
|
int decLen256 = B64ToB256Bytes(length);
|
||||||
int decodedStreamLen = decLen256 - 2;
|
int decodedStreamLen = decLen256 - 2;
|
||||||
|
rAssert(decodedStreamLen <= bufferLength);
|
||||||
|
|
||||||
if (decodedStreamLen <= 0) throw ERROR("Filename too small to decode");
|
if (decodedStreamLen <= 0) throw ERROR("Filename too small to decode");
|
||||||
|
|
||||||
|
@ -48,9 +48,9 @@ class StreamNameIO : public NameIO {
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual int encodeName(const char *plaintextName, int length, uint64_t *iv,
|
virtual int encodeName(const char *plaintextName, int length, uint64_t *iv,
|
||||||
char *encodedName) const;
|
char *encodedName, int bufferLength) const;
|
||||||
virtual int decodeName(const char *encodedName, int length, uint64_t *iv,
|
virtual int decodeName(const char *encodedName, int length, uint64_t *iv,
|
||||||
char *plaintextName) const;
|
char *plaintextName, int bufferLength) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int _interface;
|
int _interface;
|
||||||
|
Loading…
Reference in New Issue
Block a user