diff --git a/ecc_enclave/enclave/shim.cpp b/ecc_enclave/enclave/shim.cpp index cf3c3ab7e..ff790aeb9 100644 --- a/ecc_enclave/enclave/shim.cpp +++ b/ecc_enclave/enclave/shim.cpp @@ -192,7 +192,17 @@ int unmarshal_values( { JSON_Object* pair = json_array_get_object(pairs, i); const char* key = json_object_get_string(pair, "key"); + if (key == NULL) + { + LOG_ERROR("Shim: Cannot parse json: key does not exists"); + return -1; + } const char* b64value = json_object_get_string(pair, "value"); + if (b64value == NULL) + { + LOG_ERROR("Shim: Cannot parse json: value does not exist"); + return -1; + } std::string value = base64_decode(b64value); values.insert({key, value}); } diff --git a/integration/Makefile b/integration/Makefile index f7f070a17..95f133ffc 100644 --- a/integration/Makefile +++ b/integration/Makefile @@ -7,7 +7,7 @@ include $(TOP)/build.mk all: test -test: auction_test echo_test kv_test deployment_test client_sdk_test stress_test ecc_go_test +test: auction_test echo_test kv_test deployment_test client_sdk_test stress_test ecc_go_test crash_test auction_test: ./auction_test.sh @@ -29,3 +29,6 @@ stress_test: ecc_go_test: $(MAKE) -C go_chaincode + +crash_test: + $(MAKE) -C crashtest diff --git a/integration/crashtest/.gitignore b/integration/crashtest/.gitignore new file mode 100644 index 000000000..738c7a50b --- /dev/null +++ b/integration/crashtest/.gitignore @@ -0,0 +1,3 @@ +_build/ +wallet/ +keystore/ \ No newline at end of file diff --git a/integration/crashtest/Makefile b/integration/crashtest/Makefile new file mode 100644 index 000000000..003cda45a --- /dev/null +++ b/integration/crashtest/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: Apache-2.0 + +TOP = ../.. +include $(TOP)/build.mk + +GO_TEST_DIRS=unmarshal_values + +test: + $(foreach DIR, $(GO_TEST_DIRS), $(MAKE) -C $(DIR) || exit ;) + diff --git a/integration/crashtest/unmarshal_values/CMakeLists.txt b/integration/crashtest/unmarshal_values/CMakeLists.txt new file mode 100644 index 000000000..a7c56b5e8 --- /dev/null +++ b/integration/crashtest/unmarshal_values/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.5.1) + +set(SOURCE_FILES cc.cpp) + +include($ENV{FPC_PATH}/ecc_enclave/enclave/CMakeLists-common-app-enclave.txt) diff --git a/integration/crashtest/unmarshal_values/Makefile b/integration/crashtest/unmarshal_values/Makefile new file mode 100644 index 000000000..4d986ddad --- /dev/null +++ b/integration/crashtest/unmarshal_values/Makefile @@ -0,0 +1,36 @@ +TOP = ../../.. +include $(TOP)/build.mk + +TEST_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) +BUILD_DIR := ${TEST_DIR}/_build +CC_NAME := "crash" +DOCKER_IMAGE_NAME := fpc/${CC_NAME} + +all: build docker test + +$(BUILD_DIR): + @if [ ! -d $(BUILD_DIR) ]; then \ + mkdir -p $(BUILD_DIR) && \ + cd $(BUILD_DIR) && \ + cmake ./..; \ + fi + +build: $(BUILD_DIR) + $(MAKE) --directory=$< + +docker: build + if [ "${SGX_MODE}" = "HW" ]; then \ + export HW_EXTENSION="-hw" ; \ + fi && \ + make -C ${FPC_PATH}/ecc CC_NAME=${CC_NAME} DOCKER_IMAGE=${DOCKER_IMAGE_NAME}$${HW_EXTENSION} DOCKER_ENCLAVE_SO_PATH=${BUILD_DIR}/lib all docker \ + && $(DOCKER) tag ${DOCKER_IMAGE_NAME}$${HW_EXTENSION}:$(FPC_VERSION) ${DOCKER_IMAGE_NAME}$${HW_EXTENSION}:latest + +test: docker + CC_ID=$(CC_NAME) ./test.sh + +clean: + rm -rf $(BUILD_DIR) + + + + diff --git a/integration/crashtest/unmarshal_values/cc.cpp b/integration/crashtest/unmarshal_values/cc.cpp new file mode 100644 index 000000000..abfac1491 --- /dev/null +++ b/integration/crashtest/unmarshal_values/cc.cpp @@ -0,0 +1,51 @@ +#include +#include "logging.h" +#include "shim.h" + +const std::string SEP = "."; +const std::string PREFIX = SEP + "somePrefix" + SEP; + +std::string store(std::string auction_name, std::string bidder_name, int value, shim_ctx_ptr_t ctx) +{ + std::string new_key(PREFIX + auction_name + SEP + bidder_name + SEP); + put_public_state(new_key.c_str(), (uint8_t*)&value, sizeof(int), ctx); + return "OK"; +} + +std::string retrieve(std::string auction_name, shim_ctx_ptr_t ctx) +{ + std::map values; + std::string bid_composite_key = PREFIX + auction_name + SEP; + get_public_state_by_partial_composite_key(bid_composite_key.c_str(), values, ctx); + return "STILL_ALIVE"; +} + +int invoke( + uint8_t* response, uint32_t max_response_len, uint32_t* actual_response_len, shim_ctx_ptr_t ctx) +{ + LOG_DEBUG("[+] +++ Executing chaincode invocation +++"); + + std::string function_name; + std::vector params; + get_func_and_params(function_name, params, ctx); + std::string result; + + if (function_name == "store") + result = store(params[0], params[1], std::stoi(params[2]), ctx); + else if (function_name == "retrieve") + result = retrieve(params[0], ctx); + + int neededSize = result.size(); + if (max_response_len < neededSize) + { + LOG_DEBUG("[+] Response buffer too small"); + *actual_response_len = 0; + return -1; + } + + memcpy(response, result.c_str(), neededSize); + *actual_response_len = neededSize; + LOG_DEBUG("[+] Response: %s", result.c_str()); + LOG_DEBUG("[+] +++ Executing done +++"); + return 0; +} diff --git a/integration/crashtest/unmarshal_values/test.sh b/integration/crashtest/unmarshal_values/test.sh new file mode 100755 index 000000000..37392069c --- /dev/null +++ b/integration/crashtest/unmarshal_values/test.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash + +if [[ -z "${FPC_PATH}" ]]; then + echo "Error: FPC_PATH not set"; exit 1 +fi + +FABRIC_CFG_PATH="${FPC_PATH}/integration/config" +FABRIC_SCRIPTDIR="${FPC_PATH}/fabric/bin/" + +. "${FABRIC_SCRIPTDIR}"/lib/common_utils.sh +. "${FABRIC_SCRIPTDIR}"/lib/common_ledger.sh + +# this is the path points to FPC chaincode binary +CC_PATH=${FPC_PATH}/integration/crashtest/unmarshal_values/_build/lib/ + +CC_ID="${CC_ID-crash}" +CC_VER="$(cat "${CC_PATH}"/mrenclave)" +CC_EP="OR('SampleOrg.member')" +CC_SEQ="1" + +run_test() { + say "- install chaincode" + PKG="/tmp/${CC_ID}.tar.gz" + ${PEER_CMD} lifecycle chaincode package --lang fpc-c --label "${CC_ID}" --path "${CC_PATH}" "${PKG}" + ${PEER_CMD} lifecycle chaincode install "${PKG}" + + PKG_ID=$(${PEER_CMD} lifecycle chaincode queryinstalled | awk "/Package ID: ${CC_ID}/{print}" | sed -n 's/^Package ID: //; s/, Label:.*$//;p') + + ${PEER_CMD} lifecycle chaincode approveformyorg -o "${ORDERER_ADDR}" -C "${CHAN_ID}" --package-id "${PKG_ID}" --name "${CC_ID}" --version "${CC_VER}" --sequence ${CC_SEQ} --signature-policy ${CC_EP} + ${PEER_CMD} lifecycle chaincode checkcommitreadiness -C "${CHAN_ID}" --name "${CC_ID}" --version "${CC_VER}" --sequence ${CC_SEQ} --signature-policy ${CC_EP} + ${PEER_CMD} lifecycle chaincode commit -o "${ORDERER_ADDR}" -C "${CHAN_ID}" --name "${CC_ID}" --version "${CC_VER}" --sequence ${CC_SEQ} --signature-policy ${CC_EP} + + ${PEER_CMD} lifecycle chaincode initEnclave -o "${ORDERER_ADDR}" --peerAddresses "localhost:7051" --name "${CC_ID}" + + say "- interact with the FPC chaincode using our client app" + + export CC_ID + export CHAN_ID + try go test -v ./test +} + +trap ledger_shutdown EXIT + +say "Setup ledger ..." +ledger_init + +para +say "Run test ..." +run_test + +para +say "Shutdown ledger ..." +ledger_shutdown + +yell "Test PASSED" + +exit 0 \ No newline at end of file diff --git a/integration/crashtest/unmarshal_values/test/crash_test.go b/integration/crashtest/unmarshal_values/test/crash_test.go new file mode 100644 index 000000000..f4085c7b4 --- /dev/null +++ b/integration/crashtest/unmarshal_values/test/crash_test.go @@ -0,0 +1,40 @@ +package test_test + +import ( + "os" + "testing" + + fpc "github.com/hyperledger/fabric-private-chaincode/client_sdk/go/pkg/gateway" + "github.com/hyperledger/fabric-private-chaincode/integration/client_sdk/go/utils" + "github.com/stretchr/testify/assert" +) + +func TestMustNotCrash(t *testing.T) { + ccID := os.Getenv("CC_ID") + channelID := os.Getenv("CHAN_ID") + assert.NotEmpty(t, ccID) + assert.NotEmpty(t, channelID) + t.Logf("Use channel: %v, chaincode ID: %v", channelID, ccID) + + network, err := utils.SetupNetwork(channelID) + assert.NoError(t, err) + contract := fpc.GetContract(network, ccID) + + // this bidder name might cause the enclave crashing due to a null dereferencing + // https://github.com/hyperledger/fabric-private-chaincode/blob/88b7c21cc398ed7273d807976f6dffe5e69bd18c/ecc_enclave/enclave/shim.cpp#L195 + result, err := contract.SubmitTransaction("store", "auction", "baz\",\"value\":4141},{\"key\":\"aa", "200") + assert.NoError(t, err) + assert.Equal(t, "OK", string(result)) + + result, err = contract.EvaluateTransaction("retrieve", "auction") + assert.NoError(t, err) + assert.Equal(t, "STILL_ALIVE", string(result)) + + result, err = contract.SubmitTransaction("store", "auction", "john", "200") + assert.NoError(t, err) + assert.Equal(t, "OK", string(result)) + + result, err = contract.EvaluateTransaction("retrieve", "auction") + assert.NoError(t, err) + assert.Equal(t, "STILL_ALIVE", string(result)) +}