gecko-dev/netwerk/test/fuzz/TestHttpFuzzing.cpp

272 строки
8.6 KiB
C++

#include "mozilla/LoadInfo.h"
#include "mozilla/Preferences.h"
#include "nsCOMPtr.h"
#include "nsNetCID.h"
#include "nsString.h"
#include "nsComponentManagerUtils.h"
#include "nsContentUtils.h"
#include "nsILoadInfo.h"
#include "nsIProxiedProtocolHandler.h"
#include "nsIOService.h"
#include "nsProtocolProxyService.h"
#include "nsScriptSecurityManager.h"
#include "nsServiceManagerUtils.h"
#include "nsNetUtil.h"
#include "NullPrincipal.h"
#include "nsCycleCollector.h"
#include "RequestContextService.h"
#include "nsSandboxFlags.h"
#include "FuzzingInterface.h"
#include "FuzzingStreamListener.h"
#include "FuzzyLayer.h"
namespace mozilla {
namespace net {
// Target spec and optional proxy type to use, set by the respective
// initialization function so we can cover all combinations.
static nsAutoCString httpSpec;
static nsAutoCString proxyType;
static int FuzzingInitNetworkHttp(int* argc, char*** argv) {
Preferences::SetBool("network.dns.native-is-localhost", true);
Preferences::SetBool("fuzzing.necko.enabled", true);
Preferences::SetInt("network.http.speculative-parallel-limit", 0);
Preferences::SetInt("network.http.spdy.default-concurrent", 1);
if (httpSpec.IsEmpty()) {
httpSpec = "http://127.0.0.1/";
}
return 0;
}
static int FuzzingInitNetworkHttp2(int* argc, char*** argv) {
httpSpec = "https://127.0.0.1/";
return FuzzingInitNetworkHttp(argc, argv);
}
static int FuzzingInitNetworkHttpProxyHttp2(int* argc, char*** argv) {
// This is http over an https proxy
proxyType = "https";
return FuzzingInitNetworkHttp(argc, argv);
}
static int FuzzingInitNetworkHttp2ProxyHttp2(int* argc, char*** argv) {
// This is https over an https proxy
proxyType = "https";
return FuzzingInitNetworkHttp2(argc, argv);
}
static int FuzzingInitNetworkHttpProxyPlain(int* argc, char*** argv) {
// This is http over an http proxy
proxyType = "http";
return FuzzingInitNetworkHttp(argc, argv);
}
static int FuzzingInitNetworkHttp2ProxyPlain(int* argc, char*** argv) {
// This is https over an http proxy
proxyType = "http";
return FuzzingInitNetworkHttp2(argc, argv);
}
static int FuzzingRunNetworkHttp(const uint8_t* data, size_t size) {
// Set the data to be processed
addNetworkFuzzingBuffer(data, size);
nsWeakPtr channelRef;
nsCOMPtr<nsIRequestContextService> rcsvc =
mozilla::net::RequestContextService::GetOrCreate();
uint64_t rcID;
{
nsCOMPtr<nsIURI> url;
nsresult rv;
if (NS_NewURI(getter_AddRefs(url), httpSpec) != NS_OK) {
MOZ_CRASH("Call to NS_NewURI failed.");
}
nsLoadFlags loadFlags;
loadFlags = nsIRequest::LOAD_BACKGROUND | nsIRequest::LOAD_BYPASS_CACHE |
nsIRequest::INHIBIT_CACHING |
nsIRequest::LOAD_FRESH_CONNECTION |
nsIChannel::LOAD_INITIAL_DOCUMENT_URI;
nsSecurityFlags secFlags;
secFlags = nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL;
uint32_t sandboxFlags = SANDBOXED_ORIGIN;
nsCOMPtr<nsIChannel> channel;
nsCOMPtr<nsILoadInfo> loadInfo;
if (!proxyType.IsEmpty()) {
nsAutoCString proxyHost("127.0.0.2");
nsCOMPtr<nsIProtocolProxyService2> ps =
do_GetService(NS_PROTOCOLPROXYSERVICE_CID);
if (!ps) {
MOZ_CRASH("Failed to create nsIProtocolProxyService2");
}
mozilla::net::nsProtocolProxyService* pps =
static_cast<mozilla::net::nsProtocolProxyService*>(ps.get());
nsCOMPtr<nsIProxyInfo> proxyInfo;
rv = pps->NewProxyInfo(proxyType, proxyHost, 443,
EmptyCString(), // aProxyAuthorizationHeader
EmptyCString(), // aConnectionIsolationKey
0, // aFlags
UINT32_MAX, // aFailoverTimeout
nullptr, // aFailoverProxy
getter_AddRefs(proxyInfo));
if (NS_FAILED(rv)) {
MOZ_CRASH("Call to NewProxyInfo failed.");
}
nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
if (NS_FAILED(rv)) {
MOZ_CRASH("do_GetIOService failed.");
}
nsCOMPtr<nsIProtocolHandler> handler;
rv = ioService->GetProtocolHandler("http", getter_AddRefs(handler));
if (NS_FAILED(rv)) {
MOZ_CRASH("GetProtocolHandler failed.");
}
nsCOMPtr<nsIProxiedProtocolHandler> pph = do_QueryInterface(handler, &rv);
if (NS_FAILED(rv)) {
MOZ_CRASH("do_QueryInterface failed.");
}
loadInfo = new LoadInfo(
nsContentUtils::GetSystemPrincipal(), // loading principal
nsContentUtils::GetSystemPrincipal(), // triggering principal
nullptr, // Context
secFlags, nsIContentPolicy::TYPE_INTERNAL_XMLHTTPREQUEST,
Maybe<mozilla::dom::ClientInfo>(),
Maybe<mozilla::dom::ServiceWorkerDescriptor>(), sandboxFlags);
rv = pph->NewProxiedChannel(url, proxyInfo,
0, // aProxyResolveFlags
nullptr, // aProxyURI
loadInfo, getter_AddRefs(channel));
if (NS_FAILED(rv)) {
MOZ_CRASH("Call to newProxiedChannel failed.");
}
} else {
rv = NS_NewChannel(getter_AddRefs(channel), url,
nsContentUtils::GetSystemPrincipal(), secFlags,
nsIContentPolicy::TYPE_INTERNAL_XMLHTTPREQUEST,
nullptr, // aCookieJarSettings
nullptr, // aPerformanceStorage
nullptr, // loadGroup
nullptr, // aCallbacks
loadFlags, // aLoadFlags
nullptr, // aIoService
sandboxFlags);
if (NS_FAILED(rv)) {
MOZ_CRASH("Call to NS_NewChannel failed.");
}
loadInfo = channel->LoadInfo();
}
if (NS_FAILED(loadInfo->SetSkipContentSniffing(true))) {
MOZ_CRASH("Failed to call SetSkipContentSniffing");
}
RefPtr<FuzzingStreamListener> gStreamListener;
nsCOMPtr<nsIHttpChannel> gHttpChannel;
gHttpChannel = do_QueryInterface(channel);
rv = gHttpChannel->SetRequestMethod(NS_LITERAL_CSTRING("GET"));
if (NS_FAILED(rv)) {
MOZ_CRASH("SetRequestMethod on gHttpChannel failed.");
}
nsCOMPtr<nsIRequestContext> rc;
rv = rcsvc->NewRequestContext(getter_AddRefs(rc));
if (NS_FAILED(rv)) {
MOZ_CRASH("NewRequestContext failed.");
}
rcID = rc->GetID();
rv = gHttpChannel->SetRequestContextID(rcID);
if (NS_FAILED(rv)) {
MOZ_CRASH("SetRequestContextID on gHttpChannel failed.");
}
if (!proxyType.IsEmpty()) {
// NewProxiedChannel doesn't allow us to pass loadFlags directly
rv = gHttpChannel->SetLoadFlags(loadFlags);
if (rv != NS_OK) {
MOZ_CRASH("SetRequestMethod on gHttpChannel failed.");
}
}
gStreamListener = new FuzzingStreamListener();
gHttpChannel->AsyncOpen(gStreamListener);
// Wait for StopRequest
gStreamListener->waitUntilDone();
bool mainPingBack = false;
NS_DispatchBackgroundTask(NS_NewRunnableFunction("Dummy", [&]() {
NS_DispatchToMainThread(
NS_NewRunnableFunction("Dummy", [&]() { mainPingBack = true; }));
}));
SpinEventLoopUntil([&]() -> bool { return mainPingBack; });
channelRef = do_GetWeakReference(gHttpChannel);
}
// Wait for the channel to be destroyed
SpinEventLoopUntil([&]() -> bool {
nsCycleCollector_collect(nullptr);
nsCOMPtr<nsIHttpChannel> channel = do_QueryReferent(channelRef);
return channel == nullptr;
});
if (!signalNetworkFuzzingDone()) {
// Wait for the connection to indicate closed
SpinEventLoopUntil([&]() -> bool { return gFuzzingConnClosed; });
}
rcsvc->RemoveRequestContext(rcID);
return 0;
}
MOZ_FUZZING_INTERFACE_RAW(FuzzingInitNetworkHttp, FuzzingRunNetworkHttp,
NetworkHttp);
MOZ_FUZZING_INTERFACE_RAW(FuzzingInitNetworkHttp2, FuzzingRunNetworkHttp,
NetworkHttp2);
MOZ_FUZZING_INTERFACE_RAW(FuzzingInitNetworkHttp2ProxyHttp2,
FuzzingRunNetworkHttp, NetworkHttp2ProxyHttp2);
MOZ_FUZZING_INTERFACE_RAW(FuzzingInitNetworkHttpProxyHttp2,
FuzzingRunNetworkHttp, NetworkHttpProxyHttp2);
MOZ_FUZZING_INTERFACE_RAW(FuzzingInitNetworkHttpProxyPlain,
FuzzingRunNetworkHttp, NetworkHttpProxyPlain);
MOZ_FUZZING_INTERFACE_RAW(FuzzingInitNetworkHttp2ProxyPlain,
FuzzingRunNetworkHttp, NetworkHttp2ProxyPlain);
} // namespace net
} // namespace mozilla