Tool/software:
In function "bdb_TCProcessJoiningList", the pointer "tempJoiningDescNode" is released by "bdb_TCJoiningDeviceFree" when the "NodeJoinTimeout" of "tempJoiningDescNode" is "0", but later the pointer "tempJoiningDescNode" point to the next item from itself. After the pointer "tempJoiningDescNode" is released, the value in "tempJoiningDescNode" is not correct.
This function can be fixed like this
void bdb_TCProcessJoiningList(void)
{
bdb_joiningDeviceList_t* tempJoiningDescNode;
if(bdb_joiningDeviceList)
{
tempJoiningDescNode = bdb_joiningDeviceList;
while(tempJoiningDescNode)
{
if(tempJoiningDescNode->NodeJoinTimeout)
{
tempJoiningDescNode->NodeJoinTimeout--;
}
if(tempJoiningDescNode->NodeJoinTimeout == 0)
{
uint8_t isTCLKExchangeRequired = bdb_doTrustCenterRequireKeyExchange();
//Check if the key exchange is required
if(isTCLKExchangeRequired)
{
AddrMgrEntry_t entry;
entry.user = ADDRMGR_USER_DEFAULT;
OsalPort_memcpy(entry.extAddr,tempJoiningDescNode->bdbJoiningNodeEui64, Z_EXTADDR_LEN);
if(AddrMgrEntryLookupExt(&entry))
{
ZDSecMgrAPSRemove(entry.nwkAddr,entry.extAddr,tempJoiningDescNode->parentAddr);
}
}
// If we are here, a joining device has been expired due to timeout either because it is a
// legacy device (does not perform key exchange), it is an Z3.0 device that did not perform
// key exchange intentionally, or it is a Z3.0 device that has failed to perform key exchange.
// Depending on our TC settings, below we decide if this joiner should be removed from the
// security manager
uint16_t keyNvIndex;
uint16_t index;
APSME_TCLinkKeyNVEntry_t TCLKDevEntry;
uint8_t found;
//search for the entry in the TCLK table
keyNvIndex = APSME_SearchTCLinkKeyEntry(tempJoiningDescNode->bdbJoiningNodeEui64,&found, &TCLKDevEntry);
uint16_t nwkAddr;
//Look up nwkAddr before it is cleared by ZDSecMgrAddrClear
AddrMgrNwkAddrLookup(tempJoiningDescNode->bdbJoiningNodeEui64, &nwkAddr);
// If TC is mandating key exchange, remove devices that have not successfully performed key exchange.
// Keep entries for ZG_PROVISIONAL_KEY so install code derived key is maintained, so joiner can reattempt join
// If we got here and have a ZG_VERIFIED_KEY (unexpected), do not remove this entry either
if( (isTCLKExchangeRequired == true) &&
(TCLKDevEntry.keyAttributes != ZG_PROVISIONAL_KEY) &&
(TCLKDevEntry.keyAttributes != ZG_VERIFIED_KEY)
)
{
//Remove the entry in address manager
ZDSecMgrAddrClear(tempJoiningDescNode->bdbJoiningNodeEui64);
//If found, erase it.
if(found == TRUE)
{
memset(&TCLKDevEntry,0,sizeof(APSME_TCLinkKeyNVEntry_t));
TCLKDevEntry.keyAttributes = ZG_DEFAULT_KEY;
//Increase the shift by one. Validate the maximum shift of the seed which is 15
index = keyNvIndex;
TCLinkKeyRAMEntry[index].rxFrmCntr = 0;
TCLinkKeyRAMEntry[index].txFrmCntr = 0;
TCLinkKeyRAMEntry[index].entryUsed = FALSE;
//Update the entry
osal_nv_write_ex( ZCD_NV_EX_TCLK_TABLE, keyNvIndex,
sizeof(APSME_TCLinkKeyNVEntry_t),
&TCLKDevEntry );
}
}
if(pfnTCLinkKeyExchangeProcessCB)
{
bdb_TCLinkKeyExchProcess_t bdb_TCLinkKeyExchProcess;
OsalPort_memcpy(bdb_TCLinkKeyExchProcess.extAddr,tempJoiningDescNode->bdbJoiningNodeEui64, Z_EXTADDR_LEN);
bdb_TCLinkKeyExchProcess.nwkAddr = nwkAddr;
bdb_TCLinkKeyExchProcess.status = BDB_TC_LK_EXCH_PROCESS_EXCH_FAIL;
bdb_SendMsg(bdb_TaskID, BDB_TC_LINK_KEY_EXCHANGE_PROCESS, BDB_MSG_EVENT_SUCCESS,sizeof(bdb_TCLinkKeyExchProcess_t),(uint8_t*)&bdb_TCLinkKeyExchProcess);
}
//Free the device from the list
//The next pointer needs to be obtained before the previous pointer is released, fixed by Luoyiming at 2025-03-06
bdb_joiningDeviceList_t* joiningDeviceToRemove = tempJoiningDescNode;
tempJoiningDescNode = tempJoiningDescNode->nextDev;
bdb_TCJoiningDeviceFree(joiningDeviceToRemove);
}
else
{
//The next pointer can only be obtained when the previous pointer has not been released, fixed by Luoyiming at 2025-03-06
tempJoiningDescNode = tempJoiningDescNode->nextDev;
}
}
}
//we are done with the list
if(bdb_joiningDeviceList == NULL)
{
OsalPortTimers_stopTimer(bdb_TaskID,BDB_TC_JOIN_TIMEOUT);
}
}