pjproject: patch CVE-2026-57166

Details:
https://nvd.nist.gov/vuln/detail/cve-2026-57166

(cherry picked from commit 59a6a134d6ff923bf9ee081a62755cdbde2a88c0)

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
Signed-off-by: Khem Raj <khem.raj@oss.qualcomm.com>
This commit is contained in:
Ankur Tyagi authored and Khem Raj committed 2026-10-19 15:08:25 -07:00
1 parent 0851231b2d
commit f1274b1221
2 files changed
+229

No files matched your search

@@ -0,0 +1,228 @@
From d0b42b902bb6ca8a0a1393799db487642d3bf8ae Mon Sep 17 00:00:00 2001
From: Nanang Izzuddin <nanang@teluu.com>
Date: Wed, 17 Jun 2026 15:55:53 +0700
Subject: [PATCH] Merge commit from fork
* Fix pre-auth stack overflow formatting telnet CLI error indicator
send_err_arg() in cli_telnet.c rendered the error caret into a fixed
256-byte stack buffer using unchecked pj_strcat2; info->err_pos is
bounded only by PJ_CLI_MAX_CMDBUF, so a long command line overflowed
the buffer. Stream the spaces in bounded chunks via telnet_sess_send2,
clamp the caret offset to PJ_CLI_MAX_CMDBUF, and send the message,
prompt and echoed command separately, removing the stack buffer.
Co-Authored-By Claude Code
* Apply the same overflow fix to send_ambi_arg()
Per review, send_ambi_arg() has the same issue as send_err_arg(): it
renders an attacker-influenced number of caret spaces and appends the
last command into a fixed 1028-byte stack buffer with unchecked
pj_strcat2. info->err_pos and sess->rcmd->rbuf are bounded only by
PJ_CLI_MAX_CMDBUF, so a long ambiguous command line could overflow it.
Stream the caret offset in bounded chunks (clamped to PJ_CLI_MAX_CMDBUF)
and stream the clamped last command separately, mirroring the
send_err_arg() fix, instead of writing them into the fixed buffer. The
shared SPACES constant is hoisted to file scope.
Co-Authored-By Claude Code
* Bound completion append in handle_tab()
handle_tab() appended the matched command name into the fixed-size
sess->rcmd->rbuf at offset len (the current command length) without
checking that len + name length fits the buffer. len is bounded by the
receive path, but the completion suffix is added on top, so a long
completable command line could write past rbuf and its NUL terminator.
Clamp the appended length to the space remaining in rbuf, leaving room
for the terminator. Found while auditing the telnet CLI for the same
fixed-buffer overflow pattern as send_err_arg()/send_ambi_arg().
Co-Authored-By Claude Code
(cherry picked from commit 4472a31d77a7506ff175dad5abef490f4e31bed1)
CVE: CVE-2026-57166
Upstream-Status: Backport [https://github.com/pjsip/pjproject/commit/4472a31d77a7506ff175dad5abef490f4e31bed1]
Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
pjlib-util/src/pjlib-util/cli_telnet.c | 116 ++++++++++++++++++-------
1 file changed, 84 insertions(+), 32 deletions(-)
diff --git a/pjlib-util/src/pjlib-util/cli_telnet.c b/pjlib-util/src/pjlib-util/cli_telnet.c
index 0a2954bd4..67898fdd8 100644
--- a/pjlib-util/src/pjlib-util/cli_telnet.c
+++ b/pjlib-util/src/pjlib-util/cli_telnet.c
@@ -680,6 +680,13 @@ static void send_prompt_str(cli_telnet_sess *sess)
telnet_sess_send(sess, &send_data);
}
+/* Buffer of spaces, used to stream the caret offset in bounded chunks
+ * instead of writing an attacker-influenced number of spaces into a
+ * fixed-size stack buffer. Shared by send_err_arg() and send_ambi_arg().
+ */
+static const unsigned char SPACES[64] =
+ " ";
+
/*
* This method is used to send error message to client, including
* the error position of the source command.
@@ -690,32 +697,45 @@ static void send_err_arg(cli_telnet_sess *sess,
pj_bool_t with_return,
pj_bool_t with_last_cmd)
{
- pj_str_t send_data;
- char data_str[256];
- pj_size_t len;
- unsigned i;
+ pj_size_t len, remaining;
cli_telnet_fe *fe = (cli_telnet_fe *)sess->base.fe;
- send_data.ptr = data_str;
- send_data.slen = 0;
-
if (with_return)
- pj_strcat2(&send_data, "\r\n");
+ telnet_sess_send2(sess, (const unsigned char*)"\r\n", 2);
+ /* Compute the caret offset. info->err_pos is derived from
+ * attacker-supplied input (pj_cli_sess_parse) and is bounded only by
+ * PJ_CLI_MAX_CMDBUF, so clamp it before emitting spaces. Otherwise a
+ * ~500-byte command line would overflow the fixed-size stack buffer
+ * this function previously used.
+ */
len = fe->cfg.prompt_str.slen + info->err_pos;
-
- /* Set the error pointer mark */
- for (i=0;i<len;++i) {
- pj_strcat2(&send_data, " ");
+ if (len > PJ_CLI_MAX_CMDBUF)
+ len = PJ_CLI_MAX_CMDBUF;
+
+ remaining = len;
+ while (remaining > 0) {
+ pj_size_t chunk = (remaining > sizeof(SPACES)) ? sizeof(SPACES)
+ : remaining;
+ telnet_sess_send2(sess, SPACES, (int)chunk);
+ remaining -= chunk;
}
- pj_strcat2(&send_data, "^");
- pj_strcat2(&send_data, "\r\n");
- pj_strcat(&send_data, msg);
- pj_strcat(&send_data, &fe->cfg.prompt_str);
- if (with_last_cmd)
- pj_strcat2(&send_data, (char *)sess->rcmd->rbuf);
- telnet_sess_send(sess, &send_data);
+ telnet_sess_send2(sess, (const unsigned char*)"^\r\n", 3);
+
+ if (msg && msg->slen > 0)
+ telnet_sess_send(sess, msg);
+ if (fe->cfg.prompt_str.slen > 0)
+ telnet_sess_send(sess, &fe->cfg.prompt_str);
+ if (with_last_cmd) {
+ pj_str_t last;
+ last.ptr = (char *)sess->rcmd->rbuf;
+ last.slen = (pj_ssize_t)pj_ansi_strlen((const char *)sess->rcmd->rbuf);
+ if (last.slen > PJ_CLI_MAX_CMDBUF)
+ last.slen = PJ_CLI_MAX_CMDBUF;
+ if (last.slen > 0)
+ telnet_sess_send(sess, &last);
+ }
}
static void send_inv_arg(cli_telnet_sess *sess,
@@ -765,7 +785,7 @@ static void send_ambi_arg(cli_telnet_sess *sess,
pj_bool_t with_last_cmd)
{
unsigned i;
- pj_size_t len;
+ pj_size_t len, remaining;
pj_str_t send_data;
char data[1028];
cli_telnet_fe *fe = (cli_telnet_fe *)sess->base.fe;
@@ -779,14 +799,25 @@ static void send_ambi_arg(cli_telnet_sess *sess,
send_data.slen = 0;
if (with_return)
- pj_strcat2(&send_data, "\r\n");
+ telnet_sess_send2(sess, (const unsigned char*)"\r\n", 2);
+ /* Compute and clamp the caret offset, then stream the spaces, like
+ * send_err_arg(). info->err_pos is attacker-bounded only by
+ * PJ_CLI_MAX_CMDBUF, so it must not drive writes into data[].
+ */
len = fe->cfg.prompt_str.slen + info->err_pos;
-
- for (i=0;i<len;++i) {
- pj_strcat2(&send_data, " ");
+ if (len > PJ_CLI_MAX_CMDBUF)
+ len = PJ_CLI_MAX_CMDBUF;
+
+ remaining = len;
+ while (remaining > 0) {
+ pj_size_t chunk = (remaining > sizeof(SPACES)) ? sizeof(SPACES)
+ : remaining;
+ telnet_sess_send2(sess, SPACES, (int)chunk);
+ remaining -= chunk;
}
- pj_strcat2(&send_data, "^");
+ telnet_sess_send2(sess, (const unsigned char*)"^", 1);
+
/* Get the max length of the command name */
for (i=0;i<info->hint_cnt;++i) {
if (hint[i].type.slen > 0) {
@@ -874,10 +905,21 @@ static void send_ambi_arg(cli_telnet_sess *sess,
}
pj_strcat2(&send_data, "\r\n");
pj_strcat(&send_data, &fe->cfg.prompt_str);
- if (with_last_cmd)
- pj_strcat2(&send_data, (char *)sess->rcmd->rbuf);
-
telnet_sess_send(sess, &send_data);
+
+ /* Stream the last command separately with a clamp; sess->rcmd->rbuf
+ * is attacker-bounded only by PJ_CLI_MAX_CMDBUF, so appending it into
+ * data[] could overflow the fixed-size buffer.
+ */
+ if (with_last_cmd) {
+ pj_str_t last;
+ last.ptr = (char *)sess->rcmd->rbuf;
+ last.slen = (pj_ssize_t)pj_ansi_strlen((const char *)sess->rcmd->rbuf);
+ if (last.slen > PJ_CLI_MAX_CMDBUF)
+ last.slen = PJ_CLI_MAX_CMDBUF;
+ if (last.slen > 0)
+ telnet_sess_send(sess, &last);
+ }
}
/*
@@ -1035,10 +1077,20 @@ static pj_bool_t handle_tab(cli_telnet_sess *sess)
}
send_comp_arg(sess, &info);
- pj_memcpy(&sess->rcmd->rbuf[len], info.hint[0].name.ptr,
- info.hint[0].name.slen);
-
- len += (unsigned)info.hint[0].name.slen;
+ /* Append the matched name into the fixed-size rbuf. len is
+ * attacker-influenced (the typed command length), so clamp
+ * the copy to leave room for the NUL terminator and avoid
+ * overflowing rbuf.
+ */
+ if (len < sizeof(sess->rcmd->rbuf) - 1) {
+ pj_size_t avail = sizeof(sess->rcmd->rbuf) - 1 - len;
+ pj_size_t cplen = (pj_size_t)info.hint[0].name.slen;
+ if (cplen > avail)
+ cplen = avail;
+ pj_memcpy(&sess->rcmd->rbuf[len],
+ info.hint[0].name.ptr, cplen);
+ len += (unsigned)cplen;
+ }
sess->rcmd->rbuf[len] = 0;
}
} else {
@@ -20,6 +20,7 @@ SRC_URI = "git://github.com/pjsip/pjproject.git;protocol=https;branch=master;tag
file://CVE-2026-57163.patch \
file://CVE-2026-57164.patch \
file://CVE-2026-57165.patch \
file://CVE-2026-57166.patch \
"
SRCREV = "5a457451fa2712ba18e12b01738e8ff3af2b26fd"