/* * 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 #include 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(); 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(Transport::Type::kLast) + 1; Transport::Type fuzzedTransportType = static_cast(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; }