Skip to content

Commit 4374633

Browse files
bzbarsky-applepull[bot]
authored andcommitted
Enforce spec range restrictions on most nullable integer types for command/struct fields. (#13072)
This does not enforce restrictions for the "odd-sized" (3-, 5-, 6-, 7-byte) integers, because at the point when we do TLV decoding for command/struct fields we don't know we're dealing with one of those. Those should generally not be used in command/struct fields anyway.
1 parent c7fa772 commit 4374633

File tree

10 files changed

+70
-18
lines changed

10 files changed

+70
-18
lines changed

src/app/data-model/Decode.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,12 @@ CHIP_ERROR Decode(TLV::TLVReader & reader, Nullable<X> & x)
158158
}
159159

160160
// We have a value; decode it.
161-
return Decode(reader, x.SetNonNull());
161+
ReturnErrorOnFailure(Decode(reader, x.SetNonNull()));
162+
if (!x.HasValidValue())
163+
{
164+
return CHIP_ERROR_IM_CONSTRAINT_ERROR;
165+
}
166+
return CHIP_NO_ERROR;
162167
}
163168

164169
} // namespace DataModel

src/app/data-model/Encode.h

+11
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
#include <lib/core/CHIPTLV.h>
2323
#include <lib/core/Optional.h>
2424

25+
#include <type_traits>
26+
2527
namespace chip {
2628
namespace app {
2729
namespace DataModel {
@@ -115,6 +117,15 @@ CHIP_ERROR Encode(TLV::TLVWriter & writer, TLV::Tag tag, const Nullable<X> & x)
115117
{
116118
return writer.PutNull(tag);
117119
}
120+
// Allow sending invalid values for nullables when
121+
// CONFIG_IM_BUILD_FOR_UNIT_TEST is true, so we can test how the other side
122+
// responds.
123+
#if !CONFIG_IM_BUILD_FOR_UNIT_TEST
124+
if (!x.HasValidValue())
125+
{
126+
return CHIP_ERROR_IM_CONSTRAINT_ERROR;
127+
}
128+
#endif // !CONFIG_IM_BUILD_FOR_UNIT_TEST
118129
return Encode(writer, tag, x.Value());
119130
}
120131

src/app/data-model/Nullable.h

+21
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,11 @@
1818

1919
#pragma once
2020

21+
#include <app/util/attribute-storage-null-handling.h>
2122
#include <lib/core/Optional.h>
2223

24+
#include <type_traits>
25+
2326
namespace chip {
2427
namespace app {
2528
namespace DataModel {
@@ -52,6 +55,24 @@ struct Nullable : protected Optional<T>
5255
{
5356
return Optional<T>::Emplace(std::forward<Args>(args)...);
5457
}
58+
59+
// For integer types, being nullable involves a range restriction.
60+
template <
61+
typename U = std::decay_t<T>,
62+
typename std::enable_if_t<(std::is_integral<U>::value && !std::is_same<U, bool>::value) || std::is_enum<U>::value, int> = 0>
63+
constexpr bool HasValidValue() const
64+
{
65+
return NumericAttributeTraits<T>::CanRepresentValue(/* isNullable = */ true, Value());
66+
}
67+
68+
// For all other types, all values are valid.
69+
template <typename U = std::decay_t<T>,
70+
typename std::enable_if_t<(!std::is_integral<U>::value || std::is_same<U, bool>::value) && !std::is_enum<U>::value,
71+
int> = 0>
72+
constexpr bool HasValidValue() const
73+
{
74+
return true;
75+
}
5576
};
5677

5778
} // namespace DataModel

src/darwin/CHIPTool/CHIPTool/Framework Helpers/DefaultsUtils.m

+1-1
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ BOOL CHIPIsDevicePaired(uint64_t deviceId)
119119

120120
NSError * error;
121121
bool paired = [controller isDevicePaired:deviceId error:&error];
122-
if (error.code != CHIPSuccess) {
122+
if (error != nil) {
123123
NSLog(@"Error retrieving device info for deviceId %llu", deviceId);
124124
paired = NO;
125125
}

src/darwin/CHIPTool/CHIPTool/View Controllers/QRCode/QRCodeViewController.m

+4-4
Original file line numberDiff line numberDiff line change
@@ -474,9 +474,9 @@ - (void)setVendorIDOnAccessory
474474
}
475475

476476
// MARK: CHIPDevicePairingDelegate
477-
- (void)onPairingComplete:(NSError *)error
477+
- (void)onPairingComplete:(NSError * _Nullable)error
478478
{
479-
if (error.code != CHIPSuccess) {
479+
if (error != nil) {
480480
NSLog(@"Got pairing error back %@", error);
481481
} else {
482482
dispatch_async(dispatch_get_main_queue(), ^{
@@ -721,9 +721,9 @@ - (void)onConnectNetworkResponse:(NSError *)error
721721
[controller updateDevice:deviceId fabricId:0];
722722
}
723723

724-
- (void)onAddressUpdated:(NSError *)error
724+
- (void)onAddressUpdated:(NSError * _Nullable)error
725725
{
726-
if (error.code != CHIPSuccess) {
726+
if (error != nil) {
727727
NSLog(@"Error retrieving device informations over Mdns: %@", error);
728728
return;
729729
}

src/darwin/Framework/CHIP/CHIPError.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@
2020
NS_ASSUME_NONNULL_BEGIN
2121
FOUNDATION_EXPORT NSErrorDomain const CHIPErrorDomain;
2222

23+
// clang-format off
2324
typedef NS_ERROR_ENUM(CHIPErrorDomain, CHIPErrorCode){
24-
CHIPSuccess = 0,
2525
CHIPErrorCodeUndefinedError = 1,
2626
CHIPErrorCodeInvalidStringLength = 2,
2727
CHIPErrorCodeInvalidIntegerValue = 3,
@@ -39,5 +39,6 @@ typedef NS_ERROR_ENUM(CHIPErrorDomain, CHIPErrorCode){
3939
CHIPErrorCodeUnsupportedWrite = 0x88,
4040
CHIPErrorCodeUnsupportedCluster = 0xC3,
4141
};
42+
// clang-format on
4243

4344
NS_ASSUME_NONNULL_END

src/darwin/Framework/CHIP/CHIPError.mm

+15-8
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,14 @@ + (NSError *)errorForCHIPErrorCode:(CHIP_ERROR)errorCode
6363
userInfo:@{ NSLocalizedDescriptionKey : NSLocalizedString(@"Integrity check failed.", nil) }];
6464
}
6565

66-
if (errorCode == CHIP_NO_ERROR) {
66+
if (errorCode == CHIP_ERROR_IM_CONSTRAINT_ERROR) {
6767
return [NSError errorWithDomain:CHIPErrorDomain
68-
code:CHIPSuccess
69-
userInfo:@{ NSLocalizedDescriptionKey : NSLocalizedString(@"Success.", nil) }];
68+
code:CHIPErrorCodeConstraintError
69+
userInfo:@{ NSLocalizedDescriptionKey : NSLocalizedString(@"Value out of range.", nil) }];
70+
}
71+
72+
if (errorCode == CHIP_NO_ERROR) {
73+
return nil;
7074
}
7175

7276
return [NSError errorWithDomain:CHIPErrorDomain
@@ -132,8 +136,12 @@ + (NSError *)errorForZCLErrorCode:(uint8_t)errorCode
132136
}
133137
}
134138

135-
+ (CHIP_ERROR)errorToCHIPErrorCode:(NSError *)error
139+
+ (CHIP_ERROR)errorToCHIPErrorCode:(NSError * _Nullable)error
136140
{
141+
if (error == nil) {
142+
return CHIP_NO_ERROR;
143+
}
144+
137145
if (error.domain != CHIPErrorDomain) {
138146
return CHIP_ERROR_INTERNAL;
139147
}
@@ -151,8 +159,8 @@ + (CHIP_ERROR)errorToCHIPErrorCode:(NSError *)error
151159
return CHIP_ERROR_INCORRECT_STATE;
152160
case CHIPErrorCodeIntegrityCheckFailed:
153161
return CHIP_ERROR_INTEGRITY_CHECK_FAILED;
154-
case CHIPSuccess:
155-
return CHIP_NO_ERROR;
162+
case CHIPErrorCodeConstraintError:
163+
return CHIP_ERROR_IM_CONSTRAINT_ERROR;
156164
default:
157165
return CHIP_ERROR_INTERNAL;
158166
}
@@ -165,6 +173,7 @@ + (uint8_t)errorToZCLErrorCode:(NSError * _Nullable)error
165173
if (error == nil) {
166174
return EMBER_ZCL_STATUS_SUCCESS;
167175
}
176+
168177
if (error.domain != CHIPErrorDomain) {
169178
return EMBER_ZCL_STATUS_FAILURE;
170179
}
@@ -186,8 +195,6 @@ + (uint8_t)errorToZCLErrorCode:(NSError * _Nullable)error
186195
return EMBER_ZCL_STATUS_UNSUPPORTED_WRITE;
187196
case CHIPErrorCodeUnsupportedCluster:
188197
return EMBER_ZCL_STATUS_UNSUPPORTED_CLUSTER;
189-
case CHIPSuccess:
190-
return EMBER_ZCL_STATUS_SUCCESS;
191198
default:
192199
return EMBER_ZCL_STATUS_FAILURE;
193200
}

src/darwin/Framework/CHIP/CHIPError_Internal.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ NS_ASSUME_NONNULL_BEGIN
2424
@interface CHIPError : NSObject
2525
+ (nullable NSError *)errorForCHIPErrorCode:(CHIP_ERROR)errorCode;
2626
+ (nullable NSError *)errorForZCLErrorCode:(uint8_t)errorCode;
27-
+ (CHIP_ERROR)errorToCHIPErrorCode:(NSError *)error;
27+
+ (CHIP_ERROR)errorToCHIPErrorCode:(NSError * _Nullable)error;
2828
+ (uint8_t)errorToZCLErrorCode:(NSError * _Nullable)error;
2929
@end
3030

src/darwin/Framework/CHIPTests/CHIPErrorTestUtils.mm

-2
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,6 @@ + (uint8_t)errorToZCLErrorCode:(NSError * _Nullable)error
5454
return EMBER_ZCL_STATUS_UNSUPPORTED_WRITE;
5555
case CHIPErrorCodeUnsupportedCluster:
5656
return EMBER_ZCL_STATUS_UNSUPPORTED_CLUSTER;
57-
case CHIPSuccess:
58-
return EMBER_ZCL_STATUS_SUCCESS;
5957
default:
6058
return EMBER_ZCL_STATUS_FAILURE;
6159
}

src/lib/core/CHIPError.h

+9
Original file line numberDiff line numberDiff line change
@@ -2357,6 +2357,15 @@ using CHIP_ERROR = ::chip::ChipError;
23572357
*/
23582358
#define CHIP_ERROR_MISSING_URI_SEPARATOR CHIP_CORE_ERROR(0xd7)
23592359

2360+
/**
2361+
* @def CHIP_ERROR_IM_CONSTRAINT_ERROR
2362+
*
2363+
* @brief
2364+
* The equivalent of a CONSTRAINT_ERROR status: a value was out of the valid
2365+
* range.
2366+
*/
2367+
#define CHIP_ERROR_IM_CONSTRAINT_ERROR CHIP_CORE_ERROR(0xd8)
2368+
23602369
/**
23612370
* @}
23622371
*/

0 commit comments

Comments
 (0)