CVE-2020-11068: Buffer Copy without Checking Size of Input ('Classic Buffer Overflow') (CWE-120)
value: In LoRaMac-node before 4.4.4, a reception buffer overflow can happen due to the received buffer size not being checked. This has been fixed in 4.4.4.
CWE description: The product copies an input buffer to an output buffer without verifying that the size of the input buffer is less than the size of the output buffer, leading to a buffer overflow.
CVSS v3 base score: 8.8
Published: 2020-06-23T17:15Z
Repository: https://github.com/Lora-net/LoRaMac-node
Language: C
Files changed: src/mac/LoRaMac.c, src/peripherals/atecc608a-tnglora-se/atecc608a-tnglora-se.c, src/peripherals/lr1110-se/lr1110-se.c, src/peripherals/soft-se/soft-se.c
Commit date: 2020-04-16 17:05:15 +0200
Commit message: Added received buffer size checks.

Diff: diff --git a/src/mac/LoRaMac.c b/src/mac/LoRaMac.c
index 47264c06..d0c477fb 100644
--- a/src/mac/LoRaMac.c
+++ b/src/mac/LoRaMac.c
@@ -995,10 +995,17 @@ static void ProcessRadioRxDone( void )
     macHdr.Value = payload[pktHeaderLen++];
 
     switch( macHdr.Bits.MType )
     {
         case FRAME_TYPE_JOIN_ACCEPT:
+            // Check if the received frame size is valid
+            if( size < LORAMAC_JOIN_ACCEPT_FRAME_MIN_SIZE )
+            {
+                MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
+                PrepareRxDoneAbort( );
+                return;
+            }
             macMsgJoinAccept.Buffer = payload;
             macMsgJoinAccept.BufSize = size;
 
             // Abort in case if the device isn't joined yet and no rejoin request is ongoing.
             if( MacCtx.NvmCtx->NetworkActivation != ACTIVATION_TYPE_NONE )
@@ -1066,11 +1073,12 @@ static void ProcessRadioRxDone( void )
             // Check if the received payload size is valid
             getPhy.UplinkDwellTime = MacCtx.NvmCtx->MacParams.DownlinkDwellTime;
             getPhy.Datarate = MacCtx.McpsIndication.RxDatarate;
             getPhy.Attribute = PHY_MAX_PAYLOAD;
             phyParam = RegionGetPhyParam( MacCtx.NvmCtx->Region, &getPhy );
-            if( MAX( 0, ( int16_t )( ( int16_t ) size - ( int16_t ) LORA_MAC_FRMPAYLOAD_OVERHEAD ) ) > ( int16_t )phyParam.Value )
+            if( ( MAX( 0, ( int16_t )( ( int16_t ) size - ( int16_t ) LORAMAC_FRAME_PAYLOAD_OVERHEAD_SIZE ) ) > ( int16_t )phyParam.Value ) ||
+                ( size < LORAMAC_FRAME_PAYLOAD_MIN_SIZE ) )
             {
                 MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
                 PrepareRxDoneAbort( );
                 return;
             }
diff --git a/src/peripherals/atecc608a-tnglora-se/atecc608a-tnglora-se.c b/src/peripherals/atecc608a-tnglora-se/atecc608a-tnglora-se.c
index c487d7e5..14e56805 100644
--- a/src/peripherals/atecc608a-tnglora-se/atecc608a-tnglora-se.c
+++ b/src/peripherals/atecc608a-tnglora-se/atecc608a-tnglora-se.c
@@ -497,10 +497,16 @@ SecureElementStatus_t SecureElementProcessJoinAccept( JoinReqIdentifier_t joinRe
     if( ( encJoinAccept == NULL ) || ( decJoinAccept == NULL ) || ( versionMinor == NULL ) )
     {
         return SECURE_ELEMENT_ERROR_NPE;
     }
 
+    // Check that frame size isn't bigger than a JoinAccept with CFList size
+    if( encJoinAcceptSize > LORAMAC_JOIN_ACCEPT_FRAME_MAX_SIZE )
+    {
+        return SECURE_ELEMENT_ERROR_BUF_SIZE;
+    }
+
     // Determine decryption key
     KeyIdentifier_t encKeyID = NWK_KEY;
 
     if( joinReqType != JOIN_REQ )
     {
diff --git a/src/peripherals/lr1110-se/lr1110-se.c b/src/peripherals/lr1110-se/lr1110-se.c
index 106e92d0..56e027df 100644
--- a/src/peripherals/lr1110-se/lr1110-se.c
+++ b/src/peripherals/lr1110-se/lr1110-se.c
@@ -288,10 +288,16 @@ SecureElementStatus_t SecureElementProcessJoinAccept( JoinReqIdentifier_t joinRe
     if( ( encJoinAccept == NULL ) || ( decJoinAccept == NULL ) || ( versionMinor == NULL ) )
     {
         return SECURE_ELEMENT_ERROR_NPE;
     }
 
+    // Check that frame size isn't bigger than a JoinAccept with CFList size
+    if( encJoinAcceptSize > LORAMAC_JOIN_ACCEPT_FRAME_MAX_SIZE )
+    {
+        return SECURE_ELEMENT_ERROR_BUF_SIZE;
+    }
+
     // Determine decryption key
     KeyIdentifier_t encKeyID = NWK_KEY;
 
     if( joinReqType != JOIN_REQ )
     {
diff --git a/src/peripherals/soft-se/soft-se.c b/src/peripherals/soft-se/soft-se.c
index 80ad18e2..14946fd7 100644
--- a/src/peripherals/soft-se/soft-se.c
+++ b/src/peripherals/soft-se/soft-se.c
@@ -393,10 +393,16 @@ SecureElementStatus_t SecureElementProcessJoinAccept( JoinReqIdentifier_t joinRe
     if( ( encJoinAccept == NULL ) || ( decJoinAccept == NULL ) || ( versionMinor == NULL ) )
     {
         return SECURE_ELEMENT_ERROR_NPE;
     }
 
+    // Check that frame size isn't bigger than a JoinAccept with CFList size
+    if( encJoinAcceptSize > LORAMAC_JOIN_ACCEPT_FRAME_MAX_SIZE )
+    {
+        return SECURE_ELEMENT_ERROR_BUF_SIZE;
+    }
+
     // Determine decryption key
     KeyIdentifier_t encKeyID = NWK_KEY;
 
     if( joinReqType != JOIN_REQ )
     {

Vulnerable code:             if( MAX( 0, ( int16_t )( ( int16_t ) size - ( int16_t ) LORA_MAC_FRMPAYLOAD_OVERHEAD ) ) > ( int16_t )phyParam.Value )
Fixed code:             // Check if the received frame size is valid
            if( size < LORAMAC_JOIN_ACCEPT_FRAME_MIN_SIZE )
            {
                MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
                PrepareRxDoneAbort( );
                return;
            }
            if( ( MAX( 0, ( int16_t )( ( int16_t ) size - ( int16_t ) LORAMAC_FRAME_PAYLOAD_OVERHEAD_SIZE ) ) > ( int16_t )phyParam.Value ) ||
                ( size < LORAMAC_FRAME_PAYLOAD_MIN_SIZE ) )
    // Check that frame size isn't bigger than a JoinAccept with CFList size
    if( encJoinAcceptSize > LORAMAC_JOIN_ACCEPT_FRAME_MAX_SIZE )
    {
        return SECURE_ELEMENT_ERROR_BUF_SIZE;
    }

    // Check that frame size isn't bigger than a JoinAccept with CFList size
    if( encJoinAcceptSize > LORAMAC_JOIN_ACCEPT_FRAME_MAX_SIZE )
    {
        return SECURE_ELEMENT_ERROR_BUF_SIZE;
    }

    // Check that frame size isn't bigger than a JoinAccept with CFList size
    if( encJoinAcceptSize > LORAMAC_JOIN_ACCEPT_FRAME_MAX_SIZE )
    {
        return SECURE_ELEMENT_ERROR_BUF_SIZE;
    }