@@ -187,6 +187,31 @@ static void VideoReceiveThreadProc(void* context) {
187
187
if (encrypted ) {
188
188
PENC_VIDEO_HEADER encHeader = (PENC_VIDEO_HEADER )encryptedBuffer ;
189
189
190
+ // If this frame is below our current frame number, discard it before decryption
191
+ // to save CPU cycles decrypting FEC shards for a frame we already reassembled.
192
+ //
193
+ // Since this is happening _before_ decryption, this packet is not trusted yet.
194
+ // It's imperative that we do not mutate any state based on this packet until
195
+ // after it has been decrypted successfully!
196
+ //
197
+ // It's possible for an attacker to inject a fake packet that has any value of
198
+ // header fields they want, however this provides them no benefit because we will
199
+ // simply drop said packet here (if it's below the current frame number) or it
200
+ // will pass this check and be dropped during decryption (if contents is tampered)
201
+ // or after decryption in the RTP queue (if it's a replay of a previous authentic
202
+ // packet from the host).
203
+ //
204
+ // In short, an attacker spoofing this value via MITM or sending malicious values
205
+ // impersonating the host from off-link doesn't gain them anything. If they have
206
+ // a true MITM, they can DoS our connection by just dropping all our traffic, so
207
+ // tampering with packets to fail this check doesn't accomplish anything they
208
+ // couldn't already do. If they're not on-link, we just throw their malicious
209
+ // traffic away (as mentioned in the paragraph above) and continue accepting
210
+ // legitmate video traffic.
211
+ if (encHeader -> frameNumber && LE32 (encHeader -> frameNumber ) < RtpvGetCurrentFrameNumber (& rtpQueue )) {
212
+ continue ;
213
+ }
214
+
190
215
if (!PltDecryptMessage (decryptionCtx , ALGORITHM_AES_GCM , 0 ,
191
216
(unsigned char * )StreamConfig .remoteInputAesKey , sizeof (StreamConfig .remoteInputAesKey ),
192
217
encHeader -> iv , sizeof (encHeader -> iv ),
0 commit comments