blob: 78b7bfd53887349270f0640f5ded986f515f95a0 [file]
/*
*
* Copyright (c) 2026 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// FuzzTest harness for the WiFiPAFTP transport-protocol engine, seeded with real PAFTP fragment
// shapes so the mutator starts past the header-validation gate.
#include <cstdint>
#include <utility>
#include <vector>
#include <pw_fuzzer/fuzztest.h>
#include <pw_unit_test/framework.h>
#include <lib/support/CHIPMem.h>
#include <lib/support/CodeUtils.h>
#include <system/SystemPacketBuffer.h>
#include <wifipaf/WiFiPAFTP.h>
namespace {
using chip::System::PacketBufferHandle;
using chip::WiFiPAF::SequenceNumber_t;
using chip::WiFiPAF::WiFiPAFTP;
using namespace fuzztest;
void EnsureInitialized()
{
static const bool sInitialized = [] {
VerifyOrDie(chip::Platform::MemoryInit() == CHIP_NO_ERROR);
return true;
}();
(void) sInitialized;
}
// Real PAFTP fragment shapes (capability + data-phase variants).
std::vector<std::vector<uint8_t>> PaftpFragmentSeeds()
{
return {
{ 0x65, 0x6c, 0x04, 0x00, 0x00, 0x00, 0x5e, 0x01, 0x06 }, // capability request
{ 0x65, 0x6c, 0x04, 0x5b, 0x01, 0x06 }, // capability response
{ 0x05, 0x01, 0x01, 0x00, 0x00, 0xAA }, // start+end, seq 1
{ 0x01, 0x00, 0x01, 0x00, 0x00, 0xDE, 0xAD }, // start only
{ 0x02, 0x02, 0xBE, 0xEF }, // continue
{ 0x04, 0x03, 0xCA, 0xFE }, // end
{ 0x08, 0x02 }, // ack-only
{ 0x05, 0x01, 0x05, 0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF }, // out-of-order seq 5
};
}
void WiFiPAFTPDoesNotCrash(bool expectFirstAck, const std::vector<uint8_t> & frag0, const std::vector<uint8_t> & frag1,
const std::vector<uint8_t> & frag2, const std::vector<uint8_t> & frag3)
{
EnsureInitialized();
WiFiPAFTP engine;
if (engine.Init(nullptr, expectFirstAck) != CHIP_NO_ERROR)
{
return;
}
for (const auto * frag : { &frag0, &frag1, &frag2, &frag3 })
{
auto buf = PacketBufferHandle::NewWithData(frag->data(), frag->size());
if (buf.IsNull())
{
continue;
}
SequenceNumber_t receivedAck = 0;
bool didReceiveAck = false;
// Fuzzer asserts only the no-crash property; the parse status is irrelevant here.
RETURN_SAFELY_IGNORED engine.HandleCharacteristicReceived(std::move(buf), receivedAck, didReceiveAck);
if (engine.RxState() == WiFiPAFTP::kState_Error)
{
break;
}
}
}
FUZZ_TEST(FuzzWiFiPAFTPPW, WiFiPAFTPDoesNotCrash)
.WithDomains(Arbitrary<bool>(), Arbitrary<std::vector<uint8_t>>().WithSeeds(PaftpFragmentSeeds()),
Arbitrary<std::vector<uint8_t>>().WithSeeds(PaftpFragmentSeeds()),
Arbitrary<std::vector<uint8_t>>().WithSeeds(PaftpFragmentSeeds()),
Arbitrary<std::vector<uint8_t>>().WithSeeds(PaftpFragmentSeeds()));
} // namespace