| /* | 
 |  *    Copyright (c) 2022 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. | 
 |  */ | 
 |  | 
 | #include "AppMain.h" | 
 | #include <app/server/Server.h> | 
 | #include <data-model-providers/codegen/Instance.h> | 
 |  | 
 | #include <CommissionableInit.h> | 
 |  | 
 | using namespace chip; | 
 | using namespace chip::DeviceLayer; | 
 |  | 
 | namespace { | 
 |  | 
 | LinuxCommissionableDataProvider gCommissionableDataProvider; | 
 |  | 
 | } | 
 |  | 
 | void CleanShutdown() | 
 | { | 
 |     ApplicationShutdown(); | 
 |     Server::GetInstance().Shutdown(); | 
 |     PlatformMgr().Shutdown(); | 
 |     // TODO: We don't Platform::MemoryShutdown because ~CASESessionManager calls | 
 |     // Dnssd::ResolverProxy::Shutdown, which starts doing Platform::Delete. | 
 |     // Platform::MemoryShutdown(); | 
 | } | 
 |  | 
 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t * aData, size_t aSize) | 
 | { | 
 |     static bool matterStackInitialized = false; | 
 |     if (!matterStackInitialized) | 
 |     { | 
 |         // Might be simpler to do ChipLinuxAppInit() with argc == 0, argv set to | 
 |         // just a fake executable name? | 
 |         VerifyOrDie(Platform::MemoryInit() == CHIP_NO_ERROR); | 
 |         VerifyOrDie(PlatformMgr().InitChipStack() == CHIP_NO_ERROR); | 
 |  | 
 |         VerifyOrDie(chip::examples::InitCommissionableDataProvider(gCommissionableDataProvider, | 
 |                                                                    LinuxDeviceOptions::GetInstance()) == CHIP_NO_ERROR); | 
 |         SetCommissionableDataProvider(&gCommissionableDataProvider); | 
 |  | 
 |         // ChipLinuxAppMainLoop blocks, and we don't want that here. | 
 |         static chip::CommonCaseDeviceServerInitParams initParams; | 
 |         (void) initParams.InitializeStaticResourcesBeforeServerInit(); | 
 |         initParams.dataModelProvider = app::CodegenDataModelProviderInstance(initParams.persistentStorageDelegate); | 
 |         VerifyOrDie(Server::GetInstance().Init(initParams) == CHIP_NO_ERROR); | 
 |  | 
 |         ApplicationInit(); | 
 |  | 
 |         // We don't start the event loop task, because we don't plan to deliver | 
 |         // data on a separate thread. | 
 |  | 
 |         matterStackInitialized = true; | 
 |  | 
 |         // The fuzzer does not have a way to tell us when it's done, so just | 
 |         // shut down things on exit. | 
 |         atexit(CleanShutdown); | 
 |     } | 
 |  | 
 |     // For now, just dump the data as a UDP payload into the session manager. | 
 |     // But maybe we should try to separately extract a PeerAddress and data from | 
 |     // the incoming data? | 
 |  | 
 |     // To avoid out-of-bounds access when acessing aData[1] | 
 |     if (aSize < 2) | 
 |     { | 
 |         return 0; | 
 |     } | 
 |  | 
 |     // dumping payload with fuzzed transport types | 
 |     constexpr uint8_t numberOfTypes     = static_cast<int>(Transport::Type::kLast) + 1; | 
 |     Transport::Type fuzzedTransportType = static_cast<Transport::Type>(aData[0] % numberOfTypes); | 
 |     Transport::PeerAddress peerAddr(fuzzedTransportType); | 
 |  | 
 |     System::PacketBufferHandle buf = | 
 |         System::PacketBufferHandle::NewWithData(&aData[1], aSize - 1, /* aAdditionalSize = */ 0, /* aReservedSize = */ 0); | 
 |     if (buf.IsNull()) | 
 |     { | 
 |         // Too big; we couldn't represent this as a packetbuffer to start with. | 
 |         return 0; | 
 |     } | 
 |  | 
 |     // Ignoring the return value from OnMessageReceived, because we might be | 
 |     // passing it all sorts of garbage that will cause it to fail. | 
 |  | 
 |     // for TCP we need to have MessageTransportContext | 
 |     if (fuzzedTransportType == Transport::Type::kTcp) | 
 |     { | 
 |         Transport::MessageTransportContext msgContext; | 
 |         Server::GetInstance().GetSecureSessionManager().OnMessageReceived(peerAddr, std::move(buf), &msgContext); | 
 |     } | 
 |     else | 
 |     { | 
 |         Server::GetInstance().GetSecureSessionManager().OnMessageReceived(peerAddr, std::move(buf)); | 
 |     } | 
 |     // Now process pending events until our sentinel is reached. | 
 |     PlatformMgr().ScheduleWork([](intptr_t) { PlatformMgr().StopEventLoopTask(); }); | 
 |     PlatformMgr().RunEventLoop(); | 
 |     return 0; | 
 | } |