WebRTC - VP9 Processing Use-After-Free

EDB-ID:

45443


Platform:

Multiple

Published:

2018-09-21

There is a use-after-free in VP9 processing in WebRTC. In the method RtpFrameReferenceFinder::ManageFrameVp9 the following code occurs:

 auto gof_info_it = gof_info_.find((codec_header.temporal_idx == 0)
                                          ? codec_header.tl0_pic_idx - 1
                                          : codec_header.tl0_pic_idx);

   ... // snip

    info = &gof_info_it->second;
  }

  // Clean up info for base layers that are too old.
  uint8_t old_tl0_pic_idx = codec_header.tl0_pic_idx - kMaxGofSaved;
  auto clean_gof_info_to = gof_info_.lower_bound(old_tl0_pic_idx);
  gof_info_.erase(gof_info_.begin(), clean_gof_info_to);

  FrameReceivedVp9(frame->id.picture_id, info);

tl0_pic_idx is extracted from the incoming packet, and it if is higher than any picture id that exists in gof_info_, the entire vector will be erased, and info will be used in the call FrameReceivedVp9 even though it has been freed.

ASAN output:

==163231==ERROR: AddressSanitizer: heap-use-after-free on address 0x6060000031d0 at pc 0x0000014b0e1e bp 0x7ffe607dfd30 sp 0x7ffe607dfd28
READ of size 2 at 0x6060000031d0 thread T0
    #0 0x14b0e1d in webrtc::video_coding::RtpFrameReferenceFinder::FrameReceivedVp9(unsigned short, webrtc::video_coding::RtpFrameReferenceFinder::GofInfo*) modules/video_coding/rtp_frame_reference_finder.cc:569:31
    #1 0x14ac2c5 in webrtc::video_coding::RtpFrameReferenceFinder::ManageFrameVp9(webrtc::video_coding::RtpFrameObject*) modules/video_coding/rtp_frame_reference_finder.cc:499:3
    #2 0x14a7849 in ManageFrameInternal modules/video_coding/rtp_frame_reference_finder.cc:89:14
    #3 0x14a7849 in webrtc::video_coding::RtpFrameReferenceFinder::ManageFrame(std::__1::unique_ptr<webrtc::video_coding::RtpFrameObject, std::__1::default_delete<webrtc::video_coding::RtpFrameObject> >) modules/video_coding/rtp_frame_reference_finder.cc:43
    #4 0x148a87e in non-virtual thunk to webrtc::RtpVideoStreamReceiver::OnReceivedFrame(std::__1::unique_ptr<webrtc::video_coding::RtpFrameObject, std::__1::default_delete<webrtc::video_coding::RtpFrameObject> >) video/rtp_video_stream_receiver.cc:336:22
    #5 0x1496f41 in webrtc::video_coding::PacketBuffer::InsertPacket(webrtc::VCMPacket*) modules/video_coding/packet_buffer.cc:130:31
    #6 0x1487e59 in webrtc::RtpVideoStreamReceiver::OnReceivedPayloadData(unsigned char const*, unsigned long, webrtc::WebRtcRTPHeader const*) video/rtp_video_stream_receiver.cc:231:19
    #7 0x12d9144 in webrtc::RTPReceiverVideo::ParseRtpPacket(webrtc::WebRtcRTPHeader*, webrtc::PayloadUnion const&, unsigned char const*, unsigned long, long) modules/rtp_rtcp/source/rtp_receiver_video.cc:109:26
    #8 0x12cc80d in webrtc::RtpReceiverImpl::IncomingRtpPacket(webrtc::RTPHeader const&, unsigned char const*, unsigned long, webrtc::PayloadUnion) modules/rtp_rtcp/source/rtp_receiver_impl.cc:181:42
    #9 0x1488e52 in webrtc::RtpVideoStreamReceiver::ReceivePacket(unsigned char const*, unsigned long, webrtc::RTPHeader const&) video/rtp_video_stream_receiver.cc:399:20
    #10 0x1488b03 in webrtc::RtpVideoStreamReceiver::OnRecoveredPacket(unsigned char const*, unsigned long) video/rtp_video_stream_receiver.cc:245:3
    #11 0x14b925c in webrtc::UlpfecReceiverImpl::ProcessReceivedFec() modules/rtp_rtcp/source/ulpfec_receiver_impl.cc:244:35
    #12 0x148bd42 in webrtc::RtpVideoStreamReceiver::ParseAndHandleEncapsulatingHeader(unsigned char const*, unsigned long, webrtc::RTPHeader const&) video/rtp_video_stream_receiver.cc:421:23
    #13 0x1488d51 in webrtc::RtpVideoStreamReceiver::ReceivePacket(unsigned char const*, unsigned long, webrtc::RTPHeader const&) video/rtp_video_stream_receiver.cc:390:5
    #14 0x14899f8 in webrtc::RtpVideoStreamReceiver::OnRtpPacket(webrtc::RtpPacketReceived const&) video/rtp_video_stream_receiver.cc:290:3
    #15 0x90c486 in webrtc::RtpDemuxer::OnRtpPacket(webrtc::RtpPacketReceived const&) call/rtp_demuxer.cc:157:11
    #16 0x9131bd in webrtc::RtpStreamReceiverController::OnRtpPacket(webrtc::RtpPacketReceived const&) call/rtp_stream_receiver_controller.cc:55:19
    #17 0x129940d in webrtc::internal::Call::DeliverRtp(webrtc::MediaType, rtc::CopyOnWriteBuffer, webrtc::PacketTime const&) call/call.cc:1321:36
    #18 0x129a8d5 in webrtc::internal::Call::DeliverPacket(webrtc::MediaType, rtc::CopyOnWriteBuffer, webrtc::PacketTime const&) call/call.cc:1361:10
    #19 0x61fe06 in webrtc::RtpReplay() video/replay.cc:279:31
    #20 0x62337d in main video/replay.cc:343:3
    #21 0x7f5ae03d82b0 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x202b0)

0x6060000031d0 is located 48 bytes inside of 56-byte region [0x6060000031a0,0x6060000031d8)
freed by thread T0 here:
    #0 0x61bbb2 in operator delete(void*) /b/build/slave/linux_upload_clang/build/src/third_party/llvm/compiler-rt/lib/asan/asan_new_delete.cc:150:3
    #1 0x14ac26c in __libcpp_deallocate buildtools/third_party/libc++/trunk/include/new:279:10
    #2 0x14ac26c in deallocate buildtools/third_party/libc++/trunk/include/memory:1802
    #3 0x14ac26c in deallocate buildtools/third_party/libc++/trunk/include/memory:1556
    #4 0x14ac26c in erase buildtools/third_party/libc++/trunk/include/__tree:2370
    #5 0x14ac26c in erase buildtools/third_party/libc++/trunk/include/__tree:2379
    #6 0x14ac26c in erase buildtools/third_party/libc++/trunk/include/map:1200
    #7 0x14ac26c in webrtc::video_coding::RtpFrameReferenceFinder::ManageFrameVp9(webrtc::video_coding::RtpFrameObject*) modules/video_coding/rtp_frame_reference_finder.cc:497
    #8 0x14a7849 in ManageFrameInternal modules/video_coding/rtp_frame_reference_finder.cc:89:14
    #9 0x14a7849 in webrtc::video_coding::RtpFrameReferenceFinder::ManageFrame(std::__1::unique_ptr<webrtc::video_coding::RtpFrameObject, std::__1::default_delete<webrtc::video_coding::RtpFrameObject> >) modules/video_coding/rtp_frame_reference_finder.cc:43
    #10 0x148a87e in non-virtual thunk to webrtc::RtpVideoStreamReceiver::OnReceivedFrame(std::__1::unique_ptr<webrtc::video_coding::RtpFrameObject, std::__1::default_delete<webrtc::video_coding::RtpFrameObject> >) video/rtp_video_stream_receiver.cc:336:22
    #11 0x1496f41 in webrtc::video_coding::PacketBuffer::InsertPacket(webrtc::VCMPacket*) modules/video_coding/packet_buffer.cc:130:31
    #12 0x1487e59 in webrtc::RtpVideoStreamReceiver::OnReceivedPayloadData(unsigned char const*, unsigned long, webrtc::WebRtcRTPHeader const*) video/rtp_video_stream_receiver.cc:231:19
    #13 0x12d9144 in webrtc::RTPReceiverVideo::ParseRtpPacket(webrtc::WebRtcRTPHeader*, webrtc::PayloadUnion const&, unsigned char const*, unsigned long, long) modules/rtp_rtcp/source/rtp_receiver_video.cc:109:26
    #14 0x12cc80d in webrtc::RtpReceiverImpl::IncomingRtpPacket(webrtc::RTPHeader const&, unsigned char const*, unsigned long, webrtc::PayloadUnion) modules/rtp_rtcp/source/rtp_receiver_impl.cc:181:42
    #15 0x1488e52 in webrtc::RtpVideoStreamReceiver::ReceivePacket(unsigned char const*, unsigned long, webrtc::RTPHeader const&) video/rtp_video_stream_receiver.cc:399:20
    #16 0x1488b03 in webrtc::RtpVideoStreamReceiver::OnRecoveredPacket(unsigned char const*, unsigned long) video/rtp_video_stream_receiver.cc:245:3
    #17 0x14b925c in webrtc::UlpfecReceiverImpl::ProcessReceivedFec() modules/rtp_rtcp/source/ulpfec_receiver_impl.cc:244:35
    #18 0x148bd42 in webrtc::RtpVideoStreamReceiver::ParseAndHandleEncapsulatingHeader(unsigned char const*, unsigned long, webrtc::RTPHeader const&) video/rtp_video_stream_receiver.cc:421:23
    #19 0x1488d51 in webrtc::RtpVideoStreamReceiver::ReceivePacket(unsigned char const*, unsigned long, webrtc::RTPHeader const&) video/rtp_video_stream_receiver.cc:390:5
    #20 0x14899f8 in webrtc::RtpVideoStreamReceiver::OnRtpPacket(webrtc::RtpPacketReceived const&) video/rtp_video_stream_receiver.cc:290:3
    #21 0x90c486 in webrtc::RtpDemuxer::OnRtpPacket(webrtc::RtpPacketReceived const&) call/rtp_demuxer.cc:157:11
    #22 0x9131bd in webrtc::RtpStreamReceiverController::OnRtpPacket(webrtc::RtpPacketReceived const&) call/rtp_stream_receiver_controller.cc:55:19
    #23 0x129940d in webrtc::internal::Call::DeliverRtp(webrtc::MediaType, rtc::CopyOnWriteBuffer, webrtc::PacketTime const&) call/call.cc:1321:36
    #24 0x129a8d5 in webrtc::internal::Call::DeliverPacket(webrtc::MediaType, rtc::CopyOnWriteBuffer, webrtc::PacketTime const&) call/call.cc:1361:10
    #25 0x61fe06 in webrtc::RtpReplay() video/replay.cc:279:31
    #26 0x62337d in main video/replay.cc:343:3
    #27 0x7f5ae03d82b0 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x202b0)

previously allocated by thread T0 here:
    #0 0x61af72 in operator new(unsigned long) /b/build/slave/linux_upload_clang/build/src/third_party/llvm/compiler-rt/lib/asan/asan_new_delete.cc:93:3
    #1 0x14b664f in __libcpp_allocate buildtools/third_party/libc++/trunk/include/new:259:10
    #2 0x14b664f in allocate buildtools/third_party/libc++/trunk/include/memory:1799
    #3 0x14b664f in allocate buildtools/third_party/libc++/trunk/include/memory:1548
    #4 0x14b664f in __construct_node<const short &, webrtc::video_coding::RtpFrameReferenceFinder::GofInfo> buildtools/third_party/libc++/trunk/include/__tree:2191
    #5 0x14b664f in std::__1::pair<std::__1::__tree_iterator<std::__1::__value_type<unsigned char, webrtc::video_coding::RtpFrameReferenceFinder::GofInfo>, std::__1::__tree_node<std::__1::__value_type<unsigned char, webrtc::video_coding::RtpFrameReferenceFinder::GofInfo>, void*>*, long>, bool> std::__1::__tree<std::__1::__value_type<unsigned char, webrtc::video_coding::RtpFrameReferenceFinder::GofInfo>, std::__1::__map_value_compare<unsigned char, std::__1::__value_type<unsigned char, webrtc::video_coding::RtpFrameReferenceFinder::GofInfo>, webrtc::DescendingSeqNumComp<unsigned char, (unsigned char)0>, true>, std::__1::allocator<std::__1::__value_type<unsigned char, webrtc::video_coding::RtpFrameReferenceFinder::GofInfo> > >::__emplace_unique_impl<short const&, webrtc::video_coding::RtpFrameReferenceFinder::GofInfo>(short const&, webrtc::video_coding::RtpFrameReferenceFinder::GofInfo&&) buildtools/third_party/libc++/trunk/include/__tree:2203
    #6 0x14ab9ca in __emplace_unique<const short &, webrtc::video_coding::RtpFrameReferenceFinder::GofInfo> buildtools/third_party/libc++/trunk/include/__tree:1193:16
    #7 0x14ab9ca in emplace<const short &, webrtc::video_coding::RtpFrameReferenceFinder::GofInfo> buildtools/third_party/libc++/trunk/include/map:1041
    #8 0x14ab9ca in webrtc::video_coding::RtpFrameReferenceFinder::ManageFrameVp9(webrtc::video_coding::RtpFrameObject*) modules/video_coding/rtp_frame_reference_finder.cc:445
    #9 0x14a7849 in ManageFrameInternal modules/video_coding/rtp_frame_reference_finder.cc:89:14
    #10 0x14a7849 in webrtc::video_coding::RtpFrameReferenceFinder::ManageFrame(std::__1::unique_ptr<webrtc::video_coding::RtpFrameObject, std::__1::default_delete<webrtc::video_coding::RtpFrameObject> >) modules/video_coding/rtp_frame_reference_finder.cc:43
    #11 0x148a87e in non-virtual thunk to webrtc::RtpVideoStreamReceiver::OnReceivedFrame(std::__1::unique_ptr<webrtc::video_coding::RtpFrameObject, std::__1::default_delete<webrtc::video_coding::RtpFrameObject> >) video/rtp_video_stream_receiver.cc:336:22
    #12 0x1496f41 in webrtc::video_coding::PacketBuffer::InsertPacket(webrtc::VCMPacket*) modules/video_coding/packet_buffer.cc:130:31
    #13 0x1487e59 in webrtc::RtpVideoStreamReceiver::OnReceivedPayloadData(unsigned char const*, unsigned long, webrtc::WebRtcRTPHeader const*) video/rtp_video_stream_receiver.cc:231:19
    #14 0x12d9144 in webrtc::RTPReceiverVideo::ParseRtpPacket(webrtc::WebRtcRTPHeader*, webrtc::PayloadUnion const&, unsigned char const*, unsigned long, long) modules/rtp_rtcp/source/rtp_receiver_video.cc:109:26
    #15 0x12cc80d in webrtc::RtpReceiverImpl::IncomingRtpPacket(webrtc::RTPHeader const&, unsigned char const*, unsigned long, webrtc::PayloadUnion) modules/rtp_rtcp/source/rtp_receiver_impl.cc:181:42
    #16 0x1488e52 in webrtc::RtpVideoStreamReceiver::ReceivePacket(unsigned char const*, unsigned long, webrtc::RTPHeader const&) video/rtp_video_stream_receiver.cc:399:20
    #17 0x1488b03 in webrtc::RtpVideoStreamReceiver::OnRecoveredPacket(unsigned char const*, unsigned long) video/rtp_video_stream_receiver.cc:245:3
    #18 0x14b925c in webrtc::UlpfecReceiverImpl::ProcessReceivedFec() modules/rtp_rtcp/source/ulpfec_receiver_impl.cc:244:35
    #19 0x148bd42 in webrtc::RtpVideoStreamReceiver::ParseAndHandleEncapsulatingHeader(unsigned char const*, unsigned long, webrtc::RTPHeader const&) video/rtp_video_stream_receiver.cc:421:23
    #20 0x1488d51 in webrtc::RtpVideoStreamReceiver::ReceivePacket(unsigned char const*, unsigned long, webrtc::RTPHeader const&) video/rtp_video_stream_receiver.cc:390:5
    #21 0x14899f8 in webrtc::RtpVideoStreamReceiver::OnRtpPacket(webrtc::RtpPacketReceived const&) video/rtp_video_stream_receiver.cc:290:3
    #22 0x90c486 in webrtc::RtpDemuxer::OnRtpPacket(webrtc::RtpPacketReceived const&) call/rtp_demuxer.cc:157:11
    #23 0x9131bd in webrtc::RtpStreamReceiverController::OnRtpPacket(webrtc::RtpPacketReceived const&) call/rtp_stream_receiver_controller.cc:55:19
    #24 0x129940d in webrtc::internal::Call::DeliverRtp(webrtc::MediaType, rtc::CopyOnWriteBuffer, webrtc::PacketTime const&) call/call.cc:1321:36
    #25 0x129a8d5 in webrtc::internal::Call::DeliverPacket(webrtc::MediaType, rtc::CopyOnWriteBuffer, webrtc::PacketTime const&) call/call.cc:1361:10
    #26 0x61fe06 in webrtc::RtpReplay() video/replay.cc:279:31
    #27 0x62337d in main video/replay.cc:343:3
    #28 0x7f5ae03d82b0 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x202b0)

SUMMARY: AddressSanitizer: heap-use-after-free modules/video_coding/rtp_frame_reference_finder.cc:569:31 in webrtc::video_coding::RtpFrameReferenceFinder::FrameReceivedVp9(unsigned short, webrtc::video_coding::RtpFrameReferenceFinder::GofInfo*)
Shadow bytes around the buggy address:
  0x0c0c7fff85e0: 00 00 00 00 00 00 00 fa fa fa fa fa fd fd fd fd
  0x0c0c7fff85f0: fd fd fd fd fa fa fa fa 00 00 00 00 00 00 00 00
  0x0c0c7fff8600: fa fa fa fa 00 00 00 00 00 00 00 00 fa fa fa fa
  0x0c0c7fff8610: 00 00 00 00 00 00 00 00 fa fa fa fa 00 00 00 00
  0x0c0c7fff8620: 00 00 00 00 fa fa fa fa fd fd fd fd fd fd fd fa
=>0x0c0c7fff8630: fa fa fa fa fd fd fd fd fd fd[fd]fa fa fa fa fa
  0x0c0c7fff8640: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0c7fff8650: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0c7fff8660: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0c7fff8670: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0c7fff8680: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==163231==ABORTING

To reproduce the issue:

1) apply new.patch to your webrtc directory
2) build video_replay
3) download the attached filed into the same directory
4) run ./video_replay --input_file uaf


Proof of Concept:
https://github.com/offensive-security/exploitdb-bin-sploits/raw/master/bin-sploits/45443.zip