summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorseteiro <[email protected]>2026-11-11 15:11:22 +0800
committerRbb666 <[email protected]>2026-11-13 09:38:07 +0800
commite69e6620322f3394f7da5c56ebfcfed408669efb (patch)
treee2b284ef5b3addfe76c3bc0386b4394b688421cd
parent9d670b739c72123e90380995f77ec6a2c3f0977f (diff)
[utilities][rt-link] bound long-frame reassembly against allocation size
Record the allocated buffer length in struct rt_link_record::dataspace_size and enforce bounds checking during long-frame receive reassembly: - Validate extend.parameter in _long_handle_first() (must be non-zero and at most RT_LINK_FRAMES_MAX * RT_LINK_MAX_DATA_LENGTH), aborting cleanly on invalid length or allocation failure. - Validate data_len <= RT_LINK_MAX_DATA_LENGTH, index < RT_LINK_FRAMES_MAX and index < total, and overflow-safe offset + data_len <= dataspace_size before rt_link_hw_copy() in _long_handle_second(), aborting cleanly on bounds violation and passing dataspace_size to rt_link_recv_finish(). - Clear dataspace_size on all paths that release or reset dataspace. - Reject data frames whose head.length exceeds RT_LINK_MAX_DATA_LENGTH in rt_link_frame_check() to align the receive path with rt_link_send(). Fix #12030
-rw-r--r--components/utilities/rt-link/inc/rtlink.h9
-rw-r--r--components/utilities/rt-link/src/rtlink.c83
2 files changed, 84 insertions, 8 deletions
diff --git a/components/utilities/rt-link/inc/rtlink.h b/components/utilities/rt-link/inc/rtlink.h
index 9cf22ec93e..6b80fd2072 100644
--- a/components/utilities/rt-link/inc/rtlink.h
+++ b/components/utilities/rt-link/inc/rtlink.h
@@ -130,10 +130,11 @@ struct rt_link_frame_head
/* record frame information that opposite */
struct rt_link_record
{
- rt_uint8_t rx_seq; /* record the opposite sequence */
- rt_uint8_t total; /* the number of long frame number */
- rt_uint8_t long_count; /* long packet recv counter */
- rt_uint8_t *dataspace; /* the space of long frame */
+ rt_uint8_t rx_seq; /* record the opposite sequence */
+ rt_uint8_t total; /* the number of long frame number */
+ rt_uint8_t long_count; /* long packet recv counter */
+ rt_uint8_t *dataspace; /* the space of long frame */
+ rt_size_t dataspace_size; /* allocated byte size of dataspace */
};
struct rt_link_extend
diff --git a/components/utilities/rt-link/src/rtlink.c b/components/utilities/rt-link/src/rtlink.c
index 2581488c0c..9380da15e5 100644
--- a/components/utilities/rt-link/src/rtlink.c
+++ b/components/utilities/rt-link/src/rtlink.c
@@ -339,6 +339,7 @@ static void _stop_recv_long(void)
rt_free(rt_link_scb->rx_record.dataspace);
rt_link_scb->rx_record.dataspace = RT_NULL;
}
+ rt_link_scb->rx_record.dataspace_size = 0;
rt_link_scb->rx_record.long_count = 0;
rt_link_scb->rx_record.total = 0;
}
@@ -351,6 +352,7 @@ static rt_err_t rt_link_frame_stop_receive(struct rt_link_frame *frame)
rt_free(rt_link_scb->rx_record.dataspace);
}
rt_link_scb->rx_record.dataspace = RT_NULL;
+ rt_link_scb->rx_record.dataspace_size = 0;
rt_link_scb->rx_record.long_count = 0;
rt_link_scb->rx_record.total = 0;
@@ -458,9 +460,14 @@ static void rt_link_recv_finish(rt_uint16_t serv, void *data, rt_size_t size)
static rt_err_t rt_link_short_handle(struct rt_link_frame *receive_frame)
{
LOG_D("Seq(%d) short data", receive_frame->head.sequence);
+ if (rt_link_scb->rx_record.dataspace != RT_NULL)
+ {
+ _stop_recv_long();
+ }
rt_link_scb->rx_record.dataspace = rt_malloc(receive_frame->data_len);
if (rt_link_scb->rx_record.dataspace != RT_NULL)
{
+ rt_link_scb->rx_record.dataspace_size = receive_frame->data_len;
if (receive_frame->head.ack)
{
rt_link_command_frame_send(receive_frame->head.service,
@@ -471,6 +478,7 @@ static rt_err_t rt_link_short_handle(struct rt_link_frame *receive_frame)
rt_link_hw_copy(rt_link_scb->rx_record.dataspace, receive_frame->real_data, receive_frame->data_len);
rt_link_recv_finish(receive_frame->head.service, rt_link_scb->rx_record.dataspace, receive_frame->data_len);
rt_link_scb->rx_record.dataspace = RT_NULL;
+ rt_link_scb->rx_record.dataspace_size = 0;
}
else
{
@@ -482,6 +490,21 @@ static rt_err_t rt_link_short_handle(struct rt_link_frame *receive_frame)
static void _long_handle_first(struct rt_link_frame *receive_frame)
{
+ rt_size_t max_payload = (rt_size_t)RT_LINK_FRAMES_MAX * RT_LINK_MAX_DATA_LENGTH;
+
+ if ((receive_frame->extend.parameter == 0) ||
+ ((rt_size_t)receive_frame->extend.parameter > max_payload))
+ {
+ LOG_W("long data invalid len (%uB).", (unsigned int)receive_frame->extend.parameter);
+ _stop_recv_long();
+ return;
+ }
+
+ if (rt_link_scb->rx_record.dataspace != RT_NULL)
+ {
+ _stop_recv_long();
+ }
+
if (receive_frame->extend.parameter % RT_LINK_MAX_DATA_LENGTH == 0)
{
receive_frame->total = receive_frame->extend.parameter / RT_LINK_MAX_DATA_LENGTH;
@@ -491,12 +514,16 @@ static void _long_handle_first(struct rt_link_frame *receive_frame)
receive_frame->total = receive_frame->extend.parameter / RT_LINK_MAX_DATA_LENGTH + 1;
}
- rt_link_scb->rx_record.total = receive_frame->total;
rt_link_scb->rx_record.dataspace = rt_malloc(receive_frame->extend.parameter);
if (rt_link_scb->rx_record.dataspace == RT_NULL)
{
LOG_W("long data (%dB) alloc failed.", receive_frame->extend.parameter);
+ _stop_recv_long();
+ return;
}
+
+ rt_link_scb->rx_record.dataspace_size = receive_frame->extend.parameter;
+ rt_link_scb->rx_record.total = receive_frame->total;
}
static void _long_handle_second(struct rt_link_frame *receive_frame)
@@ -512,14 +539,45 @@ static void _long_handle_second(struct rt_link_frame *receive_frame)
, receive_frame->total
, rt_link_scb->rx_record.long_count);
- if ((receive_frame->index > RT_LINK_FRAMES_MAX) || (rt_link_scb->rx_record.long_count & (0x01 << receive_frame->index)))
+ if (receive_frame->data_len > RT_LINK_MAX_DATA_LENGTH)
+ {
+ LOG_W("ERR:long data_len %u exceeds max %u",
+ (unsigned int)receive_frame->data_len,
+ (unsigned int)RT_LINK_MAX_DATA_LENGTH);
+ _stop_recv_long();
+ return;
+ }
+
+ if ((receive_frame->index >= RT_LINK_FRAMES_MAX) ||
+ (receive_frame->index >= rt_link_scb->rx_record.total))
+ {
+ LOG_D("ERR:index %d, total %d, rx_seq %d",
+ receive_frame->index,
+ rt_link_scb->rx_record.total,
+ rt_link_scb->rx_record.rx_seq);
+ _stop_recv_long();
+ return;
+ }
+
+ if (rt_link_scb->rx_record.long_count & (0x01 << receive_frame->index))
{
LOG_D("ERR:index %d, rx_seq %d", receive_frame->index, rt_link_scb->rx_record.rx_seq);
}
else if (rt_link_scb->rx_record.dataspace != RT_NULL)
{
+ offset = (rt_size_t)RT_LINK_MAX_DATA_LENGTH * (rt_size_t)receive_frame->index;
+ if ((offset > rt_link_scb->rx_record.dataspace_size) ||
+ ((rt_size_t)receive_frame->data_len > (rt_link_scb->rx_record.dataspace_size - offset)))
+ {
+ LOG_W("ERR:long data offset %u len %u exceeds size %u",
+ (unsigned int)offset,
+ (unsigned int)receive_frame->data_len,
+ (unsigned int)rt_link_scb->rx_record.dataspace_size);
+ _stop_recv_long();
+ return;
+ }
+
rt_link_scb->rx_record.long_count |= (0x01 << receive_frame->index);
- offset = RT_LINK_MAX_DATA_LENGTH * receive_frame->index;
rt_link_hw_copy(rt_link_scb->rx_record.dataspace + offset, receive_frame->real_data, receive_frame->data_len);
if (receive_frame->head.ack)
@@ -543,12 +601,15 @@ static void _long_handle_second(struct rt_link_frame *receive_frame)
if (rt_link_utils_num1(rt_link_scb->rx_record.long_count) == rt_link_scb->rx_record.total)
{
rt_timer_stop(&rt_link_scb->longframetimer);
- rt_link_recv_finish(receive_frame->head.service, rt_link_scb->rx_record.dataspace, receive_frame->extend.parameter);
+ rt_link_recv_finish(receive_frame->head.service,
+ rt_link_scb->rx_record.dataspace,
+ rt_link_scb->rx_record.dataspace_size);
rt_enter_critical();
/* empty rx_record */
rt_link_scb->rx_record.rx_seq += rt_link_scb->rx_record.total;
rt_link_scb->rx_record.dataspace = RT_NULL;
+ rt_link_scb->rx_record.dataspace_size = 0;
rt_link_scb->rx_record.long_count = 0;
rt_link_scb->rx_record.total = 0;
ack_mask = RT_LINK_ACK_MAX;
@@ -561,6 +622,10 @@ static void _long_handle_second(struct rt_link_frame *receive_frame)
rt_timer_start(&rt_link_scb->longframetimer);
}
}
+ else
+ {
+ _stop_recv_long();
+ }
}
static rt_err_t rt_link_long_handle(struct rt_link_frame *receive_frame)
@@ -805,6 +870,16 @@ static void rt_link_frame_check(void)
rt_link_hw_buffer_point_shift(&rt_link_scb->rx_buffer->read_point, 1);
goto __find_head;
}
+ if (((receive_frame.attribute == RT_LINK_SHORT_DATA_FRAME) ||
+ (receive_frame.attribute == RT_LINK_LONG_DATA_FRAME)) &&
+ (receive_frame.data_len > RT_LINK_MAX_DATA_LENGTH))
+ {
+ LOG_W("data frame length (%u) exceeds max (%u).",
+ (unsigned int)receive_frame.data_len,
+ (unsigned int)RT_LINK_MAX_DATA_LENGTH);
+ rt_link_hw_buffer_point_shift(&rt_link_scb->rx_buffer->read_point, 1);
+ goto __find_head;
+ }
buff_len += receive_frame.data_len;
if (receive_frame.head.crc)
{