- GOOSE receiver: added additional length and plausibility checks to fix #509

v1.5
Michael Zillgith 1 year ago
parent fd820643c5
commit a49d0cc78b

@ -662,10 +662,12 @@ parseGoosePayload(GooseReceiver self, uint8_t* buffer, int apduLength)
uint32_t numberOfDatSetEntries = 0; uint32_t numberOfDatSetEntries = 0;
if (buffer[bufPos++] == 0x61) { if (buffer[bufPos++] == 0x61)
{
int gooseLength; int gooseLength;
bufPos = BerDecoder_decodeLength(buffer, &gooseLength, bufPos, apduLength); bufPos = BerDecoder_decodeLength(buffer, &gooseLength, bufPos, apduLength);
if (bufPos < 0) { if (bufPos < 0)
{
if (DEBUG_GOOSE_SUBSCRIBER) if (DEBUG_GOOSE_SUBSCRIBER)
printf("GOOSE_SUBSCRIBER: Malformed message: failed to decode BER length tag!\n"); printf("GOOSE_SUBSCRIBER: Malformed message: failed to decode BER length tag!\n");
return 0; return 0;
@ -673,12 +675,14 @@ parseGoosePayload(GooseReceiver self, uint8_t* buffer, int apduLength)
int gooseEnd = bufPos + gooseLength; int gooseEnd = bufPos + gooseLength;
while (bufPos < gooseEnd) { while (bufPos < gooseEnd)
{
int elementLength; int elementLength;
uint8_t tag = buffer[bufPos++]; uint8_t tag = buffer[bufPos++];
bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, apduLength); bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, apduLength);
if (bufPos < 0) { if (bufPos < 0)
{
if (DEBUG_GOOSE_SUBSCRIBER) if (DEBUG_GOOSE_SUBSCRIBER)
printf("GOOSE_SUBSCRIBER: Malformed message: failed to decode BER length tag!\n"); printf("GOOSE_SUBSCRIBER: Malformed message: failed to decode BER length tag!\n");
return 0; return 0;
@ -696,7 +700,8 @@ parseGoosePayload(GooseReceiver self, uint8_t* buffer, int apduLength)
{ {
LinkedList element = LinkedList_getNext(self->subscriberList); LinkedList element = LinkedList_getNext(self->subscriberList);
while (element != NULL) { while (element)
{
GooseSubscriber subscriber = (GooseSubscriber) LinkedList_getData(element); GooseSubscriber subscriber = (GooseSubscriber) LinkedList_getData(element);
if (subscriber->isObserver) if (subscriber->isObserver)
@ -713,8 +718,10 @@ parseGoosePayload(GooseReceiver self, uint8_t* buffer, int apduLength)
matchingSubscriber = subscriber; matchingSubscriber = subscriber;
break; break;
} }
else if (subscriber->goCBRefLen == elementLength) { else if (subscriber->goCBRefLen == elementLength)
if (memcmp(subscriber->goCBRef, buffer + bufPos, elementLength) == 0) { {
if (memcmp(subscriber->goCBRef, buffer + bufPos, elementLength) == 0)
{
if (DEBUG_GOOSE_SUBSCRIBER) if (DEBUG_GOOSE_SUBSCRIBER)
printf("GOOSE_SUBSCRIBER: gocbRef is matching!\n"); printf("GOOSE_SUBSCRIBER: gocbRef is matching!\n");
matchingSubscriber = subscriber; matchingSubscriber = subscriber;
@ -832,15 +839,17 @@ parseGoosePayload(GooseReceiver self, uint8_t* buffer, int apduLength)
bufPos += elementLength; bufPos += elementLength;
} }
if (matchingSubscriber != NULL) { if (matchingSubscriber != NULL)
{
matchingSubscriber->timeAllowedToLive = timeAllowedToLive; matchingSubscriber->timeAllowedToLive = timeAllowedToLive;
matchingSubscriber->ndsCom = ndsCom; matchingSubscriber->ndsCom = ndsCom;
matchingSubscriber->simulation = simulation; matchingSubscriber->simulation = simulation;
if (matchingSubscriber->dataSetValuesSelfAllocated) { if (matchingSubscriber->dataSetValuesSelfAllocated)
{
/* when confRev changed replaced old data set */ /* when confRev changed replaced old data set */
if ((matchingSubscriber->dataSetValues != NULL) && (matchingSubscriber->confRev != confRev)) { if ((matchingSubscriber->dataSetValues != NULL) && (matchingSubscriber->confRev != confRev))
{
MmsValue_delete(matchingSubscriber->dataSetValues); MmsValue_delete(matchingSubscriber->dataSetValues);
matchingSubscriber->dataSetValues = NULL; matchingSubscriber->dataSetValues = NULL;
} }
@ -866,7 +875,8 @@ parseGoosePayload(GooseReceiver self, uint8_t* buffer, int apduLength)
if (matchingSubscriber->dataSetValues == NULL) if (matchingSubscriber->dataSetValues == NULL)
matchingSubscriber->dataSetValues = parseAllDataUnknownValue(matchingSubscriber, dataSetBufferAddress, dataSetBufferLength, false); matchingSubscriber->dataSetValues = parseAllDataUnknownValue(matchingSubscriber, dataSetBufferAddress, dataSetBufferLength, false);
else { else
{
GooseParseError parseError = parseAllData(dataSetBufferAddress, dataSetBufferLength, matchingSubscriber->dataSetValues); GooseParseError parseError = parseAllData(dataSetBufferAddress, dataSetBufferLength, matchingSubscriber->dataSetValues);
if (parseError != GOOSE_PARSE_ERROR_NO_ERROR) { if (parseError != GOOSE_PARSE_ERROR_NO_ERROR) {
@ -876,7 +886,8 @@ parseGoosePayload(GooseReceiver self, uint8_t* buffer, int apduLength)
matchingSubscriber->parseError = parseError; matchingSubscriber->parseError = parseError;
} }
if (matchingSubscriber->stNum == stNum) { if (matchingSubscriber->stNum == stNum)
{
if (matchingSubscriber->sqNum >= sqNum) { if (matchingSubscriber->sqNum >= sqNum) {
isValid = false; isValid = false;
} }
@ -920,13 +931,18 @@ parseGooseMessage(GooseReceiver self, uint8_t* buffer, int numbytes)
uint8_t priority = 0; uint8_t priority = 0;
uint16_t vlanId = 0; uint16_t vlanId = 0;
bool vlanSet = false; bool vlanSet = false;
/* check for VLAN tag */ /* check for VLAN tag */
if ((buffer[bufPos] == 0x81) && (buffer[bufPos + 1] == 0x00)) { if ((buffer[bufPos] == 0x81) && (buffer[bufPos + 1] == 0x00))
{
priority = buffer[bufPos + 2] & 0xF8 >> 5; priority = buffer[bufPos + 2] & 0xF8 >> 5;
vlanId = ((buffer[bufPos + 2] & 0x07) << 8) + buffer[bufPos + 3]; vlanId = ((buffer[bufPos + 2] & 0x07) << 8) + buffer[bufPos + 3];
vlanSet = true; vlanSet = true;
bufPos += 4; /* skip VLAN tag */ bufPos += 4; /* skip VLAN tag */
headerLength += 4; headerLength += 4;
if (numbytes < (22 + 4))
return;
} }
/* check for GOOSE Ethertype */ /* check for GOOSE Ethertype */
@ -956,13 +972,22 @@ parseGooseMessage(GooseReceiver self, uint8_t* buffer, int numbytes)
int apduLength = length - 8; int apduLength = length - 8;
if (numbytes < length + headerLength) { if (apduLength < 0)
{
if (DEBUG_GOOSE_SUBSCRIBER)
printf("GOOSE_SUBSCRIBER: Invalid length field\n");
return;
}
if (numbytes < length + headerLength)
{
if (DEBUG_GOOSE_SUBSCRIBER) if (DEBUG_GOOSE_SUBSCRIBER)
printf("GOOSE_SUBSCRIBER: Invalid PDU size\n"); printf("GOOSE_SUBSCRIBER: Invalid PDU size\n");
return; return;
} }
if (DEBUG_GOOSE_SUBSCRIBER) { if (DEBUG_GOOSE_SUBSCRIBER)
{
printf("GOOSE_SUBSCRIBER: GOOSE message:\nGOOSE_SUBSCRIBER: ----------------\n"); printf("GOOSE_SUBSCRIBER: GOOSE message:\nGOOSE_SUBSCRIBER: ----------------\n");
printf("GOOSE_SUBSCRIBER: DST-MAC: %02x:%02x:%02x:%02x:%02X:%02X\n", printf("GOOSE_SUBSCRIBER: DST-MAC: %02x:%02x:%02x:%02x:%02X:%02X\n",
dstMac[0], dstMac[1], dstMac[2], dstMac[3], dstMac[4], dstMac[5]); dstMac[0], dstMac[1], dstMac[2], dstMac[3], dstMac[4], dstMac[5]);
@ -974,7 +999,8 @@ parseGooseMessage(GooseReceiver self, uint8_t* buffer, int numbytes)
/* check if there is an interested subscriber */ /* check if there is an interested subscriber */
LinkedList element = LinkedList_getNext(self->subscriberList); LinkedList element = LinkedList_getNext(self->subscriberList);
while (element != NULL) { while (element)
{
GooseSubscriber subscriber = (GooseSubscriber) LinkedList_getData(element); GooseSubscriber subscriber = (GooseSubscriber) LinkedList_getData(element);
if (subscriber->isObserver) if (subscriber->isObserver)
@ -990,7 +1016,8 @@ parseGooseMessage(GooseReceiver self, uint8_t* buffer, int numbytes)
} }
if (((subscriber->appId == -1) || (subscriber->appId == appId)) && if (((subscriber->appId == -1) || (subscriber->appId == appId)) &&
(!subscriber->dstMacSet || (memcmp(subscriber->dstMac, dstMac,6) == 0))) { (!subscriber->dstMacSet || (memcmp(subscriber->dstMac, dstMac,6) == 0)))
{
subscriberFound = true; subscriberFound = true;
break; break;
} }

Loading…
Cancel
Save