Prevent plain KeyValueHolder size overflow

This commit is contained in:
guoling
2026-09-03 17:04:49 +08:00
parent a444b13449
commit eae63c9865
2 changed files with 20 additions and 7 deletions
+13 -7
View File
@@ -449,6 +449,7 @@ static bool encodedEntrySize(size_t keyDataLength,
uint32_t originKeyLength,
size_t dataLength,
bool isDataHolder,
bool needsPlainHolder,
EncodedEntrySize &result) {
constexpr auto MaxEncodedLength = numeric_limits<uint32_t>::max();
if (originKeyLength > KeySizeLimit || keyDataLength < originKeyLength || keyDataLength > MaxEncodedLength) {
@@ -460,11 +461,14 @@ static bool encodedEntrySize(size_t keyDataLength,
return false;
}
uint64_t totalSize =
static_cast<uint64_t>(keyDataLength) + result.valueLength + pbRawVarint32Size(result.valueLength);
uint64_t keyValueSize = static_cast<uint64_t>(keyDataLength) + pbRawVarint32Size(result.valueLength);
if (!result.keyAlreadyEncoded) {
totalSize += pbRawVarint32Size(static_cast<uint32_t>(keyDataLength));
keyValueSize += pbRawVarint32Size(static_cast<uint32_t>(keyDataLength));
}
if (needsPlainHolder && keyValueSize > numeric_limits<uint16_t>::max()) {
return false;
}
auto totalSize = keyValueSize + result.valueLength;
if (totalSize > MaxEncodedLength) {
return false;
}
@@ -962,7 +966,8 @@ bool MMKV::removeDataForKey(MMKVKey_t key) {
KVHolderRet_t
MMKV::doAppendDataWithKey(const MMBuffer &data, const MMBuffer &keyData, bool isDataHolder, uint32_t originKeyLength) {
EncodedEntrySize entry;
if (!encodedEntrySize(keyData.length(), originKeyLength, data.length(), isDataHolder, entry)) {
if (!encodedEntrySize(keyData.length(), originKeyLength, data.length(), isDataHolder, m_crypter == nullptr,
entry)) {
MMKVError("[%s] reject unrepresentable key/value lengths, keyData=%zu, key=%u, value=%zu",
m_mmapID.c_str(), keyData.length(), originKeyLength, data.length());
return make_pair(false, KeyValueHolder());
@@ -1024,7 +1029,8 @@ KVHolderRet_t MMKV::doOverrideDataWithKey(const MMBuffer &data,
bool isDataHolder,
uint32_t originKeyLength) {
EncodedEntrySize entry;
if (!encodedEntrySize(keyData.length(), originKeyLength, data.length(), isDataHolder, entry)) {
if (!encodedEntrySize(keyData.length(), originKeyLength, data.length(), isDataHolder, m_crypter == nullptr,
entry)) {
MMKVError("[%s] reject unrepresentable key/value lengths, keyData=%zu, key=%u, value=%zu",
m_mmapID.c_str(), keyData.length(), originKeyLength, data.length());
return make_pair(false, KeyValueHolder());
@@ -1139,7 +1145,7 @@ KVHolderRet_t MMKV::appendDataWithKey(const MMBuffer &data, const KeyValueHolder
// ensureMemorySize() might change kvHolder.offset, so have to do it early
{
EncodedEntrySize entry;
if (!encodedEntrySize(rawKeySize, keyLength, data.length(), isDataHolder, entry)) {
if (!encodedEntrySize(rawKeySize, keyLength, data.length(), isDataHolder, m_crypter == nullptr, entry)) {
return make_pair(false, KeyValueHolder());
}
bool hasEnoughSize = ensureMemorySize(entry.totalSize);
@@ -1166,7 +1172,7 @@ KVHolderRet_t MMKV::overrideDataWithKey(const MMBuffer &data, const KeyValueHold
// might change kvHolder.offset, so have to do it early
{
EncodedEntrySize entry;
if (!encodedEntrySize(rawKeySize, keyLength, data.length(), isDataHolder, entry)) {
if (!encodedEntrySize(rawKeySize, keyLength, data.length(), isDataHolder, m_crypter == nullptr, entry)) {
return make_pair(false, KeyValueHolder());
}
bool hasEnoughSize = checkSizeForOverride(entry.totalSize);
+7
View File
@@ -221,7 +221,14 @@ void testOversizedKey(MMKV *mmkv) {
string out;
ret = mmkv->getString(key, out);
assert(ret && out == "V");
// The key still fits, but a two-byte value-length prefix would overflow
// KeyValueHolder::computedKVSize. Reject the update before writing it.
assert(!mmkv->set(string(127, 'V'), key));
assert(mmkv->getString(key, out) && out == "V");
mmkv->removeValueForKey(key);
assert(!mmkv->set(string(127, 'V'), key));
assert(!mmkv->containsKey(key));
}
// Keys at 65532 bytes and above must be rejected (would overflow uint16_t fields)
{