#include "mozilla/Preferences.h" #include "mozilla/SpinEventLoopUntil.h" #include "nsCOMPtr.h" #include "nsNetCID.h" #include "nsString.h" #include "nsComponentManagerUtils.h" #include "nsContentUtils.h" #include "nsScriptSecurityManager.h" #include "nsServiceManagerUtils.h" #include "nsNetUtil.h" #include "NullPrincipal.h" #include "nsCycleCollector.h" #include "nsIChannel.h" #include "nsSandboxFlags.h" #include "nsFtpProtocolHandler.h" #include "FuzzingInterface.h" #include "FuzzingStreamListener.h" #include "FuzzyLayer.h" namespace mozilla { namespace net { static nsAutoCString ftpSpec; static int FuzzingInitNetworkFtp(int* argc, char*** argv) { Preferences::SetBool("network.dns.native-is-localhost", true); Preferences::SetBool("fuzzing.necko.enabled", true); Preferences::SetBool("network.connectivity-service.enabled", false); if (ftpSpec.IsEmpty()) { ftpSpec = "ftp://127.0.0.1/"; } return 0; } static int FuzzingInitNetworkFtpDownload(int* argc, char*** argv) { ftpSpec = "ftp://127.0.0.1/test.txt"; return FuzzingInitNetworkFtp(argc, argv); } static int FuzzingRunNetworkFtp(const uint8_t* data, size_t size) { // Set the data to be processed if (size > 1024) { // If we have more than 1024 bytes, we use the excess for // an optional data connection. addNetworkFuzzingBuffer(data, 1024, true); addNetworkFuzzingBuffer(data + 1024, size - 1024, true, true); } else { addNetworkFuzzingBuffer(data, size, true); } nsWeakPtr channelRef; { nsCOMPtr url; nsAutoCString spec; nsresult rv; if (NS_NewURI(getter_AddRefs(url), ftpSpec) != 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 channel; 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 (rv != NS_OK) { MOZ_CRASH("Call to NS_NewChannel failed."); } RefPtr gStreamListener; gStreamListener = new FuzzingStreamListener(); rv = channel->AsyncOpen(gStreamListener); if (NS_FAILED(rv)) { MOZ_CRASH("asyncOpen failed"); } FUZZING_LOG(("Spinning for StopRequest")); // Wait for StopRequest gStreamListener->waitUntilDone(); // The FTP code can cache control connections which would cause // a strong reference to be held to our channel. After performing // all requests here, we need to prune all cached connections to // let the channel die. In the future we can test the caching further // with multiple requests using a cached control connection. gFtpHandler->Observe(nullptr, "net:clear-active-logins", nullptr); channelRef = do_GetWeakReference(channel); } FUZZING_LOG(("Spinning for channel == nullptr")); // Wait for the channel to be destroyed SpinEventLoopUntil([&]() -> bool { nsCycleCollector_collect(nullptr); nsCOMPtr channel = do_QueryReferent(channelRef); return channel == nullptr; }); if (!signalNetworkFuzzingDone()) { // Wait for the connection to indicate closed FUZZING_LOG(("Spinning for gFuzzingConnClosed")); SpinEventLoopUntil([&]() -> bool { return gFuzzingConnClosed; }); } FUZZING_LOG(("End of iteration")); return 0; } MOZ_FUZZING_INTERFACE_RAW(FuzzingInitNetworkFtp, FuzzingRunNetworkFtp, NetworkFtp); MOZ_FUZZING_INTERFACE_RAW(FuzzingInitNetworkFtpDownload, FuzzingRunNetworkFtp, NetworkFtpDownload); } // namespace net } // namespace mozilla