From d27ba35548f6c18f55c37d6393ade53dd18d0b20 Mon Sep 17 00:00:00 2001 From: Alami-Amine Date: Fri, 26 Jun 2026 14:23:32 +0200 Subject: [PATCH 1/2] [fuzz] Guard PASE fuzz harness against uninitialized verifier on Generate() failure FuzzPASE_PW.cpp's Pake1/Pake2/Pake3 harnesses ignored mPASEVerifier.Generate()'s result and then read the verifier via BeginVerifier()/HandleMsg*(). Generate() can fail because the fuzz domains intentionally include out-of-range PBKDF iteration counts and salt lengths; on failure mPASEVerifier stays uninitialized and is read downstream (an MSan use-of-uninitialized-value flagged by the OSS-Fuzz memory build). Guard each site with VerifyOrReturn; production always checks Generate(), so this is a test-harness gap, not a product bug. --- .../secure_channel/tests/FuzzPASE_PW.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/protocols/secure_channel/tests/FuzzPASE_PW.cpp b/src/protocols/secure_channel/tests/FuzzPASE_PW.cpp index f73b408342797b..ff5c43460f0018 100644 --- a/src/protocols/secure_channel/tests/FuzzPASE_PW.cpp +++ b/src/protocols/secure_channel/tests/FuzzPASE_PW.cpp @@ -648,7 +648,10 @@ void TestPASESession::FuzzHandlePake1(const uint32_t fuzzedSetupPasscode, const // Compute mPASEVerifier (in order for mSpake2p.BeginVerifier() to use it, once it is called by the pairingAccessory through // HandleMsg1_and_SendMsg2) - RETURN_SAFELY_IGNORED pairingAccessory.mPASEVerifier.Generate(fuzzedPBKDF2Iter, fuzzedSaltSpan, fuzzedSetupPasscode); + // If Generate() fails (the fuzz domains intentionally include out-of-range iter/salt), + // mPASEVerifier stays uninitialized; reading it below (BeginVerifier / HandleMsg*) would be an + // MSan false positive that cannot occur in production, which checks Generate(). Bail instead. + VerifyOrReturn(pairingAccessory.mPASEVerifier.Generate(fuzzedPBKDF2Iter, fuzzedSaltSpan, fuzzedSetupPasscode) == CHIP_NO_ERROR); /************************Injecting Fuzzed Pake1 Message into PaseSession::OnMessageReceived*************************/ @@ -750,7 +753,10 @@ void TestPASESession::FuzzHandlePake2(const uint32_t fuzzedSetupPasscode, const // Below Steps take place in HandleMsg1 // Compute mPASEVerifier to be able to pass it to BeginVerifier() - RETURN_SAFELY_IGNORED pairingAccessory.mPASEVerifier.Generate(fuzzedPBKDF2Iter, fuzzedSaltSpan, fuzzedSetupPasscode); + // If Generate() fails (the fuzz domains intentionally include out-of-range iter/salt), + // mPASEVerifier stays uninitialized; reading it below (BeginVerifier / HandleMsg*) would be an + // MSan false positive that cannot occur in production, which checks Generate(). Bail instead. + VerifyOrReturn(pairingAccessory.mPASEVerifier.Generate(fuzzedPBKDF2Iter, fuzzedSaltSpan, fuzzedSetupPasscode) == CHIP_NO_ERROR); RETURN_SAFELY_IGNORED pairingAccessory.mSpake2p.BeginVerifier(nullptr, 0, nullptr, 0, pairingAccessory.mPASEVerifier.mW0, kP256_FE_Length, pairingAccessory.mPASEVerifier.mL, @@ -880,7 +886,10 @@ void TestPASESession::FuzzHandlePake3(const uint32_t fuzzedSetupPasscode, const // Below Steps take place in HandleMsg1 // compute mPASEVerifier to be able to pass it to BeginVerifier() - RETURN_SAFELY_IGNORED pairingAccessory.mPASEVerifier.Generate(fuzzedPBKDF2Iter, fuzzedSaltSpan, fuzzedSetupPasscode); + // If Generate() fails (the fuzz domains intentionally include out-of-range iter/salt), + // mPASEVerifier stays uninitialized; reading it below (BeginVerifier / HandleMsg*) would be an + // MSan false positive that cannot occur in production, which checks Generate(). Bail instead. + VerifyOrReturn(pairingAccessory.mPASEVerifier.Generate(fuzzedPBKDF2Iter, fuzzedSaltSpan, fuzzedSetupPasscode) == CHIP_NO_ERROR); RETURN_SAFELY_IGNORED pairingAccessory.mSpake2p.BeginVerifier(nullptr, 0, nullptr, 0, pairingAccessory.mPASEVerifier.mW0, kP256_FE_Length, pairingAccessory.mPASEVerifier.mL, From 0e01ae3e0fe82e8e69ff9f5994d26f6ada501b6d Mon Sep 17 00:00:00 2001 From: Alami-Amine Date: Fri, 26 Jun 2026 22:14:10 +0200 Subject: [PATCH 2/2] [fuzz] Use ReturnOnFailure for PASE verifier Generate() checks Address review: ReturnOnFailure takes the CHIP_ERROR directly instead of VerifyOrReturn(... == CHIP_NO_ERROR), at all three Generate() sites. --- src/protocols/secure_channel/tests/FuzzPASE_PW.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/protocols/secure_channel/tests/FuzzPASE_PW.cpp b/src/protocols/secure_channel/tests/FuzzPASE_PW.cpp index ff5c43460f0018..9d3225f603c8fb 100644 --- a/src/protocols/secure_channel/tests/FuzzPASE_PW.cpp +++ b/src/protocols/secure_channel/tests/FuzzPASE_PW.cpp @@ -651,7 +651,7 @@ void TestPASESession::FuzzHandlePake1(const uint32_t fuzzedSetupPasscode, const // If Generate() fails (the fuzz domains intentionally include out-of-range iter/salt), // mPASEVerifier stays uninitialized; reading it below (BeginVerifier / HandleMsg*) would be an // MSan false positive that cannot occur in production, which checks Generate(). Bail instead. - VerifyOrReturn(pairingAccessory.mPASEVerifier.Generate(fuzzedPBKDF2Iter, fuzzedSaltSpan, fuzzedSetupPasscode) == CHIP_NO_ERROR); + ReturnOnFailure(pairingAccessory.mPASEVerifier.Generate(fuzzedPBKDF2Iter, fuzzedSaltSpan, fuzzedSetupPasscode)); /************************Injecting Fuzzed Pake1 Message into PaseSession::OnMessageReceived*************************/ @@ -756,7 +756,7 @@ void TestPASESession::FuzzHandlePake2(const uint32_t fuzzedSetupPasscode, const // If Generate() fails (the fuzz domains intentionally include out-of-range iter/salt), // mPASEVerifier stays uninitialized; reading it below (BeginVerifier / HandleMsg*) would be an // MSan false positive that cannot occur in production, which checks Generate(). Bail instead. - VerifyOrReturn(pairingAccessory.mPASEVerifier.Generate(fuzzedPBKDF2Iter, fuzzedSaltSpan, fuzzedSetupPasscode) == CHIP_NO_ERROR); + ReturnOnFailure(pairingAccessory.mPASEVerifier.Generate(fuzzedPBKDF2Iter, fuzzedSaltSpan, fuzzedSetupPasscode)); RETURN_SAFELY_IGNORED pairingAccessory.mSpake2p.BeginVerifier(nullptr, 0, nullptr, 0, pairingAccessory.mPASEVerifier.mW0, kP256_FE_Length, pairingAccessory.mPASEVerifier.mL, @@ -889,7 +889,7 @@ void TestPASESession::FuzzHandlePake3(const uint32_t fuzzedSetupPasscode, const // If Generate() fails (the fuzz domains intentionally include out-of-range iter/salt), // mPASEVerifier stays uninitialized; reading it below (BeginVerifier / HandleMsg*) would be an // MSan false positive that cannot occur in production, which checks Generate(). Bail instead. - VerifyOrReturn(pairingAccessory.mPASEVerifier.Generate(fuzzedPBKDF2Iter, fuzzedSaltSpan, fuzzedSetupPasscode) == CHIP_NO_ERROR); + ReturnOnFailure(pairingAccessory.mPASEVerifier.Generate(fuzzedPBKDF2Iter, fuzzedSaltSpan, fuzzedSetupPasscode)); RETURN_SAFELY_IGNORED pairingAccessory.mSpake2p.BeginVerifier(nullptr, 0, nullptr, 0, pairingAccessory.mPASEVerifier.mW0, kP256_FE_Length, pairingAccessory.mPASEVerifier.mL,