public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
* [rpms/sipp] f44: Fix CVEs
@ 2026-09-17 13:42 Peter Lemenkov
0 siblings, 0 replies; only message in thread
From: Peter Lemenkov @ 2026-09-17 13:42 UTC (permalink / raw)
To: git-commits
A new commit has been pushed.
Repo : rpms/sipp
Branch : f44
Commit : 374897767d7c0f952b8fe0baafc38b184596caff
Author : Peter Lemenkov <lemenkov@gmail.com>
Date : 2026-09-16T12:44:49+02:00
Stats : +202/-0 in 4 file(s)
URL : https://src.fedoraproject.org/rpms/sipp/c/374897767d7c0f952b8fe0baafc38b184596caff?branch=f44
Log:
Fix CVEs
Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
---
diff --git a/sipp-0007-fix-use-getAuthParameter-for-algorithm-in-createAuth.patch b/sipp-0007-fix-use-getAuthParameter-for-algorithm-in-createAuth.patch
new file mode 100644
index 0000000..5a0eabd
--- /dev/null
+++ b/sipp-0007-fix-use-getAuthParameter-for-algorithm-in-createAuth.patch
@@ -0,0 +1,44 @@
+From: Orgad Shaneh <orgad.shaneh@audiocodes.com>
+Date: Mon, 24 Aug 2026 11:57:09 +0300
+Subject: [PATCH] fix: use getAuthParameter() for algorithm in
+ createAuthHeader()
+
+createAuthHeader() parsed the algorithm= value from a 401/407
+challenge with an inline strncpy bounded by the source length
+instead of the destination's 32-byte stack buffer, allowing a
+malicious SIP server to overflow it. verifyAuthHeader() already
+parses the same field safely via getAuthParameter(), which is
+bounded by sizeof(algo); reuse it here instead of the unbounded
+inline parser.
+diff --git a/src/auth.cpp b/src/auth.cpp
+index d66771d..5e38d4d 100644
+--- a/src/auth.cpp
++++ b/src/auth.cpp
+@@ -163,7 +163,7 @@ int createAuthHeader(
+ {
+
+ char algo[32] = "MD5";
+- char *start, *end;
++ char *start;
+
+ if ((start = stristr(auth, "Digest")) == nullptr) {
+ snprintf(result, result_len, "createAuthHeader: authentication must be digest");
+@@ -175,15 +175,9 @@ int createAuthHeader(
+ return 0;
+ }
+
+- if ((start = stristr(auth, "algorithm=")) != nullptr) {
+- start = start + strlen("algorithm=");
+- if (*start == '"') {
+- start++;
+- }
+- end = start + strcspn(start, " ,\"\r\n");
+- strncpy(algo, start, end - start);
+- algo[end - start] ='\0';
+-
++ getAuthParameter("algorithm", auth, algo, sizeof(algo));
++ if (algo[0] == '\0') {
++ strcpy(algo, "MD5");
+ }
+
+ if (strncasecmp(algo, "MD5", 3)==0) {
diff --git a/sipp-0008-fix-bound-get_peer_tag-copy-against-buffer-size.patch b/sipp-0008-fix-bound-get_peer_tag-copy-against-buffer-size.patch
new file mode 100644
index 0000000..f1aae3c
--- /dev/null
+++ b/sipp-0008-fix-bound-get_peer_tag-copy-against-buffer-size.patch
@@ -0,0 +1,23 @@
+From: Orgad Shaneh <orgad.shaneh@audiocodes.com>
+Date: Mon, 24 Aug 2026 11:57:09 +0300
+Subject: [PATCH] fix: bound get_peer_tag() copy against buffer size
+
+get_peer_tag() copied the To header's tag= value into a static
+2049-byte buffer byte-by-byte with no bounds check on the write
+index. A malicious SIP server sending a response with an
+oversized tag parameter could overflow this BSS buffer with
+attacker-controlled data before the caller's length check ever
+runs.
+diff --git a/src/sip_parser.cpp b/src/sip_parser.cpp
+index 2ba638d..aeb7ce5 100644
+--- a/src/sip_parser.cpp
++++ b/src/sip_parser.cpp
+@@ -104,7 +104,7 @@ char* get_peer_tag(const char* msg)
+ }
+
+ while (*ptr && *ptr != ' ' && *ptr != ';' && *ptr != '\t' &&
+- *ptr != '\r' && *ptr != '\n') {
++ *ptr != '\r' && *ptr != '\n' && tag_i < (int) sizeof(tag) - 1) {
+ tag[tag_i++] = *(ptr++);
+ }
+ tag[tag_i] = '\0';
diff --git a/sipp-0009-fix-bound-get_header-writes-against-last_header-buff.patch b/sipp-0009-fix-bound-get_header-writes-against-last_header-buff.patch
new file mode 100644
index 0000000..5513c3f
--- /dev/null
+++ b/sipp-0009-fix-bound-get_header-writes-against-last_header-buff.patch
@@ -0,0 +1,131 @@
+From: Peter Lemenkov <lemenkov@gmail.com>
+Date: Tue, 8 Sep 2026 13:14:21 +0200
+Subject: [PATCH] fix: bound get_header() writes against last_header buffer
+ size
+
+get_header() accumulates matching headers into a static
+last_header[MAX_HEADER_LEN * 10] buffer using a series of unbounded
+sprintf() calls. When a message contains a header (or several repeated
+headers, e.g. Via or Record-Route) whose combined content exceeds the
+buffer, the content copy
+
+ dest += sprintf(dest, "%s", src);
+
+writes past the end of last_header with attacker-controlled data. The
+source is taken from the message's pre-body section, which can be far
+larger than the 20490-byte destination.
+
+Convert the name, separator, and content writes to snprintf() bounded by
+the space remaining in last_header, and bail out via a truncated: label
+when a write would not fit. On truncation the partially-written header
+is dropped and the accumulated result so far is returned, so callers
+still get a well-formed, NUL-terminated string.
+
+Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
+Assisted-by: Claude (Anthropic) <https://claude.ai>
+diff --git a/src/sip_parser.cpp b/src/sip_parser.cpp
+index aeb7ce5..b22b37d 100644
+--- a/src/sip_parser.cpp
++++ b/src/sip_parser.cpp
+@@ -122,6 +122,7 @@ char* get_header(const char* message, const char* name, bool content)
+ {
+ /* non reentrant. consider accepting char buffer as param */
+ static char last_header[MAX_HEADER_LEN * 10];
++ const char *last_header_end = last_header + sizeof(last_header);
+ const char *cptr;
+ char *src, *src_copy, *dest, *start, *ptr;
+ bool first_time = true;
+@@ -164,8 +165,10 @@ char* get_header(const char* message, const char* name, bool content)
+ while ((src = internal_match_header(
+ src, header_with_newline, compact_header_with_newline))) {
+ if (!content && first_time) {
+- // Add the name to the string;
+- dest += sprintf(dest, "%s", name);
++ int n = snprintf(dest, last_header_end - dest, "%s", name);
++ if (n < 0 || n >= last_header_end - dest)
++ goto truncated;
++ dest += n;
+ first_time = false;
+ }
+
+@@ -210,12 +213,23 @@ char* get_header(const char* message, const char* name, bool content)
+ }
+
+ if (*(dest-1) == ':') {
+- dest += sprintf(dest, " ");
++ int n = snprintf(dest, last_header_end - dest, " ");
++ if (n < 0 || n >= last_header_end - dest) goto truncated;
++ dest += n;
+ } else {
+- dest += sprintf(dest, ", ");
++ int n = snprintf(dest, last_header_end - dest, ", ");
++ if (n < 0 || n >= last_header_end - dest) goto truncated;
++ dest += n;
+ }
+ }
+- dest += sprintf(dest, "%s", src);
++
++ int n = snprintf(dest, last_header_end - dest, "%s", src);
++ if (n < 0 || n >= last_header_end - dest) {
++ /* restore the newline we may have nulled, then bail */
++ if (ptr) *ptr = '\n';
++ goto truncated;
++ }
++ dest += n;
+
+ if (ptr) {
+ *ptr = '\n';
+@@ -226,6 +240,7 @@ char* get_header(const char* message, const char* name, bool content)
+ }
+ }
+
++truncated:
+ /* No header found? */
+ if (dest == last_header) {
+ free(src_copy);
+@@ -549,6 +564,7 @@ static const char* internal_skip_lws(const char* ptr)
+
+ #ifdef GTEST
+ #include "gtest/gtest.h"
++#include <string>
+
+ TEST(Parser, internal_find_header) {
+ char data[] = "OPTIONS sip:server SIP/2.0\r\n"
+@@ -680,6 +696,37 @@ From: SIP/2.0/UDP 85.55.55.12:6090;branch=z9hG4bK831a.2bb3de85.0\r\n\
+ EXPECT_STREQ("", get_header(data, "Via:", false));
+ }
+
++TEST(Parser, get_header_oversized_single) {
++ /* A single header whose content is larger than the static
++ * last_header[MAX_HEADER_LEN * 10] buffer must be truncated, not
++ * overflowed. Run under ASan/Valgrind this catches the overflow;
++ * everywhere it asserts the result stays within the buffer. */
++ std::string msg = "SIP/2.0 200 OK\r\nSubject: ";
++ msg += std::string(MAX_HEADER_LEN * 12, 'A');
++ msg += "\r\n\r\n";
++
++ char* result = get_header(msg.c_str(), "Subject:", true);
++ ASSERT_NE(result, nullptr);
++ EXPECT_EQ(result[0], 'A');
++ EXPECT_LT(strlen(result), (size_t)(MAX_HEADER_LEN * 10));
++}
++
++TEST(Parser, get_header_oversized_repeated) {
++ /* Many repeated headers whose concatenated content exceeds the
++ * buffer must be truncated, not overflowed. */
++ std::string msg = "SIP/2.0 200 OK\r\n";
++ for (int i = 0; i < 500; ++i) {
++ msg += "Via: SIP/2.0/UDP host" + std::to_string(i) +
++ ".example.com:5060;branch=z9hG4bK" +
++ std::string(50, 'x') + "\r\n";
++ }
++ msg += "\r\n";
++
++ char* result = get_header(msg.c_str(), "Via:", true);
++ ASSERT_NE(result, nullptr);
++ EXPECT_LT(strlen(result), (size_t)(MAX_HEADER_LEN * 10));
++}
++
+ TEST(Parser, get_peer_tag__notag) {
+ EXPECT_STREQ(nullptr, get_peer_tag("...\r\nTo: <abc>\r\n;tag=notag\r\n\r\n"));
+ }
diff --git a/sipp.spec b/sipp.spec
index be06c05..db31e44 100644
--- a/sipp.spec
+++ b/sipp.spec
@@ -12,6 +12,10 @@ Patch: sipp-0003-Make-SSL-library-mandatory.patch
Patch: sipp-0004-Removed-outdated-md5-implementation.patch
Patch: sipp-0005-Removed-outdated-Rijndael-Vincent-Rijmen-et-al.-impl.patch
Patch: sipp-0006-Raise-minimal-OpenSSL-version-to-1.1.1.patch
+# Security fixes backported from upstream master (unreleased as of 3.7.7)
+Patch: sipp-0007-fix-use-getAuthParameter-for-algorithm-in-createAuth.patch
+Patch: sipp-0008-fix-bound-get_peer_tag-copy-against-buffer-size.patch
+Patch: sipp-0009-fix-bound-get_header-writes-against-last_header-buff.patch
BuildRequires: cmake
BuildRequires: gcc
BuildRequires: gcc-c++
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2026-09-17 13:42 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-17 13:42 [rpms/sipp] f44: Fix CVEs Peter Lemenkov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox