res_rtp_asterisk.c: Address 2 potential T.140 RED buffer overruns.

* Add check to red_t140_to_red() to ensure that the new primary payload
can't cause the rtp_red->len array items to wrap or cause an overrun of
the rtp_red->t140red_data buffer.

* Add check to rtp_red_buffer() to ensure that a T.140 frame to be sent
can't cause rtp_red->len array items to wrap or cause an overrun of
the rtp_red->buf_data buffer.

Resolves: #GHSA-vfhr-r9x9-c687
Resolves: #GHSA-j2mm-57pq-jh94
This commit is contained in:
George Joseph
2026-04-27 08:29:29 -06:00
committed by George Joseph
parent 8e42fa57de
commit 0749d2a43e
+45 -1
View File
@@ -5517,6 +5517,17 @@ static struct ast_frame *red_t140_to_red(struct rtp_red *red)
/* Store length of each generation and primary data length*/
for (i = 0; i < red->num_gen; i++)
red->len[i] = red->len[i+1];
/*
* RED generation payload sizes are limited to 255 (UCHAR_MAX) bytes by virtue of
* red->len being an array of usigned chars. If the new primary payload exceeds that,
* we're going to truncate it to 255.
*/
if (red->t140.datalen > UCHAR_MAX) {
ast_log(LOG_WARNING, "New T.140 frame of %d bytes exceeds max of %u. Discarding %d bytes.\n",
red->t140.datalen, UCHAR_MAX, red->t140.datalen - UCHAR_MAX);
red->t140.datalen = UCHAR_MAX;
}
red->len[i] = red->t140.datalen;
/* write each generation length in red header */
@@ -9301,7 +9312,13 @@ static int rtp_red_init(struct ast_rtp_instance *instance, int buffer_time, int
return 0;
}
/*! \pre instance is locked */
/*! \pre instance is locked
*
* \warning This code was written many years ago and it's unclear why we actually
* buffer OUTGOING T.140 text frames until a command is encountered but we do.
*
* This may change in the future.
*/
static int rtp_red_buffer(struct ast_rtp_instance *instance, struct ast_frame *frame)
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
@@ -9312,6 +9329,8 @@ static int rtp_red_buffer(struct ast_rtp_instance *instance, struct ast_frame *f
}
if (frame->datalen > 0) {
int space_available = 0;
if (red->t140.datalen > 0) {
const unsigned char *primary = red->buf_data;
@@ -9328,6 +9347,31 @@ static int rtp_red_buffer(struct ast_rtp_instance *instance, struct ast_frame *f
}
}
/*
* RED generation payload sizes are limited to 255 (UCHAR_MAX) bytes by virtue of
* red->len being an array of usigned chars. If adding the current frame will
* exceed that, we're going to flush the saved frame then try again. If the new
* frame fits, great otherwise we're going to toss it. Without understanding
* the purpose of the buffering, that's all we can do now.
*/
space_available = UCHAR_MAX - red->t140.datalen;
if (frame->datalen > space_available) {
ast_rtp_write(instance, &rtp->red->t140);
/*
* ast_rtp_write() calls red_t140_to_red() which resets red->t140.datalen
* back to 0 so we now have UCHAR_MAX space available.
*/
space_available = UCHAR_MAX;
}
if (frame->datalen > space_available) {
ast_log(LOG_WARNING, "%s: T.140 frame of %d bytes exceeds max of %u. Discarding.\n",
ast_rtp_instance_get_channel_id(instance),
frame->datalen, UCHAR_MAX);
return -1;
}
memcpy(&red->buf_data[red->t140.datalen], frame->data.ptr, frame->datalen);
red->t140.datalen += frame->datalen;
red->t140.ts = frame->ts;