Skip to content

Commit fa46641

Browse files
andy31415andreilitvinbzbarsky-apple
authored
Event validation simplification - pull logic into InteractionModelEngine.cpp only (#36251)
* Pull back the event path validity mixin, start with a datamodel implementation * Fix compile logic after I moved things away * Add one more check * Restyle * Fix typo * Fix includes * Restyle * Update src/app/InteractionModelEngine.cpp Co-authored-by: Boris Zbarsky <bzbarsky@apple.com> * Rename method * Restyle * More renames * Restyle * Fix some renames * Restyle * A few more renames * Restyle --------- Co-authored-by: Andrei Litvin <andreilitvin@google.com> Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>
1 parent c18a6de commit fa46641

File tree

10 files changed

+153
-212
lines changed

10 files changed

+153
-212
lines changed

src/app/BUILD.gn

+1-5
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,6 @@ static_library("interaction-model") {
255255
"reporting/Read-Ember.cpp",
256256
"reporting/Read-Ember.h",
257257
]
258-
public_deps += [ "${chip_root}/src/app/ember_coupling" ]
259258
} else if (chip_use_data_model_interface == "check") {
260259
sources += [
261260
"reporting/Read-Checked.cpp",
@@ -265,10 +264,7 @@ static_library("interaction-model") {
265264
"reporting/Read-Ember.cpp",
266265
"reporting/Read-Ember.h",
267266
]
268-
public_deps += [
269-
"${chip_root}/src/app/data-model-provider",
270-
"${chip_root}/src/app/ember_coupling",
271-
]
267+
public_deps += [ "${chip_root}/src/app/data-model-provider" ]
272268
} else { # enabled
273269
sources += [
274270
"reporting/Read-DataModel.cpp",

src/app/InteractionModelEngine.cpp

+152-29
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,13 @@
2727

2828
#include <cinttypes>
2929

30+
#include <access/AccessRestrictionProvider.h>
31+
#include <access/Privilege.h>
3032
#include <access/RequestPath.h>
3133
#include <access/SubjectDescriptor.h>
3234
#include <app/AppConfig.h>
3335
#include <app/CommandHandlerInterfaceRegistry.h>
36+
#include <app/EventPathParams.h>
3437
#include <app/RequiredPrivilege.h>
3538
#include <app/data-model-provider/ActionReturnStatus.h>
3639
#include <app/data-model-provider/MetadataTypes.h>
@@ -39,6 +42,7 @@
3942
#include <app/util/af-types.h>
4043
#include <app/util/ember-compatibility-functions.h>
4144
#include <app/util/endpoint-config-api.h>
45+
#include <lib/core/CHIPError.h>
4246
#include <lib/core/DataModelTypes.h>
4347
#include <lib/core/Global.h>
4448
#include <lib/core/TLVUtilities.h>
@@ -53,12 +57,148 @@
5357
#include <app/codegen-data-model-provider/Instance.h>
5458
#endif
5559

56-
#if !CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
57-
#include <app/ember_coupling/EventPathValidity.mixin.h> // nogncheck
58-
#endif
59-
6060
namespace chip {
6161
namespace app {
62+
namespace {
63+
64+
/**
65+
* Helper to handle wildcard events in the event path.
66+
*
67+
* Validates that ACL access is permitted to:
68+
* - Cluster::View in case the path is a wildcard for the event id
69+
* - Event read if the path is a concrete event path
70+
*/
71+
bool MayHaveAccessibleEventPathForEndpointAndCluster(const ConcreteClusterPath & path, const EventPathParams & aEventPath,
72+
const Access::SubjectDescriptor & aSubjectDescriptor)
73+
{
74+
Access::RequestPath requestPath{ .cluster = path.mClusterId,
75+
.endpoint = path.mEndpointId,
76+
.requestType = Access::RequestType::kEventReadRequest };
77+
78+
Access::Privilege requiredPrivilege = Access::Privilege::kView;
79+
80+
if (!aEventPath.HasWildcardEventId())
81+
{
82+
requestPath.entityId = aEventPath.mEventId;
83+
requiredPrivilege =
84+
RequiredPrivilege::ForReadEvent(ConcreteEventPath(path.mEndpointId, path.mClusterId, aEventPath.mEventId));
85+
}
86+
87+
return (Access::GetAccessControl().Check(aSubjectDescriptor, requestPath, requiredPrivilege) == CHIP_NO_ERROR);
88+
}
89+
90+
#if CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
91+
92+
bool MayHaveAccessibleEventPathForEndpoint(DataModel::Provider * aProvider, EndpointId aEndpoint,
93+
const EventPathParams & aEventPath, const Access::SubjectDescriptor & aSubjectDescriptor)
94+
{
95+
if (!aEventPath.HasWildcardClusterId())
96+
{
97+
return MayHaveAccessibleEventPathForEndpointAndCluster(ConcreteClusterPath(aEndpoint, aEventPath.mClusterId), aEventPath,
98+
aSubjectDescriptor);
99+
}
100+
101+
DataModel::ClusterEntry clusterEntry = aProvider->FirstCluster(aEventPath.mEndpointId);
102+
while (clusterEntry.IsValid())
103+
{
104+
if (MayHaveAccessibleEventPathForEndpointAndCluster(clusterEntry.path, aEventPath, aSubjectDescriptor))
105+
{
106+
return true;
107+
}
108+
clusterEntry = aProvider->NextCluster(clusterEntry.path);
109+
}
110+
111+
return false;
112+
}
113+
114+
bool MayHaveAccessibleEventPath(DataModel::Provider * aProvider, const EventPathParams & aEventPath,
115+
const Access::SubjectDescriptor & subjectDescriptor)
116+
{
117+
VerifyOrReturnValue(aProvider != nullptr, false);
118+
119+
if (!aEventPath.HasWildcardEndpointId())
120+
{
121+
return MayHaveAccessibleEventPathForEndpoint(aProvider, aEventPath.mEndpointId, aEventPath, subjectDescriptor);
122+
}
123+
124+
for (EndpointId endpointId = aProvider->FirstEndpoint(); endpointId != kInvalidEndpointId;
125+
endpointId = aProvider->NextEndpoint(endpointId))
126+
{
127+
if (MayHaveAccessibleEventPathForEndpoint(aProvider, endpointId, aEventPath, subjectDescriptor))
128+
{
129+
return true;
130+
}
131+
}
132+
return false;
133+
}
134+
135+
#else
136+
137+
/**
138+
* Helper to handle wildcard clusters in the event path.
139+
*/
140+
bool MayHaveAccessibleEventPathForEndpoint(EndpointId aEndpoint, const EventPathParams & aEventPath,
141+
const Access::SubjectDescriptor & aSubjectDescriptor)
142+
{
143+
if (aEventPath.HasWildcardClusterId())
144+
{
145+
auto * endpointType = emberAfFindEndpointType(aEndpoint);
146+
if (endpointType == nullptr)
147+
{
148+
// Not going to have any valid paths in here.
149+
return false;
150+
}
151+
152+
for (decltype(endpointType->clusterCount) idx = 0; idx < endpointType->clusterCount; ++idx)
153+
{
154+
bool mayHaveAccessiblePath = MayHaveAccessibleEventPathForEndpointAndCluster(
155+
ConcreteClusterPath(aEndpoint, endpointType->cluster[idx].clusterId), aEventPath, aSubjectDescriptor);
156+
if (mayHaveAccessiblePath)
157+
{
158+
return true;
159+
}
160+
}
161+
162+
return false;
163+
}
164+
165+
auto * cluster = emberAfFindServerCluster(aEndpoint, aEventPath.mClusterId);
166+
if (cluster == nullptr)
167+
{
168+
// Nothing valid here.
169+
return false;
170+
}
171+
return MayHaveAccessibleEventPathForEndpointAndCluster(ConcreteClusterPath(aEndpoint, cluster->clusterId), aEventPath,
172+
aSubjectDescriptor);
173+
}
174+
175+
bool MayHaveAccessibleEventPath(const EventPathParams & aEventPath, const Access::SubjectDescriptor & aSubjectDescriptor)
176+
{
177+
if (!aEventPath.HasWildcardEndpointId())
178+
{
179+
// No need to check whether the endpoint is enabled, because
180+
// emberAfFindEndpointType returns null for disabled endpoints.
181+
return MayHaveAccessibleEventPathForEndpoint(aEventPath.mEndpointId, aEventPath, aSubjectDescriptor);
182+
}
183+
184+
for (uint16_t endpointIndex = 0; endpointIndex < emberAfEndpointCount(); ++endpointIndex)
185+
{
186+
if (!emberAfEndpointIndexIsEnabled(endpointIndex))
187+
{
188+
continue;
189+
}
190+
if (MayHaveAccessibleEventPathForEndpoint(emberAfEndpointFromIndex(endpointIndex), aEventPath, aSubjectDescriptor))
191+
{
192+
return true;
193+
}
194+
}
195+
196+
// none of the paths matched
197+
return false;
198+
}
199+
#endif
200+
201+
} // namespace
62202

63203
class AutoReleaseSubscriptionInfoIterator
64204
{
@@ -583,30 +723,13 @@ CHIP_ERROR InteractionModelEngine::ParseEventPaths(const Access::SubjectDescript
583723
continue;
584724
}
585725

586-
#if CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
587-
aHasValidEventPath = mDataModelProvider->EventPathIncludesAccessibleConcretePath(eventPath, aSubjectDescriptor);
588-
#else
589726
// The definition of "valid path" is "path exists and ACL allows
590727
// access". We need to do some expansion of wildcards to handle that.
591-
if (eventPath.HasWildcardEndpointId())
592-
{
593-
for (uint16_t endpointIndex = 0; !aHasValidEventPath && endpointIndex < emberAfEndpointCount(); ++endpointIndex)
594-
{
595-
if (!emberAfEndpointIndexIsEnabled(endpointIndex))
596-
{
597-
continue;
598-
}
599-
aHasValidEventPath =
600-
HasValidEventPathForEndpoint(emberAfEndpointFromIndex(endpointIndex), eventPath, aSubjectDescriptor);
601-
}
602-
}
603-
else
604-
{
605-
// No need to check whether the endpoint is enabled, because
606-
// emberAfFindEndpointType returns null for disabled endpoints.
607-
aHasValidEventPath = HasValidEventPathForEndpoint(eventPath.mEndpointId, eventPath, aSubjectDescriptor);
608-
}
609-
#endif // CHIP_CONFIG_USE_EMBER_DATA_MODEL
728+
#if CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
729+
aHasValidEventPath = MayHaveAccessibleEventPath(mDataModelProvider, eventPath, aSubjectDescriptor);
730+
#else
731+
aHasValidEventPath = MayHaveAccessibleEventPath(eventPath, aSubjectDescriptor);
732+
#endif
610733
}
611734

612735
if (err == CHIP_ERROR_END_OF_TLV)
@@ -676,7 +799,7 @@ Protocols::InteractionModel::Status InteractionModelEngine::OnReadInitialRequest
676799
size_t requestedEventPathCount = 0;
677800
AttributePathIBs::Parser attributePathListParser;
678801
bool hasValidAttributePath = false;
679-
bool hasValidEventPath = false;
802+
bool mayHaveValidEventPath = false;
680803

681804
CHIP_ERROR err = subscribeRequestParser.GetAttributeRequests(&attributePathListParser);
682805
if (err == CHIP_NO_ERROR)
@@ -699,7 +822,7 @@ Protocols::InteractionModel::Status InteractionModelEngine::OnReadInitialRequest
699822
if (err == CHIP_NO_ERROR)
700823
{
701824
auto subjectDescriptor = apExchangeContext->GetSessionHandle()->AsSecureSession()->GetSubjectDescriptor();
702-
err = ParseEventPaths(subjectDescriptor, eventPathListParser, hasValidEventPath, requestedEventPathCount);
825+
err = ParseEventPaths(subjectDescriptor, eventPathListParser, mayHaveValidEventPath, requestedEventPathCount);
703826
if (err != CHIP_NO_ERROR)
704827
{
705828
return Status::InvalidAction;
@@ -719,7 +842,7 @@ Protocols::InteractionModel::Status InteractionModelEngine::OnReadInitialRequest
719842
return Status::InvalidAction;
720843
}
721844

722-
if (!hasValidAttributePath && !hasValidEventPath)
845+
if (!hasValidAttributePath && !mayHaveValidEventPath)
723846
{
724847
ChipLogError(InteractionModel,
725848
"Subscription from [%u:" ChipLogFormatX64 "] has no access at all. Rejecting request.",

src/app/codegen-data-model-provider/CodegenDataModelProvider.cpp

-28
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,6 @@
3333
#include <lib/core/DataModelTypes.h>
3434
#include <lib/support/CodeUtils.h>
3535

36-
// separated out for code-reuse
37-
#include <app/ember_coupling/EventPathValidity.mixin.h>
38-
3936
#include <optional>
4037
#include <variant>
4138

@@ -772,30 +769,5 @@ std::optional<DataModel::DeviceTypeEntry> CodegenDataModelProvider::NextDeviceTy
772769
return DeviceTypeEntryFromEmber(deviceTypes[idx]);
773770
}
774771

775-
bool CodegenDataModelProvider::EventPathIncludesAccessibleConcretePath(const EventPathParams & path,
776-
const Access::SubjectDescriptor & descriptor)
777-
{
778-
779-
if (!path.HasWildcardEndpointId())
780-
{
781-
// No need to check whether the endpoint is enabled, because
782-
// emberAfFindEndpointType returns null for disabled endpoints.
783-
return HasValidEventPathForEndpoint(path.mEndpointId, path, descriptor);
784-
}
785-
786-
for (uint16_t endpointIndex = 0; endpointIndex < emberAfEndpointCount(); ++endpointIndex)
787-
{
788-
if (!emberAfEndpointIndexIsEnabled(endpointIndex))
789-
{
790-
continue;
791-
}
792-
if (HasValidEventPathForEndpoint(emberAfEndpointFromIndex(endpointIndex), path, descriptor))
793-
{
794-
return true;
795-
}
796-
}
797-
return false;
798-
}
799-
800772
} // namespace app
801773
} // namespace chip

src/app/codegen-data-model-provider/CodegenDataModelProvider.h

-2
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,6 @@ class CodegenDataModelProvider : public chip::app::DataModel::Provider
141141
return CHIP_NO_ERROR;
142142
}
143143

144-
bool EventPathIncludesAccessibleConcretePath(const EventPathParams & path,
145-
const Access::SubjectDescriptor & descriptor) override;
146144
DataModel::ActionReturnStatus ReadAttribute(const DataModel::ReadAttributeRequest & request,
147145
AttributeValueEncoder & encoder) override;
148146
DataModel::ActionReturnStatus WriteAttribute(const DataModel::WriteAttributeRequest & request,

src/app/codegen-data-model-provider/model.gni

-1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,5 @@ codegen_data_model_SOURCES = [
3939
codegen_data_model_PUBLIC_DEPS = [
4040
"${chip_root}/src/app/common:attribute-type",
4141
"${chip_root}/src/app/data-model-provider",
42-
"${chip_root}/src/app/ember_coupling",
4342
"${chip_root}/src/app/codegen-data-model-provider:instance-header",
4443
]

src/app/data-model-provider/Provider.h

-10
Original file line numberDiff line numberDiff line change
@@ -59,16 +59,6 @@ class Provider : public ProviderMetadataTree
5959
// event emitting, path marking and other operations
6060
virtual InteractionModelContext CurrentContext() const { return mContext; }
6161

62-
/// Validates that the given event path is supported, where path may contain wildcards.
63-
///
64-
/// If any wild cards exist on the given path, the implementation is expected to validate
65-
/// that an accessible event path exists on some wildcard expansion.
66-
///
67-
/// At the very minimum this will validate that a valid endpoint/cluster can be expanded
68-
/// from the input path and that the given descriptor has access to it.
69-
virtual bool EventPathIncludesAccessibleConcretePath(const EventPathParams & path,
70-
const Access::SubjectDescriptor & descriptor) = 0;
71-
7262
/// TEMPORARY/TRANSITIONAL requirement for transitioning from ember-specific code
7363
/// ReadAttribute is REQUIRED to perform:
7464
/// - ACL validation (see notes on OperationFlags::kInternal)

src/app/ember_coupling/BUILD.gn

-23
This file was deleted.

0 commit comments

Comments
 (0)