From 464374da5ffb02d2371b61401f8b29bbe89bf47a Mon Sep 17 00:00:00 2001 From: Ken Zangelin Date: Fri, 17 Jan 2020 23:06:37 +0100 Subject: [PATCH] Bug/crash in patch entity attrs when relationship without object release branch (#314) * New version string for develop branch (#312) * bug/crash-in-patch-entity-attrs-when-relationship-without-object (#313) * Implemented attribute check in incoming payload data for PATCH /entities/*/attrs - avoided a crash * Fixed a stupid mistake * new alpha bugfix number: 0.1.1 --- src/lib/orionld/common/orionldState.h | 2 +- .../serviceRoutines/orionldPatchEntity.cpp | 109 +++++++++++++++++- ...ttrs-when-relationship-without-object.test | 93 +++++++++++++++ 3 files changed, 202 insertions(+), 2 deletions(-) create mode 100644 test/functionalTest/cases/0000_ngsild/ngsild_crash-in-patch-entity-attrs-when-relationship-without-object.test diff --git a/src/lib/orionld/common/orionldState.h b/src/lib/orionld/common/orionldState.h index 39835f5cd5..386b7e320c 100644 --- a/src/lib/orionld/common/orionldState.h +++ b/src/lib/orionld/common/orionldState.h @@ -56,7 +56,7 @@ extern "C" // // ORIONLD_VERSION - // -#define ORIONLD_VERSION "v0.1.0-alpha" +#define ORIONLD_VERSION "v0.1.1-alpha" diff --git a/src/lib/orionld/serviceRoutines/orionldPatchEntity.cpp b/src/lib/orionld/serviceRoutines/orionldPatchEntity.cpp index 1c333b7ad3..4fc3e44394 100644 --- a/src/lib/orionld/serviceRoutines/orionldPatchEntity.cpp +++ b/src/lib/orionld/serviceRoutines/orionldPatchEntity.cpp @@ -40,6 +40,7 @@ extern "C" #include "orionld/common/orionldErrorResponse.h" // orionldErrorResponseCreate #include "orionld/common/OrionldConnection.h" // orionldState #include "orionld/common/SCOMPARE.h" // SCOMPAREx +#include "orionld/common/CHECK.h" // DUPLICATE_CHECK, STRING_CHECK, ... #include "orionld/context/orionldContextItemExpand.h" // orionldContextItemExpand #include "orionld/context/orionldContextValueExpand.h" // orionldContextValueExpand #include "orionld/kjTree/kjTreeToContextAttribute.h" // kjTreeToContextAttribute @@ -49,6 +50,95 @@ extern "C" +// ---------------------------------------------------------------------------- +// +// attributeCheck - +// +// FIXME - move to separate module - should be used also for: +// * POST /entities/*/attrs +// * PATCH /entities/*/attrs +// * etc +// +bool attributeCheck(ConnectionInfo* ciP, KjNode* attrNodeP, char** titleP, char** detailP) +{ + if (attrNodeP->type != KjObject) + { + *titleP = (char*) "Invalid JSON Type"; + *detailP = (char*) "Attribute must be an object"; + + return false; + } + + KjNode* typeP = NULL; + KjNode* valueP = NULL; + KjNode* objectP = NULL; + int attrType = 0; // 1: Property, 2: Relationship, 3: GeoProperty, 4: TemporalProperty + + for (KjNode* nodeP = attrNodeP->value.firstChildP; nodeP != NULL; nodeP = nodeP->next) + { + if (strcmp(nodeP->name, "type") == 0) + { + DUPLICATE_CHECK(typeP, "type", nodeP); + STRING_CHECK(typeP, "type"); + + if (strcmp(typeP->value.s, "Property") == 0) attrType = 1; + else if (strcmp(typeP->value.s, "Relationship") == 0) attrType = 2; + else if (strcmp(typeP->value.s, "GeoProperty") == 0) attrType = 3; + else if (strcmp(typeP->value.s, "TemporalProperty") == 0) attrType = 4; + else + { + *titleP = (char*) "Invalid Value of Attribute Type"; + *detailP = typeP->value.s; + + return false; + } + } + else if (strcmp(nodeP->name, "value") == 0) + { + DUPLICATE_CHECK(valueP, "value", nodeP); + } + else if (strcmp(nodeP->name, "object") == 0) + { + DUPLICATE_CHECK(objectP, "object", nodeP); + } + } + + if (typeP == NULL) + { + *titleP = (char*) "Mandatory field missing"; + *detailP = (char*) "attribute type"; + + return false; + } + + if (attrType == 2) // 2 == Relationship + { + // Relationships MUST have an "object" + if (objectP == NULL) + { + *titleP = (char*) "Mandatory field missing"; + *detailP = (char*) "Relationship object"; + + return false; + } + } + else + { + // Properties MUST have a "value" + if (valueP == NULL) + { + *titleP = (char*) "Mandatory field missing"; + *detailP = (char*) "Property value"; + + return false; + } + } + + return true; +} + + + // ---------------------------------------------------------------------------- // // orionldPatchEntity - @@ -78,7 +168,6 @@ bool orionldPatchEntity(ConnectionInfo* ciP) return false; } - // Is the payload not a JSON object? if (orionldState.requestTree->type != KjObject) { @@ -95,6 +184,7 @@ bool orionldPatchEntity(ConnectionInfo* ciP) return false; } + // Get the Entity from the database if ((currentEntityTree = dbEntityLookup(entityId)) == NULL) { ciP->httpStatusCode = SccNotFound; @@ -102,6 +192,7 @@ bool orionldPatchEntity(ConnectionInfo* ciP) return false; } + // // o Make sure the attributes to be patched exist. If not - ignore! // o Expand attribute values if the @context says they should be expanded @@ -119,6 +210,22 @@ bool orionldPatchEntity(ConnectionInfo* ciP) next = attrNodeP->next; + // + // Is the incoming payload correct? + // 1. All attributes must have a type + // 2. All attributes must have a value/object + // + char* title; + char* detail; + + if (attributeCheck(ciP, attrNodeP, &title, &detail) == false) + { + LM_E(("attributeCheck: %s: %s", title, detail)); + orionldErrorResponseCreate(OrionldBadRequestData, title, detail); + ciP->httpStatusCode = SccBadRequest; + return false; + } + if ((strncmp(attrNodeP->name, "http://", 7) == 0) || (strncmp(attrNodeP->name, "https://", 8) == 0)) attrName = attrNodeP->name; else diff --git a/test/functionalTest/cases/0000_ngsild/ngsild_crash-in-patch-entity-attrs-when-relationship-without-object.test b/test/functionalTest/cases/0000_ngsild/ngsild_crash-in-patch-entity-attrs-when-relationship-without-object.test new file mode 100644 index 0000000000..d0a3f4cd6c --- /dev/null +++ b/test/functionalTest/cases/0000_ngsild/ngsild_crash-in-patch-entity-attrs-when-relationship-without-object.test @@ -0,0 +1,93 @@ +# Copyright 2019 FIWARE Foundation e.V. +# +# This file is part of Orion-LD Context Broker. +# +# Orion-LD Context Broker is free software: you can redistribute it and/or +# modify it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# Orion-LD Context Broker is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero +# General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with Orion-LD Context Broker. If not, see http://www.gnu.org/licenses/. +# +# For those usages not covered by this license please contact with +# orionld at fiware dot org + +# VALGRIND_READY - to mark the test ready for valgrindTestSuite.sh + +--NAME-- +Crash in PATCH /entities/*/attrs when relationship without object + +--SHELL-INIT-- +export BROKER=orionld +dbInit CB +brokerStart CB + +--SHELL-- + +# +# 01. Create an entity urn:ngsi-ld:T:001, with a relationship R1 +# 02. Update the attribute R1 using PATCH /ngsi-ld/v1/entities/urn:ngsi-ld:T:001/attrs, but without 'object' - see error and make sure no crash +# + +echo "01. Create an entity urn:ngsi-ld:T:001, with a relationship R1" +echo "==============================================================" +payload='{ + "id": "urn:ngsi-ld:T:001", + "type": "T", + "R1": { + "type": "Relationship", + "object": "http://a.b.c/hola" + } +}' +orionCurl --url /ngsi-ld/v1/entities -X POST --payload "$payload" +echo +echo + + +echo "02. Update the attribute R1 using PATCH /ngsi-ld/v1/entities/urn:ngsi-ld:T:001/attrs, but without 'object' - see error and make sure no crash" +echo "=============================================================================================================================================" +payload='{ + "R1": { + "type": "Relationship", + "value": "http://a.b.c/hola2" + } +}' +orionCurl --url /ngsi-ld/v1/entities/urn:ngsi-ld:T:001/attrs -X PATCH --payload "$payload" +echo +echo + + +--REGEXPECT-- +01. Create an entity urn:ngsi-ld:T:001, with a relationship R1 +============================================================== +HTTP/1.1 201 Created +Content-Length: 0 +Link: ; rel="http://www.w3.org/ns/json-ld#context"; type="application/ld+json" +Location: /ngsi-ld/v1/entities/urn:ngsi-ld:T:001 +Date: REGEX(.*) + + + +02. Update the attribute R1 using PATCH /ngsi-ld/v1/entities/urn:ngsi-ld:T:001/attrs, but without 'object' - see error and make sure no crash +============================================================================================================================================= +HTTP/1.1 400 Bad Request +Content-Length: 126 +Content-Type: application/json +Date: REGEX(.*) + +{ + "detail": "Relationship object", + "title": "Mandatory field missing", + "type": "https://uri.etsi.org/ngsi-ld/errors/BadRequestData" +} + + +--TEARDOWN-- +brokerStop CB +dbDrop CB