Commit 6556c886 authored by Cedric Roux's avatar Cedric Roux

nr rlc: tolerate bogus data

Some unfriendly entity may play with the RLC module and send bogus data to
trigger funky behaviors here and there.

A report sent by Dhanish, India, indentifies one such issue.

From analyzing this report, a possible scenario is the following.

Unfriendly entity sends an RLC PDU with:
is_first=0
is_last=0
so=15
lenght of data, whatever, let's say 1.

This PDU is put in the RX list.

Then later it sends another PDU (for the same SN, obviously), with:
is_first=1
is_last=1
so=0 (well, since is_first=1, necessarily so=0; it is not transmitted,
see 38.322 6.2.2.3 for UM and 38.322 6.2.2.4 for AM)
length=10, let's say.

This PDU is also put in the RX list, before the previous one.

Then the function sdu_full() returns 1, so reassemble_and_deliver() is
called and the 'while (pdu)' loop is executed for both PDUs. When the
second (bogus one) is processed, so==10 (after processing the first
PDU) and the line: int len = pdu->size - (so - pdu->so)
is: int len = 1 - (10 - 15)
which is not good.

So we detect the case 'pdu->so > so' and reject the SDU. We could label
the other entity as bogus, since no standard RLC implementation will
produce such a case, but let's remain friendly, even with unfriendly
entities. (To be changed later if needed.)

The problem was reported for RLC AM but is also present in RLC UM.
(Not in RLC TM, where there is no segmentation.)

Note: according to the report, this bug was found using a fuzzer
described as 'AI-assisted custom 5G NR protocol fuzzer'. It had
to be said.
parent af4b0d53
......@@ -185,6 +185,12 @@ static void reassemble_and_deliver(nr_rlc_entity_am_t *entity, int sn)
/* reassemble - free 'data' of each segment after processing */
while (pdu != NULL) {
if (pdu->so > so && !bad_sdu) {
/* pdu->so > so is possible when the other end sends bogus data */
LOG_E(RLC, "%s:%d:%s: inconsistent SDU, discarding\n",
__FILE__, __LINE__, __FUNCTION__);
bad_sdu = 1;
}
int len = pdu->size - (so - pdu->so);
if (so + len > NR_SDU_MAX && !bad_sdu) {
LOG_E(RLC, "%s:%d:%s: bad SDU, too big, discarding\n",
......
......@@ -139,6 +139,12 @@ static void reassemble_and_deliver(nr_rlc_entity_um_t *entity, int sn)
/* reassemble - free 'data' of each segment after processing */
while (pdu != NULL && pdu->sn == sn) {
if (pdu->so > so && !bad_sdu) {
/* pdu->so > so is possible when the other end sends bogus data */
LOG_E(RLC, "%s:%d:%s: inconsistent SDU, discarding\n",
__FILE__, __LINE__, __FUNCTION__);
bad_sdu = 1;
}
int len = pdu->size - (so - pdu->so);
if (so + len > NR_SDU_MAX && !bad_sdu) {
LOG_E(RLC, "%s:%d:%s: bad SDU, too big, discarding\n",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment