tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

TestWebsocketFuzzing.cpp (6991B)


      1 #include "mozilla/Preferences.h"
      2 
      3 #include "FuzzingInterface.h"
      4 #include "FuzzyLayer.h"
      5 #include "mozilla/SpinEventLoopUntil.h"
      6 #include "nsComponentManagerUtils.h"
      7 #include "nsCOMPtr.h"
      8 #include "nsContentUtils.h"
      9 #include "nsCycleCollector.h"
     10 #include "nsIPrincipal.h"
     11 #include "nsIWebSocketChannel.h"
     12 #include "nsIWebSocketListener.h"
     13 #include "nsNetCID.h"
     14 #include "nsNetUtil.h"
     15 #include "nsString.h"
     16 #include "nsScriptSecurityManager.h"
     17 #include "nsServiceManagerUtils.h"
     18 #include "NullPrincipal.h"
     19 #include "nsSandboxFlags.h"
     20 
     21 namespace mozilla {
     22 namespace net {
     23 
     24 // Used to determine if the fuzzing target should use https:// in spec.
     25 static bool fuzzWSS = true;
     26 
     27 class FuzzingWebSocketListener final : public nsIWebSocketListener {
     28 public:
     29  NS_DECL_ISUPPORTS
     30  NS_DECL_NSIWEBSOCKETLISTENER
     31 
     32  FuzzingWebSocketListener() = default;
     33 
     34  void waitUntilDoneOrStarted() {
     35    SpinEventLoopUntil("FuzzingWebSocketListener::waitUntilDoneOrStarted"_ns,
     36                       [&]() { return mChannelDone || mChannelStarted; });
     37  }
     38 
     39  void waitUntilDone() {
     40    SpinEventLoopUntil("FuzzingWebSocketListener::waitUntilDone"_ns,
     41                       [&]() { return mChannelDone; });
     42  }
     43 
     44  void waitUntilDoneOrAck() {
     45    SpinEventLoopUntil("FuzzingWebSocketListener::waitUntilDoneOrAck"_ns,
     46                       [&]() { return mChannelDone || mChannelAck; });
     47  }
     48 
     49  bool isStarted() { return mChannelStarted; }
     50 
     51 private:
     52  ~FuzzingWebSocketListener() = default;
     53  bool mChannelDone = false;
     54  bool mChannelStarted = false;
     55  bool mChannelAck = false;
     56 };
     57 
     58 NS_IMPL_ISUPPORTS(FuzzingWebSocketListener, nsIWebSocketListener)
     59 
     60 NS_IMETHODIMP
     61 FuzzingWebSocketListener::OnStart(nsISupports* aContext) {
     62  FUZZING_LOG(("FuzzingWebSocketListener::OnStart"));
     63  mChannelStarted = true;
     64  return NS_OK;
     65 }
     66 
     67 NS_IMETHODIMP
     68 FuzzingWebSocketListener::OnStop(nsISupports* aContext, nsresult aStatusCode) {
     69  FUZZING_LOG(("FuzzingWebSocketListener::OnStop"));
     70  mChannelDone = true;
     71  return NS_OK;
     72 }
     73 
     74 NS_IMETHODIMP
     75 FuzzingWebSocketListener::OnAcknowledge(nsISupports* aContext, uint32_t aSize) {
     76  FUZZING_LOG(("FuzzingWebSocketListener::OnAcknowledge"));
     77  mChannelAck = true;
     78  return NS_OK;
     79 }
     80 
     81 NS_IMETHODIMP
     82 FuzzingWebSocketListener::OnServerClose(nsISupports* aContext, uint16_t aCode,
     83                                        const nsACString& aReason) {
     84  FUZZING_LOG(("FuzzingWebSocketListener::OnServerClose"));
     85  return NS_OK;
     86 }
     87 
     88 NS_IMETHODIMP
     89 FuzzingWebSocketListener::OnMessageAvailable(nsISupports* aContext,
     90                                             const nsACString& aMsg) {
     91  FUZZING_LOG(("FuzzingWebSocketListener::OnMessageAvailable"));
     92  return NS_OK;
     93 }
     94 
     95 NS_IMETHODIMP
     96 FuzzingWebSocketListener::OnBinaryMessageAvailable(nsISupports* aContext,
     97                                                   const nsACString& aMsg) {
     98  FUZZING_LOG(("FuzzingWebSocketListener::OnBinaryMessageAvailable"));
     99  return NS_OK;
    100 }
    101 
    102 NS_IMETHODIMP
    103 FuzzingWebSocketListener::OnError() {
    104  FUZZING_LOG(("FuzzingWebSocketListener::OnError"));
    105  return NS_OK;
    106 }
    107 
    108 static int FuzzingInitNetworkWebsocket(int* argc, char*** argv) {
    109  Preferences::SetBool("network.dns.native-is-localhost", true);
    110  Preferences::SetBool("fuzzing.necko.enabled", true);
    111  Preferences::SetBool("network.websocket.delay-failed-reconnects", false);
    112  Preferences::SetBool("network.http.http3.enable", false);
    113  Preferences::SetInt("network.http.speculative-parallel-limit", 0);
    114  Preferences::SetInt("network.proxy.type", 0);  // PROXYCONFIG_DIRECT
    115  return 0;
    116 }
    117 
    118 static int FuzzingInitNetworkWebsocketPlain(int* argc, char*** argv) {
    119  fuzzWSS = false;
    120  return FuzzingInitNetworkWebsocket(argc, argv);
    121 }
    122 
    123 static int FuzzingRunNetworkWebsocket(const uint8_t* data, size_t size) {
    124  // Set the data to be processed
    125  addNetworkFuzzingBuffer(data, size);
    126 
    127  nsWeakPtr channelRef;
    128 
    129  {
    130    nsresult rv;
    131 
    132    nsSecurityFlags secFlags;
    133    secFlags = nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL;
    134    uint32_t sandboxFlags = SANDBOXED_ORIGIN;
    135 
    136    nsCOMPtr<nsIURI> url;
    137    nsAutoCString spec;
    138    RefPtr<FuzzingWebSocketListener> gWebSocketListener;
    139    nsCOMPtr<nsIWebSocketChannel> gWebSocketChannel;
    140 
    141    if (fuzzWSS) {
    142      spec = "https://127.0.0.1/";
    143      gWebSocketChannel =
    144          do_CreateInstance("@mozilla.org/network/protocol;1?name=wss", &rv);
    145    } else {
    146      spec = "http://127.0.0.1/";
    147      gWebSocketChannel =
    148          do_CreateInstance("@mozilla.org/network/protocol;1?name=ws", &rv);
    149    }
    150 
    151    if (rv != NS_OK) {
    152      MOZ_CRASH("Failed to create WebSocketChannel");
    153    }
    154 
    155    if (NS_NewURI(getter_AddRefs(url), spec) != NS_OK) {
    156      MOZ_CRASH("Call to NS_NewURI failed.");
    157    }
    158 
    159    nsCOMPtr<nsIPrincipal> nullPrincipal =
    160        NullPrincipal::CreateWithoutOriginAttributes();
    161 
    162    rv = gWebSocketChannel->InitLoadInfoNative(
    163        nullptr, nullPrincipal, nsContentUtils::GetSystemPrincipal(), nullptr,
    164        secFlags, nsIContentPolicy::TYPE_WEBSOCKET, sandboxFlags);
    165 
    166    if (rv != NS_OK) {
    167      MOZ_CRASH("Failed to call InitLoadInfo");
    168    }
    169 
    170    gWebSocketListener = new FuzzingWebSocketListener();
    171 
    172    OriginAttributes attrs;
    173    rv = gWebSocketChannel->AsyncOpenNative(url, spec, attrs, 0,
    174                                            gWebSocketListener, nullptr);
    175 
    176    if (rv == NS_OK) {
    177      FUZZING_LOG(("Successful call to AsyncOpen"));
    178 
    179      // Wait for StartRequest or StopRequest
    180      gWebSocketListener->waitUntilDoneOrStarted();
    181 
    182      if (gWebSocketListener->isStarted()) {
    183        rv = gWebSocketChannel->SendBinaryMsg("Hello world"_ns);
    184 
    185        if (rv != NS_OK) {
    186          FUZZING_LOG(("Warning: Failed to call SendBinaryMsg"));
    187        } else {
    188          gWebSocketListener->waitUntilDoneOrAck();
    189        }
    190 
    191        rv = gWebSocketChannel->Close(1000, ""_ns);
    192 
    193        if (rv != NS_OK) {
    194          FUZZING_LOG(("Warning: Failed to call close"));
    195        }
    196      }
    197 
    198      // Wait for StopRequest
    199      gWebSocketListener->waitUntilDone();
    200    } else {
    201      FUZZING_LOG(("Warning: Failed to call AsyncOpen"));
    202    }
    203 
    204    channelRef = do_GetWeakReference(gWebSocketChannel);
    205  }
    206 
    207  // Wait for the channel to be destroyed
    208  SpinEventLoopUntil(
    209      "FuzzingRunNetworkWebsocket(channel == nullptr)"_ns, [&]() -> bool {
    210        nsCycleCollector_collect(CCReason::API, nullptr);
    211        nsCOMPtr<nsIWebSocketChannel> channel = do_QueryReferent(channelRef);
    212        return channel == nullptr;
    213      });
    214 
    215  if (!signalNetworkFuzzingDone()) {
    216    // Wait for the connection to indicate closed
    217    SpinEventLoopUntil("FuzzingRunNetworkWebsocket(gFuzzingConnClosed)"_ns,
    218                       [&]() -> bool { return gFuzzingConnClosed; });
    219  }
    220 
    221  return 0;
    222 }
    223 
    224 MOZ_FUZZING_INTERFACE_RAW(FuzzingInitNetworkWebsocket,
    225                          FuzzingRunNetworkWebsocket, NetworkWebsocket);
    226 MOZ_FUZZING_INTERFACE_RAW(FuzzingInitNetworkWebsocketPlain,
    227                          FuzzingRunNetworkWebsocket, NetworkWebsocketPlain);
    228 
    229 }  // namespace net
    230 }  // namespace mozilla