Harden QuicFramer::DecryptPayload to avoid dereferencing bad EncryptionLevels This was originally dschinazi's cl/246356749 This provides another layer of defense for fixing the bugs also fixed by cl/246391380. gfe-relnote: Add bounds checks to QuicFramer::DecryptPayload; not flag protected PiperOrigin-RevId: 246411510 Change-Id: Ibe6c71327716e56a465ef88e9d24018b6db93b77
diff --git a/quic/core/quic_framer.cc b/quic/core/quic_framer.cc index 0264e80..eb1c8c0 100644 --- a/quic/core/quic_framer.cc +++ b/quic/core/quic_framer.cc
@@ -3978,12 +3978,25 @@ size_t buffer_length, size_t* decrypted_length, EncryptionLevel* decrypted_level) { + if (!EncryptionLevelIsValid(decrypter_level_)) { + QUIC_BUG << "Attempted to decrypt with bad decrypter_level_"; + return false; + } EncryptionLevel level = decrypter_level_; QuicDecrypter* decrypter = decrypter_[level].get(); QuicDecrypter* alternative_decrypter = nullptr; if (version().KnowsWhichDecrypterToUse()) { QUIC_RELOADABLE_FLAG_COUNT(quic_v44_disable_trial_decryption); + if (header.form == GOOGLE_QUIC_PACKET) { + QUIC_BUG << "Attempted to decrypt GOOGLE_QUIC_PACKET with a version that " + "knows which decrypter to use"; + return false; + } level = GetEncryptionLevel(header); + if (!EncryptionLevelIsValid(level)) { + QUIC_BUG << "Attempted to decrypt with bad level"; + return false; + } decrypter = decrypter_[level].get(); if (decrypter == nullptr) { return false; @@ -3993,10 +4006,17 @@ decrypter->SetDiversificationNonce(*header.nonce); } } else if (alternative_decrypter_level_ != NUM_ENCRYPTION_LEVELS) { + if (!EncryptionLevelIsValid(alternative_decrypter_level_)) { + QUIC_BUG << "Attempted to decrypt with bad alternative_decrypter_level_"; + return false; + } alternative_decrypter = decrypter_[alternative_decrypter_level_].get(); } - DCHECK(decrypter != nullptr); + if (decrypter == nullptr) { + QUIC_BUG << "Attempting to decrypt without decrypter"; + return false; + } bool success = decrypter->DecryptPacket( header.packet_number.ToUint64(), associated_data, encrypted, @@ -4030,6 +4050,11 @@ visitor_->OnDecryptedPacket(alternative_decrypter_level_); *decrypted_level = decrypter_level_; if (alternative_decrypter_latch_) { + if (!EncryptionLevelIsValid(alternative_decrypter_level_)) { + QUIC_BUG << "Attempted to latch alternate decrypter with bad " + "alternative_decrypter_level_"; + return false; + } // Switch to the alternative decrypter and latch so that we cannot // switch back. decrypter_level_ = alternative_decrypter_level_;
diff --git a/quic/core/quic_types.h b/quic/core/quic_types.h index 9b114f1..9031d2a 100644 --- a/quic/core/quic_types.h +++ b/quic/core/quic_types.h
@@ -390,6 +390,10 @@ NUM_ENCRYPTION_LEVELS, }; +inline bool EncryptionLevelIsValid(EncryptionLevel level) { + return ENCRYPTION_INITIAL <= level && level < NUM_ENCRYPTION_LEVELS; +} + enum AddressChangeType : uint8_t { // IP address and port remain unchanged. NO_CHANGE,