diff options
Diffstat (limited to '')
-rw-r--r-- | netwerk/test/fuzz/TestHttpFuzzing.cpp | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/netwerk/test/fuzz/TestHttpFuzzing.cpp b/netwerk/test/fuzz/TestHttpFuzzing.cpp new file mode 100644 index 0000000000..e717b608e7 --- /dev/null +++ b/netwerk/test/fuzz/TestHttpFuzzing.cpp @@ -0,0 +1,297 @@ +#include "mozilla/LoadInfo.h" +#include "mozilla/Preferences.h" +#include "mozilla/SpinEventLoopUntil.h" + +#include "nsCOMPtr.h" +#include "nsNetCID.h" +#include "nsString.h" +#include "nsComponentManagerUtils.h" +#include "nsContentUtils.h" +#include "nsIChannel.h" +#include "nsIHttpChannel.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 size_t minSize; + +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.http2.default-concurrent", 1); + + if (httpSpec.IsEmpty()) { + httpSpec = "http://127.0.0.1/"; + } + + net_EnsurePSMInit(); + + return 0; +} + +static int FuzzingInitNetworkHttp2(int* argc, char*** argv) { + httpSpec = "https://127.0.0.1/"; + return FuzzingInitNetworkHttp(argc, argv); +} + +static int FuzzingInitNetworkHttp3(int* argc, char*** argv) { + Preferences::SetBool("fuzzing.necko.http3", true); + Preferences::SetBool("network.http.http3.enable", true); + Preferences::SetCString("network.http.http3.alt-svc-mapping-for-testing", + "fuzz.bad.tld;h3=:443"); + httpSpec = "https://fuzz.bad.tld/"; + minSize = 1200; + 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) { + if (size < minSize) { + return 0; + } + + // 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_SEC_CONTEXT_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, + ""_ns, // aProxyAuthorizationHeader + ""_ns, // 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("GET"_ns); + 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("FuzzingRunNetworkHttp(mainPingBack)"_ns, + [&]() -> bool { return mainPingBack; }); + + channelRef = do_GetWeakReference(gHttpChannel); + } + + // Wait for the channel to be destroyed + SpinEventLoopUntil( + "FuzzingRunNetworkHttp(channel == nullptr)"_ns, [&]() -> bool { + nsCycleCollector_collect(CCReason::API, nullptr); + nsCOMPtr<nsIHttpChannel> channel = do_QueryReferent(channelRef); + return channel == nullptr; + }); + + if (!signalNetworkFuzzingDone()) { + // Wait for the connection to indicate closed + SpinEventLoopUntil("FuzzingRunNetworkHttp(gFuzzingConnClosed)"_ns, + [&]() -> 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(FuzzingInitNetworkHttp3, FuzzingRunNetworkHttp, + NetworkHttp3); + +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 |