Skip to content

Commit

Permalink
bugfix: set/zset/hash member may overflow (#2106)
Browse files Browse the repository at this point in the history
* Update base_meta_value_format.h

* Update redis_hashes.cc

* Update redis_sets.cc

* Update redis_zsets.cc
  • Loading branch information
u6th9d authored Nov 10, 2023
1 parent 28831ef commit 89444f7
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 0 deletions.
16 changes: 16 additions & 0 deletions src/storage/src/base_meta_value_format.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,13 @@ class ParsedBaseMetaValue : public ParsedInternalValue {

int32_t count() { return count_; }

bool check_set_count(size_t count) {
if (count > INT32_MAX) {
return false;
}
return true;
}

void set_count(int32_t count) {
count_ = count;
if (value_) {
Expand All @@ -97,6 +104,15 @@ class ParsedBaseMetaValue : public ParsedInternalValue {
}
}

bool CheckModifyCount(int32_t delta) {
int64_t count = count_;
count += delta;
if (count < 0 || count > INT32_MAX) {
return false;
}
return true;
}

void ModifyCount(int32_t delta) {
count_ += delta;
if (value_) {
Expand Down
21 changes: 21 additions & 0 deletions src/storage/src/redis_hashes.cc
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,9 @@ Status RedisHashes::HDel(const Slice& key, const std::vector<std::string>& field
}
}
*ret = del_cnt;
if (!parsed_hashes_meta_value.CheckModifyCount(-del_cnt)){
return Status::InvalidArgument("hash size overflow");
}
parsed_hashes_meta_value.ModifyCount(-del_cnt);
batch.Put(handles_[0], key, meta_value);
}
Expand Down Expand Up @@ -348,6 +351,9 @@ Status RedisHashes::HIncrby(const Slice& key, const Slice& field, int64_t value,
statistic++;
} else if (s.IsNotFound()) {
Int64ToStr(value_buf, 32, value);
if (!parsed_hashes_meta_value.CheckModifyCount(1)){
return Status::InvalidArgument("hash size overflow");
}
parsed_hashes_meta_value.ModifyCount(1);
batch.Put(handles_[0], key, meta_value);
batch.Put(handles_[1], hashes_data_key.Encode(), value_buf);
Expand Down Expand Up @@ -421,6 +427,9 @@ Status RedisHashes::HIncrbyfloat(const Slice& key, const Slice& field, const Sli
statistic++;
} else if (s.IsNotFound()) {
LongDoubleToStr(long_double_by, new_value);
if (!parsed_hashes_meta_value.CheckModifyCount(1)){
return Status::InvalidArgument("hash size overflow");
}
parsed_hashes_meta_value.ModifyCount(1);
batch.Put(handles_[0], key, meta_value);
batch.Put(handles_[1], hashes_data_key.Encode(), *new_value);
Expand Down Expand Up @@ -561,6 +570,9 @@ Status RedisHashes::HMSet(const Slice& key, const std::vector<FieldValue>& fvs)
ParsedHashesMetaValue parsed_hashes_meta_value(&meta_value);
if (parsed_hashes_meta_value.IsStale() || parsed_hashes_meta_value.count() == 0) {
version = parsed_hashes_meta_value.InitialMetaValue();
if (!parsed_hashes_meta_value.check_set_count(static_cast<int32_t>(filtered_fvs.size()))) {
return Status::InvalidArgument("hash size overflow");
}
parsed_hashes_meta_value.set_count(static_cast<int32_t>(filtered_fvs.size()));
batch.Put(handles_[0], key, meta_value);
for (const auto& fv : filtered_fvs) {
Expand All @@ -584,6 +596,9 @@ Status RedisHashes::HMSet(const Slice& key, const std::vector<FieldValue>& fvs)
return s;
}
}
if (!parsed_hashes_meta_value.CheckModifyCount(count)){
return Status::InvalidArgument("hash size overflow");
}
parsed_hashes_meta_value.ModifyCount(count);
batch.Put(handles_[0], key, meta_value);
}
Expand Down Expand Up @@ -634,6 +649,9 @@ Status RedisHashes::HSet(const Slice& key, const Slice& field, const Slice& valu
statistic++;
}
} else if (s.IsNotFound()) {
if (!parsed_hashes_meta_value.CheckModifyCount(1)){
return Status::InvalidArgument("hash size overflow");
}
parsed_hashes_meta_value.ModifyCount(1);
batch.Put(handles_[0], key, meta_value);
batch.Put(handles_[1], hashes_data_key.Encode(), value);
Expand Down Expand Up @@ -683,6 +701,9 @@ Status RedisHashes::HSetnx(const Slice& key, const Slice& field, const Slice& va
if (s.ok()) {
*ret = 0;
} else if (s.IsNotFound()) {
if (!parsed_hashes_meta_value.CheckModifyCount(1)){
return Status::InvalidArgument("hash size overflow");
}
parsed_hashes_meta_value.ModifyCount(1);
batch.Put(handles_[0], key, meta_value);
batch.Put(handles_[1], hashes_data_key.Encode(), value);
Expand Down
27 changes: 27 additions & 0 deletions src/storage/src/redis_sets.cc
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,9 @@ rocksdb::Status RedisSets::SAdd(const Slice& key, const std::vector<std::string>
ParsedSetsMetaValue parsed_sets_meta_value(&meta_value);
if (parsed_sets_meta_value.IsStale() || parsed_sets_meta_value.count() == 0) {
version = parsed_sets_meta_value.InitialMetaValue();
if (!parsed_sets_meta_value.check_set_count(static_cast<int32_t>(filtered_members.size()))) {
return Status::InvalidArgument("set size overflow");
}
parsed_sets_meta_value.set_count(static_cast<int32_t>(filtered_members.size()));
batch.Put(handles_[0], key, meta_value);
for (const auto& member : filtered_members) {
Expand All @@ -243,6 +246,9 @@ rocksdb::Status RedisSets::SAdd(const Slice& key, const std::vector<std::string>
if (cnt == 0) {
return rocksdb::Status::OK();
} else {
if (!parsed_sets_meta_value.CheckModifyCount(cnt)){
return Status::InvalidArgument("set size overflow");
}
parsed_sets_meta_value.ModifyCount(cnt);
batch.Put(handles_[0], key, meta_value);
}
Expand Down Expand Up @@ -420,6 +426,9 @@ rocksdb::Status RedisSets::SDiffstore(const Slice& destination, const std::vecto
ParsedSetsMetaValue parsed_sets_meta_value(&meta_value);
statistic = parsed_sets_meta_value.count();
version = parsed_sets_meta_value.InitialMetaValue();
if (!parsed_sets_meta_value.check_set_count(static_cast<int32_t>(members.size()))) {
return Status::InvalidArgument("set size overflow");
}
parsed_sets_meta_value.set_count(static_cast<int32_t>(members.size()));
batch.Put(handles_[0], destination, meta_value);
} else if (s.IsNotFound()) {
Expand Down Expand Up @@ -603,6 +612,9 @@ rocksdb::Status RedisSets::SInterstore(const Slice& destination, const std::vect
ParsedSetsMetaValue parsed_sets_meta_value(&meta_value);
statistic = parsed_sets_meta_value.count();
version = parsed_sets_meta_value.InitialMetaValue();
if (!parsed_sets_meta_value.check_set_count(static_cast<int32_t>(members.size()))) {
return Status::InvalidArgument("set size overflow");
}
parsed_sets_meta_value.set_count(static_cast<int32_t>(members.size()));
batch.Put(handles_[0], destination, meta_value);
} else if (s.IsNotFound()) {
Expand Down Expand Up @@ -714,6 +726,9 @@ rocksdb::Status RedisSets::SMove(const Slice& source, const Slice& destination,
s = db_->Get(default_read_options_, handles_[1], sets_member_key.Encode(), &member_value);
if (s.ok()) {
*ret = 1;
if (!parsed_sets_meta_value.CheckModifyCount(-1)){
return Status::InvalidArgument("set size overflow");
}
parsed_sets_meta_value.ModifyCount(-1);
batch.Put(handles_[0], source, meta_value);
batch.Delete(handles_[1], sets_member_key.Encode());
Expand Down Expand Up @@ -747,6 +762,9 @@ rocksdb::Status RedisSets::SMove(const Slice& source, const Slice& destination,
SetsMemberKey sets_member_key(destination, version, member);
s = db_->Get(default_read_options_, handles_[1], sets_member_key.Encode(), &member_value);
if (s.IsNotFound()) {
if (!parsed_sets_meta_value.CheckModifyCount(1)){
return Status::InvalidArgument("set size overflow");
}
parsed_sets_meta_value.ModifyCount(1);
batch.Put(handles_[0], destination, meta_value);
batch.Put(handles_[1], sets_member_key.Encode(), Slice());
Expand Down Expand Up @@ -843,6 +861,9 @@ rocksdb::Status RedisSets::SPop(const Slice& key, std::vector<std::string>* memb
}
}

if (!parsed_sets_meta_value.CheckModifyCount(static_cast<int32_t>(-cnt))){
return Status::InvalidArgument("set size overflow");
}
parsed_sets_meta_value.ModifyCount(static_cast<int32_t>(-cnt));
batch.Put(handles_[0], key, meta_value);
delete iter;
Expand Down Expand Up @@ -974,6 +995,9 @@ rocksdb::Status RedisSets::SRem(const Slice& key, const std::vector<std::string>
}
}
*ret = cnt;
if (!parsed_sets_meta_value.CheckModifyCount(-cnt)){
return Status::InvalidArgument("set size overflow");
}
parsed_sets_meta_value.ModifyCount(-cnt);
batch.Put(handles_[0], key, meta_value);
}
Expand Down Expand Up @@ -1086,6 +1110,9 @@ rocksdb::Status RedisSets::SUnionstore(const Slice& destination, const std::vect
ParsedSetsMetaValue parsed_sets_meta_value(&meta_value);
statistic = parsed_sets_meta_value.count();
version = parsed_sets_meta_value.InitialMetaValue();
if (!parsed_sets_meta_value.check_set_count(static_cast<int32_t>(members.size()))) {
return Status::InvalidArgument("set size overflow");
}
parsed_sets_meta_value.set_count(static_cast<int32_t>(members.size()));
batch.Put(handles_[0], destination, meta_value);
} else if (s.IsNotFound()) {
Expand Down
30 changes: 30 additions & 0 deletions src/storage/src/redis_zsets.cc
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,9 @@ Status RedisZSets::ZPopMax(const Slice& key, const int64_t count, std::vector<Sc
batch.Delete(handles_[2], iter->key());
}
delete iter;
if (!parsed_zsets_meta_value.CheckModifyCount(-del_cnt)){
return Status::InvalidArgument("zset size overflow");
}
parsed_zsets_meta_value.ModifyCount(-del_cnt);
batch.Put(handles_[0], key, meta_value);
s = db_->Write(default_write_options_, &batch);
Expand Down Expand Up @@ -284,6 +287,9 @@ Status RedisZSets::ZPopMin(const Slice& key, const int64_t count, std::vector<Sc
batch.Delete(handles_[2], iter->key());
}
delete iter;
if (!parsed_zsets_meta_value.CheckModifyCount(-del_cnt)){
return Status::InvalidArgument("zset size overflow");
}
parsed_zsets_meta_value.ModifyCount(-del_cnt);
batch.Put(handles_[0], key, meta_value);
s = db_->Write(default_write_options_, &batch);
Expand Down Expand Up @@ -360,6 +366,9 @@ Status RedisZSets::ZAdd(const Slice& key, const std::vector<ScoreMember>& score_
cnt++;
}
}
if (!parsed_zsets_meta_value.CheckModifyCount(cnt)){
return Status::InvalidArgument("zset size overflow");
}
parsed_zsets_meta_value.ModifyCount(cnt);
batch.Put(handles_[0], key, meta_value);
*ret = cnt;
Expand Down Expand Up @@ -494,6 +503,9 @@ Status RedisZSets::ZIncrby(const Slice& key, const Slice& member, double increme
statistic++;
} else if (s.IsNotFound()) {
score = increment;
if (!parsed_zsets_meta_value.CheckModifyCount(1)){
return Status::InvalidArgument("zset size overflow");
}
parsed_zsets_meta_value.ModifyCount(1);
batch.Put(handles_[0], key, meta_value);
} else {
Expand Down Expand Up @@ -717,6 +729,9 @@ Status RedisZSets::ZRem(const Slice& key, const std::vector<std::string>& member
}
}
*ret = del_cnt;
if (!parsed_zsets_meta_value.CheckModifyCount(-del_cnt)){
return Status::InvalidArgument("zset size overflow");
}
parsed_zsets_meta_value.ModifyCount(-del_cnt);
batch.Put(handles_[0], key, meta_value);
}
Expand Down Expand Up @@ -768,6 +783,9 @@ Status RedisZSets::ZRemrangebyrank(const Slice& key, int32_t start, int32_t stop
}
delete iter;
*ret = del_cnt;
if (!parsed_zsets_meta_value.CheckModifyCount(-del_cnt)){
return Status::InvalidArgument("zset size overflow");
}
parsed_zsets_meta_value.ModifyCount(-del_cnt);
batch.Put(handles_[0], key, meta_value);
}
Expand Down Expand Up @@ -832,6 +850,9 @@ Status RedisZSets::ZRemrangebyscore(const Slice& key, double min, double max, bo
}
delete iter;
*ret = del_cnt;
if (!parsed_zsets_meta_value.CheckModifyCount(-del_cnt)){
return Status::InvalidArgument("zset size overflow");
}
parsed_zsets_meta_value.ModifyCount(-del_cnt);
batch.Put(handles_[0], key, meta_value);
}
Expand Down Expand Up @@ -1093,6 +1114,9 @@ Status RedisZSets::ZUnionstore(const Slice& destination, const std::vector<std::
ParsedZSetsMetaValue parsed_zsets_meta_value(&meta_value);
statistic = parsed_zsets_meta_value.count();
version = parsed_zsets_meta_value.InitialMetaValue();
if (!parsed_zsets_meta_value.check_set_count(static_cast<int32_t>(member_score_map.size()))) {
return Status::InvalidArgument("zset size overflow");
}
parsed_zsets_meta_value.set_count(static_cast<int32_t>(member_score_map.size()));
batch.Put(handles_[0], destination, meta_value);
} else {
Expand Down Expand Up @@ -1220,6 +1244,9 @@ Status RedisZSets::ZInterstore(const Slice& destination, const std::vector<std::
ParsedZSetsMetaValue parsed_zsets_meta_value(&meta_value);
statistic = parsed_zsets_meta_value.count();
version = parsed_zsets_meta_value.InitialMetaValue();
if (!parsed_zsets_meta_value.check_set_count(static_cast<int32_t>(final_score_members.size()))) {
return Status::InvalidArgument("zset size overflow");
}
parsed_zsets_meta_value.set_count(static_cast<int32_t>(final_score_members.size()));
batch.Put(handles_[0], destination, meta_value);
} else {
Expand Down Expand Up @@ -1360,6 +1387,9 @@ Status RedisZSets::ZRemrangebylex(const Slice& key, const Slice& min, const Slic
delete iter;
}
if (del_cnt > 0) {
if (!parsed_zsets_meta_value.CheckModifyCount(-del_cnt)){
return Status::InvalidArgument("zset size overflow");
}
parsed_zsets_meta_value.ModifyCount(-del_cnt);
batch.Put(handles_[0], key, meta_value);
*ret = del_cnt;
Expand Down

0 comments on commit 89444f7

Please sign in to comment.