Skip to content

Commit 89444f7

Browse files
authored
bugfix: set/zset/hash member may overflow (#2106)
* Update base_meta_value_format.h * Update redis_hashes.cc * Update redis_sets.cc * Update redis_zsets.cc
1 parent 28831ef commit 89444f7

4 files changed

Lines changed: 94 additions & 0 deletions

File tree

src/storage/src/base_meta_value_format.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,13 @@ class ParsedBaseMetaValue : public ParsedInternalValue {
8989

9090
int32_t count() { return count_; }
9191

92+
bool check_set_count(size_t count) {
93+
if (count > INT32_MAX) {
94+
return false;
95+
}
96+
return true;
97+
}
98+
9299
void set_count(int32_t count) {
93100
count_ = count;
94101
if (value_) {
@@ -97,6 +104,15 @@ class ParsedBaseMetaValue : public ParsedInternalValue {
97104
}
98105
}
99106

107+
bool CheckModifyCount(int32_t delta) {
108+
int64_t count = count_;
109+
count += delta;
110+
if (count < 0 || count > INT32_MAX) {
111+
return false;
112+
}
113+
return true;
114+
}
115+
100116
void ModifyCount(int32_t delta) {
101117
count_ += delta;
102118
if (value_) {

src/storage/src/redis_hashes.cc

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,9 @@ Status RedisHashes::HDel(const Slice& key, const std::vector<std::string>& field
234234
}
235235
}
236236
*ret = del_cnt;
237+
if (!parsed_hashes_meta_value.CheckModifyCount(-del_cnt)){
238+
return Status::InvalidArgument("hash size overflow");
239+
}
237240
parsed_hashes_meta_value.ModifyCount(-del_cnt);
238241
batch.Put(handles_[0], key, meta_value);
239242
}
@@ -348,6 +351,9 @@ Status RedisHashes::HIncrby(const Slice& key, const Slice& field, int64_t value,
348351
statistic++;
349352
} else if (s.IsNotFound()) {
350353
Int64ToStr(value_buf, 32, value);
354+
if (!parsed_hashes_meta_value.CheckModifyCount(1)){
355+
return Status::InvalidArgument("hash size overflow");
356+
}
351357
parsed_hashes_meta_value.ModifyCount(1);
352358
batch.Put(handles_[0], key, meta_value);
353359
batch.Put(handles_[1], hashes_data_key.Encode(), value_buf);
@@ -421,6 +427,9 @@ Status RedisHashes::HIncrbyfloat(const Slice& key, const Slice& field, const Sli
421427
statistic++;
422428
} else if (s.IsNotFound()) {
423429
LongDoubleToStr(long_double_by, new_value);
430+
if (!parsed_hashes_meta_value.CheckModifyCount(1)){
431+
return Status::InvalidArgument("hash size overflow");
432+
}
424433
parsed_hashes_meta_value.ModifyCount(1);
425434
batch.Put(handles_[0], key, meta_value);
426435
batch.Put(handles_[1], hashes_data_key.Encode(), *new_value);
@@ -561,6 +570,9 @@ Status RedisHashes::HMSet(const Slice& key, const std::vector<FieldValue>& fvs)
561570
ParsedHashesMetaValue parsed_hashes_meta_value(&meta_value);
562571
if (parsed_hashes_meta_value.IsStale() || parsed_hashes_meta_value.count() == 0) {
563572
version = parsed_hashes_meta_value.InitialMetaValue();
573+
if (!parsed_hashes_meta_value.check_set_count(static_cast<int32_t>(filtered_fvs.size()))) {
574+
return Status::InvalidArgument("hash size overflow");
575+
}
564576
parsed_hashes_meta_value.set_count(static_cast<int32_t>(filtered_fvs.size()));
565577
batch.Put(handles_[0], key, meta_value);
566578
for (const auto& fv : filtered_fvs) {
@@ -584,6 +596,9 @@ Status RedisHashes::HMSet(const Slice& key, const std::vector<FieldValue>& fvs)
584596
return s;
585597
}
586598
}
599+
if (!parsed_hashes_meta_value.CheckModifyCount(count)){
600+
return Status::InvalidArgument("hash size overflow");
601+
}
587602
parsed_hashes_meta_value.ModifyCount(count);
588603
batch.Put(handles_[0], key, meta_value);
589604
}
@@ -634,6 +649,9 @@ Status RedisHashes::HSet(const Slice& key, const Slice& field, const Slice& valu
634649
statistic++;
635650
}
636651
} else if (s.IsNotFound()) {
652+
if (!parsed_hashes_meta_value.CheckModifyCount(1)){
653+
return Status::InvalidArgument("hash size overflow");
654+
}
637655
parsed_hashes_meta_value.ModifyCount(1);
638656
batch.Put(handles_[0], key, meta_value);
639657
batch.Put(handles_[1], hashes_data_key.Encode(), value);
@@ -683,6 +701,9 @@ Status RedisHashes::HSetnx(const Slice& key, const Slice& field, const Slice& va
683701
if (s.ok()) {
684702
*ret = 0;
685703
} else if (s.IsNotFound()) {
704+
if (!parsed_hashes_meta_value.CheckModifyCount(1)){
705+
return Status::InvalidArgument("hash size overflow");
706+
}
686707
parsed_hashes_meta_value.ModifyCount(1);
687708
batch.Put(handles_[0], key, meta_value);
688709
batch.Put(handles_[1], hashes_data_key.Encode(), value);

src/storage/src/redis_sets.cc

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,9 @@ rocksdb::Status RedisSets::SAdd(const Slice& key, const std::vector<std::string>
217217
ParsedSetsMetaValue parsed_sets_meta_value(&meta_value);
218218
if (parsed_sets_meta_value.IsStale() || parsed_sets_meta_value.count() == 0) {
219219
version = parsed_sets_meta_value.InitialMetaValue();
220+
if (!parsed_sets_meta_value.check_set_count(static_cast<int32_t>(filtered_members.size()))) {
221+
return Status::InvalidArgument("set size overflow");
222+
}
220223
parsed_sets_meta_value.set_count(static_cast<int32_t>(filtered_members.size()));
221224
batch.Put(handles_[0], key, meta_value);
222225
for (const auto& member : filtered_members) {
@@ -243,6 +246,9 @@ rocksdb::Status RedisSets::SAdd(const Slice& key, const std::vector<std::string>
243246
if (cnt == 0) {
244247
return rocksdb::Status::OK();
245248
} else {
249+
if (!parsed_sets_meta_value.CheckModifyCount(cnt)){
250+
return Status::InvalidArgument("set size overflow");
251+
}
246252
parsed_sets_meta_value.ModifyCount(cnt);
247253
batch.Put(handles_[0], key, meta_value);
248254
}
@@ -420,6 +426,9 @@ rocksdb::Status RedisSets::SDiffstore(const Slice& destination, const std::vecto
420426
ParsedSetsMetaValue parsed_sets_meta_value(&meta_value);
421427
statistic = parsed_sets_meta_value.count();
422428
version = parsed_sets_meta_value.InitialMetaValue();
429+
if (!parsed_sets_meta_value.check_set_count(static_cast<int32_t>(members.size()))) {
430+
return Status::InvalidArgument("set size overflow");
431+
}
423432
parsed_sets_meta_value.set_count(static_cast<int32_t>(members.size()));
424433
batch.Put(handles_[0], destination, meta_value);
425434
} else if (s.IsNotFound()) {
@@ -603,6 +612,9 @@ rocksdb::Status RedisSets::SInterstore(const Slice& destination, const std::vect
603612
ParsedSetsMetaValue parsed_sets_meta_value(&meta_value);
604613
statistic = parsed_sets_meta_value.count();
605614
version = parsed_sets_meta_value.InitialMetaValue();
615+
if (!parsed_sets_meta_value.check_set_count(static_cast<int32_t>(members.size()))) {
616+
return Status::InvalidArgument("set size overflow");
617+
}
606618
parsed_sets_meta_value.set_count(static_cast<int32_t>(members.size()));
607619
batch.Put(handles_[0], destination, meta_value);
608620
} else if (s.IsNotFound()) {
@@ -714,6 +726,9 @@ rocksdb::Status RedisSets::SMove(const Slice& source, const Slice& destination,
714726
s = db_->Get(default_read_options_, handles_[1], sets_member_key.Encode(), &member_value);
715727
if (s.ok()) {
716728
*ret = 1;
729+
if (!parsed_sets_meta_value.CheckModifyCount(-1)){
730+
return Status::InvalidArgument("set size overflow");
731+
}
717732
parsed_sets_meta_value.ModifyCount(-1);
718733
batch.Put(handles_[0], source, meta_value);
719734
batch.Delete(handles_[1], sets_member_key.Encode());
@@ -747,6 +762,9 @@ rocksdb::Status RedisSets::SMove(const Slice& source, const Slice& destination,
747762
SetsMemberKey sets_member_key(destination, version, member);
748763
s = db_->Get(default_read_options_, handles_[1], sets_member_key.Encode(), &member_value);
749764
if (s.IsNotFound()) {
765+
if (!parsed_sets_meta_value.CheckModifyCount(1)){
766+
return Status::InvalidArgument("set size overflow");
767+
}
750768
parsed_sets_meta_value.ModifyCount(1);
751769
batch.Put(handles_[0], destination, meta_value);
752770
batch.Put(handles_[1], sets_member_key.Encode(), Slice());
@@ -843,6 +861,9 @@ rocksdb::Status RedisSets::SPop(const Slice& key, std::vector<std::string>* memb
843861
}
844862
}
845863

864+
if (!parsed_sets_meta_value.CheckModifyCount(static_cast<int32_t>(-cnt))){
865+
return Status::InvalidArgument("set size overflow");
866+
}
846867
parsed_sets_meta_value.ModifyCount(static_cast<int32_t>(-cnt));
847868
batch.Put(handles_[0], key, meta_value);
848869
delete iter;
@@ -974,6 +995,9 @@ rocksdb::Status RedisSets::SRem(const Slice& key, const std::vector<std::string>
974995
}
975996
}
976997
*ret = cnt;
998+
if (!parsed_sets_meta_value.CheckModifyCount(-cnt)){
999+
return Status::InvalidArgument("set size overflow");
1000+
}
9771001
parsed_sets_meta_value.ModifyCount(-cnt);
9781002
batch.Put(handles_[0], key, meta_value);
9791003
}
@@ -1086,6 +1110,9 @@ rocksdb::Status RedisSets::SUnionstore(const Slice& destination, const std::vect
10861110
ParsedSetsMetaValue parsed_sets_meta_value(&meta_value);
10871111
statistic = parsed_sets_meta_value.count();
10881112
version = parsed_sets_meta_value.InitialMetaValue();
1113+
if (!parsed_sets_meta_value.check_set_count(static_cast<int32_t>(members.size()))) {
1114+
return Status::InvalidArgument("set size overflow");
1115+
}
10891116
parsed_sets_meta_value.set_count(static_cast<int32_t>(members.size()));
10901117
batch.Put(handles_[0], destination, meta_value);
10911118
} else if (s.IsNotFound()) {

src/storage/src/redis_zsets.cc

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,9 @@ Status RedisZSets::ZPopMax(const Slice& key, const int64_t count, std::vector<Sc
242242
batch.Delete(handles_[2], iter->key());
243243
}
244244
delete iter;
245+
if (!parsed_zsets_meta_value.CheckModifyCount(-del_cnt)){
246+
return Status::InvalidArgument("zset size overflow");
247+
}
245248
parsed_zsets_meta_value.ModifyCount(-del_cnt);
246249
batch.Put(handles_[0], key, meta_value);
247250
s = db_->Write(default_write_options_, &batch);
@@ -284,6 +287,9 @@ Status RedisZSets::ZPopMin(const Slice& key, const int64_t count, std::vector<Sc
284287
batch.Delete(handles_[2], iter->key());
285288
}
286289
delete iter;
290+
if (!parsed_zsets_meta_value.CheckModifyCount(-del_cnt)){
291+
return Status::InvalidArgument("zset size overflow");
292+
}
287293
parsed_zsets_meta_value.ModifyCount(-del_cnt);
288294
batch.Put(handles_[0], key, meta_value);
289295
s = db_->Write(default_write_options_, &batch);
@@ -360,6 +366,9 @@ Status RedisZSets::ZAdd(const Slice& key, const std::vector<ScoreMember>& score_
360366
cnt++;
361367
}
362368
}
369+
if (!parsed_zsets_meta_value.CheckModifyCount(cnt)){
370+
return Status::InvalidArgument("zset size overflow");
371+
}
363372
parsed_zsets_meta_value.ModifyCount(cnt);
364373
batch.Put(handles_[0], key, meta_value);
365374
*ret = cnt;
@@ -494,6 +503,9 @@ Status RedisZSets::ZIncrby(const Slice& key, const Slice& member, double increme
494503
statistic++;
495504
} else if (s.IsNotFound()) {
496505
score = increment;
506+
if (!parsed_zsets_meta_value.CheckModifyCount(1)){
507+
return Status::InvalidArgument("zset size overflow");
508+
}
497509
parsed_zsets_meta_value.ModifyCount(1);
498510
batch.Put(handles_[0], key, meta_value);
499511
} else {
@@ -717,6 +729,9 @@ Status RedisZSets::ZRem(const Slice& key, const std::vector<std::string>& member
717729
}
718730
}
719731
*ret = del_cnt;
732+
if (!parsed_zsets_meta_value.CheckModifyCount(-del_cnt)){
733+
return Status::InvalidArgument("zset size overflow");
734+
}
720735
parsed_zsets_meta_value.ModifyCount(-del_cnt);
721736
batch.Put(handles_[0], key, meta_value);
722737
}
@@ -768,6 +783,9 @@ Status RedisZSets::ZRemrangebyrank(const Slice& key, int32_t start, int32_t stop
768783
}
769784
delete iter;
770785
*ret = del_cnt;
786+
if (!parsed_zsets_meta_value.CheckModifyCount(-del_cnt)){
787+
return Status::InvalidArgument("zset size overflow");
788+
}
771789
parsed_zsets_meta_value.ModifyCount(-del_cnt);
772790
batch.Put(handles_[0], key, meta_value);
773791
}
@@ -832,6 +850,9 @@ Status RedisZSets::ZRemrangebyscore(const Slice& key, double min, double max, bo
832850
}
833851
delete iter;
834852
*ret = del_cnt;
853+
if (!parsed_zsets_meta_value.CheckModifyCount(-del_cnt)){
854+
return Status::InvalidArgument("zset size overflow");
855+
}
835856
parsed_zsets_meta_value.ModifyCount(-del_cnt);
836857
batch.Put(handles_[0], key, meta_value);
837858
}
@@ -1093,6 +1114,9 @@ Status RedisZSets::ZUnionstore(const Slice& destination, const std::vector<std::
10931114
ParsedZSetsMetaValue parsed_zsets_meta_value(&meta_value);
10941115
statistic = parsed_zsets_meta_value.count();
10951116
version = parsed_zsets_meta_value.InitialMetaValue();
1117+
if (!parsed_zsets_meta_value.check_set_count(static_cast<int32_t>(member_score_map.size()))) {
1118+
return Status::InvalidArgument("zset size overflow");
1119+
}
10961120
parsed_zsets_meta_value.set_count(static_cast<int32_t>(member_score_map.size()));
10971121
batch.Put(handles_[0], destination, meta_value);
10981122
} else {
@@ -1220,6 +1244,9 @@ Status RedisZSets::ZInterstore(const Slice& destination, const std::vector<std::
12201244
ParsedZSetsMetaValue parsed_zsets_meta_value(&meta_value);
12211245
statistic = parsed_zsets_meta_value.count();
12221246
version = parsed_zsets_meta_value.InitialMetaValue();
1247+
if (!parsed_zsets_meta_value.check_set_count(static_cast<int32_t>(final_score_members.size()))) {
1248+
return Status::InvalidArgument("zset size overflow");
1249+
}
12231250
parsed_zsets_meta_value.set_count(static_cast<int32_t>(final_score_members.size()));
12241251
batch.Put(handles_[0], destination, meta_value);
12251252
} else {
@@ -1360,6 +1387,9 @@ Status RedisZSets::ZRemrangebylex(const Slice& key, const Slice& min, const Slic
13601387
delete iter;
13611388
}
13621389
if (del_cnt > 0) {
1390+
if (!parsed_zsets_meta_value.CheckModifyCount(-del_cnt)){
1391+
return Status::InvalidArgument("zset size overflow");
1392+
}
13631393
parsed_zsets_meta_value.ModifyCount(-del_cnt);
13641394
batch.Put(handles_[0], key, meta_value);
13651395
*ret = del_cnt;

0 commit comments

Comments
 (0)