FuzzURLPattern.cpp (5116B)
1 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 4 * You can obtain one at http://mozilla.org/MPL/2.0/. 5 */ 6 #include "FuzzedDataProvider.h" 7 #include "FuzzingInterface.h" 8 #include "js/RootingAPI.h" // JS::PersistentRooted 9 #include "mozilla/ErrorResult.h" // ErrorResult 10 #include "mozilla/dom/BindingDeclarations.h" // GlobalObject 11 #include "mozilla/dom/ScriptSettings.h" // AutoJSAPI 12 #include "mozilla/dom/SimpleGlobalObject.h" // SimpleGlobalObject 13 #include "mozilla/dom/URLPattern.h" // URLPattern class 14 #include "mozilla/dom/URLPatternBinding.h" // UTF8StringOrURLPatternInit, URLPatternOptions 15 #include "nsReadableUtils.h" // CopyUTF8toUTF16, CopyUTF16toUTF8 16 17 using namespace mozilla; 18 using namespace mozilla::dom; 19 20 static MOZ_RUNINIT JS::PersistentRooted<JSObject*> global; 21 22 static int FuzzingInit(int* argc, char*** argv) { 23 JSObject* simpleGlobal = 24 SimpleGlobalObject::Create(SimpleGlobalObject::GlobalType::BindingDetail); 25 global.init(mozilla::dom::RootingCx()); 26 global.set(simpleGlobal); 27 return 0; 28 } 29 30 // Helper function to simulate JS->WebIDL UTF8String conversion 31 static void SanitizeToUTF8(const std::string& input, nsACString& output) { 32 nsAutoString utf16; 33 CopyUTF8toUTF16(mozilla::Span(input.data(), input.length()), utf16); 34 CopyUTF16toUTF8(utf16, output); 35 } 36 37 // Helper function to create an optional baseURL string 38 static void MaybeCreateBaseURL(FuzzedDataProvider& fdp, 39 Optional<nsACString>& base, nsCString& baseUrl) { 40 if (fdp.ConsumeBool()) { 41 std::string str = fdp.ConsumeRandomLengthString(); 42 SanitizeToUTF8(str, baseUrl); 43 base = &baseUrl; 44 } 45 } 46 47 static void CreateURLPatternInput(FuzzedDataProvider& fdp, 48 UTF8StringOrURLPatternInit& input) { 49 if (fdp.ConsumeBool()) { 50 // URLPatternInit 51 auto maybeSetField = [&fdp](auto& field) { 52 if (fdp.ConsumeBool()) { 53 std::string str = fdp.ConsumeRandomLengthString(); 54 nsCString sanitized; 55 SanitizeToUTF8(str, sanitized); 56 field.Construct(sanitized); 57 } 58 }; 59 60 URLPatternInit& init = input.SetAsURLPatternInit(); 61 maybeSetField(init.mProtocol); 62 maybeSetField(init.mUsername); 63 maybeSetField(init.mPassword); 64 maybeSetField(init.mHostname); 65 maybeSetField(init.mPort); 66 maybeSetField(init.mPathname); 67 maybeSetField(init.mSearch); 68 maybeSetField(init.mHash); 69 maybeSetField(init.mBaseURL); 70 } else { 71 // Plain UTF8String 72 std::string str = fdp.ConsumeRandomLengthString(); 73 auto& utf8Str = input.RawSetAsUTF8String(); 74 SanitizeToUTF8(str, *reinterpret_cast<nsCString*>(&utf8Str)); 75 } 76 } 77 78 static int FuzzingRunURLPattern(const uint8_t* data, size_t size) { 79 FuzzedDataProvider fdp(data, size); 80 81 AutoJSAPI jsapi; 82 MOZ_RELEASE_ASSERT(jsapi.Init(global)); 83 JSContext* cx = jsapi.cx(); 84 GlobalObject globalObj(cx, global); 85 86 UTF8StringOrURLPatternInit input; 87 CreateURLPatternInput(fdp, input); 88 89 URLPatternOptions options; 90 options.mIgnoreCase = fdp.ConsumeBool(); 91 92 ErrorResult rv; 93 94 RefPtr<URLPattern> pattern; 95 if (fdp.ConsumeBool()) { 96 pattern = URLPattern::Constructor(globalObj, input, options, rv); 97 } else { 98 nsCString base; 99 std::string str = fdp.ConsumeRandomLengthString(); 100 SanitizeToUTF8(str, base); 101 pattern = URLPattern::Constructor(globalObj, input, base, options, rv); 102 } 103 104 if (MOZ_UNLIKELY(rv.Failed())) { 105 return 0; 106 } 107 108 // Table of getters 109 using GetterFunc = void (URLPattern::*)(nsACString&) const; 110 static const GetterFunc kGetters[] = { 111 &URLPattern::GetProtocol, &URLPattern::GetUsername, 112 &URLPattern::GetPassword, &URLPattern::GetHostname, 113 &URLPattern::GetPort, &URLPattern::GetPathname, 114 &URLPattern::GetSearch, &URLPattern::GetHash, 115 }; 116 117 while (fdp.remaining_bytes() > 0) { 118 uint8_t operation = fdp.ConsumeIntegralInRange<uint8_t>(0, 10); 119 if (operation <= 7) { 120 // Access getters 121 nsAutoCString result; 122 (pattern.get()->*kGetters[operation])(result); 123 } else if (operation == 8) { 124 (void)pattern->HasRegExpGroups(); 125 } else if (operation == 9) { 126 // Test 127 UTF8StringOrURLPatternInit testInput; 128 CreateURLPatternInput(fdp, testInput); 129 130 Optional<nsACString> base; 131 nsCString baseUrl; 132 MaybeCreateBaseURL(fdp, base, baseUrl); 133 134 ErrorResult testRv; 135 (void)pattern->Test(testInput, base, testRv); 136 } else if (operation == 10) { 137 // Exec 138 UTF8StringOrURLPatternInit execInput; 139 CreateURLPatternInput(fdp, execInput); 140 141 Optional<nsACString> base; 142 nsCString baseUrl; 143 MaybeCreateBaseURL(fdp, base, baseUrl); 144 145 Nullable<URLPatternResult> result; 146 ErrorResult execRv; 147 pattern->Exec(execInput, base, result, execRv); 148 } 149 } 150 151 return 0; 152 } 153 154 MOZ_FUZZING_INTERFACE_RAW(FuzzingInit, FuzzingRunURLPattern, URLPattern);