tor-browser

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

TestHttpFuzzing.cpp (9773B)


      1 #include "mozilla/LoadInfo.h"
      2 #include "mozilla/Preferences.h"
      3 #include "mozilla/SpinEventLoopUntil.h"
      4 
      5 #include "nsCOMPtr.h"
      6 #include "nsNetCID.h"
      7 #include "nsString.h"
      8 #include "nsComponentManagerUtils.h"
      9 #include "nsContentUtils.h"
     10 #include "nsIChannel.h"
     11 #include "nsIHttpChannel.h"
     12 #include "nsILoadInfo.h"
     13 #include "nsIProxiedProtocolHandler.h"
     14 #include "nsIOService.h"
     15 #include "nsProtocolProxyService.h"
     16 #include "nsScriptSecurityManager.h"
     17 #include "nsServiceManagerUtils.h"
     18 #include "nsNetUtil.h"
     19 #include "NullPrincipal.h"
     20 #include "nsCycleCollector.h"
     21 #include "RequestContextService.h"
     22 #include "nsSandboxFlags.h"
     23 
     24 #include "FuzzingInterface.h"
     25 #include "FuzzingStreamListener.h"
     26 #include "FuzzyLayer.h"
     27 
     28 namespace mozilla {
     29 namespace net {
     30 
     31 // Target spec and optional proxy type to use, set by the respective
     32 // initialization function so we can cover all combinations.
     33 MOZ_RUNINIT static nsAutoCString httpSpec;
     34 MOZ_RUNINIT static nsAutoCString proxyType;
     35 static size_t minSize;
     36 
     37 static int FuzzingInitNetworkHttp(int* argc, char*** argv) {
     38  Preferences::SetBool("network.dns.native-is-localhost", true);
     39  Preferences::SetBool("fuzzing.necko.enabled", true);
     40  Preferences::SetInt("network.http.speculative-parallel-limit", 0);
     41  Preferences::SetInt("network.http.http2.default-concurrent", 1);
     42 
     43  if (httpSpec.IsEmpty()) {
     44    httpSpec = "http://127.0.0.1/";
     45  }
     46 
     47  net_EnsurePSMInit();
     48 
     49  return 0;
     50 }
     51 
     52 static int FuzzingInitNetworkHttp2(int* argc, char*** argv) {
     53  httpSpec = "https://127.0.0.1/";
     54  return FuzzingInitNetworkHttp(argc, argv);
     55 }
     56 
     57 static int FuzzingInitNetworkHttp3(int* argc, char*** argv) {
     58  Preferences::SetBool("fuzzing.necko.http3", true);
     59  Preferences::SetBool("network.http.http3.enable", true);
     60  Preferences::SetCString("network.http.http3.alt-svc-mapping-for-testing",
     61                          "fuzz.bad.tld;h3=:443");
     62  httpSpec = "https://fuzz.bad.tld/";
     63  minSize = 1200;
     64  return FuzzingInitNetworkHttp(argc, argv);
     65 }
     66 
     67 static int FuzzingInitNetworkHttpProxyHttp2(int* argc, char*** argv) {
     68  // This is http over an https proxy
     69  proxyType = "https";
     70 
     71  return FuzzingInitNetworkHttp(argc, argv);
     72 }
     73 
     74 static int FuzzingInitNetworkHttp2ProxyHttp2(int* argc, char*** argv) {
     75  // This is https over an https proxy
     76  proxyType = "https";
     77 
     78  return FuzzingInitNetworkHttp2(argc, argv);
     79 }
     80 
     81 static int FuzzingInitNetworkHttpProxyPlain(int* argc, char*** argv) {
     82  // This is http over an http proxy
     83  proxyType = "http";
     84 
     85  return FuzzingInitNetworkHttp(argc, argv);
     86 }
     87 
     88 static int FuzzingInitNetworkHttp2ProxyPlain(int* argc, char*** argv) {
     89  // This is https over an http proxy
     90  proxyType = "http";
     91 
     92  return FuzzingInitNetworkHttp2(argc, argv);
     93 }
     94 
     95 static int FuzzingRunNetworkHttp(const uint8_t* data, size_t size) {
     96  if (size < minSize) {
     97    return 0;
     98  }
     99 
    100  // Set the data to be processed
    101  addNetworkFuzzingBuffer(data, size);
    102 
    103  nsWeakPtr channelRef;
    104 
    105  nsCOMPtr<nsIRequestContextService> rcsvc =
    106      mozilla::net::RequestContextService::GetOrCreate();
    107  uint64_t rcID;
    108 
    109  {
    110    nsCOMPtr<nsIURI> url;
    111    nsresult rv;
    112 
    113    if (NS_NewURI(getter_AddRefs(url), httpSpec) != NS_OK) {
    114      MOZ_CRASH("Call to NS_NewURI failed.");
    115    }
    116 
    117    nsLoadFlags loadFlags;
    118    loadFlags = nsIRequest::LOAD_BACKGROUND | nsIRequest::LOAD_BYPASS_CACHE |
    119                nsIRequest::INHIBIT_CACHING |
    120                nsIRequest::LOAD_FRESH_CONNECTION |
    121                nsIChannel::LOAD_INITIAL_DOCUMENT_URI;
    122    nsSecurityFlags secFlags;
    123    secFlags = nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL;
    124    uint32_t sandboxFlags = SANDBOXED_ORIGIN;
    125 
    126    nsCOMPtr<nsIChannel> channel;
    127    nsCOMPtr<nsILoadInfo> loadInfo;
    128 
    129    if (!proxyType.IsEmpty()) {
    130      nsAutoCString proxyHost("127.0.0.2");
    131 
    132      nsCOMPtr<nsIProtocolProxyService2> ps =
    133          do_GetService(NS_PROTOCOLPROXYSERVICE_CID);
    134      if (!ps) {
    135        MOZ_CRASH("Failed to create nsIProtocolProxyService2");
    136      }
    137 
    138      mozilla::net::nsProtocolProxyService* pps =
    139          static_cast<mozilla::net::nsProtocolProxyService*>(ps.get());
    140 
    141      nsCOMPtr<nsIProxyInfo> proxyInfo;
    142      rv = pps->NewProxyInfo(proxyType, proxyHost, 443,
    143                             ""_ns,       // aProxyAuthorizationHeader
    144                             ""_ns,       // aConnectionIsolationKey
    145                             0,           // aFlags
    146                             UINT32_MAX,  // aFailoverTimeout
    147                             nullptr,     // aFailoverProxy
    148                             getter_AddRefs(proxyInfo));
    149 
    150      if (NS_FAILED(rv)) {
    151        MOZ_CRASH("Call to NewProxyInfo failed.");
    152      }
    153 
    154      nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
    155      if (NS_FAILED(rv)) {
    156        MOZ_CRASH("do_GetIOService failed.");
    157      }
    158 
    159      nsCOMPtr<nsIProtocolHandler> handler;
    160      rv = ioService->GetProtocolHandler("http", getter_AddRefs(handler));
    161      if (NS_FAILED(rv)) {
    162        MOZ_CRASH("GetProtocolHandler failed.");
    163      }
    164 
    165      nsCOMPtr<nsIProxiedProtocolHandler> pph = do_QueryInterface(handler, &rv);
    166      if (NS_FAILED(rv)) {
    167        MOZ_CRASH("do_QueryInterface failed.");
    168      }
    169 
    170      loadInfo =
    171          LoadInfo::Create(
    172              nsContentUtils::GetSystemPrincipal(),  // loading principal
    173              nsContentUtils::GetSystemPrincipal(),  // triggering principal
    174              nullptr,                               // Context
    175              secFlags, nsIContentPolicy::TYPE_INTERNAL_XMLHTTPREQUEST_ASYNC,
    176              Maybe<mozilla::dom::ClientInfo>(),
    177              Maybe<mozilla::dom::ServiceWorkerDescriptor>(), sandboxFlags)
    178              .unwrap();
    179 
    180      rv = pph->NewProxiedChannel(url, proxyInfo,
    181                                  0,        // aProxyResolveFlags
    182                                  nullptr,  // aProxyURI
    183                                  loadInfo, getter_AddRefs(channel));
    184 
    185      if (NS_FAILED(rv)) {
    186        MOZ_CRASH("Call to newProxiedChannel failed.");
    187      }
    188    } else {
    189      rv = NS_NewChannel(getter_AddRefs(channel), url,
    190                         nsContentUtils::GetSystemPrincipal(), secFlags,
    191                         nsIContentPolicy::TYPE_INTERNAL_XMLHTTPREQUEST_ASYNC,
    192                         nullptr,    // aCookieJarSettings
    193                         nullptr,    // aPerformanceStorage
    194                         nullptr,    // loadGroup
    195                         nullptr,    // aCallbacks
    196                         loadFlags,  // aLoadFlags
    197                         nullptr,    // aIoService
    198                         sandboxFlags);
    199 
    200      if (NS_FAILED(rv)) {
    201        MOZ_CRASH("Call to NS_NewChannel failed.");
    202      }
    203 
    204      loadInfo = channel->LoadInfo();
    205    }
    206 
    207    if (NS_FAILED(loadInfo->SetSkipContentSniffing(true))) {
    208      MOZ_CRASH("Failed to call SetSkipContentSniffing");
    209    }
    210 
    211    RefPtr<FuzzingStreamListener> gStreamListener;
    212    nsCOMPtr<nsIHttpChannel> gHttpChannel;
    213 
    214    gHttpChannel = do_QueryInterface(channel);
    215    rv = gHttpChannel->SetRequestMethod("GET"_ns);
    216    if (NS_FAILED(rv)) {
    217      MOZ_CRASH("SetRequestMethod on gHttpChannel failed.");
    218    }
    219 
    220    nsCOMPtr<nsIRequestContext> rc;
    221    rv = rcsvc->NewRequestContext(getter_AddRefs(rc));
    222    if (NS_FAILED(rv)) {
    223      MOZ_CRASH("NewRequestContext failed.");
    224    }
    225    rcID = rc->GetID();
    226 
    227    rv = gHttpChannel->SetRequestContextID(rcID);
    228    if (NS_FAILED(rv)) {
    229      MOZ_CRASH("SetRequestContextID on gHttpChannel failed.");
    230    }
    231 
    232    if (!proxyType.IsEmpty()) {
    233      // NewProxiedChannel doesn't allow us to pass loadFlags directly
    234      rv = gHttpChannel->SetLoadFlags(loadFlags);
    235      if (rv != NS_OK) {
    236        MOZ_CRASH("SetRequestMethod on gHttpChannel failed.");
    237      }
    238    }
    239 
    240    gStreamListener = new FuzzingStreamListener();
    241    gHttpChannel->AsyncOpen(gStreamListener);
    242 
    243    // Wait for StopRequest
    244    gStreamListener->waitUntilDone();
    245 
    246    bool mainPingBack = false;
    247 
    248    NS_DispatchBackgroundTask(NS_NewRunnableFunction("Dummy", [&]() {
    249      NS_DispatchToMainThread(
    250          NS_NewRunnableFunction("Dummy", [&]() { mainPingBack = true; }));
    251    }));
    252 
    253    SpinEventLoopUntil("FuzzingRunNetworkHttp(mainPingBack)"_ns,
    254                       [&]() -> bool { return mainPingBack; });
    255 
    256    channelRef = do_GetWeakReference(gHttpChannel);
    257  }
    258 
    259  // Wait for the channel to be destroyed
    260  SpinEventLoopUntil(
    261      "FuzzingRunNetworkHttp(channel == nullptr)"_ns, [&]() -> bool {
    262        nsCycleCollector_collect(CCReason::API, nullptr);
    263        nsCOMPtr<nsIHttpChannel> channel = do_QueryReferent(channelRef);
    264        return channel == nullptr;
    265      });
    266 
    267  if (!signalNetworkFuzzingDone()) {
    268    // Wait for the connection to indicate closed
    269    SpinEventLoopUntil("FuzzingRunNetworkHttp(gFuzzingConnClosed)"_ns,
    270                       [&]() -> bool { return gFuzzingConnClosed; });
    271  }
    272 
    273  rcsvc->RemoveRequestContext(rcID);
    274  return 0;
    275 }
    276 
    277 MOZ_FUZZING_INTERFACE_RAW(FuzzingInitNetworkHttp, FuzzingRunNetworkHttp,
    278                          NetworkHttp);
    279 
    280 MOZ_FUZZING_INTERFACE_RAW(FuzzingInitNetworkHttp2, FuzzingRunNetworkHttp,
    281                          NetworkHttp2);
    282 
    283 MOZ_FUZZING_INTERFACE_RAW(FuzzingInitNetworkHttp3, FuzzingRunNetworkHttp,
    284                          NetworkHttp3);
    285 
    286 MOZ_FUZZING_INTERFACE_RAW(FuzzingInitNetworkHttp2ProxyHttp2,
    287                          FuzzingRunNetworkHttp, NetworkHttp2ProxyHttp2);
    288 
    289 MOZ_FUZZING_INTERFACE_RAW(FuzzingInitNetworkHttpProxyHttp2,
    290                          FuzzingRunNetworkHttp, NetworkHttpProxyHttp2);
    291 
    292 MOZ_FUZZING_INTERFACE_RAW(FuzzingInitNetworkHttpProxyPlain,
    293                          FuzzingRunNetworkHttp, NetworkHttpProxyPlain);
    294 
    295 MOZ_FUZZING_INTERFACE_RAW(FuzzingInitNetworkHttp2ProxyPlain,
    296                          FuzzingRunNetworkHttp, NetworkHttp2ProxyPlain);
    297 
    298 }  // namespace net
    299 }  // namespace mozilla