blob: 5056f08cce65f438f7dbeacf80bf330ec9b4db98 [file] [log] [blame] [edit]
/*
* 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/codegen-data-model-provider/Instance.h>
#include <app/server/Server.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();
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;
}