Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] srt-live-transmit Fails to Recover from Malformed NAK Packet #3088

Open
FelixSodermanNeti opened this issue Dec 13, 2024 · 13 comments · May be fixed by #3105
Open

[BUG] srt-live-transmit Fails to Recover from Malformed NAK Packet #3088

FelixSodermanNeti opened this issue Dec 13, 2024 · 13 comments · May be fixed by #3105
Labels
[core] Area: Changes in SRT library core Type: Bug Indicates an unexpected problem or unintended behavior
Milestone

Comments

@FelixSodermanNeti
Copy link

Issue: srt-live-transmit Fails to Recover from Malformed NAK Packet

Describe the Bug

The srt-live-transmit application fails to recover when it receives a malformed NAK (Negative Acknowledgment) packet with the "Up to sequence number" field in the Loss List set to -1 (0xFFFFFFFF). Once this state is triggered, the listener enters an error state where all received bytes are dropped. Additionally, the caller cannot reconnect, even after a restart, unless the listener is manually restarted.

Packet Structure:

Below is the structure of the relevant SRT header and Loss List (NAK packet):

    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+- SRT Header +-+-+-+-+-+-+-+-+-+-+-+-+-+
   |1|        Control Type         |           Reserved            |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                   Type-specific Information                   |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                           Timestamp                           |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                   Destination SRT Socket ID                   |
   +-+-+-+-+-+-+-+-+-+-+-+- CIF (Loss List) -+-+-+-+-+-+-+-+-+-+-+-+
   |1|         Range of lost packets from sequence number          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |0|                    Up to sequence number                    |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Example Packets:

  • Correct NAK Packet:
80 03 00 00  
00 00 00 00  
00 29 9d 2a  
3f 0d a6 fb  
aa d4 2a e3  
2a d4 2a e7
  • Malformed NAK Packet: (NOTE: Only the last row is changed)
80 03 00 00  
00 00 00 00  
00 29 9d 2a  
3f 0d a6 fb  
aa d4 2a e3  
ff ff ff ff

Steps to Reproduce

  1. Use a two-way UDP proxy to drop three consecutive packets and modify the NAK packet on its return path.
    UDP proxy script: Link to Proxy Script.

  2. Run the following setup:

    • Listener (Source):

      ./srt-live-transmit udp://127.0.0.1:1111 "srt://127.0.0.1:3333?adapter=127.0.0.1&latency=120&maxbw=-1&mode=listener"
    • Caller (Target):

      ./srt-live-transmit "srt://127.0.0.1:2222?latency=120&conntimeo=31393&mode=caller" udp://127.0.0.1:4444
    • UDP Proxy:

      python3 srt-proxy.py --caller-port 2222 --listener-port 3333 --break-at-pkt-NAK 5000
    • UDP Stream Input:

      tsplay MY_FAVORITE_MOVIE.ts 127.0.0.1:1111 -loop
    • (Optional) UDP Stream Monitor:

      ffplay udp://127.0.0.1:4444
  3. Observe logs on the listener when the malformed NAK packet is received.

Listener Logs Example:

15:34:11.722690/SRT:RcvQ:w1!W:SRT.in: @936953725: rcv LOSSREPORT rng 1266728376 - -1 with last sent 1266728394 - DISCARDING
15:34:11.722795/SRT:RcvQ:w1!W:SRT.in: @936953725: out-of-band LOSSREPORT received; BUG or ATTACK - last sent %1266728394 vs loss %-1
...

The listener reports repeated byte losses and fails to recover:

3102188 bytes lost, 6655576 bytes sent, 18314020 bytes received  
15226120 bytes lost, 6655576 bytes sent, 30437952 bytes received  
...

Expected Behavior

The srt-live-transmit listener should handle malformed NAK packets gracefully, recover from the error state, and allow new callers to connect without requiring a restart.

System Information

  • OS: Linux Ubuntu 22.04.4 LTS
  • SRT Version: 1.5.4
@FelixSodermanNeti FelixSodermanNeti added the Type: Bug Indicates an unexpected problem or unintended behavior label Dec 13, 2024
@maxsharabayko maxsharabayko added the [core] Area: Changes in SRT library core label Dec 13, 2024
@maxsharabayko maxsharabayko added this to the v1.5.5 milestone Dec 13, 2024
@FelixSodermanNeti
Copy link
Author

FelixSodermanNeti commented Dec 16, 2024

I was able to fix the issue by adding the following two lines to the void processCtrlLossReport function in srtcore/core.cpp:

updateBrokenConnection();
completeBrokenConnectionDependencies(SRT_ECONNFAIL); // LOCKS!

Original Code:

Before the modification, the code looked like this:

if (!secure)
{
    LOGC(inlog.Warn,
        log << CONID() << "out-of-band LOSSREPORT received; BUG or ATTACK - last sent %" << m_iSndCurrSeqNo
        << " vs loss %" << wrong_loss);
    // this should not happen: attack or bug
    m_bBroken = true;
    m_iBrokenCounter = 0;
    return;
}

Updated Code:

After applying the fix, the updated code is as follows:

if (!secure)
{
    LOGC(inlog.Warn,
        log << CONID() << "out-of-band LOSSREPORT received; BUG or ATTACK - last sent %" << m_iSndCurrSeqNo
        << " vs loss %" << wrong_loss);
    // this should not happen: attack or bug
    m_bBroken = true;
    m_iBrokenCounter = 0;
    updateBrokenConnection();
    completeBrokenConnectionDependencies(SRT_ECONNFAIL); // LOCKS!
    return;
}

Does this seem like a reasonable fix, or could this change introduce any unintended side effects?

@FelixSodermanNeti
Copy link
Author

Furthermore, I found similar code in the void processCtrlAck function in srtcore/core.cpp:

// Check the validation of the ack
if (CSeqNo::seqcmp(ackdata_seqno, CSeqNo::incseq(m_iSndCurrSeqNo)) > 0)
{
    // this should not happen: attack or bug
    LOGC(gglog.Error,
            log << CONID() << "ATTACK/IPE: incoming ack seq " << ackdata_seqno << " exceeds current "
            << m_iSndCurrSeqNo << " by " << (CSeqNo::seqoff(m_iSndCurrSeqNo, ackdata_seqno) - 1) << "!");
    m_bBroken        = true;
    m_iBrokenCounter = 0;
    return;
}

I haven’t attempted to reproduce this issue, but I suspect it might be vulnerable to a similar type of malformed packet.

@ethouris
Copy link
Collaborator

ethouris commented Dec 17, 2024

These two calls are prone to introduce deadlocks, hence one needs to be extremely careful with this.

Would you be able to compile it using thread sanitizer and try to reproduce the problem on that fixed version and see what problems it reports? Note that some of the reports will come, but don't worry, many are worked around and or are false-positives.

NOTE: SRT_EXTRA_CFLAGS variable in CMake can be used for extra flags, such as -fsanitize=thread.

@FelixSodermanNeti
Copy link
Author

FelixSodermanNeti commented Dec 18, 2024

Here are the results when running with -fsanitize=thread enabled. This build is from the master track (commit hash: f109fb1).

Listener:

./srt-live-transmit udp://127.0.0.1:1111 "srt://127.0.0.1:3333?adapter=127.0.0.1&latency=120&maxbw=-1&mode=listener"
Media path: 'udp://127.0.0.1:1111' --> 'srt://127.0.0.1:3333?adapter=127.0.0.1&latency=120&maxbw=-1&mode=listener'
12:34:23.821204/srt-live-transm*E:SRT.ea: remove_usock: @899641007 not found as either socket or group. Removing only from epoll system.
Accepted SRT target connection
==================
WARNING: ThreadSanitizer: data race (pid=20887)
  Read of size 8 at 0x7ba80000c0e0 by thread T3:
    #0 srt::CUDT::updateCC(srt::ETransmissionEvent, srt::EventVariant) <null> (srt-live-transmit+0xeba4e)
    #1 srt::CUDT::checkTimers() <null> (srt-live-transmit+0xf36c3)
    #2 srt::CRcvQueue::worker(void*) <null> (srt-live-transmit+0x15284b)

  Previous write of size 8 at 0x7ba80000c0e0 by main thread (mutexes: write M300, write M305, write M304):
    #0 srt::CSrtConfig::set(SRT_SOCKOPT, void const*, int) <null> (srt-live-transmit+0x160bf3)
    #1 srt::CUDT::setOpt(SRT_SOCKOPT, void const*, int) <null> (srt-live-transmit+0xefa72)
    #2 srt::CUDT::setsockopt(int, int, SRT_SOCKOPT, void const*, int) <null> (srt-live-transmit+0xa671e)
    #3 srt_setsockopt <null> (srt-live-transmit+0x161d76)
    #4 bool SocketOption::apply<(SocketOption::Domain)1, int>(int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) const <null> (srt-live-transmit+0x7aef6)
    #5 SrtCommon::ConfigurePost(int) <null> (srt-live-transmit+0x81659)
    #6 SrtCommon::AcceptNewClient() <null> (srt-live-transmit+0x7dc1c)
    #7 SrtTarget::AcceptNewClient() <null> (srt-live-transmit+0x870f3)
    #8 main <null> (srt-live-transmit+0x4813a)

  Location is heap block of size 22128 at 0x7ba80000c000 allocated by thread T3:
    #0 operator new(unsigned long) ../../../../src/libsanitizer/tsan/tsan_new_delete.cpp:64 (libtsan.so.0+0x8bc72)
    #1 srt::CUDTUnited::newConnection(int, srt::sockaddr_any const&, srt::CPacket const&, srt::CHandShake&, int&, srt::CUDT*&) <null> (srt-live-transmit+0xb1cbf)
    #2 srt::CUDT::processConnectRequest(srt::sockaddr_any const&, srt::CPacket&) <null> (srt-live-transmit+0xff006)
    #3 srt::CRcvQueue::worker_ProcessConnectionRequest(srt::CUnit*, srt::sockaddr_any const&) <null> (srt-live-transmit+0x150fe5)
    #4 srt::CRcvQueue::worker(void*) <null> (srt-live-transmit+0x152721)

  Mutex M300 (0x7ba800011198) created at:
    #0 pthread_mutex_init ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1220 (libtsan.so.0+0x4a616)
    #1 srt::sync::Mutex::Mutex() <null> (srt-live-transmit+0x169b61)
    #2 srt::CUDT::CUDT(srt::CUDTSocket*, srt::CUDT const&) <null> (srt-live-transmit+0xfc7b3)
    #3 srt::CUDTUnited::newConnection(int, srt::sockaddr_any const&, srt::CPacket const&, srt::CHandShake&, int&, srt::CUDT*&) <null> (srt-live-transmit+0xb1de0)
    #4 srt::CUDT::processConnectRequest(srt::sockaddr_any const&, srt::CPacket&) <null> (srt-live-transmit+0xff006)
    #5 srt::CRcvQueue::worker_ProcessConnectionRequest(srt::CUnit*, srt::sockaddr_any const&) <null> (srt-live-transmit+0x150fe5)
    #6 srt::CRcvQueue::worker(void*) <null> (srt-live-transmit+0x152721)

  Mutex M305 (0x7ba8000112c0) created at:
    #0 pthread_mutex_init ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1220 (libtsan.so.0+0x4a616)
    #1 srt::sync::Mutex::Mutex() <null> (srt-live-transmit+0x169b61)
    #2 srt::CUDT::CUDT(srt::CUDTSocket*, srt::CUDT const&) <null> (srt-live-transmit+0xfc854)
    #3 srt::CUDTUnited::newConnection(int, srt::sockaddr_any const&, srt::CPacket const&, srt::CHandShake&, int&, srt::CUDT*&) <null> (srt-live-transmit+0xb1de0)
    #4 srt::CUDT::processConnectRequest(srt::sockaddr_any const&, srt::CPacket&) <null> (srt-live-transmit+0xff006)
    #5 srt::CRcvQueue::worker_ProcessConnectionRequest(srt::CUnit*, srt::sockaddr_any const&) <null> (srt-live-transmit+0x150fe5)
    #6 srt::CRcvQueue::worker(void*) <null> (srt-live-transmit+0x152721)

  Mutex M304 (0x7ba800011298) created at:
    #0 pthread_mutex_init ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1220 (libtsan.so.0+0x4a616)
    #1 srt::sync::Mutex::Mutex() <null> (srt-live-transmit+0x169b61)
    #2 srt::CUDT::CUDT(srt::CUDTSocket*, srt::CUDT const&) <null> (srt-live-transmit+0xfc83d)
    #3 srt::CUDTUnited::newConnection(int, srt::sockaddr_any const&, srt::CPacket const&, srt::CHandShake&, int&, srt::CUDT*&) <null> (srt-live-transmit+0xb1de0)
    #4 srt::CUDT::processConnectRequest(srt::sockaddr_any const&, srt::CPacket&) <null> (srt-live-transmit+0xff006)
    #5 srt::CRcvQueue::worker_ProcessConnectionRequest(srt::CUnit*, srt::sockaddr_any const&) <null> (srt-live-transmit+0x150fe5)
    #6 srt::CRcvQueue::worker(void*) <null> (srt-live-transmit+0x152721)

  Thread T3 (tid=20891, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:962 (libtsan.so.0+0x5ea79)
    #1 srt::sync::CThread::create(void* (*)(void*), void*) <null> (srt-live-transmit+0x16b12d)
    #2 srt::sync::CThread::CThread(void* (*)(void*), void*) <null> (srt-live-transmit+0x16b889)
    #3 srt::sync::StartThread(srt::sync::CThread&, void* (*)(void*), void*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) <null> (srt-live-transmit+0x163f55)
    #4 srt::CRcvQueue::init(int, unsigned long, int, int, srt::CChannel*, srt::sync::CTimer*) <null> (srt-live-transmit+0x14cdce)
    #5 srt::CUDTUnited::updateMux(srt::CUDTSocket*, srt::sockaddr_any const&, int const*) <null> (srt-live-transmit+0xa9aa5)
    #6 srt::CUDTUnited::bind(srt::CUDTSocket*, srt::sockaddr_any const&) <null> (srt-live-transmit+0xacb7f)
    #7 srt::CUDT::bind(int, sockaddr const*, int) <null> (srt-live-transmit+0xacdd3)
    #8 srt_bind <null> (srt-live-transmit+0x1618a9)
    #9 SrtCommon::PrepareListener(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, int) <null> (srt-live-transmit+0x7d576)
    #10 SrtCommon::Init(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, bool) <null> (srt-live-transmit+0x84d8a)
    #11 std::unique_ptr<Target, std::default_delete<Target> > CreateMedium<Target>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) <null> (srt-live-transmit+0x90353)
    #12 Target::Create(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) <null> (srt-live-transmit+0x85fd5)
    #13 main <null> (srt-live-transmit+0x48c1e)

SUMMARY: ThreadSanitizer: data race (/home/felsod/Downloads/srt/srt-live-transmit+0xeba4e) in srt::CUDT::updateCC(srt::ETransmissionEvent, srt::EventVariant)
==================
==================
WARNING: ThreadSanitizer: data race (pid=20887)
  Read of size 8 at 0x7b1400002810 by thread T3:
    #0 srt::CUDT::updateCC(srt::ETransmissionEvent, srt::EventVariant) <null> (srt-live-transmit+0xec4b3)
    #1 srt::CUDT::checkTimers() <null> (srt-live-transmit+0xf36c3)
    #2 srt::CRcvQueue::worker(void*) <null> (srt-live-transmit+0x15284b)

  Previous write of size 8 at 0x7b1400002810 by main thread (mutexes: write M300, write M305, write M304):
    #0 srt::LiveCC::updateBandwidth(long, long) <null> (srt-live-transmit+0x154fe6)
    #1 srt::CUDT::updateCC(srt::ETransmissionEvent, srt::EventVariant) <null> (srt-live-transmit+0xec6cc)
    #2 srt::CUDT::setOpt(SRT_SOCKOPT, void const*, int) <null> (srt-live-transmit+0xf0357)
    #3 srt::CUDT::setsockopt(int, int, SRT_SOCKOPT, void const*, int) <null> (srt-live-transmit+0xa671e)
    #4 srt_setsockopt <null> (srt-live-transmit+0x161d76)
    #5 bool SocketOption::apply<(SocketOption::Domain)1, int>(int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) const <null> (srt-live-transmit+0x7aef6)
    #6 SrtCommon::ConfigurePost(int) <null> (srt-live-transmit+0x81659)
    #7 SrtCommon::AcceptNewClient() <null> (srt-live-transmit+0x7dc1c)
    #8 SrtTarget::AcceptNewClient() <null> (srt-live-transmit+0x870f3)
    #9 main <null> (srt-live-transmit+0x4813a)

  Location is heap block of size 80 at 0x7b1400002800 allocated by thread T3:
    #0 operator new(unsigned long) ../../../../src/libsanitizer/tsan/tsan_new_delete.cpp:64 (libtsan.so.0+0x8bc72)
    #1 srt::Creator<srt::LiveCC>::Create(srt::CUDT*) <null> (srt-live-transmit+0x157118)
    #2 srt::SrtCongestion::configure(srt::CUDT*) <null> (srt-live-transmit+0x153fd7)
    #3 srt::CUDT::setupCC() <null> (srt-live-transmit+0xed269)
    #4 srt::CUDT::acceptAndRespond(srt::sockaddr_any const&, srt::sockaddr_any const&, srt::CPacket const&, srt::CHandShake&) <null> (srt-live-transmit+0x1102e8)
    #5 srt::CUDTUnited::newConnection(int, srt::sockaddr_any const&, srt::CPacket const&, srt::CHandShake&, int&, srt::CUDT*&) <null> (srt-live-transmit+0xb255a)
    #6 srt::CUDT::processConnectRequest(srt::sockaddr_any const&, srt::CPacket&) <null> (srt-live-transmit+0xff006)
    #7 srt::CRcvQueue::worker_ProcessConnectionRequest(srt::CUnit*, srt::sockaddr_any const&) <null> (srt-live-transmit+0x150fe5)
    #8 srt::CRcvQueue::worker(void*) <null> (srt-live-transmit+0x152721)

  Mutex M300 (0x7ba800011198) created at:
    #0 pthread_mutex_init ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1220 (libtsan.so.0+0x4a616)
    #1 srt::sync::Mutex::Mutex() <null> (srt-live-transmit+0x169b61)
    #2 srt::CUDT::CUDT(srt::CUDTSocket*, srt::CUDT const&) <null> (srt-live-transmit+0xfc7b3)
    #3 srt::CUDTUnited::newConnection(int, srt::sockaddr_any const&, srt::CPacket const&, srt::CHandShake&, int&, srt::CUDT*&) <null> (srt-live-transmit+0xb1de0)
    #4 srt::CUDT::processConnectRequest(srt::sockaddr_any const&, srt::CPacket&) <null> (srt-live-transmit+0xff006)
    #5 srt::CRcvQueue::worker_ProcessConnectionRequest(srt::CUnit*, srt::sockaddr_any const&) <null> (srt-live-transmit+0x150fe5)
    #6 srt::CRcvQueue::worker(void*) <null> (srt-live-transmit+0x152721)

  Mutex M305 (0x7ba8000112c0) created at:
    #0 pthread_mutex_init ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1220 (libtsan.so.0+0x4a616)
    #1 srt::sync::Mutex::Mutex() <null> (srt-live-transmit+0x169b61)
    #2 srt::CUDT::CUDT(srt::CUDTSocket*, srt::CUDT const&) <null> (srt-live-transmit+0xfc854)
    #3 srt::CUDTUnited::newConnection(int, srt::sockaddr_any const&, srt::CPacket const&, srt::CHandShake&, int&, srt::CUDT*&) <null> (srt-live-transmit+0xb1de0)
    #4 srt::CUDT::processConnectRequest(srt::sockaddr_any const&, srt::CPacket&) <null> (srt-live-transmit+0xff006)
    #5 srt::CRcvQueue::worker_ProcessConnectionRequest(srt::CUnit*, srt::sockaddr_any const&) <null> (srt-live-transmit+0x150fe5)
    #6 srt::CRcvQueue::worker(void*) <null> (srt-live-transmit+0x152721)

  Mutex M304 (0x7ba800011298) created at:
    #0 pthread_mutex_init ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1220 (libtsan.so.0+0x4a616)
    #1 srt::sync::Mutex::Mutex() <null> (srt-live-transmit+0x169b61)
    #2 srt::CUDT::CUDT(srt::CUDTSocket*, srt::CUDT const&) <null> (srt-live-transmit+0xfc83d)
    #3 srt::CUDTUnited::newConnection(int, srt::sockaddr_any const&, srt::CPacket const&, srt::CHandShake&, int&, srt::CUDT*&) <null> (srt-live-transmit+0xb1de0)
    #4 srt::CUDT::processConnectRequest(srt::sockaddr_any const&, srt::CPacket&) <null> (srt-live-transmit+0xff006)
    #5 srt::CRcvQueue::worker_ProcessConnectionRequest(srt::CUnit*, srt::sockaddr_any const&) <null> (srt-live-transmit+0x150fe5)
    #6 srt::CRcvQueue::worker(void*) <null> (srt-live-transmit+0x152721)

  Thread T3 (tid=20891, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:962 (libtsan.so.0+0x5ea79)
    #1 srt::sync::CThread::create(void* (*)(void*), void*) <null> (srt-live-transmit+0x16b12d)
    #2 srt::sync::CThread::CThread(void* (*)(void*), void*) <null> (srt-live-transmit+0x16b889)
    #3 srt::sync::StartThread(srt::sync::CThread&, void* (*)(void*), void*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) <null> (srt-live-transmit+0x163f55)
    #4 srt::CRcvQueue::init(int, unsigned long, int, int, srt::CChannel*, srt::sync::CTimer*) <null> (srt-live-transmit+0x14cdce)
    #5 srt::CUDTUnited::updateMux(srt::CUDTSocket*, srt::sockaddr_any const&, int const*) <null> (srt-live-transmit+0xa9aa5)
    #6 srt::CUDTUnited::bind(srt::CUDTSocket*, srt::sockaddr_any const&) <null> (srt-live-transmit+0xacb7f)
    #7 srt::CUDT::bind(int, sockaddr const*, int) <null> (srt-live-transmit+0xacdd3)
    #8 srt_bind <null> (srt-live-transmit+0x1618a9)
    #9 SrtCommon::PrepareListener(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, int) <null> (srt-live-transmit+0x7d576)
    #10 SrtCommon::Init(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, bool) <null> (srt-live-transmit+0x84d8a)
    #11 std::unique_ptr<Target, std::default_delete<Target> > CreateMedium<Target>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) <null> (srt-live-transmit+0x90353)
    #12 Target::Create(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) <null> (srt-live-transmit+0x85fd5)
    #13 main <null> (srt-live-transmit+0x48c1e)

SUMMARY: ThreadSanitizer: data race (/home/felsod/Downloads/srt/srt-live-transmit+0xec4b3) in srt::CUDT::updateCC(srt::ETransmissionEvent, srt::EventVariant)
==================
==================
WARNING: ThreadSanitizer: data race (pid=20887)
  Read of size 8 at 0x7b1400002818 by thread T3:
    #0 srt::CUDT::updateCC(srt::ETransmissionEvent, srt::EventVariant) <null> (srt-live-transmit+0xec523)
    #1 srt::CUDT::checkTimers() <null> (srt-live-transmit+0xf36c3)
    #2 srt::CRcvQueue::worker(void*) <null> (srt-live-transmit+0x15284b)

  Previous write of size 8 at 0x7b1400002818 by main thread (mutexes: write M300, write M305, write M304):
    #0 srt::LiveCC::updateBandwidth(long, long) <null> (srt-live-transmit+0x154f3b)
    #1 srt::CUDT::updateCC(srt::ETransmissionEvent, srt::EventVariant) <null> (srt-live-transmit+0xec6cc)
    #2 srt::CUDT::setOpt(SRT_SOCKOPT, void const*, int) <null> (srt-live-transmit+0xf0357)
    #3 srt::CUDT::setsockopt(int, int, SRT_SOCKOPT, void const*, int) <null> (srt-live-transmit+0xa671e)
    #4 srt_setsockopt <null> (srt-live-transmit+0x161d76)
    #5 bool SocketOption::apply<(SocketOption::Domain)1, int>(int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) const <null> (srt-live-transmit+0x7aef6)
    #6 SrtCommon::ConfigurePost(int) <null> (srt-live-transmit+0x81659)
    #7 SrtCommon::AcceptNewClient() <null> (srt-live-transmit+0x7dc1c)
    #8 SrtTarget::AcceptNewClient() <null> (srt-live-transmit+0x870f3)
    #9 main <null> (srt-live-transmit+0x4813a)

  Location is heap block of size 80 at 0x7b1400002800 allocated by thread T3:
    #0 operator new(unsigned long) ../../../../src/libsanitizer/tsan/tsan_new_delete.cpp:64 (libtsan.so.0+0x8bc72)
    #1 srt::Creator<srt::LiveCC>::Create(srt::CUDT*) <null> (srt-live-transmit+0x157118)
    #2 srt::SrtCongestion::configure(srt::CUDT*) <null> (srt-live-transmit+0x153fd7)
    #3 srt::CUDT::setupCC() <null> (srt-live-transmit+0xed269)
    #4 srt::CUDT::acceptAndRespond(srt::sockaddr_any const&, srt::sockaddr_any const&, srt::CPacket const&, srt::CHandShake&) <null> (srt-live-transmit+0x1102e8)
    #5 srt::CUDTUnited::newConnection(int, srt::sockaddr_any const&, srt::CPacket const&, srt::CHandShake&, int&, srt::CUDT*&) <null> (srt-live-transmit+0xb255a)
    #6 srt::CUDT::processConnectRequest(srt::sockaddr_any const&, srt::CPacket&) <null> (srt-live-transmit+0xff006)
    #7 srt::CRcvQueue::worker_ProcessConnectionRequest(srt::CUnit*, srt::sockaddr_any const&) <null> (srt-live-transmit+0x150fe5)
    #8 srt::CRcvQueue::worker(void*) <null> (srt-live-transmit+0x152721)

  Mutex M300 (0x7ba800011198) created at:
    #0 pthread_mutex_init ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1220 (libtsan.so.0+0x4a616)
    #1 srt::sync::Mutex::Mutex() <null> (srt-live-transmit+0x169b61)
    #2 srt::CUDT::CUDT(srt::CUDTSocket*, srt::CUDT const&) <null> (srt-live-transmit+0xfc7b3)
    #3 srt::CUDTUnited::newConnection(int, srt::sockaddr_any const&, srt::CPacket const&, srt::CHandShake&, int&, srt::CUDT*&) <null> (srt-live-transmit+0xb1de0)
    #4 srt::CUDT::processConnectRequest(srt::sockaddr_any const&, srt::CPacket&) <null> (srt-live-transmit+0xff006)
    #5 srt::CRcvQueue::worker_ProcessConnectionRequest(srt::CUnit*, srt::sockaddr_any const&) <null> (srt-live-transmit+0x150fe5)
    #6 srt::CRcvQueue::worker(void*) <null> (srt-live-transmit+0x152721)

  Mutex M305 (0x7ba8000112c0) created at:
    #0 pthread_mutex_init ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1220 (libtsan.so.0+0x4a616)
    #1 srt::sync::Mutex::Mutex() <null> (srt-live-transmit+0x169b61)
    #2 srt::CUDT::CUDT(srt::CUDTSocket*, srt::CUDT const&) <null> (srt-live-transmit+0xfc854)
    #3 srt::CUDTUnited::newConnection(int, srt::sockaddr_any const&, srt::CPacket const&, srt::CHandShake&, int&, srt::CUDT*&) <null> (srt-live-transmit+0xb1de0)
    #4 srt::CUDT::processConnectRequest(srt::sockaddr_any const&, srt::CPacket&) <null> (srt-live-transmit+0xff006)
    #5 srt::CRcvQueue::worker_ProcessConnectionRequest(srt::CUnit*, srt::sockaddr_any const&) <null> (srt-live-transmit+0x150fe5)
    #6 srt::CRcvQueue::worker(void*) <null> (srt-live-transmit+0x152721)

  Mutex M304 (0x7ba800011298) created at:
    #0 pthread_mutex_init ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1220 (libtsan.so.0+0x4a616)
    #1 srt::sync::Mutex::Mutex() <null> (srt-live-transmit+0x169b61)
    #2 srt::CUDT::CUDT(srt::CUDTSocket*, srt::CUDT const&) <null> (srt-live-transmit+0xfc83d)
    #3 srt::CUDTUnited::newConnection(int, srt::sockaddr_any const&, srt::CPacket const&, srt::CHandShake&, int&, srt::CUDT*&) <null> (srt-live-transmit+0xb1de0)
    #4 srt::CUDT::processConnectRequest(srt::sockaddr_any const&, srt::CPacket&) <null> (srt-live-transmit+0xff006)
    #5 srt::CRcvQueue::worker_ProcessConnectionRequest(srt::CUnit*, srt::sockaddr_any const&) <null> (srt-live-transmit+0x150fe5)
    #6 srt::CRcvQueue::worker(void*) <null> (srt-live-transmit+0x152721)

  Thread T3 (tid=20891, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:962 (libtsan.so.0+0x5ea79)
    #1 srt::sync::CThread::create(void* (*)(void*), void*) <null> (srt-live-transmit+0x16b12d)
    #2 srt::sync::CThread::CThread(void* (*)(void*), void*) <null> (srt-live-transmit+0x16b889)
    #3 srt::sync::StartThread(srt::sync::CThread&, void* (*)(void*), void*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) <null> (srt-live-transmit+0x163f55)
    #4 srt::CRcvQueue::init(int, unsigned long, int, int, srt::CChannel*, srt::sync::CTimer*) <null> (srt-live-transmit+0x14cdce)
    #5 srt::CUDTUnited::updateMux(srt::CUDTSocket*, srt::sockaddr_any const&, int const*) <null> (srt-live-transmit+0xa9aa5)
    #6 srt::CUDTUnited::bind(srt::CUDTSocket*, srt::sockaddr_any const&) <null> (srt-live-transmit+0xacb7f)
    #7 srt::CUDT::bind(int, sockaddr const*, int) <null> (srt-live-transmit+0xacdd3)
    #8 srt_bind <null> (srt-live-transmit+0x1618a9)
    #9 SrtCommon::PrepareListener(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, int) <null> (srt-live-transmit+0x7d576)
    #10 SrtCommon::Init(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, bool) <null> (srt-live-transmit+0x84d8a)
    #11 std::unique_ptr<Target, std::default_delete<Target> > CreateMedium<Target>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) <null> (srt-live-transmit+0x90353)
    #12 Target::Create(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) <null> (srt-live-transmit+0x85fd5)
    #13 main <null> (srt-live-transmit+0x48c1e)

SUMMARY: ThreadSanitizer: data race (/home/felsod/Downloads/srt/srt-live-transmit+0xec523) in srt::CUDT::updateCC(srt::ETransmissionEvent, srt::EventVariant)
==================
12:34:24.821358/SRT:GC*E:SRT.ei: epoll/update: IPE: update struck E1 which is NOT SUBSCRIBED to @899641007
12:34:24.821570/SRT:GC*E:SRT.ei: epoll/update: IPE: update struck E1 which is NOT SUBSCRIBED to @899641007
12:34:39.993915/SRT:RcvQ:w1!W:SRT.in: @899641006: rcv LOSSREPORT rng 101977244 - -1 with last sent 101977254 - DISCARDING
12:34:39.994116/SRT:RcvQ:w1!W:SRT.in: @899641006: out-of-band LOSSREPORT received; BUG or ATTACK - last sent %101977255 vs loss %-1
3948 bytes lost, 6647116 bytes sent, 6651064 bytes received
SRT target disconnected
12:34:40.012381/srt-live-transm*E:SRT.ea: remove_usock: @899641005 not found as either socket or group. Removing only from epoll system.
Accepted SRT target connection
12:34:41.012429/SRT:GC*E:SRT.ei: epoll/update: IPE: update struck E1 which is NOT SUBSCRIBED to @899641005
12:34:41.012556/SRT:GC*E:SRT.ei: epoll/update: IPE: update struck E1 which is NOT SUBSCRIBED to @899641005
28952 bytes lost, 9692152 bytes sent, 16374800 bytes received
ThreadSanitizer: reported 3 warnings

Caller:

 ./srt-live-transmit "srt://127.0.0.1:2222?latency=120&conntimeo=31393&mode=caller" udp://127.0.0.1:4444
Media path: 'srt://127.0.0.1:2222?latency=120&conntimeo=31393&mode=caller' --> 'udp://127.0.0.1:4444'
==================
WARNING: ThreadSanitizer: data race (pid=20880)
  Read of size 1 at 0x7ba8000000a9 by thread T3 (mutexes: write M290):
    #0 srt::CRendezvousQueue::qualifyToHandle(srt::EReadStatus, srt::EConnectStatus, int, std::vector<srt::CRendezvousQueue::LinkStatusInfo, std::allocator<srt::CRendezvousQueue::LinkStatusInfo> >&, std::vector<srt::CRendezvousQueue::LinkStatusInfo, std::allocator<srt::CRendezvousQueue::LinkStatusInfo> >&) <null> (srt-live-transmit+0x14d0a5)
    #1 srt::CRendezvousQueue::updateConnStatus(srt::EReadStatus, srt::EConnectStatus, srt::CUnit*) <null> (srt-live-transmit+0x14d6a8)
    #2 srt::CRcvQueue::worker(void*) <null> (srt-live-transmit+0x152899)

  Previous write of size 1 at 0x7ba8000000a9 by main thread (mutexes: write M121, write M126, write M125):
    #0 srt::CSrtConfig::set(SRT_SOCKOPT, void const*, int) <null> (srt-live-transmit+0x1608a9)
    #1 srt::CUDT::setOpt(SRT_SOCKOPT, void const*, int) <null> (srt-live-transmit+0xefa72)
    #2 srt::CUDT::setsockopt(int, int, SRT_SOCKOPT, void const*, int) <null> (srt-live-transmit+0xa671e)
    #3 srt_setsockopt <null> (srt-live-transmit+0x161d76)
    #4 SrtCommon::ConfigurePost(int) <null> (srt-live-transmit+0x8116f)
    #5 SrtCommon::ConnectClient(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int) <null> (srt-live-transmit+0x7e2fc)
    #6 SrtCommon::OpenClient(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int) <null> (srt-live-transmit+0x7e6a6)
    #7 SrtCommon::Init(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, bool) <null> (srt-live-transmit+0x84ba2)
    #8 SrtSource::SrtSource(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > const&) <null> (srt-live-transmit+0x8565b)
    #9 std::unique_ptr<Source, std::default_delete<Source> > CreateMedium<Source>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) <null> (srt-live-transmit+0x8ee8b)
    #10 Source::Create(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) <null> (srt-live-transmit+0x85f65)
    #11 main <null> (srt-live-transmit+0x48dd8)

  Location is heap block of size 22128 at 0x7ba800000000 allocated by main thread:
    #0 operator new(unsigned long) ../../../../src/libsanitizer/tsan/tsan_new_delete.cpp:64 (libtsan.so.0+0x8bc72)
    #1 srt::CUDTUnited::newSocket(srt::CUDTSocket**) <null> (srt-live-transmit+0x9ea3d)
    #2 srt::CUDT::socket() <null> (srt-live-transmit+0xa605f)
    #3 srt_create_socket <null> (srt-live-transmit+0x161534)
    #4 SrtCommon::PrepareClient() <null> (srt-live-transmit+0x7dfd6)
    #5 SrtCommon::OpenClient(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int) <null> (srt-live-transmit+0x7e5c0)
    #6 SrtCommon::Init(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, bool) <null> (srt-live-transmit+0x84ba2)
    #7 SrtSource::SrtSource(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > const&) <null> (srt-live-transmit+0x8565b)
    #8 std::unique_ptr<Source, std::default_delete<Source> > CreateMedium<Source>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) <null> (srt-live-transmit+0x8ee8b)
    #9 Source::Create(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) <null> (srt-live-transmit+0x85f65)
    #10 main <null> (srt-live-transmit+0x48dd8)

  Mutex M290 (0x7b1000000298) created at:
    #0 pthread_mutex_init ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1220 (libtsan.so.0+0x4a616)
    #1 srt::sync::Mutex::Mutex() <null> (srt-live-transmit+0x169b61)
    #2 srt::CRendezvousQueue::CRendezvousQueue() <null> (srt-live-transmit+0x1492cc)
    #3 srt::CRcvQueue::init(int, unsigned long, int, int, srt::CChannel*, srt::sync::CTimer*) <null> (srt-live-transmit+0x14c6e1)
    #4 srt::CUDTUnited::updateMux(srt::CUDTSocket*, srt::sockaddr_any const&, int const*) <null> (srt-live-transmit+0xa9aa5)
    #5 srt::CUDTUnited::connectIn(srt::CUDTSocket*, srt::sockaddr_any const&, int) <null> (srt-live-transmit+0xad257)
    #6 srt::CUDTUnited::connect(int, sockaddr const*, int, int) <null> (srt-live-transmit+0xae72b)
    #7 srt::CUDT::connect(int, sockaddr const*, int, int) <null> (srt-live-transmit+0xae808)
    #8 srt_connect <null> (srt-live-transmit+0x161a3e)
    #9 SrtCommon::ConnectClient(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int) <null> (srt-live-transmit+0x7e2c9)
    #10 SrtCommon::OpenClient(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int) <null> (srt-live-transmit+0x7e6a6)
    #11 SrtCommon::Init(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, bool) <null> (srt-live-transmit+0x84ba2)
    #12 SrtSource::SrtSource(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > const&) <null> (srt-live-transmit+0x8565b)
    #13 std::unique_ptr<Source, std::default_delete<Source> > CreateMedium<Source>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) <null> (srt-live-transmit+0x8ee8b)
    #14 Source::Create(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) <null> (srt-live-transmit+0x85f65)
    #15 main <null> (srt-live-transmit+0x48dd8)

  Mutex M121 (0x7ba800005198) created at:
    #0 pthread_mutex_init ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1220 (libtsan.so.0+0x4a616)
    #1 srt::sync::Mutex::Mutex() <null> (srt-live-transmit+0x169b61)
    #2 srt::CUDT::CUDT(srt::CUDTSocket*) <null> (srt-live-transmit+0xfaad9)
    #3 srt::CUDTUnited::newSocket(srt::CUDTSocket**) <null> (srt-live-transmit+0x9eb1b)
    #4 srt::CUDT::socket() <null> (srt-live-transmit+0xa605f)
    #5 srt_create_socket <null> (srt-live-transmit+0x161534)
    #6 SrtCommon::PrepareClient() <null> (srt-live-transmit+0x7dfd6)
    #7 SrtCommon::OpenClient(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int) <null> (srt-live-transmit+0x7e5c0)
    #8 SrtCommon::Init(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, bool) <null> (srt-live-transmit+0x84ba2)
    #9 SrtSource::SrtSource(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > const&) <null> (srt-live-transmit+0x8565b)
    #10 std::unique_ptr<Source, std::default_delete<Source> > CreateMedium<Source>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) <null> (srt-live-transmit+0x8ee8b)
    #11 Source::Create(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) <null> (srt-live-transmit+0x85f65)
    #12 main <null> (srt-live-transmit+0x48dd8)

  Mutex M126 (0x7ba8000052c0) created at:
    #0 pthread_mutex_init ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1220 (libtsan.so.0+0x4a616)
    #1 srt::sync::Mutex::Mutex() <null> (srt-live-transmit+0x169b61)
    #2 srt::CUDT::CUDT(srt::CUDTSocket*) <null> (srt-live-transmit+0xfab65)
    #3 srt::CUDTUnited::newSocket(srt::CUDTSocket**) <null> (srt-live-transmit+0x9eb1b)
    #4 srt::CUDT::socket() <null> (srt-live-transmit+0xa605f)
    #5 srt_create_socket <null> (srt-live-transmit+0x161534)
    #6 SrtCommon::PrepareClient() <null> (srt-live-transmit+0x7dfd6)
    #7 SrtCommon::OpenClient(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int) <null> (srt-live-transmit+0x7e5c0)
    #8 SrtCommon::Init(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, bool) <null> (srt-live-transmit+0x84ba2)
    #9 SrtSource::SrtSource(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > const&) <null> (srt-live-transmit+0x8565b)
    #10 std::unique_ptr<Source, std::default_delete<Source> > CreateMedium<Source>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) <null> (srt-live-transmit+0x8ee8b)
    #11 Source::Create(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) <null> (srt-live-transmit+0x85f65)
    #12 main <null> (srt-live-transmit+0x48dd8)

  Mutex M125 (0x7ba800005298) created at:
    #0 pthread_mutex_init ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1220 (libtsan.so.0+0x4a616)
    #1 srt::sync::Mutex::Mutex() <null> (srt-live-transmit+0x169b61)
    #2 srt::CUDT::CUDT(srt::CUDTSocket*) <null> (srt-live-transmit+0xfab51)
    #3 srt::CUDTUnited::newSocket(srt::CUDTSocket**) <null> (srt-live-transmit+0x9eb1b)
    #4 srt::CUDT::socket() <null> (srt-live-transmit+0xa605f)
    #5 srt_create_socket <null> (srt-live-transmit+0x161534)
    #6 SrtCommon::PrepareClient() <null> (srt-live-transmit+0x7dfd6)
    #7 SrtCommon::OpenClient(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int) <null> (srt-live-transmit+0x7e5c0)
    #8 SrtCommon::Init(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, bool) <null> (srt-live-transmit+0x84ba2)
    #9 SrtSource::SrtSource(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > const&) <null> (srt-live-transmit+0x8565b)
    #10 std::unique_ptr<Source, std::default_delete<Source> > CreateMedium<Source>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) <null> (srt-live-transmit+0x8ee8b)
    #11 Source::Create(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) <null> (srt-live-transmit+0x85f65)
    #12 main <null> (srt-live-transmit+0x48dd8)

  Thread T3 (tid=20884, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:962 (libtsan.so.0+0x5ea79)
    #1 srt::sync::CThread::create(void* (*)(void*), void*) <null> (srt-live-transmit+0x16b12d)
    #2 srt::sync::CThread::CThread(void* (*)(void*), void*) <null> (srt-live-transmit+0x16b889)
    #3 srt::sync::StartThread(srt::sync::CThread&, void* (*)(void*), void*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) <null> (srt-live-transmit+0x163f55)
    #4 srt::CRcvQueue::init(int, unsigned long, int, int, srt::CChannel*, srt::sync::CTimer*) <null> (srt-live-transmit+0x14cdce)
    #5 srt::CUDTUnited::updateMux(srt::CUDTSocket*, srt::sockaddr_any const&, int const*) <null> (srt-live-transmit+0xa9aa5)
    #6 srt::CUDTUnited::connectIn(srt::CUDTSocket*, srt::sockaddr_any const&, int) <null> (srt-live-transmit+0xad257)
    #7 srt::CUDTUnited::connect(int, sockaddr const*, int, int) <null> (srt-live-transmit+0xae72b)
    #8 srt::CUDT::connect(int, sockaddr const*, int, int) <null> (srt-live-transmit+0xae808)
    #9 srt_connect <null> (srt-live-transmit+0x161a3e)
    #10 SrtCommon::ConnectClient(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int) <null> (srt-live-transmit+0x7e2c9)
    #11 SrtCommon::OpenClient(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int) <null> (srt-live-transmit+0x7e6a6)
    #12 SrtCommon::Init(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, bool) <null> (srt-live-transmit+0x84ba2)
    #13 SrtSource::SrtSource(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > const&) <null> (srt-live-transmit+0x8565b)
    #14 std::unique_ptr<Source, std::default_delete<Source> > CreateMedium<Source>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) <null> (srt-live-transmit+0x8ee8b)
    #15 Source::Create(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) <null> (srt-live-transmit+0x85f65)
    #16 main <null> (srt-live-transmit+0x48dd8)

SUMMARY: ThreadSanitizer: data race (/home/felsod/Downloads/srt/srt-live-transmit+0x14d0a5) in srt::CRendezvousQueue::qualifyToHandle(srt::EReadStatus, srt::EConnectStatus, int, std::vector<srt::CRendezvousQueue::LinkStatusInfo, std::allocator<srt::CRendezvousQueue::LinkStatusInfo> >&, std::vector<srt::CRendezvousQueue::LinkStatusInfo, std::allocator<srt::CRendezvousQueue::LinkStatusInfo> >&)
==================
SRT source connected
SRT source disconnected
==================
WARNING: ThreadSanitizer: data race (pid=20880)
  Read of size 1 at 0x7ba8000060a9 by thread T6:
    #0 srt::CRcvQueue::worker_TryAsyncRend_OrStore(int, srt::CUnit*, srt::sockaddr_any const&) <null> (srt-live-transmit+0x14fd3b)
    #1 srt::CRcvQueue::worker_ProcessAddressedPacket(int, srt::CUnit*, srt::sockaddr_any const&) <null> (srt-live-transmit+0x152398)
    #2 srt::CRcvQueue::worker(void*) <null> (srt-live-transmit+0x1528b1)

  Previous write of size 1 at 0x7ba8000060a9 by main thread (mutexes: write M729437626142077336, write M730845001025630912, write M730563526048920216):
    #0 srt::CSrtConfig::set(SRT_SOCKOPT, void const*, int) <null> (srt-live-transmit+0x1608a9)
    #1 srt::CUDT::setOpt(SRT_SOCKOPT, void const*, int) <null> (srt-live-transmit+0xefa72)
    #2 srt::CUDT::setsockopt(int, int, SRT_SOCKOPT, void const*, int) <null> (srt-live-transmit+0xa671e)
    #3 srt_setsockopt <null> (srt-live-transmit+0x161d76)
    #4 SrtCommon::ConfigurePost(int) <null> (srt-live-transmit+0x8116f)
    #5 SrtCommon::ConnectClient(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int) <null> (srt-live-transmit+0x7e2fc)
    #6 SrtCommon::OpenClient(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int) <null> (srt-live-transmit+0x7e6a6)
    #7 SrtCommon::Init(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, bool) <null> (srt-live-transmit+0x84ba2)
    #8 SrtSource::SrtSource(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > const&) <null> (srt-live-transmit+0x8565b)
    #9 std::unique_ptr<Source, std::default_delete<Source> > CreateMedium<Source>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) <null> (srt-live-transmit+0x8ee8b)
    #10 Source::Create(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) <null> (srt-live-transmit+0x85f65)
    #11 main <null> (srt-live-transmit+0x48dd8)

  Location is heap block of size 22128 at 0x7ba800006000 allocated by main thread:
    #0 operator new(unsigned long) ../../../../src/libsanitizer/tsan/tsan_new_delete.cpp:64 (libtsan.so.0+0x8bc72)
    #1 srt::CUDTUnited::newSocket(srt::CUDTSocket**) <null> (srt-live-transmit+0x9ea3d)
    #2 srt::CUDT::socket() <null> (srt-live-transmit+0xa605f)
    #3 srt_create_socket <null> (srt-live-transmit+0x161534)
    #4 SrtCommon::PrepareClient() <null> (srt-live-transmit+0x7dfd6)
    #5 SrtCommon::OpenClient(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int) <null> (srt-live-transmit+0x7e5c0)
    #6 SrtCommon::Init(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, bool) <null> (srt-live-transmit+0x84ba2)
    #7 SrtSource::SrtSource(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > const&) <null> (srt-live-transmit+0x8565b)
    #8 std::unique_ptr<Source, std::default_delete<Source> > CreateMedium<Source>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) <null> (srt-live-transmit+0x8ee8b)
    #9 Source::Create(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) <null> (srt-live-transmit+0x85f65)
    #10 main <null> (srt-live-transmit+0x48dd8)

  Mutex M729437626142077336 is already destroyed.

  Mutex M730845001025630912 is already destroyed.

  Mutex M730563526048920216 is already destroyed.

  Thread T6 (tid=20899, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:962 (libtsan.so.0+0x5ea79)
    #1 srt::sync::CThread::create(void* (*)(void*), void*) <null> (srt-live-transmit+0x16b12d)
    #2 srt::sync::CThread::CThread(void* (*)(void*), void*) <null> (srt-live-transmit+0x16b889)
    #3 srt::sync::StartThread(srt::sync::CThread&, void* (*)(void*), void*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) <null> (srt-live-transmit+0x163f55)
    #4 srt::CRcvQueue::init(int, unsigned long, int, int, srt::CChannel*, srt::sync::CTimer*) <null> (srt-live-transmit+0x14cdce)
    #5 srt::CUDTUnited::updateMux(srt::CUDTSocket*, srt::sockaddr_any const&, int const*) <null> (srt-live-transmit+0xa9aa5)
    #6 srt::CUDTUnited::connectIn(srt::CUDTSocket*, srt::sockaddr_any const&, int) <null> (srt-live-transmit+0xad257)
    #7 srt::CUDTUnited::connect(int, sockaddr const*, int, int) <null> (srt-live-transmit+0xae72b)
    #8 srt::CUDT::connect(int, sockaddr const*, int, int) <null> (srt-live-transmit+0xae808)
    #9 srt_connect <null> (srt-live-transmit+0x161a3e)
    #10 SrtCommon::ConnectClient(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int) <null> (srt-live-transmit+0x7e2c9)
    #11 SrtCommon::OpenClient(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int) <null> (srt-live-transmit+0x7e6a6)
    #12 SrtCommon::Init(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, bool) <null> (srt-live-transmit+0x84ba2)
    #13 SrtSource::SrtSource(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > const&) <null> (srt-live-transmit+0x8565b)
    #14 std::unique_ptr<Source, std::default_delete<Source> > CreateMedium<Source>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) <null> (srt-live-transmit+0x8ee8b)
    #15 Source::Create(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) <null> (srt-live-transmit+0x85f65)
    #16 main <null> (srt-live-transmit+0x48dd8)

SUMMARY: ThreadSanitizer: data race (/home/felsod/Downloads/srt/srt-live-transmit+0x14fd3b) in srt::CRcvQueue::worker_TryAsyncRend_OrStore(int, srt::CUnit*, srt::sockaddr_any const&)
==================
SRT source connected
ThreadSanitizer: reported 2 warnings

@ethouris
Copy link
Collaborator

Many thanks! I see no dangers introduced by this fix; we may need to test it also more intensively, but so far it looks good.

@maxsharabayko please take a look.

@FelixSodermanNeti
Copy link
Author

Update: I have been able to recreate this issue using a malformed ACK. As mentioned in my comment previously.

Furthermore, I found similar code in the void processCtrlAck function in srtcore/core.cpp:

// Check the validation of the ack
if (CSeqNo::seqcmp(ackdata_seqno, CSeqNo::incseq(m_iSndCurrSeqNo)) > 0)
{
    // this should not happen: attack or bug
    LOGC(gglog.Error,
            log << CONID() << "ATTACK/IPE: incoming ack seq " << ackdata_seqno << " exceeds current "
            << m_iSndCurrSeqNo << " by " << (CSeqNo::seqoff(m_iSndCurrSeqNo, ackdata_seqno) - 1) << "!");
    m_bBroken        = true;
    m_iBrokenCounter = 0;
    return;
}

I haven’t attempted to reproduce this issue, but I suspect it might be vulnerable to a similar type of malformed packet.

I updates the proxy to support this (see revision 2): Link to Proxy Script.

The same replication steps apply other than changing the startup command of the proxy to:
python3 srt-proxy.py --caller-port 2222 --listener-port 3333 --break-at-pkt-ACK 500

Unfortunately, Applying the same fix as in the NAK case seem to cause a potential deadlock according to the thread sanitizer.

ThreadSanitizer output:

==================
WARNING: ThreadSanitizer: lock-order-inversion (potential deadlock) (pid=17935)
  Cycle in lock order graph: M305 (0x7ba8000112c0) => M303 (0x7ba800011240) => M305

  Mutex M303 acquired here while holding mutex M305 in main thread:
    #0 pthread_mutex_lock ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:4165 (libtsan.so.0+0x526fc)
    #1 srt::sync::Mutex::lock() <null> (srt-live-transmit+0x16adba)
    #2 srt::CUDT::sendmsg2(char const*, int, SRT_MsgCtrl_&) <null> (srt-live-transmit+0xe3293)
    #3 srt::CUDT::sendmsg2(int, char const*, int, SRT_MsgCtrl_&) <null> (srt-live-transmit+0xa79e4)
    #4 srt_sendmsg2 <null> (srt-live-transmit+0x1632e8)
    #5 SrtTarget::Write(char const*, unsigned long, long, std::ostream&) <null> (srt-live-transmit+0x7c98c)
    #6 main <null> (srt-live-transmit+0x48b4e)

    Hint: use TSAN_OPTIONS=second_deadlock_stack=1 to get more informative warning message

  Mutex M305 acquired here while holding mutex M303 in thread T3:
    #0 pthread_mutex_lock ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:4165 (libtsan.so.0+0x526fc)
    #1 srt::sync::Mutex::lock() <null> (srt-live-transmit+0x16adba)
    #2 srt::CUDT::releaseSynch() <null> (srt-live-transmit+0xd6baf)
    #3 srt::CUDT::updateBrokenConnection() <null> (srt-live-transmit+0xd8474)
    #4 srt::CUDT::processCtrlAck(srt::CPacket const&, srt::sync::TimePoint<srt::sync::steady_clock> const&) <null> (srt-live-transmit+0xf5aaf)
    #5 srt::CUDT::processCtrl(srt::CPacket const&) <null> (srt-live-transmit+0x11568d)
    #6 srt::CRcvQueue::worker_ProcessAddressedPacket(int, srt::CUnit*, srt::sockaddr_any const&) <null> (srt-live-transmit+0x153669)
    #7 srt::CRcvQueue::worker(void*) <null> (srt-live-transmit+0x153ab1)

  Thread T3 (tid=17939, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:962 (libtsan.so.0+0x5ea79)
    #1 srt::sync::CThread::create(void* (*)(void*), void*) <null> (srt-live-transmit+0x16c32d)
    #2 srt::sync::CThread::CThread(void* (*)(void*), void*) <null> (srt-live-transmit+0x16ca89)
    #3 srt::sync::StartThread(srt::sync::CThread&, void* (*)(void*), void*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) <null> (srt-live-transmit+0x165155)
    #4 srt::CRcvQueue::init(int, unsigned long, int, int, srt::CChannel*, srt::sync::CTimer*) <null> (srt-live-transmit+0x14dfce)
    #5 srt::CUDTUnited::updateMux(srt::CUDTSocket*, srt::sockaddr_any const&, int const*) <null> (srt-live-transmit+0xaac95)
    #6 srt::CUDTUnited::bind(srt::CUDTSocket*, srt::sockaddr_any const&) <null> (srt-live-transmit+0xadd6f)
    #7 srt::CUDT::bind(int, sockaddr const*, int) <null> (srt-live-transmit+0xadfc3)
    #8 srt_bind <null> (srt-live-transmit+0x162aa9)
    #9 SrtCommon::PrepareListener(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, int) <null> (srt-live-transmit+0x7d796)
    #10 SrtCommon::Init(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, bool) <null> (srt-live-transmit+0x84faa)
    #11 std::unique_ptr<Target, std::default_delete<Target> > CreateMedium<Target>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) <null> (srt-live-transmit+0x90573)
    #12 Target::Create(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) <null> (srt-live-transmit+0x861f5)
    #13 main <null> (srt-live-transmit+0x48e3e)

SUMMARY: ThreadSanitizer: lock-order-inversion (potential deadlock) (/home/felsod/Downloads/srt/srt-live-transmit+0x16adba) in srt::sync::Mutex::lock()
==================

I do not know how to continue the investigation.
Should I create a separate issue or rename this issue to mention both ACK and NAK?

@ethouris
Copy link
Collaborator

Ok, that doesn't sound good.

Could you please describe the exact reproduction procedure, using your helper script?

(I would also save this script in our repository, if you don't mind - bug detection helper scripts are never too many.)

I'll be investigating it myself.

@FelixSodermanNeti
Copy link
Author

FelixSodermanNeti commented Jan 13, 2025

You are allowed to save the script in the repository.

Steps to Reproduce ACK

  1. Use a two-way UDP proxy to modify the ACK packet in its path.
    UDP proxy script: Link to Proxy Script.

  2. Run the following setup:

    • Listener (Source):

      ./srt-live-transmit udp://127.0.0.1:1111 "srt://127.0.0.1:3333?adapter=127.0.0.1&latency=120&maxbw=-1&mode=listener"
    • Caller (Target):

      ./srt-live-transmit "srt://127.0.0.1:2222?latency=120&conntimeo=31393&mode=caller" udp://127.0.0.1:4444
    • UDP Proxy:

      python3 srt-proxy.py --caller-port 2222 --listener-port 3333 --break-at-pkt-ACK 500
    • UDP Stream Input:

      tsplay MY_FAVORITE_MOVIE.ts 127.0.0.1:1111 -loop

      Example stream: https://tsduck.io/streams/japan-nippontv/BS-Nippon-Television.ts

    • (Optional) UDP Stream Monitor:

      ffplay udp://127.0.0.1:4444

After starting all programs, wait for a few seconds (as the proxy in this configuration only drops the 500th ACK) and observe that the system breaks. When the proxy drops the ACK it will print to standard out. Running an unpatched version of srt-live-transmitt, the connection will break and the caller is not able to reconnect (as the listener does not know the connection is broken).

If one applies the following patch:

if (CSeqNo::seqcmp(ackdata_seqno, CSeqNo::incseq(m_iSndCurrSeqNo)) > 0)
{
    // this should not happen: attack or bug
    LOGC(gglog.Error,
            log << CONID() << "ATTACK/IPE: incoming ack seq " << ackdata_seqno << " exceeds current "
            << m_iSndCurrSeqNo << " by " << (CSeqNo::seqoff(m_iSndCurrSeqNo, ackdata_seqno) - 1) << "!");
    m_bBroken        = true;
    m_iBrokenCounter = 0;
    updateBrokenConnection();
    completeBrokenConnectionDependencies(SRT_ECONNFAIL); // LOCKS!
    return;
}

Adding the updateBrokenConnection() and completeBrokenConnectionDependencies() calls to the processCtrlAck function.

The behavior changes to a deadlock.

Please add a comment if anything is unclear or does not work on your machine.

@ethouris
Copy link
Collaborator

ethouris commented Jan 13, 2025

Both these functions you call here do locking. What you can try is that the lock on m_RecvAckLock that is above the if condition line can be unlocked forcefully BEFORE you call these functions. For that you can call unlock() on the scoped lock, although you have to change ScopedLock into UniqueLock.

That's my first thought, I'll still be trying to repro it myself.

@ethouris
Copy link
Collaborator

Ok, after reproduction, I can see something weird here: after the rogue ACK has come, all further ACKs are rejected. The transmission is no longer possible, but the connection doesn't get broken.

The fix you proposed simply breaks the connection (the rejection code is wrong, but I'll choose the right one). I'm not sure if that is exctly what should happen, though. I need to dig a bit deeper.

@ethouris
Copy link
Collaborator

... and yes, when applying the fix as you have shown, with my correction for the forcefully unlocked mutex, seems to work at least as expected - that is, the connection breaks and gets reconnected. We just need to check several other things, but your proposed fix seems to be the right approach.

@ethouris
Copy link
Collaborator

Please check on the attached PR. I have checked it myself for both solving the problem and lack of any disturbing thread sanity reports.

@FelixSodermanNeti
Copy link
Author

FelixSodermanNeti commented Jan 14, 2025

The PR looks good. I am not able to decode what these changes are (probably only indentation changes).
image.

I looked at the diff in a GitHub Codespace and there it looks better (does not include the changes in the image) and the changes there look good.

You can close this issue when the PR is merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[core] Area: Changes in SRT library core Type: Bug Indicates an unexpected problem or unintended behavior
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants