Skip to content

IN-DEV: Synchronize access to CastingApp/CastingPlayer to avoid race conditions#43082

Open
chrisdecenzo wants to merge 1 commit intoproject-chip:masterfrom
chrisdecenzo:cast16
Open

IN-DEV: Synchronize access to CastingApp/CastingPlayer to avoid race conditions#43082
chrisdecenzo wants to merge 1 commit intoproject-chip:masterfrom
chrisdecenzo:cast16

Conversation

@chrisdecenzo
Copy link
Copy Markdown
Contributor

Summary

Avoid synchronization issues when Server.init is slow.

When running multiple instances of the CastingApp on the phone (in different apps), synchronization issues have been observed

Testing

iOS and Android phone. More TBD

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request aims to address potential race conditions and synchronization issues by adding state checks and synchronized blocks in CastingApp and MatterCastingPlayer. While the PR introduces valuable improvements for thread safety, two significant security issues were identified: a race condition in the singleton initialization of CastingApp on Android, and a potential Use-After-Free vulnerability in the JNI layer due to improper management of unique_ptr lifetimes when handling IdentificationDeclarationOptions. Additionally, the changes in CASESessionManager.cpp have introduced some redundant checks in private helper functions. Overall, these changes improve the stability and safety of the casting application, but the identified security vulnerabilities require further attention.

Comment on lines +80 to 97
matter::casting::core::IdentificationDeclarationOptions idOptions;
if (jIdentificationDeclarationOptions != nullptr)
{
ChipLogProgress(AppServer,
"MatterCastingPlayer-JNI::sendUDC() Optional jIdentificationDeclarationOptions not "
"provided by the client");
ChipLogProgress(
AppServer,
"MatterCastingPlayer-JNI::sendUDCNative() Optional jIdentificationDeclarationOptions was provided by client");
std::unique_ptr<matter::casting::core::IdentificationDeclarationOptions> idOptionsCpp(
support::convertIdentificationDeclarationOptionsFromJavaToCpp(jIdentificationDeclarationOptions));
if (idOptionsCpp == nullptr)
{
ChipLogError(AppServer,
"MatterCastingPlayer-JNI::sendUDCNative() "
"convertIdentificationDeclarationOptionsFromJavaToCpp() error");
return support::convertMatterErrorFromCppToJava(CHIP_ERROR_INVALID_ARGUMENT);
}
idOptions = *idOptionsCpp;
idOptions.LogDetail();
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-high high

A potential Use-After-Free (UAF) vulnerability exists here. A unique_ptr named idOptionsCpp is created within the local scope of the if block (lines 81-97). The object it points to is copied to the stack variable idOptions via idOptions = *idOptionsCpp; at line 95. In the Matter SDK, these options structs frequently use non-owning pointers (like chip::CharSpan) to refer to internal data. When idOptionsCpp goes out of scope at line 97, it destroys the original object and its owned data, leaving any spans in the idOptions copy dangling. Subsequent use of idOptions at line 126 results in a Use-After-Free.

This same pattern is repeated in verifyOrEstablishConnectionNative at lines 170-187. To remediate this, extend the lifetime of the unique_ptr to cover the call to the native Matter functions, or avoid the copy by using a pointer that points to either a default object or the object managed by the unique_ptr.

References
  1. When a stack-allocated object is passed by reference to a function that stores the reference, ensure the object's lifetime is static to prevent dangling references and undefined behavior.

Log.e(
TAG,
"CastingApp.initialize() failed to updateCommissionableDataProviderData() on AndroidChipPlatform");
synchronized (mStateLock) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-medium medium

The getInstance() method (lines 55-60) is not thread-safe, which allows multiple instances of the CastingApp singleton to be created if accessed concurrently. While this PR adds synchronization to instance methods like initialize() using an instance-level lock (mStateLock), this synchronization is ineffective if multiple instances of CastingApp exist, as each instance will have its own lock. This can lead to multiple initializations of the global Matter stack and inconsistent application state.

To fix this, implement a thread-safe singleton pattern in getInstance(), such as using a synchronized block or the 'initialization-on-demand holder' idiom.

Comment on lines +227 to +231
if (mConfig.sessionSetupPool == nullptr)
{
ChipLogError(CASESessionManager, "FindExistingSessionSetup called before CASESessionManager is initialized");
return nullptr;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This null check for mConfig.sessionSetupPool is redundant. FindExistingSessionSetup is a private method, and all its callers (FindOrEstablishSessionHelper, UpdatePeerAddress, and ReleaseSession(const ScopedNodeId&) in this file) already perform the same null check before calling it.

To improve maintainability and reduce code duplication, you could remove this check and rely on the checks in the calling functions.

A similar pattern of redundant checks has been introduced for FindExistingSession and its caller GetPeerAddress.

References
  1. To improve maintainability and reduce code duplication, extract common logic from similar methods into private helper functions.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Feb 11, 2026

PR #43082: Size comparison from feb7cc3 to 36061fd

Full report (12 builds for cc13x4_26x4, cc32xx, nrfconnect, qpg, realtek, stm32)
platform target config section feb7cc3 36061fd change % change
cc13x4_26x4 lighting-app LP_EM_CC1354P10_6 FLASH 772448 772824 376 0.0
RAM 103200 103200 0 0.0
lock-ftd LP_EM_CC1354P10_6 FLASH 785256 785632 376 0.0
RAM 108480 108480 0 0.0
pump-app LP_EM_CC1354P10_6 FLASH 730344 730812 468 0.1
RAM 97236 97236 0 0.0
pump-controller-app LP_EM_CC1354P10_6 FLASH 714856 715324 468 0.1
RAM 97436 97436 0 0.0
cc32xx air-purifier CC3235SF_LAUNCHXL FLASH 555776 556192 416 0.1
RAM 204432 204432 0 0.0
lock CC3235SF_LAUNCHXL FLASH 589964 590380 416 0.1
RAM 204720 204720 0 0.0
nrfconnect all-clusters-app nrf52840dk_nrf52840 FLASH 938644 939116 472 0.1
RAM 161925 161925 0 0.0
qpg lighting-app qpg6200+debug FLASH 839580 839972 392 0.0
RAM 127740 127740 0 0.0
lock-app qpg6200+debug FLASH 778240 778632 392 0.1
RAM 118688 118688 0 0.0
realtek light-switch-app rtl8777g FLASH 703448 703952 504 0.1
RAM 113356 113356 0 0.0
lighting-app rtl8777g FLASH 745344 745760 416 0.1
RAM 114564 114564 0 0.0
stm32 light STM32WB5MM-DK FLASH 472220 472612 392 0.1
RAM 141208 141208 0 0.0

@chrisdecenzo chrisdecenzo changed the title Synchronize access to CastingApp/CastingPlayer to avoid race conditions IN-DEV: Synchronize access to CastingApp/CastingPlayer to avoid race conditions Feb 19, 2026
@mergify mergify Bot added the conflict label Feb 19, 2026
@mergify mergify Bot added conflict and removed conflict labels Apr 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant