diff --git a/tddb/td/db/binlog/Binlog.cpp b/tddb/td/db/binlog/Binlog.cpp index a49bbbc5..63f687c9 100644 --- a/tddb/td/db/binlog/Binlog.cpp +++ b/tddb/td/db/binlog/Binlog.cpp @@ -121,9 +121,9 @@ class BinlogReader { return Status::Error(PSLICE() << "Too small event " << tag("size", size_)); } if (size_ % 4 != 0) { - return Status::Error(-2, PSLICE() << "Event of size " << size_ << " at offset " << offset() << " out of " << expected_size_ << ' ' - << tag("is_encrypted", is_encrypted_) - << format::as_hex_dump<4>(Slice(input_->prepare_read().truncate(28)))); + return Status::Error(-2, PSLICE() << "Event of size " << size_ << " at offset " << offset() << " out of " + << expected_size_ << ' ' << tag("is_encrypted", is_encrypted_) + << format::as_hex_dump<4>(Slice(input_->prepare_read().truncate(28)))); } state_ = ReadEvent; } @@ -305,7 +305,12 @@ void Binlog::do_event(BinlogEvent &&event) { fd_size_ += event.raw_event_.size(); if (state_ == State::Run || state_ == State::Reindex) { - VLOG(binlog) << "Write binlog event: " << format::cond(state_ == State::Reindex, "[reindex] ") << event; + VLOG(binlog) << "Write binlog event: " << format::cond(state_ == State::Reindex, "[reindex] "); + auto validate_status = event.validate(); + if (validate_status.is_error()) { + LOG(FATAL) << "Failed to validate binlog event " << validate_status << " " + << format::as_hex_dump<4>(Slice(event.raw_event_.as_slice().truncate(28))); + } switch (encryption_type_) { case EncryptionType::None: { buffer_writer_.append(event.raw_event_.clone()); diff --git a/tddb/td/db/binlog/BinlogEvent.cpp b/tddb/td/db/binlog/BinlogEvent.cpp index b9db884d..3cadbda0 100644 --- a/tddb/td/db/binlog/BinlogEvent.cpp +++ b/tddb/td/db/binlog/BinlogEvent.cpp @@ -28,11 +28,23 @@ Status BinlogEvent::init(BufferSlice &&raw_event, bool check_crc) { auto calculated_crc = crc32(raw_event.as_slice().truncate(size_ - EVENT_TAIL_SIZE)); if (calculated_crc != crc32_) { return Status::Error(PSLICE() << "crc mismatch " << tag("actual", format::as_hex(calculated_crc)) - << tag("expected", format::as_hex(crc32_))); + << tag("expected", format::as_hex(crc32_)) << public_to_string()); } } raw_event_ = std::move(raw_event); return Status::OK(); } +Status BinlogEvent::validate() const { + BinlogEvent event; + if (raw_event_.size() < 4) { + return Status::Error("Too small event"); + } + uint32 size = TlParser(raw_event_.as_slice().truncate(4)).fetch_int(); + if (size_ != size) { + return Status::Error(PSLICE() << "Size of event changed: " << tag("was", size_) << tag("now", size)); + } + return event.init(raw_event_.clone(), true); +} + } // namespace td diff --git a/tddb/td/db/binlog/BinlogEvent.h b/tddb/td/db/binlog/BinlogEvent.h index 140d7e4f..8b1f2d9b 100644 --- a/tddb/td/db/binlog/BinlogEvent.h +++ b/tddb/td/db/binlog/BinlogEvent.h @@ -106,6 +106,8 @@ struct BinlogEvent { return PSTRING() << "LogEvent[" << tag("id", format::as_hex(id_)) << tag("type", type_) << tag("flags", flags_) << tag("data", data_.size()) << "]" << debug_info_; } + + Status validate() const; }; inline StringBuilder &operator<<(StringBuilder &sb, const BinlogEvent &event) {