Skip to content

Commit 6017925

Browse files
bzbarsky-applepull[bot]
authored andcommitted
Make AutoCommissioner::SetCommissioningParameters safer. (#24422)
* Make AutoCommissioner::SetCommissioningParameters safer. Right now, we copy all members of the incoming CommissioningParameters (which might include pointers to buffers that we don't own), then copy some of those external buffers into our own buffers. Then we also hand-copy some scalar values we have already copied. Changes in this PR: * Stop copying scalar values that operator= already handled. * Clear out all buffer references from our copy of CommissioningParameters before we start copying things into our buffers, so we don't end up with dangling pointers. * Add the missing early return when an incoming country code value is too long (used to end up with a dangling pointer). * Address review comment.
1 parent ec1f30e commit 6017925

File tree

2 files changed

+70
-29
lines changed

2 files changed

+70
-29
lines changed

src/controller/AutoCommissioner.cpp

+50-29
Original file line numberDiff line numberDiff line change
@@ -45,53 +45,83 @@ void AutoCommissioner::SetOperationalCredentialsDelegate(OperationalCredentialsD
4545
mOperationalCredentialsDelegate = operationalCredentialsDelegate;
4646
}
4747

48-
CHIP_ERROR AutoCommissioner::SetCommissioningParameters(const CommissioningParameters & params)
48+
// Returns true if maybeUnsafeSpan is pointing to a buffer that we're not sure
49+
// will live for long enough. knownSafeSpan, if it has a value, points to a
50+
// buffer that we _are_ sure will live for long enough.
51+
template <typename SpanType>
52+
static bool IsUnsafeSpan(const Optional<SpanType> & maybeUnsafeSpan, const Optional<SpanType> & knownSafeSpan)
4953
{
50-
mParams = params;
51-
if (params.GetFailsafeTimerSeconds().HasValue())
54+
if (!maybeUnsafeSpan.HasValue())
5255
{
53-
ChipLogProgress(Controller, "Setting failsafe timer from parameters");
54-
mParams.SetFailsafeTimerSeconds(params.GetFailsafeTimerSeconds().Value());
56+
return false;
5557
}
5658

57-
if (params.GetCASEFailsafeTimerSeconds().HasValue())
59+
if (!knownSafeSpan.HasValue())
5860
{
59-
ChipLogProgress(Controller, "Setting CASE failsafe timer from parameters");
60-
mParams.SetCASEFailsafeTimerSeconds(params.GetCASEFailsafeTimerSeconds().Value());
61+
return true;
6162
}
6263

63-
if (params.GetAdminSubject().HasValue())
64+
return maybeUnsafeSpan.Value().data() != knownSafeSpan.Value().data();
65+
}
66+
67+
CHIP_ERROR AutoCommissioner::SetCommissioningParameters(const CommissioningParameters & params)
68+
{
69+
// Make sure any members that point to buffers that we are not pointing to
70+
// our own buffers are not going to dangle. We can skip this step if all
71+
// the buffers pointers that we don't plan to re-point to our own buffers
72+
// below are already pointing to the same things as our own buffer pointers
73+
// (so that we know they have to be safe somehow).
74+
//
75+
// The checks are a bit painful, because Span does not have a usable
76+
// operator==, and in any case, we want to compare for pointer equality, not
77+
// data equality.
78+
bool haveMaybeDanglingBufferPointers =
79+
((params.GetNOCChainGenerationParameters().HasValue() &&
80+
(!mParams.GetNOCChainGenerationParameters().HasValue() ||
81+
params.GetNOCChainGenerationParameters().Value().nocsrElements.data() !=
82+
mParams.GetNOCChainGenerationParameters().Value().nocsrElements.data() ||
83+
params.GetNOCChainGenerationParameters().Value().signature.data() !=
84+
mParams.GetNOCChainGenerationParameters().Value().signature.data())) ||
85+
IsUnsafeSpan(params.GetRootCert(), mParams.GetRootCert()) || IsUnsafeSpan(params.GetNoc(), mParams.GetNoc()) ||
86+
IsUnsafeSpan(params.GetIcac(), mParams.GetIcac()) || IsUnsafeSpan(params.GetIpk(), mParams.GetIpk()) ||
87+
IsUnsafeSpan(params.GetAttestationElements(), mParams.GetAttestationElements()) ||
88+
IsUnsafeSpan(params.GetAttestationSignature(), mParams.GetAttestationSignature()) ||
89+
IsUnsafeSpan(params.GetPAI(), mParams.GetPAI()) || IsUnsafeSpan(params.GetDAC(), mParams.GetDAC()));
90+
91+
mParams = params;
92+
93+
if (haveMaybeDanglingBufferPointers)
6494
{
65-
ChipLogProgress(Controller, "Setting adminSubject from parameters");
66-
mParams.SetAdminSubject(params.GetAdminSubject().Value());
95+
mParams.ClearExternalBufferDependentValues();
6796
}
6897

98+
// For members of params that point to some sort of buffer, we have to copy
99+
// the data over into our own buffers.
100+
69101
if (params.GetThreadOperationalDataset().HasValue())
70102
{
71103
ByteSpan dataset = params.GetThreadOperationalDataset().Value();
72104
if (dataset.size() > CommissioningParameters::kMaxThreadDatasetLen)
73105
{
74106
ChipLogError(Controller, "Thread operational data set is too large");
107+
// Make sure our buffer pointers don't dangle.
108+
mParams.ClearExternalBufferDependentValues();
75109
return CHIP_ERROR_INVALID_ARGUMENT;
76110
}
77111
memcpy(mThreadOperationalDataset, dataset.data(), dataset.size());
78112
ChipLogProgress(Controller, "Setting thread operational dataset from parameters");
79113
mParams.SetThreadOperationalDataset(ByteSpan(mThreadOperationalDataset, dataset.size()));
80114
}
81115

82-
if (params.GetAttemptThreadNetworkScan().HasValue())
83-
{
84-
ChipLogProgress(Controller, "Setting attempt thread scan from parameters");
85-
mParams.SetAttemptThreadNetworkScan(params.GetAttemptThreadNetworkScan().Value());
86-
}
87-
88116
if (params.GetWiFiCredentials().HasValue())
89117
{
90118
WiFiCredentials creds = params.GetWiFiCredentials().Value();
91119
if (creds.ssid.size() > CommissioningParameters::kMaxSsidLen ||
92120
creds.credentials.size() > CommissioningParameters::kMaxCredentialsLen)
93121
{
94122
ChipLogError(Controller, "Wifi credentials are too large");
123+
// Make sure our buffer pointers don't dangle.
124+
mParams.ClearExternalBufferDependentValues();
95125
return CHIP_ERROR_INVALID_ARGUMENT;
96126
}
97127
memcpy(mSsid, creds.ssid.data(), creds.ssid.size());
@@ -101,12 +131,6 @@ CHIP_ERROR AutoCommissioner::SetCommissioningParameters(const CommissioningParam
101131
WiFiCredentials(ByteSpan(mSsid, creds.ssid.size()), ByteSpan(mCredentials, creds.credentials.size())));
102132
}
103133

104-
if (params.GetAttemptWiFiNetworkScan().HasValue())
105-
{
106-
ChipLogProgress(Controller, "Setting attempt wifi scan from parameters");
107-
mParams.SetAttemptWiFiNetworkScan(params.GetAttemptWiFiNetworkScan().Value());
108-
}
109-
110134
if (params.GetCountryCode().HasValue())
111135
{
112136
auto code = params.GetCountryCode().Value();
@@ -118,6 +142,9 @@ CHIP_ERROR AutoCommissioner::SetCommissioningParameters(const CommissioningParam
118142
else
119143
{
120144
ChipLogError(Controller, "Country code is too large: %u", static_cast<unsigned>(code.size()));
145+
// Make sure our buffer pointers don't dangle.
146+
mParams.ClearExternalBufferDependentValues();
147+
return CHIP_ERROR_INVALID_ARGUMENT;
121148
}
122149
}
123150

@@ -148,12 +175,6 @@ CHIP_ERROR AutoCommissioner::SetCommissioningParameters(const CommissioningParam
148175
}
149176
mParams.SetCSRNonce(ByteSpan(mCSRNonce, sizeof(mCSRNonce)));
150177

151-
if (params.GetSkipCommissioningComplete().HasValue())
152-
{
153-
ChipLogProgress(Controller, "Setting PASE-only commissioning from parameters");
154-
mParams.SetSkipCommissioningComplete(params.GetSkipCommissioningComplete().Value());
155-
}
156-
157178
return CHIP_NO_ERROR;
158179
}
159180

src/controller/CommissioningDelegate.h

+20
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,26 @@ class CommissioningParameters
425425
return *this;
426426
}
427427

428+
// Clear all members that depend on some sort of external buffer. Can be
429+
// used to make sure that we are not holding any dangling pointers.
430+
void ClearExternalBufferDependentValues()
431+
{
432+
mCSRNonce.ClearValue();
433+
mAttestationNonce.ClearValue();
434+
mWiFiCreds.ClearValue();
435+
mCountryCode.ClearValue();
436+
mThreadOperationalDataset.ClearValue();
437+
mNOCChainGenerationParameters.ClearValue();
438+
mRootCert.ClearValue();
439+
mNoc.ClearValue();
440+
mIcac.ClearValue();
441+
mIpk.ClearValue();
442+
mAttestationElements.ClearValue();
443+
mAttestationSignature.ClearValue();
444+
mPAI.ClearValue();
445+
mDAC.ClearValue();
446+
}
447+
428448
private:
429449
// Items that can be set by the commissioner
430450
Optional<uint16_t> mFailsafeTimerSeconds;

0 commit comments

Comments
 (0)