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

bugfix: set/zset/hash member may overflow #2106

Merged
merged 4 commits into from
Nov 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading