blob: e91dbfbe1008703a3c6a00b39060853c84384a9a [file] [log] [blame]
/*
*
* Copyright (c) 2020 Project CHIP Authors
* Copyright (c) 2016-2017 Nest Labs, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* Header file for the fault-injection utilities for CHIP.
*/
#pragma once
#include <lib/core/CHIPConfig.h>
#if CHIP_WITH_NLFAULTINJECTION
#ifdef NDEBUG
// TODO(#30453): After fixing the issue where CHIP_WITH_NLFAULTINJECTION is seemingly enabled on release builds,
// uncomment the line below.
// static_assert(false, "CHIP_WITH_NLFAULTINJECTION should NOT be enabled on release build");
#endif
#include <nlfaultinjection.hpp>
#include <lib/support/DLLUtil.h>
namespace chip {
namespace FaultInjection {
// X-Macro style enumeration of Fault Names and their ID.
// This list is used to generate the "Id" enum and the array of strings sFaultNames[]
// WARNING: When adding/modifying Faults to the below macro, make sure the changes are duplicated to the CHIPFaultId enum in the
// Python Module src/controller/python/matter/fault_injection/__init__.py
// BEGIN-IF-CHANGE-ALSO-CHANGE(src/controller/python/matter/fault_injection/__init__.py)
#define CHIP_FAULTS_ENUMERATE(X) \
X(AllocExchangeContext, 0) /**< Fail the allocation of an ExchangeContext */ \
X(DropIncomingUDPMsg, 1) /**< Drop an incoming UDP message without any processing */ \
X(DropOutgoingUDPMsg, 2) /**< Drop an outgoing UDP message at the chip Message layer */ \
X(AllocBinding, 3) /**< Fail the allocation of a Binding */ \
X(SendAlarm, 4) /**< Fail to send an alarm message */ \
X(HandleAlarm, 5) /**< Fail to handle an alarm message */ \
X(FuzzExchangeHeaderTx, 6) /**< Fuzz an Exchange Header in the packet buffer; expects an int argument selecting a fuzzing \
method. @see FuzzExchangeHeader */ \
X(RMPDoubleTx, 7) /**< Force RMP to transmit the outgoing message twice */ \
X(RMPSendError, 8) /**< Simulate a send error in RMP as if retransmission count exceeded */ \
X(BDXBadBlockCounter, 9) /**< Corrupt the BDX Block Counter in a BlockSend or BlockEOF message */ \
X(BDXAllocTransfer, 10) /**< Fail the allocation of a BDXTransfer object */ \
X(SecMgrBusy, 11) /**< Simulate WEAVE_ERROR_SECURITY_MANAGER_BUSY on session start */ \
X(IMInvoke_SeparateResponses, 12) /**< Respond to 2 InvokeRequestMessage commands with 2 separate responses */ \
X(IMInvoke_SeparateResponsesInvertResponseOrder, 13) /**< Respond with 2 InvokeResponses in reverse order of request */ \
X(IMInvoke_SkipSecondResponse, 14) /**< Respond to 2 commands but drop the second response */ \
X(ModifyWebRTCAnswerSessionId, 15) /**< Modify session ID in outgoing WebRTC Answer command */ \
X(ModifyWebRTCOfferSessionId, 16) /**< Modify session ID in outgoing WebRTC Offer command */ \
X(CASEServerBusy, 17) /**< Respond to CASE_Sigma1 with BUSY status */ \
X(CASESkipInitiatorResumeMIC, 18) /**< Send Sigma1 with resumptionID but omit initiatorResumeMIC */ \
X(CASESkipResumptionID, 19) /**< Send Sigma1 with initiatorResumeMIC but omit resumptionID */ \
X(CASECorruptInitiatorResumeMIC, 20) /**< Send invalid initiatorResumeMIC in Sigma1 */ \
X(CASECorruptDestinationID, 21) /**< Send Sigma1 with invalid DestinationID */ \
X(CASECorruptTBEData3Encrypted, 22) /**< Send CASE_Sigma3 with improperly generated TBEData3Encrypted */ \
X(CASECorruptSigma3NOC, 23) /**< Send Sigma3 with invalid initiatorNOC */ \
X(CASECorruptSigma3ICAC, 24) /**< Send Sigma3 with invalid initiatorICAC */ \
X(CASECorruptSigma3Signature, 25) /**< Send Sigma3 with invalid signature */ \
X(CASECorruptSigma3InitiatorEphPubKey, 26) /**< Send Sigma3 with invalid initiator ephemeral public key */ \
X(CASECorruptSigma3ResponderEphPubKey, 27) /**< Send Sigma3 with invalid responder ephemeral public key */ \
X(CASECorruptTBEData2Encrypted, 28) /**< Send Sigma2 with improperly generated TBEData2Encrypted */ \
X(CASECorruptSigma2NOC, 29) /**< Send Sigma2 with invalid responderNOC */ \
X(CASECorruptSigma2ICAC, 30) /**< Send Sigma2 with invalid responderICAC */ \
X(CASECorruptSigma2Signature, 31) /**< Send Sigma2 with invalid signature */ \
X(ModifyWebRTCICECandidatesSessionId, 32) /**< Modify session ID in outgoing WebRTC ICECandidates command */ \
X(EmptyWebRTCICECandidatesList, 33) /**< Empty Candidates List in outgoing WebRTC ICECandidates command */ \
X(ClearInMemoryAllocatedVideoStreams, 34) /**< Empty in-memory allocated video streams during attribute read */ \
X(ClearInMemoryAllocatedAudioStreams, 35) /**< Empty in-memory allocated audio streams during attribute read */ \
X(ClearInMemoryAllocatedSnapshotStreams, 36) /**< Empty in-memory allocated snapshot streams during attribute read */ \
X(LoadPersistentCameraAVSMAttributes, 37) /**< Load persisted Camera AVSM attributes during attribute read */
// END-IF-CHANGE-ALSO-CHANGE(src/controller/python/matter/fault_injection/__init__.py)
// WARNING: When adding/modifying Faults to the below macro, make sure the changes are duplicated to the CHIPFaultId enum in the
// Python Module src/controller/python/matter/fault_injection/__init__.py
/**
* @brief Fault injection points
*
* @details
* Each point in the code at which a fault can be injected
* is identified by a member of this enum.
*
* @note IMPORTANT: This enum must be kept in sync with the CHIPFaultId enum in
* src/controller/python/matter/fault_injection/__init__.py
* If you change values here, update them there as well.
*/
enum Id
{
#define _CHIP_FAULTS_ENUMERATE_DECL(FAULT, ...) kFault_##FAULT,
CHIP_FAULTS_ENUMERATE(_CHIP_FAULTS_ENUMERATE_DECL) //
kFault_NumItems // marker value
};
// Exporting kNumChipFaultsFromEnum for usage in Python bindings
const size_t kNumChipFaultsFromEnum = kFault_NumItems;
static_assert(kFault_IMInvoke_SeparateResponses == 12, "Test plan specification and automation code relies on this value being 12");
static_assert(kFault_IMInvoke_SeparateResponsesInvertResponseOrder == 13,
"Test plan specification and automation code relies on this value being 13");
static_assert(kFault_IMInvoke_SkipSecondResponse == 14,
"Test plan specification and automation code relies on this value being 14");
static_assert(kFault_ModifyWebRTCAnswerSessionId == 15,
"Test plan specification and automation code relies on this value being 15");
static_assert(kFault_ModifyWebRTCOfferSessionId == 16, "Test plan specification and automation code relies on this value being 16");
static_assert(kFault_ModifyWebRTCICECandidatesSessionId == 32,
"Test plan specification and automation code relies on this value being 32");
static_assert(kFault_EmptyWebRTCICECandidatesList == 33,
"Test plan specification and automation code relies on this value being 33");
static_assert(kFault_ClearInMemoryAllocatedVideoStreams == 34,
"Test plan specification and automation code relies on this value being 34");
static_assert(kFault_ClearInMemoryAllocatedAudioStreams == 35,
"Test plan specification and automation code relies on this value being 35");
static_assert(kFault_ClearInMemoryAllocatedSnapshotStreams == 36,
"Test plan specification and automation code relies on this value being 36");
static_assert(kFault_LoadPersistentCameraAVSMAttributes == 37,
"Test plan specification and automation code relies on this value being 37");
DLL_EXPORT nl::FaultInjection::Manager & GetManager();
DLL_EXPORT uint32_t GetFaultCounter(uint32_t faultID);
/**
* The number of ways in which chip Fault Injection fuzzers can
* alter a byte in a payload.
*/
#define CHIP_FAULT_INJECTION_NUM_FUZZ_VALUES 3
DLL_EXPORT void FuzzExchangeHeader(uint8_t * p, int32_t arg);
} // namespace FaultInjection
} // namespace chip
/**
* Execute the statements included if the chip fault is
* to be injected.
*
* @param[in] aFaultID A chip fault-injection id
* @param[in] aStatements Statements to be executed if the fault is enabled.
*/
#define CHIP_FAULT_INJECT(aFaultID, aStatements) nlFAULT_INJECT(chip::FaultInjection::GetManager(), aFaultID, aStatements)
/**
* Execute the statements included if the chip fault is
* to be injected. Also, if there are no arguments stored in the
* fault, save aMaxArg into the record so it can be printed out
* to the debug log by a callback installed on purpose.
*
* @param[in] aFaultID A chip fault-injection id
* @param[in] aMaxArg The max value accepted as argument by the statements to be injected
* @param[in] aProtectedStatements Statements to be executed if the fault is enabled while holding the
* Manager's lock
* @param[in] aUnprotectedStatements Statements to be executed if the fault is enabled without holding the
* Manager's lock
*/
#define CHIP_FAULT_INJECT_MAX_ARG(aFaultID, aMaxArg, aProtectedStatements, aUnprotectedStatements) \
do \
{ \
nl::FaultInjection::Manager & mgr = chip::FaultInjection::GetManager(); \
const nl::FaultInjection::Record * records = mgr.GetFaultRecords(); \
if (records[aFaultID].mNumArguments == 0) \
{ \
int32_t arg = aMaxArg; \
mgr.StoreArgsAtFault(aFaultID, 1, &arg); \
} \
nlFAULT_INJECT_WITH_ARGS(mgr, aFaultID, aProtectedStatements, aUnprotectedStatements); \
} while (0)
/**
* Execute the statements included if the chip fault is
* to be injected.
*
* @param[in] aFaultID A chip fault-injection id
* @param[in] aProtectedStatements Statements to be executed if the fault is enabled while holding the
* Manager's lock
* @param[in] aUnprotectedStatements Statements to be executed if the fault is enabled without holding the
* Manager's lock
*/
#define CHIP_FAULT_INJECT_WITH_ARGS(aFaultID, aProtectedStatements, aUnprotectedStatements) \
nlFAULT_INJECT_WITH_ARGS(chip::FaultInjection::GetManager(), aFaultID, aProtectedStatements, aUnprotectedStatements);
#define CHIP_FAULT_INJECTION_EXCH_HEADER_NUM_FIELDS 4
#define CHIP_FAULT_INJECTION_EXCH_HEADER_NUM_FIELDS_RMP 5
#else // CHIP_WITH_NLFAULTINJECTION
#define CHIP_FAULT_INJECT(aFaultID, aStatements)
#define CHIP_FAULT_INJECT_WITH_ARGS(aFaultID, aProtectedStatements, aUnprotectedStatements)
#define CHIP_FAULT_INJECT_MAX_ARG(aFaultID, aMaxArg, aProtectedStatements, aUnprotectedStatements)
#endif // CHIP_WITH_NLFAULTINJECTION