Bug 1562283 - FTP fuzzing target for the Necko fuzzing layer. r=michal
authorChristian Holler <choller@mozilla.com>
Mon, 07 Oct 2019 10:18:50 +0000
changeset 496540 54fa3474aca1c0674eba17bfeaa4f14536b9b20e
parent 496539 8d95f2c8867b13432cf2e0c51c7765e6592441ea
child 496541 a0d28ade0bb377f5e99b1ac4b3b87edb535c96c2
push id36661
push userccoroiu@mozilla.com
push dateMon, 07 Oct 2019 21:50:01 +0000
treeherdermozilla-central@2b4c8b7a255c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmichal
bugs1562283
milestone71.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1562283 - FTP fuzzing target for the Necko fuzzing layer. r=michal Depends on D47448 Differential Revision: https://phabricator.services.mozilla.com/D47449
netwerk/protocol/ftp/moz.build
netwerk/test/fuzz/FuzzingStreamListener.cpp
netwerk/test/fuzz/FuzzingStreamListener.h
netwerk/test/fuzz/TestFtpFuzzing.cpp
netwerk/test/fuzz/TestHttpFuzzing.cpp
netwerk/test/fuzz/moz.build
--- a/netwerk/protocol/ftp/moz.build
+++ b/netwerk/protocol/ftp/moz.build
@@ -41,8 +41,10 @@ include('/ipc/chromium/chromium-config.m
 FINAL_LIBRARY = 'xul'
 
 LOCAL_INCLUDES += [
     '/netwerk/base',
 ]
 
 if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
     CXXFLAGS += ['-Wno-error=shadow']
+
+include('/tools/fuzzing/libfuzzer-config.mozbuild')
new file mode 100644
--- /dev/null
+++ b/netwerk/test/fuzz/FuzzingStreamListener.cpp
@@ -0,0 +1,45 @@
+#include "FuzzingInterface.h"
+#include "FuzzingStreamListener.h"
+
+namespace mozilla {
+namespace net {
+
+NS_IMPL_ISUPPORTS(FuzzingStreamListener, nsIStreamListener, nsIRequestObserver)
+
+NS_IMETHODIMP
+FuzzingStreamListener::OnStartRequest(nsIRequest* aRequest) {
+  FUZZING_LOG(("FuzzingStreamListener::OnStartRequest"));
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+FuzzingStreamListener::OnDataAvailable(nsIRequest* aRequest,
+                                       nsIInputStream* aInputStream,
+                                       uint64_t aOffset, uint32_t aCount) {
+  FUZZING_LOG(("FuzzingStreamListener::OnDataAvailable"));
+  static uint32_t const kCopyChunkSize = 128 * 1024;
+  uint32_t toRead = std::min<uint32_t>(aCount, kCopyChunkSize);
+  nsCString data;
+
+  while (aCount) {
+    nsresult rv = NS_ReadInputStreamToString(aInputStream, data, toRead);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    aOffset += toRead;
+    aCount -= toRead;
+    toRead = std::min<uint32_t>(aCount, kCopyChunkSize);
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+FuzzingStreamListener::OnStopRequest(nsIRequest* aRequest,
+                                     nsresult aStatusCode) {
+  FUZZING_LOG(("FuzzingStreamListener::OnStopRequest"));
+  mChannelDone = true;
+  return NS_OK;
+}
+
+}  // namespace net
+}  // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/netwerk/test/fuzz/FuzzingStreamListener.h
@@ -0,0 +1,38 @@
+#ifndef FuzzingStreamListener_h__
+#define FuzzingStreamListener_h__
+
+#include "nsCOMPtr.h"
+#include "nsNetCID.h"
+#include "nsString.h"
+#include "nsNetUtil.h"
+#include "nsIStreamListener.h"
+#include "nsThreadUtils.h"
+
+namespace mozilla {
+namespace net {
+
+class FuzzingStreamListener final : public nsIStreamListener {
+ public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIREQUESTOBSERVER
+  NS_DECL_NSISTREAMLISTENER
+
+  FuzzingStreamListener() = default;
+
+  void waitUntilDone() {
+    SpinEventLoopUntil([&]() { return mChannelDone; });
+  }
+
+  bool isDone() {
+    return mChannelDone;
+  }
+
+ private:
+  ~FuzzingStreamListener() = default;
+  bool mChannelDone = false;
+};
+
+}  // namespace net
+}  // namespace mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/netwerk/test/fuzz/TestFtpFuzzing.cpp
@@ -0,0 +1,127 @@
+#include "mozilla/Preferences.h"
+
+#include "nsCOMPtr.h"
+#include "nsNetCID.h"
+#include "nsString.h"
+#include "nsComponentManagerUtils.h"
+#include "nsContentUtils.h"
+#include "nsIPrincipal.h"
+#include "nsScriptSecurityManager.h"
+#include "nsServiceManagerUtils.h"
+#include "nsNetUtil.h"
+#include "NullPrincipal.h"
+#include "nsCycleCollector.h"
+
+#include "nsFtpProtocolHandler.h"
+#include "nsIFTPChannel.h"
+
+#include "FuzzingInterface.h"
+#include "FuzzingStreamListener.h"
+#include "FuzzyLayer.h"
+
+namespace mozilla {
+namespace net {
+
+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);
+  return 0;
+}
+
+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<nsIURI> url;
+    nsAutoCString spec;
+    nsresult rv;
+
+    spec = "ftp://127.0.0.1/";
+    if (NS_NewURI(getter_AddRefs(url), spec) != 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 |
+               nsILoadInfo::SEC_SANDBOXED;
+    nsCOMPtr<nsIChannel> channel;
+    rv = NS_NewChannel(getter_AddRefs(channel), url,
+                       nsContentUtils::GetSystemPrincipal(), secFlags,
+                       nsIContentPolicy::TYPE_INTERNAL_XMLHTTPREQUEST,
+                       nullptr,    // aCookieSettings
+                       nullptr,    // aPerformanceStorage
+                       nullptr,    // loadGroup
+                       nullptr,    // aCallbacks
+                       loadFlags,  // aLoadFlags
+                       nullptr     // aIoService
+    );
+
+    if (rv != NS_OK) {
+      MOZ_CRASH("Call to NS_NewChannel failed.");
+    }
+
+    RefPtr<FuzzingStreamListener> 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<nsIChannel> 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);
+
+}  // namespace net
+}  // namespace mozilla
--- a/netwerk/test/fuzz/TestHttpFuzzing.cpp
+++ b/netwerk/test/fuzz/TestHttpFuzzing.cpp
@@ -14,80 +14,27 @@
 #include "nsScriptSecurityManager.h"
 #include "nsServiceManagerUtils.h"
 #include "nsNetUtil.h"
 #include "NullPrincipal.h"
 #include "nsCycleCollector.h"
 #include "RequestContextService.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.
 nsAutoCString spec;
 nsAutoCString proxyType;
 
-class FuzzingStreamListener final : public nsIStreamListener {
- public:
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIREQUESTOBSERVER
-  NS_DECL_NSISTREAMLISTENER
-
-  FuzzingStreamListener() = default;
-
-  void waitUntilDone() {
-    SpinEventLoopUntil([&]() { return mChannelDone; });
-  }
-
- private:
-  ~FuzzingStreamListener() = default;
-  bool mChannelDone = false;
-};
-
-NS_IMPL_ISUPPORTS(FuzzingStreamListener, nsIStreamListener, nsIRequestObserver)
-
-NS_IMETHODIMP
-FuzzingStreamListener::OnStartRequest(nsIRequest* aRequest) {
-  FUZZING_LOG(("FuzzingStreamListener::OnStartRequest"));
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-FuzzingStreamListener::OnDataAvailable(nsIRequest* aRequest,
-                                       nsIInputStream* aInputStream,
-                                       uint64_t aOffset, uint32_t aCount) {
-  FUZZING_LOG(("FuzzingStreamListener::OnDataAvailable"));
-  static uint32_t const kCopyChunkSize = 128 * 1024;
-  uint32_t toRead = std::min<uint32_t>(aCount, kCopyChunkSize);
-  nsCString data;
-
-  while (aCount) {
-    nsresult rv = NS_ReadInputStreamToString(aInputStream, data, toRead);
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-    aOffset += toRead;
-    aCount -= toRead;
-    toRead = std::min<uint32_t>(aCount, kCopyChunkSize);
-  }
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-FuzzingStreamListener::OnStopRequest(nsIRequest* aRequest,
-                                     nsresult aStatusCode) {
-  FUZZING_LOG(("FuzzingStreamListener::OnStopRequest"));
-  mChannelDone = true;
-  return NS_OK;
-}
-
 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 (spec.IsEmpty()) {
     spec = "http://127.0.0.1/";
--- a/netwerk/test/fuzz/moz.build
+++ b/netwerk/test/fuzz/moz.build
@@ -1,22 +1,25 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 UNIFIED_SOURCES += [
+    'FuzzingStreamListener.cpp',
+    'TestFtpFuzzing.cpp',
     'TestHttpFuzzing.cpp',
     'TestWebsocketFuzzing.cpp',
 ]
 
 LOCAL_INCLUDES += [
     '/caps',
     '/netwerk/base',
+    '/netwerk/protocol/ftp',
     '/netwerk/protocol/http',
     '/xpcom/tests/gtest',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul-gtest'