-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Handle ACL and readability in reporting/Engine.cpp
#36488
base: master
Are you sure you want to change the base?
Changes from all commits
e377109
ec586e7
476ad1a
697091a
318743f
2ee2a97
bceac0c
3523b07
1df0e39
122a60c
5d61dde
7bab9a7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,17 +16,24 @@ | |
* limitations under the License. | ||
*/ | ||
|
||
#include <access/AccessRestrictionProvider.h> | ||
#include <access/Privilege.h> | ||
#include <app/AppConfig.h> | ||
#include <app/ConcreteEventPath.h> | ||
#include <app/GlobalAttributes.h> | ||
#include <app/InteractionModelEngine.h> | ||
#include <app/RequiredPrivilege.h> | ||
#include <app/data-model-provider/ActionReturnStatus.h> | ||
#include <app/data-model-provider/MetadataTypes.h> | ||
#include <app/data-model-provider/Provider.h> | ||
#include <app/icd/server/ICDServerConfig.h> | ||
#include <app/reporting/Engine.h> | ||
#include <app/reporting/reporting.h> | ||
#include <app/util/MatterCallbacks.h> | ||
#include <lib/core/CHIPError.h> | ||
#include <lib/core/DataModelTypes.h> | ||
#include <lib/support/CodeUtils.h> | ||
#include <optional> | ||
#include <protocols/interaction_model/StatusCode.h> | ||
|
||
#if CHIP_CONFIG_ENABLE_ICD_SERVER | ||
|
@@ -52,6 +59,58 @@ Status EventPathValid(DataModel::Provider * model, const ConcreteEventPath & eve | |
return Status::Success; | ||
} | ||
|
||
/// Returns the status of ACL validation. | ||
/// if the status is set, the status is FINAL (i.e. permanent failure OR success due to path expansion logic.) | ||
/// if the status is not set, the processing can continue | ||
std::optional<CHIP_ERROR> ValidateReadACL(DataModel::Provider * dataModel, const Access::SubjectDescriptor & subjectDescriptor, | ||
const ConcreteReadAttributePath & path) | ||
{ | ||
|
||
Access::RequestPath requestPath{ .cluster = path.mClusterId, | ||
.endpoint = path.mEndpointId, | ||
.requestType = Access::RequestType::kAttributeReadRequest, | ||
.entityId = path.mAttributeId }; | ||
|
||
std::optional<DataModel::AttributeInfo> info = dataModel->GetAttributeInfo(path); | ||
|
||
chip::Access::Privilege requiredPrivilege = chip::Access::Privilege::kView; // default | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why all the extra |
||
if (info.has_value() && info->readPrivilege.has_value()) | ||
{ | ||
// set a default even if we do not know and later report the real error if ACL looks ok | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't understand what this comment is trying to say. |
||
requiredPrivilege = *info->readPrivilege; | ||
} | ||
|
||
CHIP_ERROR err = Access::GetAccessControl().Check(subjectDescriptor, requestPath, requiredPrivilege); | ||
if (err == CHIP_NO_ERROR) | ||
{ | ||
if (IsSupportedGlobalAttributeNotInMetadata(path.mAttributeId)) | ||
{ | ||
// Global attributes passing a kView check is ok | ||
return std::nullopt; | ||
} | ||
|
||
// attribute does not exist, however we do not now if this is a unsupported endpoint, cluster or attribute, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why does attribute not exist? All we know is we did an access check and it succeeeded. This code is not making any sense to me. Stopping here. |
||
// so the info.has_value() is only handled by the ReadAttribute in the DataModel::Provider. | ||
// | ||
// What we can validate is `write-only attributes` (i.e if we have info, readPrivilege should be set) | ||
|
||
// if the attribute does exist, it should be readable | ||
VerifyOrReturnError(!info.has_value() || info->readPrivilege.has_value(), CHIP_IM_GLOBAL_STATUS(UnsupportedRead)); | ||
|
||
return std::nullopt; | ||
} | ||
VerifyOrReturnError((err == CHIP_ERROR_ACCESS_DENIED) || (err == CHIP_ERROR_ACCESS_RESTRICTED_BY_ARL), err); | ||
|
||
// Implementation of 8.4.3.2 of the spec for path expansion | ||
if (path.mExpanded) | ||
{ | ||
return CHIP_NO_ERROR; | ||
} | ||
|
||
// access denied and access restricted have specific codes for IM | ||
return err == CHIP_ERROR_ACCESS_DENIED ? CHIP_IM_GLOBAL_STATUS(UnsupportedAccess) : CHIP_IM_GLOBAL_STATUS(AccessRestricted); | ||
} | ||
|
||
DataModel::ActionReturnStatus RetrieveClusterData(DataModel::Provider * dataModel, | ||
const Access::SubjectDescriptor & subjectDescriptor, bool isFabricFiltered, | ||
AttributeReportIBs::Builder & reportBuilder, | ||
|
@@ -64,10 +123,7 @@ DataModel::ActionReturnStatus RetrieveClusterData(DataModel::Provider * dataMode | |
|
||
DataModel::ReadAttributeRequest readRequest; | ||
|
||
if (isFabricFiltered) | ||
{ | ||
readRequest.readFlags.Set(DataModel::ReadFlags::kFabricFiltered); | ||
} | ||
readRequest.readFlags.Set(DataModel::ReadFlags::kFabricFiltered, isFabricFiltered); | ||
readRequest.subjectDescriptor = &subjectDescriptor; | ||
readRequest.path = path; | ||
|
||
|
@@ -84,9 +140,17 @@ DataModel::ActionReturnStatus RetrieveClusterData(DataModel::Provider * dataMode | |
TLV::TLVWriter checkpoint; | ||
reportBuilder.Checkpoint(checkpoint); | ||
|
||
DataModel::ActionReturnStatus status(CHIP_NO_ERROR); | ||
AttributeValueEncoder attributeValueEncoder(reportBuilder, subjectDescriptor, path, version, isFabricFiltered, encoderState); | ||
|
||
DataModel::ActionReturnStatus status = dataModel->ReadAttribute(readRequest, attributeValueEncoder); | ||
if (auto access_status = ValidateReadACL(dataModel, subjectDescriptor, path); access_status.has_value()) | ||
{ | ||
status = *access_status; | ||
} | ||
else | ||
{ | ||
status = dataModel->ReadAttribute(readRequest, attributeValueEncoder); | ||
} | ||
|
||
if (status.IsSuccess()) | ||
{ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.