From 036eb150d185be26ba644a47078e19967403cb19 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Mon, 15 Jan 2024 11:33:13 +0100 Subject: [PATCH] rtsp: deal with borked server responses - enforce a response body length of 0, if the response has no Content-lenght. This is according to the RTSP spec. - excess bytes in a response body are forwarded to the client writers which will report and fail the transfer Follow-up to d7b6ce6 Fixes #12701 Closes #12706 --- lib/rtsp.c | 24 ++++++++++--------- tests/data/Makefile.inc | 2 +- tests/data/test689 | 53 +++++++++++++++++++++++++++++++++++++++++ tests/libtest/lib567.c | 1 + 4 files changed, 68 insertions(+), 12 deletions(-) create mode 100644 tests/data/test689 diff --git a/lib/rtsp.c b/lib/rtsp.c index c911bb6b22..dba8ae7a67 100644 --- a/lib/rtsp.c +++ b/lib/rtsp.c @@ -822,11 +822,10 @@ static CURLcode rtsp_rtp_write_resp(struct Curl_easy *data, if(!rtspc->in_header) { /* If header parsing is done, extract interleaved RTP messages */ - if((data->set.rtspreq == RTSPREQ_DESCRIBE) && (data->req.size <= -1)) { + if(data->req.size <= -1) { /* Respect section 4.4 of rfc2326: If the Content-Length header is - absent, a length 0 must be assumed. It will prevent libcurl from - hanging on DESCRIBE request that got refused for whatever - reason */ + absent, a length 0 must be assumed. */ + data->req.size = 0; data->req.download_done = TRUE; } result = rtsp_filter_rtp(data, buf, blen, &consumed); @@ -838,13 +837,16 @@ static CURLcode rtsp_rtp_write_resp(struct Curl_easy *data, if(rtspc->state != RTP_PARSE_SKIP) *done = FALSE; - /* we MUST have consumed all bytes */ - DEBUGF(infof(data, "rtsp_rtp_write_resp(len=%zu, in_header=%d, done=%d)", - blen, rtspc->in_header, *done)); - DEBUGASSERT(blen == 0); - if(!result && is_eos) { - result = Curl_client_write(data, CLIENTWRITE_BODY|CLIENTWRITE_EOS, - (char *)buf, 0); + /* we SHOULD have consumed all bytes, unless the response is borked. + * In which case we write out the left over bytes, letting the client + * writer deal with it (it will report EXCESS and fail the transfer). */ + DEBUGF(infof(data, "rtsp_rtp_write_resp(len=%zu, in_header=%d, done=%d " + " rtspc->state=%d, req.size=%" CURL_FORMAT_CURL_OFF_T ")", + blen, rtspc->in_header, *done, rtspc->state, data->req.size)); + if(!result && (is_eos || blen)) { + result = Curl_client_write(data, CLIENTWRITE_BODY| + (is_eos? CLIENTWRITE_EOS:0), + (char *)buf, blen); } out: diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc index 5008b86e01..ab66fc4cc4 100644 --- a/tests/data/Makefile.inc +++ b/tests/data/Makefile.inc @@ -96,7 +96,7 @@ test644 test645 test646 test647 test648 test649 test650 test651 test652 \ test653 test654 test655 test656 test658 test659 test660 test661 test662 \ test663 test664 test665 test666 test667 test668 test669 test670 test671 \ test672 test673 test674 test675 test676 test677 test678 test679 test680 \ -test681 test682 test683 test684 test685 test686 test687 test688 \ +test681 test682 test683 test684 test685 test686 test687 test688 test689 \ \ test700 test701 test702 test703 test704 test705 test706 test707 test708 \ test709 test710 test711 test712 test713 test714 test715 test716 test717 \ diff --git a/tests/data/test689 b/tests/data/test689 new file mode 100644 index 0000000000..821556decf --- /dev/null +++ b/tests/data/test689 @@ -0,0 +1,53 @@ + + +#Informational + + +RTSP +OPTIONS + + + +# Server-side + + +RTSP/7.1 786 + +RTSP/ + + + + + +# Client-Side + + +rtsp + + +lib567 + + + +fuzzing crash issue #12701 + + +rtsp://%HOSTIP:%RTSPPORT/%TESTNUMBER + + + + + +OPTIONS rtsp://%HOSTIP:%RTSPPORT/%TESTNUMBER RTSP/1.0 +CSeq: 1 +User-Agent: test567 +Test-Number: 567 + + +# 8 == CURLE_WEIRD_SERVER_REPLY + +8 + + + + diff --git a/tests/libtest/lib567.c b/tests/libtest/lib567.c index 00937e71d6..a912b1663a 100644 --- a/tests/libtest/lib567.c +++ b/tests/libtest/lib567.c @@ -49,6 +49,7 @@ int test(char *URL) /* Dump data to stdout for protocol verification */ test_setopt(curl, CURLOPT_HEADERDATA, stdout); test_setopt(curl, CURLOPT_WRITEDATA, stdout); + test_setopt(curl, CURLOPT_VERBOSE, 1L); test_setopt(curl, CURLOPT_URL, URL); test_setopt(curl, CURLOPT_RTSP_STREAM_URI, URL);