Skip to content

Commit

Permalink
[ACL] Add ACL checks to event management
Browse files Browse the repository at this point in the history
  • Loading branch information
erjiaqing committed Feb 21, 2022
1 parent 4394fcb commit abc556f
Show file tree
Hide file tree
Showing 12 changed files with 349 additions and 86 deletions.
6 changes: 3 additions & 3 deletions src/app/EventLoggingTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#pragma once

#include <access/SubjectDescriptor.h>
#include <app/ClusterInfo.h>
#include <app/util/basic-types.h>
#include <lib/core/CHIPCore.h>
Expand Down Expand Up @@ -152,8 +153,7 @@ class EventOptions
struct EventLoadOutContext
{
EventLoadOutContext(TLV::TLVWriter & aWriter, PriorityLevel aPriority, EventNumber aStartingEventNumber) :
mWriter(aWriter), mPriority(aPriority), mStartingEventNumber(aStartingEventNumber), mCurrentEventNumber(0), mFirst(true),
mFabricIndex(0)
mWriter(aWriter), mPriority(aPriority), mStartingEventNumber(aStartingEventNumber), mCurrentEventNumber(0), mFirst(true)
{}

TLV::TLVWriter & mWriter;
Expand All @@ -165,7 +165,7 @@ struct EventLoadOutContext
size_t mEventCount = 0;
ClusterInfo * mpInterestedEventPaths = nullptr;
bool mFirst = true;
FabricIndex mFabricIndex = kUndefinedFabricIndex;
Access::SubjectDescriptor mSubjectDescriptor;
};
} // namespace app
} // namespace chip
151 changes: 108 additions & 43 deletions src/app/EventManagement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@
* limitations under the License.
*/

#include <access/AccessControl.h>
#include <access/RequestPath.h>
#include <access/SubjectDescriptor.h>
#include <app/EventManagement.h>
#include <app/InteractionModelEngine.h>
#include <app/RequiredPrivilege.h>
#include <inttypes.h>
#include <lib/core/CHIPEventLoggingConfig.h>
#include <lib/core/CHIPTLVUtilities.hpp>
Expand Down Expand Up @@ -77,29 +81,6 @@ struct CopyAndAdjustDeltaTimeContext
EventLoadOutContext * mpContext = nullptr;
};

/**
* @brief
* Internal structure for traversing events.
*/
struct EventEnvelopeContext
{
EventEnvelopeContext() {}

int mFieldsToRead = 0;
/* PriorityLevel and DeltaTime are there if that is not first event when putting events in report*/
#if CHIP_CONFIG_EVENT_LOGGING_UTC_TIMESTAMPS & CHIP_SYSTEM_CONFIG_PLATFORM_PROVIDES_TIME
Timestamp mCurrentTime = Timestamp::System(System::Clock::kZero);
#else
Timestamp mCurrentTime = Timestamp::Epoch(System::Clock::kZero);
#endif
PriorityLevel mPriority = PriorityLevel::First;
ClusterId mClusterId = 0;
EndpointId mEndpointId = 0;
EventId mEventId = 0;
EventNumber mEventNumber = 0;
FabricIndex mFabricIndex = kUndefinedFabricIndex;
};

void EventManagement::InitializeCounter(Platform::PersistedStorage::Key * apCounterKey, uint32_t aCounterEpoch,
PersistedCounter * apPersistedCounter)
{
Expand Down Expand Up @@ -590,46 +571,115 @@ CHIP_ERROR EventManagement::CopyEvent(const TLVReader & aReader, TLVWriter & aWr
return CHIP_NO_ERROR;
}

static bool IsInterestedEventPaths(EventLoadOutContext * eventLoadOutContext, const EventEnvelopeContext & event)
CHIP_ERROR EventManagement::WriteEventStatusIB(TLVWriter & aWriter, const ConcreteEventPath & aEvent, StatusIB aStatus)
{
TLVType containerType;
ReturnErrorOnFailure(aWriter.StartContainer(AnonymousTag(), kTLVType_Structure, containerType));

EventStatusIB::Builder builder;
builder.Init(&aWriter, to_underlying(EventReportIB::Tag::kEventStatus));

ReturnErrorOnFailure(builder.CreatePath()
.Endpoint(aEvent.mEndpointId)
.Cluster(aEvent.mClusterId)
.Event(aEvent.mEventId)
.EndOfEventPathIB()
.GetError());

ReturnErrorOnFailure(builder.CreateErrorStatus().EncodeStatusIB(aStatus).GetError());

ReturnErrorOnFailure(builder.EndOfEventStatusIB().GetError());

ReturnErrorOnFailure(aWriter.EndContainer(containerType));
ReturnErrorOnFailure(aWriter.Finalize());
return CHIP_NO_ERROR;
}

CHIP_ERROR EventManagement::IsInterestedEventPaths(EventLoadOutContext * eventLoadOutContext,
const EventManagement::EventEnvelopeContext & event)
{
if (eventLoadOutContext->mCurrentEventNumber < eventLoadOutContext->mStartingEventNumber)
{
return false;
return CHIP_NO_ERROR;
}

if (event.mFabricIndex != kUndefinedFabricIndex && eventLoadOutContext->mFabricIndex != event.mFabricIndex)
if (event.mFabricIndex != kUndefinedFabricIndex && eventLoadOutContext->mSubjectDescriptor.fabricIndex != event.mFabricIndex)
{
return false;
return CHIP_NO_ERROR;
}

ConcreteEventPath path(event.mEndpointId, event.mClusterId, event.mEventId);
CHIP_ERROR ret = CHIP_NO_ERROR;

bool isPathInterestedByConcretePath = false;

for (auto * interestedPath = eventLoadOutContext->mpInterestedEventPaths; interestedPath != nullptr;
interestedPath = interestedPath->mpNext)
{
if (interestedPath->IsEventPathSupersetOf(path))
{
return true;
ret = CHIP_EVENT_ID_FOUND;
if (!interestedPath->HasEventWildcard())
{
isPathInterestedByConcretePath = true;
break;
}
}
}

if (ret == CHIP_EVENT_ID_FOUND)
{
Access::RequestPath requestPath{ .cluster = event.mClusterId, .endpoint = event.mEndpointId };
Access::Privilege requestPrivilege = RequiredPrivilege::ForReadEvent(path);
CHIP_ERROR aclError = CHIP_NO_ERROR;

switch (GetInstance().mBypassACL)
{
case BypassACL::kAlwaysPass:
aclError = CHIP_NO_ERROR;
break;
case BypassACL::kAlwaysFail:
aclError = CHIP_ERROR_ACCESS_DENIED;
break;
case BypassACL::kNoBypass:
aclError = Access::GetAccessControl().Check(eventLoadOutContext->mSubjectDescriptor, requestPath, requestPrivilege);
break;
}

if (aclError != CHIP_NO_ERROR)
{
ReturnErrorCodeIf(aclError != CHIP_ERROR_ACCESS_DENIED, aclError);
if (isPathInterestedByConcretePath)
{
ret = CHIP_ERROR_ACCESS_DENIED;
}
else
{
ret = CHIP_NO_ERROR;
}
}
}
return false;

return ret;
}

CHIP_ERROR EventManagement::EventIterator(const TLVReader & aReader, size_t aDepth, EventLoadOutContext * apEventLoadOutContext)
CHIP_ERROR EventManagement::EventIterator(const TLVReader & aReader, size_t aDepth, EventLoadOutContext * apEventLoadOutContext,
EventEnvelopeContext * event)
{
CHIP_ERROR err = CHIP_NO_ERROR;
TLVReader innerReader;
TLVType tlvType;
TLVType tlvType1;
EventEnvelopeContext event;

innerReader.Init(aReader);
VerifyOrDie(event != nullptr);
ReturnErrorOnFailure(innerReader.EnterContainer(tlvType));
ReturnErrorOnFailure(innerReader.Next());

ReturnErrorOnFailure(innerReader.EnterContainer(tlvType1));
err = TLV::Utilities::Iterate(innerReader, FetchEventParameters, &event, false /*recurse*/);
err = TLV::Utilities::Iterate(innerReader, FetchEventParameters, event, false /*recurse*/);

if (event.mFieldsToRead != kRequiredEventField)
if (event->mFieldsToRead != kRequiredEventField)
{
return CHIP_ERROR_INVALID_ARGUMENT;
}
Expand All @@ -640,20 +690,17 @@ CHIP_ERROR EventManagement::EventIterator(const TLVReader & aReader, size_t aDep
}
ReturnErrorOnFailure(err);

apEventLoadOutContext->mCurrentTime = event.mCurrentTime;
apEventLoadOutContext->mCurrentEventNumber = event.mEventNumber;
if (IsInterestedEventPaths(apEventLoadOutContext, event))
{
return CHIP_EVENT_ID_FOUND;
}
apEventLoadOutContext->mCurrentTime = event->mCurrentTime;
apEventLoadOutContext->mCurrentEventNumber = event->mEventNumber;

return CHIP_NO_ERROR;
return IsInterestedEventPaths(apEventLoadOutContext, *event);
}

CHIP_ERROR EventManagement::CopyEventsSince(const TLVReader & aReader, size_t aDepth, void * apContext)
{
EventLoadOutContext * const loadOutContext = static_cast<EventLoadOutContext *>(apContext);
CHIP_ERROR err = EventIterator(aReader, aDepth, loadOutContext);
EventEnvelopeContext event;
CHIP_ERROR err = EventIterator(aReader, aDepth, loadOutContext, &event);
if (err == CHIP_EVENT_ID_FOUND)
{
// checkpoint the writer
Expand All @@ -675,11 +722,29 @@ CHIP_ERROR EventManagement::CopyEventsSince(const TLVReader & aReader, size_t aD
loadOutContext->mFirst = false;
loadOutContext->mEventCount++;
}
else if (err == CHIP_ERROR_ACCESS_DENIED)
{
// checkpoint the writer
TLV::TLVWriter checkpoint = loadOutContext->mWriter;

err = WriteEventStatusIB(loadOutContext->mWriter, ConcreteEventPath(event.mEndpointId, event.mClusterId, event.mEventId),
StatusIB(Protocols::InteractionModel::Status::UnsupportedAccess));

if (err != CHIP_NO_ERROR)
{
loadOutContext->mWriter = checkpoint;
return err;
}

loadOutContext->mPreviousTime.mValue = loadOutContext->mCurrentTime.mValue;
loadOutContext->mFirst = false;
loadOutContext->mEventCount++;
}
return err;
}

CHIP_ERROR EventManagement::FetchEventsSince(TLVWriter & aWriter, ClusterInfo * apClusterInfolist, EventNumber & aEventMin,
size_t & aEventCount, FabricIndex aFabricIndex)
size_t & aEventCount, const Access::SubjectDescriptor & aSubjectDescriptor)
{
// TODO: Add particular set of event Paths in FetchEventsSince so that we can filter the interested paths
CHIP_ERROR err = CHIP_NO_ERROR;
Expand All @@ -692,7 +757,7 @@ CHIP_ERROR EventManagement::FetchEventsSince(TLVWriter & aWriter, ClusterInfo *
ScopedLock lock(sInstance);
#endif // !CHIP_SYSTEM_CONFIG_NO_LOCKING

context.mFabricIndex = aFabricIndex;
context.mSubjectDescriptor = aSubjectDescriptor;
context.mpInterestedEventPaths = apClusterInfolist;
err = GetEventReader(reader, PriorityLevel::Critical, &bufWrapper);
SuccessOrExit(err);
Expand Down
57 changes: 55 additions & 2 deletions src/app/EventManagement.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@

#include "EventLoggingDelegate.h"
#include "EventLoggingTypes.h"
#include <access/SubjectDescriptor.h>
#include <app/ClusterInfo.h>
#include <app/MessageDef/EventDataIB.h>
#include <app/MessageDef/StatusIB.h>
#include <app/util/basic-types.h>
#include <lib/core/CHIPCircularTLVBuffer.h>
#include <lib/support/PersistedCounter.h>
Expand Down Expand Up @@ -339,7 +341,7 @@ class EventManagement
*
*/
CHIP_ERROR FetchEventsSince(chip::TLV::TLVWriter & aWriter, ClusterInfo * apClusterInfolist, EventNumber & aEventMin,
size_t & aEventCount, FabricIndex aFabricIndex);
size_t & aEventCount, const Access::SubjectDescriptor & aSubjectDescriptor);

/**
* @brief
Expand All @@ -360,7 +362,39 @@ class EventManagement
*/
void SetScheduledEventInfo(EventNumber & aEventNumber, uint32_t & aInitialWrittenEventBytes);

enum class BypassACL : uint8_t
{
kNoBypass = 0,
kAlwaysPass = 1,
kAlwaysFail = 2,
};

void SetBypassACL(BypassACL aConfig) { mBypassACL = aConfig; }

private:
/**
* @brief
* Internal structure for traversing events.
*/
struct EventEnvelopeContext
{
EventEnvelopeContext() {}

int mFieldsToRead = 0;
/* PriorityLevel and DeltaTime are there if that is not first event when putting events in report*/
#if CHIP_CONFIG_EVENT_LOGGING_UTC_TIMESTAMPS & CHIP_SYSTEM_CONFIG_PLATFORM_PROVIDES_TIME
Timestamp mCurrentTime = Timestamp::System(System::Clock::kZero);
#else
Timestamp mCurrentTime = Timestamp::Epoch(System::Clock::kZero);
#endif
PriorityLevel mPriority = PriorityLevel::First;
ClusterId mClusterId = 0;
EndpointId mEndpointId = 0;
EventId mEventId = 0;
EventNumber mEventNumber = 0;
FabricIndex mFabricIndex = kUndefinedFabricIndex;
};

void VendEventNumber();
CHIP_ERROR CalculateEventSize(EventLoggingDelegate * apDelegate, const EventOptions * apOptions, uint32_t & requiredSize);
/**
Expand Down Expand Up @@ -423,7 +457,8 @@ class EventManagement
* The function is used to scan through the event log to find events matching the spec in the supplied context.
* Particularly, it would check against mStartingEventNumber, and skip fetched event.
*/
static CHIP_ERROR EventIterator(const TLV::TLVReader & aReader, size_t aDepth, EventLoadOutContext * apEventLoadOutContext);
static CHIP_ERROR EventIterator(const TLV::TLVReader & aReader, size_t aDepth, EventLoadOutContext * apEventLoadOutContext,
EventEnvelopeContext * event);

/**
* @brief Internal iterator function used to fetch event into EventEnvelopeContext, then EventIterator would filter event
Expand All @@ -449,11 +484,26 @@ class EventManagement
return CHIP_ERROR_NO_MEMORY;
};

/**
* @brief checking if the given path is an interested path, this is a helper function for EventManagement::EventIterator
*
* @retval CHIP_NO_ERROR This path should be excluded in the generated event report.
* @retval CHIP_EVENT_ID_FOUND This path should be included in the generated event report.
* @retval CHIP_ERROR_ACCESS_DENIED This path should be included in the generated event report, but the client does not have
* . enough privilege to access it.
*/
static CHIP_ERROR IsInterestedEventPaths(EventLoadOutContext * eventLoadOutContext, const EventEnvelopeContext & event);

/**
* @brief copy event from circular buffer to target buffer for report
*/
static CHIP_ERROR CopyEvent(const TLV::TLVReader & aReader, TLV::TLVWriter & aWriter, EventLoadOutContext * apContext);

/**
* @brief construct EventStatusIB to target buffer for report
*/
static CHIP_ERROR WriteEventStatusIB(TLV::TLVWriter & aWriter, const ConcreteEventPath & aEvent, StatusIB aStatus);

/**
* @brief
* A function to get the circular buffer for particular priority
Expand Down Expand Up @@ -481,6 +531,9 @@ class EventManagement

EventNumber mLastEventNumber = 0; ///< Last event Number vended for this priority
Timestamp mLastEventTimestamp; ///< The timestamp of the last event in this buffer

/// Debug flag for bypassing ACL check when retrieving events
BypassACL mBypassACL = BypassACL::kNoBypass;
};
} // namespace app
} // namespace chip
8 changes: 8 additions & 0 deletions src/app/MessageDef/EventPathIB.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,14 @@ CHIP_ERROR EventPathIB::Parser::GetEvent(EventId * const apEvent) const
return GetUnsignedInteger(to_underlying(Tag::kEvent), apEvent);
}

CHIP_ERROR EventPathIB::Parser::GetEventPath(ConcreteEventPath * const apPath) const
{
VerifyOrReturnError(GetEndpoint(&(apPath->mEndpointId)) == CHIP_NO_ERROR, CHIP_ERROR_IM_MALFORMED_EVENT_PATH);
VerifyOrReturnError(GetCluster(&(apPath->mClusterId)) == CHIP_NO_ERROR, CHIP_ERROR_IM_MALFORMED_EVENT_PATH);
VerifyOrReturnError(GetEvent(&(apPath->mEventId)) == CHIP_NO_ERROR, CHIP_ERROR_IM_MALFORMED_EVENT_PATH);
return CHIP_NO_ERROR;
}

CHIP_ERROR EventPathIB::Parser::GetIsUrgent(bool * const apIsUrgent) const
{
return GetSimpleValue(to_underlying(Tag::kIsUrgent), TLV::kTLVType_Boolean, apIsUrgent);
Expand Down
Loading

0 comments on commit abc556f

Please sign in to comment.