csn1: Validate recursive array max size during decoding
This way if CSN1 encoded bitstream contains more elements than what the
defintion expects it will fail instead of overflowing the decoded
buffer.
RA cap struct placed in unit test is taken from a real android phone
sending the value when attaching to the network. Then SGSN sends it back
and osmo-pcu would crash similar to unit test:
*** stack smashing detected ***: terminated
Process terminating with default action of signal 6 (SIGABRT): dumping core
at 0x4C62CE5: raise (in /usr/lib/libc-2.31.so)
by 0x4C4C856: abort (in /usr/lib/libc-2.31.so)
by 0x4CA62AF: __libc_message (in /usr/lib/libc-2.31.so)
by 0x4D36069: __fortify_fail (in /usr/lib/libc-2.31.so)
by 0x4D36033: __stack_chk_fail (in /usr/lib/libc-2.31.so)
by 0x124706: testRAcap2(void*) (RLCMACTest.cpp:468)
Related: OS#4463
Change-Id: I9fe0e55e0a6a41ae2cc885fba490c1d4a186231e
diff --git a/src/csn1.c b/src/csn1.c
index 296bf6c..7172847 100644
--- a/src/csn1.c
+++ b/src/csn1.c
@@ -1278,9 +1278,10 @@
case CSN_RECURSIVE_TARRAY:
{ /* Recursive way to specify an array of type: <lists> ::= { 1 <type> } ** 0 ;
* M_REC_TARRAY(_STRUCT, _MEMBER, _MEMBER_TYPE, _ElementCountField)
- * {t, offsetof(_STRUCT, _ElementCountField), (void*)CSNDESCR_##_MEMBER_TYPE, offsetof(_STRUCT, _MEMBER), #_MEMBER, (StreamSerializeFcn_t)sizeof(_MEMBER_TYPE)}
+ * {t, offsetof(_STRUCT, _ElementCountField), (void*)CSNDESCR_##_MEMBER_TYPE, offsetof(_STRUCT, _MEMBER), #_MEMBER, (StreamSerializeFcn_t)sizeof(_MEMBER_TYPE), (void_fn_t)ElementsOf(((_STRUCT*)0)->_MEMBER)}
*/
gint16 nSizeElement = (gint16)(gint32)pDescr->value;
+ guint32 nSizeArray = (guint32)((uintptr_t)pDescr->aux_fn);
guint8 ElementCount = 0;
pui8 = pui8DATA(data, pDescr->offset);
@@ -1292,6 +1293,12 @@
remaining_bits_len--;
ElementCount++;
+ if (ElementCount > nSizeArray)
+ {
+ LOGPC(DCSN1, LOGL_ERROR, "error: %s: too many elements (>%u) in recursive array. Increase its size! } |", pDescr->sz, nSizeArray);
+ return ProcessError(readIndex,"csnStreamDecoder", CSN_ERROR_STREAM_NOT_SUPPORTED, pDescr);
+ }
+
{ /* unpack the following data structure */
csnStream_t arT = *ar;
gint16 Status;
@@ -1342,9 +1349,10 @@
case CSN_RECURSIVE_TARRAY_1:
{ /* Recursive way to specify an array of type: <lists> ::= <type> { 1 <type> } ** 0 ;
* M_REC_TARRAY(_STRUCT, _MEMBER, _MEMBER_TYPE, _ElementCountField)
- * {t, offsetof(_STRUCT, _ElementCountField), (void*)CSNDESCR_##_MEMBER_TYPE, offsetof(_STRUCT, _MEMBER), #_MEMBER, (StreamSerializeFcn_t)sizeof(_MEMBER_TYPE)}
+ * {t, offsetof(_STRUCT, _ElementCountField), (void*)CSNDESCR_##_MEMBER_TYPE, offsetof(_STRUCT, _MEMBER), #_MEMBER, (StreamSerializeFcn_t)sizeof(_MEMBER_TYPE), (void_fn_t)ElementsOf(((_STRUCT*)0)->_MEMBER)}
*/
gint16 nSizeElement = (gint16)(gint32)pDescr->value;
+ guint32 nSizeArray = (guint32)((uintptr_t)pDescr->aux_fn);
guint8 ElementCount = 0;
csnStream_t arT = *ar;
gboolean EndOfList = FALSE;
@@ -1355,6 +1363,12 @@
{ /* get data element */
ElementCount++;
+ if (ElementCount > nSizeArray)
+ {
+ LOGPC(DCSN1, LOGL_ERROR, "error: %s: too many elements (>%u) in recursive array. Increase its size! } |", pDescr->sz, nSizeArray);
+ return ProcessError(readIndex,"csnStreamDecoder", CSN_ERROR_STREAM_NOT_SUPPORTED, pDescr);
+ }
+
LOGPC(DCSN1, LOGL_DEBUG, "%s { | ", pDescr->sz);
csnStreamInit(&arT, bit_offset, remaining_bits_len);