Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/toolkit/components/url-classifier/./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp
Warning:line 659, column 5
Value stored to 'rv' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_url-classifier0.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/toolkit/components/url-classifier -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/toolkit/components/url-classifier -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D GOOGLE_PROTOBUF_NO_RTTI -D GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /root/firefox-clang/toolkit/components/url-classifier -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/toolkit/components/url-classifier -I /root/firefox-clang/toolkit/components/build -I /root/firefox-clang/xpcom/io -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /root/firefox-clang/ipc/chromium/src -I /root/firefox-clang/third_party/abseil-cpp -I /root/firefox-clang/toolkit/components/telemetry -I /root/firefox-clang/xpcom/base -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-character-conversion -std=gnu++20 -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-09-01-224014-2642839-1 -x c++ Unified_cpp_url-classifier0.cpp
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5#include "chromium/safebrowsing.pb.h"
6#include "chromium/safebrowsing_v5.pb.h"
7#include "nsEscape.h"
8#include "nsString.h"
9#include "nsIURI.h"
10#include "nsIURIMutator.h"
11#include "nsIURL.h"
12#include "nsIXULRuntime.h"
13#include "nsUrlClassifierUtils.h"
14#include "nsTArray.h"
15#include "nsReadableUtils.h"
16#include "plbase64.h"
17#include "nsPrintfCString.h"
18#include "mozilla/ClearOnShutdown.h"
19#include "mozilla/Sprintf.h"
20#include "mozilla/StaticPtr.h"
21#include "mozilla/Mutex.h"
22#include "nsIRedirectHistoryEntry.h"
23#include "nsIHttpChannelInternal.h"
24#include "mozIThirdPartyUtil.h"
25#include "nsIDocShell.h"
26#include "mozilla/TextUtils.h"
27#include "mozilla/Preferences.h"
28#include "mozilla/Services.h"
29#include "mozilla/glean/UrlClassifierMetrics.h"
30#include "nsNetUtil.h"
31#include "nsIHttpChannel.h"
32#include "nsIObserverService.h"
33#include "nsIPrefBranch.h"
34#include "nsIPrefService.h"
35#include "nsPIDOMWindow.h"
36#include "nsPIDOMWindowInlines.h"
37#include "nsServiceManagerUtils.h"
38#include "nsThreadManager.h"
39#include "nsTHashSet.h"
40#include "Classifier.h"
41#include "Entries.h"
42#include "prprf.h"
43#include "prtime.h"
44
45#define DEFAULT_PROTOCOL_VERSION"2.2" "2.2"
46
47using namespace mozilla;
48using namespace mozilla::safebrowsing;
49
50static mozilla::StaticRefPtr<nsUrlClassifierUtils> gUrlClassifierUtils;
51
52static char int_to_hex_digit(int32_t i) {
53 NS_ASSERTION((i >= 0) && (i <= 15), "int too big in int_to_hex_digit")do { if (!((i >= 0) && (i <= 15))) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "int too big in int_to_hex_digit", "(i >= 0) && (i <= 15)"
, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 53); MOZ_PretendNoReturn(); } } while (0)
;
54 return static_cast<char>(((i < 10) ? (i + '0') : ((i - 10) + 'A')));
55}
56
57static bool IsDecimal(const nsACString& num) {
58 for (uint32_t i = 0; i < num.Length(); i++) {
59 if (!mozilla::IsAsciiDigit(num[i])) {
60 return false;
61 }
62 }
63
64 return true;
65}
66
67static bool IsHex(const nsACString& num) {
68 if (num.Length() < 3) {
69 return false;
70 }
71
72 if (num[0] != '0' || !(num[1] == 'x' || num[1] == 'X')) {
73 return false;
74 }
75
76 for (uint32_t i = 2; i < num.Length(); i++) {
77 if (!mozilla::IsAsciiHexDigit(num[i])) {
78 return false;
79 }
80 }
81
82 return true;
83}
84
85static bool IsOctal(const nsACString& num) {
86 if (num.Length() < 2) {
87 return false;
88 }
89
90 if (num[0] != '0') {
91 return false;
92 }
93
94 for (uint32_t i = 1; i < num.Length(); i++) {
95 if (!mozilla::IsAsciiDigit(num[i]) || num[i] == '8' || num[i] == '9') {
96 return false;
97 }
98 }
99
100 return true;
101}
102
103/////////////////////////////////////////////////////////////////
104// SafeBrowsing V4 related utits.
105
106namespace mozilla {
107namespace safebrowsing {
108
109static PlatformType GetPlatformType() {
110#if defined(ANDROID)
111 return ANDROID_PLATFORM;
112#elif defined(XP_MACOSX)
113 return OSX_PLATFORM;
114#elif defined(XP_LINUX1)
115 return LINUX_PLATFORM;
116#elif defined(XP_WIN)
117 return WINDOWS_PLATFORM;
118#else
119 // Default to Linux for other platforms (see bug 1362501).
120 return LINUX_PLATFORM;
121#endif
122}
123
124typedef FetchThreatListUpdatesRequest_ListUpdateRequest ListUpdateRequest;
125typedef FetchThreatListUpdatesRequest_ListUpdateRequest_Constraints Constraints;
126
127static void InitListUpdateRequest(ThreatType aThreatType,
128 const nsCString& aStateBase64,
129 ListUpdateRequest* aListUpdateRequest) {
130 aListUpdateRequest->set_threat_type(aThreatType);
131 PlatformType platform = GetPlatformType();
132#if defined(ANDROID)
133 // Temporary hack to fix bug 1441345.
134 if ((aThreatType == SOCIAL_ENGINEERING_PUBLIC) ||
135 (aThreatType == SOCIAL_ENGINEERING)) {
136 platform = LINUX_PLATFORM;
137 }
138#endif
139 aListUpdateRequest->set_platform_type(platform);
140 aListUpdateRequest->set_threat_entry_type(URL);
141
142 Constraints* contraints = new Constraints();
143 contraints->add_supported_compressions(RICE);
144 aListUpdateRequest->set_allocated_constraints(contraints);
145
146 // Only set non-empty state.
147 if (!aStateBase64.IsEmpty()) {
148 nsCString stateBinary;
149 nsresult rv = Base64Decode(aStateBase64, stateBinary);
150 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
151 aListUpdateRequest->set_state(stateBinary.get(), stateBinary.Length());
152 }
153 }
154}
155
156static ClientInfo* CreateClientInfo() {
157 ClientInfo* c = new ClientInfo();
158
159 nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID"@mozilla.org/preferences-service;1");
160
161 nsAutoCString clientId;
162 nsresult rv = prefBranch->GetCharPref("browser.safebrowsing.id", clientId);
163
164 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
165 clientId = "Firefox"; // Use "Firefox" as fallback.
166 }
167
168 c->set_client_id(clientId.get());
169
170 return c;
171}
172
173static bool IsAllowedOnCurrentPlatform(uint32_t aThreatType) {
174 PlatformType platform = GetPlatformType();
175
176 switch (aThreatType) {
177 case POTENTIALLY_HARMFUL_APPLICATION:
178 // Bug 1388582 - Google server would respond 404 error if the request
179 // contains PHA on non-mobile platform.
180 return ANDROID_PLATFORM == platform;
181 case MALICIOUS_BINARY:
182 case CSD_DOWNLOAD_WHITELIST:
183 // Bug 1392204 - 'goog-downloadwhite-proto' and 'goog-badbinurl-proto'
184 // are not available on android.
185 return ANDROID_PLATFORM != platform;
186 }
187 // We allow every threat type not listed in the switch cases.
188 return true;
189}
190
191} // end of namespace safebrowsing.
192} // end of namespace mozilla.
193
194// static
195already_AddRefed<nsUrlClassifierUtils>
196nsUrlClassifierUtils::GetXPCOMSingleton() {
197 if (gUrlClassifierUtils) {
198 return do_AddRef(gUrlClassifierUtils);
199 }
200
201 RefPtr<nsUrlClassifierUtils> utils = new nsUrlClassifierUtils();
202 if (NS_WARN_IF(NS_FAILED(utils->Init()))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(utils
->Init())), 0))), "NS_FAILED(utils->Init())", "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 202)
) {
203 return nullptr;
204 }
205
206 // Note: This is cleared in the nsUrlClassifierUtils destructor.
207 gUrlClassifierUtils = utils.get();
208 ClearOnShutdown(&gUrlClassifierUtils);
209 return utils.forget();
210}
211
212// static
213nsUrlClassifierUtils* nsUrlClassifierUtils::GetInstance() {
214 if (!gUrlClassifierUtils) {
215 RefPtr<nsUrlClassifierUtils> utils = GetXPCOMSingleton();
216 }
217
218 return gUrlClassifierUtils;
219}
220
221nsUrlClassifierUtils::~nsUrlClassifierUtils() {
222 if (gUrlClassifierUtils) {
223 MOZ_ASSERT(gUrlClassifierUtils == this)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(gUrlClassifierUtils == this)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(gUrlClassifierUtils == this)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("gUrlClassifierUtils == this"
, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 223); AnnotateMozCrashReason("MOZ_ASSERT" "(" "gUrlClassifierUtils == this"
")"); do { MOZ_CrashSequence(__null, 223); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
224 gUrlClassifierUtils = nullptr;
225 }
226}
227
228nsresult nsUrlClassifierUtils::Init() {
229 // nsIUrlClassifierUtils is a thread-safe service so it's
230 // allowed to use on non-main threads. However, building
231 // the provider dictionary must be on the main thread.
232 // We forcefully load nsUrlClassifierUtils in
233 // nsUrlClassifierDBService::Init() to ensure we must
234 // now be on the main thread.
235 nsresult rv = ReadProvidersFromPrefs(mProviderDict);
236 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 236); return rv; } } while (false)
;
237
238 // Add an observer for shutdown
239 nsCOMPtr<nsIObserverService> observerService =
240 mozilla::services::GetObserverService();
241 if (!observerService) return NS_ERROR_FAILURE;
242
243 observerService->AddObserver(this, "xpcom-shutdown-threads", false);
244 mozilla::Preferences::AddStrongObserver(this, "browser.safebrowsing");
245
246 return NS_OK;
247}
248
249NS_IMPL_ISUPPORTS(nsUrlClassifierUtils, nsIUrlClassifierUtils, nsIObserver)MozExternalRefCountType nsUrlClassifierUtils::AddRef(void) { static_assert
(!std::is_destructible_v<nsUrlClassifierUtils>, "Reference-counted class "
"nsUrlClassifierUtils" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 249); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 249
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsUrlClassifierUtils" != nullptr)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!("nsUrlClassifierUtils" != nullptr))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("\"nsUrlClassifierUtils\" != nullptr"
" (" "Must specify a name" ")", "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 249); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsUrlClassifierUtils\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 249); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("nsUrlClassifierUtils" " not thread-safe"); nsrefcnt count =
++mRefCnt; NS_LogAddRef((this), (count), ("nsUrlClassifierUtils"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
nsUrlClassifierUtils::Release(void) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(int32_t(mRefCnt)
> 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release"
")", "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 249); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 249
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsUrlClassifierUtils" != nullptr)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!("nsUrlClassifierUtils" != nullptr))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("\"nsUrlClassifierUtils\" != nullptr"
" (" "Must specify a name" ")", "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 249); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsUrlClassifierUtils\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 249); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("nsUrlClassifierUtils" " not thread-safe"); const char* const
nametmp = "nsUrlClassifierUtils"; nsrefcnt count = --mRefCnt
; NS_LogRelease((this), (count), (nametmp)); if (count == 0) {
mRefCnt = 1; delete (this); return 0; } return count; } nsresult
nsUrlClassifierUtils::QueryInterface(const nsIID& aIID, void
** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak(
NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 249); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(2 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<nsUrlClassifierUtils, nsIUrlClassifierUtils
>, int32_t( reinterpret_cast<char*>(static_cast<nsIUrlClassifierUtils
*>((nsUrlClassifierUtils*)0x1000)) - reinterpret_cast<char
*>((nsUrlClassifierUtils*)0x1000))}, {&mozilla::detail
::kImplementedIID<nsUrlClassifierUtils, nsIObserver>, int32_t
( reinterpret_cast<char*>(static_cast<nsIObserver*>
((nsUrlClassifierUtils*)0x1000)) - reinterpret_cast<char*>
((nsUrlClassifierUtils*)0x1000))}, {&mozilla::detail::kImplementedIID
<nsUrlClassifierUtils, nsISupports>, int32_t(reinterpret_cast
<char*>(static_cast<nsISupports*>( static_cast<
nsIUrlClassifierUtils*>((nsUrlClassifierUtils*)0x1000))) -
reinterpret_cast<char*>((nsUrlClassifierUtils*)0x1000)
)}, { nullptr, 0 } } ; static_assert(std::size(table) > 1,
"need at least 1 interface"); rv = NS_TableDrivenQI(static_cast
<void*>(this), aIID, aInstancePtr, table); return rv; }
250
251/////////////////////////////////////////////////////////////////////////////
252// nsIUrlClassifierUtils
253
254NS_IMETHODIMPnsresult
255nsUrlClassifierUtils::GetKeyForURI(nsIURI* uri, nsACString& _retval) {
256 nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(uri);
257 if (!innerURI) innerURI = uri;
258
259 nsAutoCString host;
260 innerURI->GetAsciiHost(host);
261
262 if (host.IsEmpty()) {
263 return NS_ERROR_MALFORMED_URI;
264 }
265
266 nsresult rv = CanonicalizeHostname(host, _retval);
267 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 267); return rv; } } while (false)
;
268
269 nsAutoCString path;
270 rv = innerURI->GetPathQueryRef(path);
271 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 271); return rv; } } while (false)
;
272
273 // Strip fragment and query because canonicalization only applies to path
274 int32_t ref = path.FindChar('#');
275 if (ref != kNotFound) {
276 path.SetLength(ref);
277 }
278
279 int32_t query = path.FindChar('?');
280 if (query != kNotFound) {
281 path.SetLength(query);
282 }
283
284 nsAutoCString temp;
285 rv = CanonicalizePath(path, temp);
286 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 286); return rv; } } while (false)
;
287
288 _retval.Append(temp);
289
290 if (query != kNotFound) {
291 nsAutoCString query;
292 rv = innerURI->GetQuery(query);
293 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 293); return rv; } } while (false)
;
294
295 // We have to canonicalize the query too based on
296 // https://developers.google.com/safe-browsing/v4/urls-hashing?hl=en#canonicalization
297 rv = CanonicalizeQuery(query, temp);
298 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 298); return rv; } } while (false)
;
299
300 _retval.Append(temp);
301 }
302
303 return NS_OK;
304}
305
306// We use "goog-*-proto" as the list name for v4, where "proto" indicates
307// it's updated (as well as hash completion) via protobuf.
308//
309// In the mozilla official build, we are allowed to use the
310// private phishing list (goog-phish-proto). See Bug 1288840.
311static const struct {
312 const char* mListName;
313 uint32_t mThreatType;
314} THREAT_TYPE_CONV_TABLE[] = {
315 {"goog-malware-proto", MALWARE_THREAT}, // 1
316 {"googpub-phish-proto", SOCIAL_ENGINEERING_PUBLIC}, // 2
317 {"goog-unwanted-proto", UNWANTED_SOFTWARE}, // 3
318 {"goog-harmful-proto", POTENTIALLY_HARMFUL_APPLICATION}, // 4
319 {"goog-phish-proto", SOCIAL_ENGINEERING}, // 5
320
321 // For application reputation
322 {"goog-badbinurl-proto", MALICIOUS_BINARY}, // 7
323 {"goog-downloadwhite-proto", CSD_DOWNLOAD_WHITELIST}, // 9
324
325 // For testing purpose.
326 {"moztest-phish-proto", SOCIAL_ENGINEERING_PUBLIC}, // 2
327 {"test-phish-proto", SOCIAL_ENGINEERING_PUBLIC}, // 2
328 {"moztest-unwanted-proto", UNWANTED_SOFTWARE}, // 3
329 {"test-unwanted-proto", UNWANTED_SOFTWARE}, // 3
330};
331
332// The table for the list naming conversion between the local list name and the
333// SafeBrowsing V5 server list name. In the SafeBrowsing V5, the list name is
334// represented as a string of the form "uws-4b", "pha-4b", etc.
335//
336// See
337// https://developers.google.com/safe-browsing/reference/Local.Database#available-lists
338// for the current available lists for SafeBrowsing V5.
339static const struct {
340 const char* mLocalListName;
341 const char* mServerListName;
342} THREAT_NAME_CONV_TABLE_V5[] = {
343 {"goog-malware-proto", "mw-4b"},
344// Unlike the SafeBrowsing V4, the SafeBrowsing V5 only has one social
345// engineering list. We need to map the goog-phish-proto and googpub-phish-proto
346// to the V5 social engineering list name according to the official build flag
347// because the official build uses goog-phish-proto. This is also needed for
348// the backward compatibility.
349#ifdef MOZILLA_OFFICIAL
350 {"goog-phish-proto", "se-4b"},
351#else
352 {"googpub-phish-proto", "se-4b"},
353#endif
354// Map the goog-unwanted-proto to different V5 list name on Android because
355// SafeBrowsing V5 provides a different unwanted list for Android.
356#ifndef MOZ_WIDGET_ANDROID
357 {"goog-unwanted-proto", "uws-4b"},
358#else
359 {"goog-unwanted-proto", "uwsa-4b"},
360#endif
361 {"goog-harmful-proto", "pha-4b"},
362 {"goog-badbinurl-proto", "mwb-4b"},
363 {"goog-downloadwhite-proto", "csdda-32b"},
364 {"goog-globalcache-proto", "gc-32b"},
365 {"test-google5-malware-proto", "test-4b"},
366 {"test-globalcache-proto", "test-32b"},
367};
368
369static const struct {
370 const char* mListName;
371 uint32_t mThreatType;
372} THREAT_TYPE_CONV_TABLE_V5[] = {
373 {"goog-malware-proto", v5::MALWARE},
374#ifdef MOZILLA_OFFICIAL
375 {"goog-phish-proto", v5::SOCIAL_ENGINEERING},
376#else
377 {"googpub-phish-proto", v5::SOCIAL_ENGINEERING},
378#endif
379 {"goog-unwanted-proto", v5::UNWANTED_SOFTWARE},
380 {"goog-harmful-proto", v5::POTENTIALLY_HARMFUL_APPLICATION},
381 {"test-google5-malware-proto", v5::MALWARE},
382};
383
384NS_IMETHODIMPnsresult
385nsUrlClassifierUtils::ConvertThreatTypeToListNames(uint32_t aThreatType,
386 nsACString& aListNames) {
387 for (auto entry : THREAT_TYPE_CONV_TABLE) {
388 if (aThreatType == entry.mThreatType) {
389 if (!aListNames.IsEmpty()) {
390 aListNames.AppendLiteral(",");
391 }
392 aListNames += entry.mListName;
393 }
394 }
395
396 return aListNames.IsEmpty() ? NS_ERROR_FAILURE : NS_OK;
397}
398
399NS_IMETHODIMPnsresult
400nsUrlClassifierUtils::ConvertListNameToThreatType(const nsACString& aListName,
401 uint32_t* aThreatType) {
402 for (auto entry : THREAT_TYPE_CONV_TABLE) {
403 if (aListName.EqualsASCII(entry.mListName)) {
404 *aThreatType = entry.mThreatType;
405 return NS_OK;
406 }
407 }
408
409 return NS_ERROR_FAILURE;
410}
411
412NS_IMETHODIMPnsresult
413nsUrlClassifierUtils::ConvertServerListNameToLocalListNameV5(
414 const nsACString& aServerListName, nsACString& aLocalListName) {
415 for (auto entry : THREAT_NAME_CONV_TABLE_V5) {
416 if (aServerListName.EqualsASCII(entry.mServerListName)) {
417 aLocalListName = entry.mLocalListName;
418 return NS_OK;
419 }
420 }
421
422 return NS_ERROR_FAILURE;
423}
424
425NS_IMETHODIMPnsresult
426nsUrlClassifierUtils::ConvertLocalListNameToServerListNameV5(
427 const nsACString& aLocalListName, nsACString& aServerListName) {
428 for (auto entry : THREAT_NAME_CONV_TABLE_V5) {
429 if (aLocalListName.EqualsASCII(entry.mLocalListName)) {
430 aServerListName = entry.mServerListName;
431 return NS_OK;
432 }
433 }
434
435 return NS_ERROR_FAILURE;
436}
437
438NS_IMETHODIMPnsresult
439nsUrlClassifierUtils::ConvertThreatTypeToListNamesV5(uint32_t aThreatType,
440 nsACString& aListNames) {
441 bool found = false;
442 for (auto entry : THREAT_TYPE_CONV_TABLE_V5) {
443 if (aThreatType == entry.mThreatType) {
444 if (!aListNames.IsEmpty()) {
445 aListNames.AppendLiteral(",");
446 }
447 aListNames += entry.mListName;
448 found = true;
449 }
450 }
451
452 return found ? NS_OK : NS_ERROR_FAILURE;
453}
454
455NS_IMETHODIMPnsresult
456nsUrlClassifierUtils::GetProvider(const nsACString& aTableName,
457 nsACString& aProvider) {
458 MutexAutoLock lock(mProviderDictLock);
459 nsCString* provider = nullptr;
460
461 if (IsTestTable(aTableName)) {
462 aProvider = nsLiteralCString(TESTING_TABLE_PROVIDER_NAME"test");
463 } else if (mProviderDict.Get(aTableName, &provider)) {
464 aProvider = provider ? *provider : ""_ns;
465 } else {
466 aProvider.Truncate();
467 }
468 return NS_OK;
469}
470
471NS_IMETHODIMPnsresult
472nsUrlClassifierUtils::GetTelemetryProvider(const nsACString& aTableName,
473 nsACString& aProvider) {
474 GetProvider(aTableName, aProvider);
475 // Exceptionlist known providers to avoid reporting on private ones.
476 // An empty provider is treated as "other"
477 if (!"mozilla"_ns.Equals(aProvider) && !"google"_ns.Equals(aProvider) &&
478 !"google4"_ns.Equals(aProvider) && !"google5"_ns.Equals(aProvider) &&
479 !"baidu"_ns.Equals(aProvider) && !"mozcn"_ns.Equals(aProvider) &&
480 !"yandex"_ns.Equals(aProvider) &&
481 !nsLiteralCString(TESTING_TABLE_PROVIDER_NAME"test").Equals(aProvider)) {
482 aProvider.AssignLiteral("other");
483 }
484
485 return NS_OK;
486}
487
488NS_IMETHODIMPnsresult
489nsUrlClassifierUtils::GetProtocolVersion(const nsACString& aProvider,
490 nsACString& aVersion) {
491 nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID"@mozilla.org/preferences-service;1");
492 if (prefBranch) {
493 nsPrintfCString prefName("browser.safebrowsing.provider.%s.pver",
494 nsCString(aProvider).get());
495 nsAutoCString version;
496 nsresult rv = prefBranch->GetCharPref(prefName.get(), version);
497
498 aVersion = NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) ? version.get() : DEFAULT_PROTOCOL_VERSION"2.2";
499 } else {
500 aVersion = DEFAULT_PROTOCOL_VERSION"2.2";
501 }
502
503 return NS_OK;
504}
505
506NS_IMETHODIMPnsresult
507nsUrlClassifierUtils::MakeUpdateRequestV4(
508 const nsTArray<nsCString>& aListNames,
509 const nsTArray<nsCString>& aStatesBase64, nsACString& aRequest) {
510 using namespace mozilla::safebrowsing;
511
512 if (aListNames.Length() != aStatesBase64.Length()) {
513 return NS_ERROR_INVALID_ARG;
514 }
515
516 FetchThreatListUpdatesRequest r;
517 r.set_allocated_client(CreateClientInfo());
518
519 for (uint32_t i = 0; i < aListNames.Length(); i++) {
520 uint32_t threatType;
521 nsresult rv = ConvertListNameToThreatType(aListNames[i], &threatType);
522 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
523 continue; // Unknown list name.
524 }
525 if (!IsAllowedOnCurrentPlatform(threatType)) {
526 NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString( "Threat type %d (%s) is unsupported on current platform: %d"
, threatType, aListNames[i].get(), GetPlatformType()) .get(),
nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 530)
527 nsPrintfCString(NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString( "Threat type %d (%s) is unsupported on current platform: %d"
, threatType, aListNames[i].get(), GetPlatformType()) .get(),
nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 530)
528 "Threat type %d (%s) is unsupported on current platform: %d",NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString( "Threat type %d (%s) is unsupported on current platform: %d"
, threatType, aListNames[i].get(), GetPlatformType()) .get(),
nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 530)
529 threatType, aListNames[i].get(), GetPlatformType())NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString( "Threat type %d (%s) is unsupported on current platform: %d"
, threatType, aListNames[i].get(), GetPlatformType()) .get(),
nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 530)
530 .get())NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString( "Threat type %d (%s) is unsupported on current platform: %d"
, threatType, aListNames[i].get(), GetPlatformType()) .get(),
nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 530)
;
531 continue; // Some threat types are not available on some platforms.
532 }
533 auto lur = r.mutable_list_update_requests()->Add();
534 InitListUpdateRequest(static_cast<ThreatType>(threatType), aStatesBase64[i],
535 lur);
536 }
537
538 // Then serialize.
539 std::string s;
540 (void)r.SerializeToString(&s);
541
542 nsCString out;
543 nsresult rv = Base64URLEncode(s.size(), (const uint8_t*)s.c_str(),
544 Base64URLEncodePaddingPolicy::Include, out);
545 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 545); return rv; } } while (false)
;
546
547 aRequest = std::move(out);
548
549 return NS_OK;
550}
551
552NS_IMETHODIMPnsresult
553nsUrlClassifierUtils::MakeUpdateRequestV5(
554 const nsTArray<nsCString>& aListNames,
555 const nsTArray<nsCString>& aStatesBase64, nsACString& aRequest) {
556 using namespace mozilla::safebrowsing::v5;
557
558 // Verify the number of list names and states are the same.
559 if (aListNames.Length() != aStatesBase64.Length()) {
560 return NS_ERROR_INVALID_ARG;
561 }
562
563 nsTArray<nsCString> serverListNames;
564
565 // Fill the request with list names and states.
566 for (uint32_t i = 0; i < aListNames.Length(); i++) {
567 nsAutoCString serverListName;
568 nsresult rv =
569 ConvertLocalListNameToServerListNameV5(aListNames[i], serverListName);
570 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
571 continue;
572 }
573
574 serverListNames.AppendElement(std::move(serverListName));
575 }
576
577 // We omit the size_constraints to indicates that there is no size constraints
578 // for the request.
579
580 // Then serialize into query parameters.
581 nsAutoCString query;
582
583 for (const auto& listName : serverListNames) {
584 query.Append("&names=");
585 query.Append(listName);
586 }
587
588 for (const auto& stateBase64 : aStatesBase64) {
589 query.Append("&version=");
590 query.Append(stateBase64);
591 }
592
593 aRequest = std::move(query);
594
595 return NS_OK;
596}
597
598NS_IMETHODIMPnsresult
599nsUrlClassifierUtils::MakeFindFullHashRequestV4(
600 const nsTArray<nsCString>& aListNames,
601 const nsTArray<nsCString>& aListStatesBase64,
602 const nsTArray<nsCString>& aPrefixesBase64, nsACString& aRequest) {
603 if (aListNames.Length() != aListStatesBase64.Length()) {
604 return NS_ERROR_INVALID_ARG;
605 }
606
607 FindFullHashesRequest r;
608 r.set_allocated_client(CreateClientInfo());
609
610 nsresult rv;
611
612 //-------------------------------------------------------------------
613 // Set up FindFullHashesRequest.threat_info.
614 auto threatInfo = r.mutable_threat_info();
615
616 PlatformType platform = GetPlatformType();
617
618 // 1) Set threat types.
619 for (uint32_t i = 0; i < aListNames.Length(); i++) {
620 // Add threat types.
621 uint32_t threatType;
622 rv = ConvertListNameToThreatType(aListNames[i], &threatType);
623 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 623); return rv; } } while (false)
;
624 if (!IsAllowedOnCurrentPlatform(threatType)) {
625 NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString( "Threat type %d (%s) is unsupported on current platform: %d"
, threatType, aListNames[i].get(), GetPlatformType()) .get(),
nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 629)
626 nsPrintfCString(NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString( "Threat type %d (%s) is unsupported on current platform: %d"
, threatType, aListNames[i].get(), GetPlatformType()) .get(),
nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 629)
627 "Threat type %d (%s) is unsupported on current platform: %d",NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString( "Threat type %d (%s) is unsupported on current platform: %d"
, threatType, aListNames[i].get(), GetPlatformType()) .get(),
nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 629)
628 threatType, aListNames[i].get(), GetPlatformType())NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString( "Threat type %d (%s) is unsupported on current platform: %d"
, threatType, aListNames[i].get(), GetPlatformType()) .get(),
nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 629)
629 .get())NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString( "Threat type %d (%s) is unsupported on current platform: %d"
, threatType, aListNames[i].get(), GetPlatformType()) .get(),
nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 629)
;
630 continue;
631 }
632 threatInfo->add_threat_types((ThreatType)threatType);
633
634#if defined(ANDROID)
635 // Temporary hack to fix bug 1441345.
636 if (((ThreatType)threatType == SOCIAL_ENGINEERING_PUBLIC) ||
637 ((ThreatType)threatType == SOCIAL_ENGINEERING)) {
638 platform = LINUX_PLATFORM;
639 }
640#endif
641
642 // Add client states for index 'i' only when the threat type is available
643 // on current platform.
644 nsCString stateBinary;
645 rv = Base64Decode(aListStatesBase64[i], stateBinary);
646 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 646); return rv; } } while (false)
;
647 r.add_client_states(stateBinary.get(), stateBinary.Length());
648 }
649
650 // 2) Set platform type.
651 threatInfo->add_platform_types(platform);
652
653 // 3) Set threat entry type.
654 threatInfo->add_threat_entry_types(URL);
655
656 // 4) Set threat entries.
657 for (const nsCString& prefix : aPrefixesBase64) {
658 nsCString prefixBinary;
659 rv = Base64Decode(prefix, prefixBinary);
Value stored to 'rv' is never read
660 threatInfo->add_threat_entries()->set_hash(prefixBinary.get(),
661 prefixBinary.Length());
662 }
663 //-------------------------------------------------------------------
664
665 // Then serialize.
666 std::string s;
667 (void)r.SerializeToString(&s);
668
669 nsCString out;
670 rv = Base64URLEncode(s.size(), (const uint8_t*)s.c_str(),
671 Base64URLEncodePaddingPolicy::Include, out);
672 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 672); return rv; } } while (false)
;
673
674 aRequest = std::move(out);
675
676 return NS_OK;
677}
678
679NS_IMETHODIMPnsresult
680nsUrlClassifierUtils::MakeFindFullHashRequestV5(
681 const nsTArray<nsCString>& aHashPrefixes, nsACString& aRequest) {
682 if (aHashPrefixes.IsEmpty()) {
683 return NS_ERROR_INVALID_ARG;
684 }
685
686 aRequest.Truncate();
687
688 // See
689 // https://developers.google.com/safe-browsing/reference/rest/v5/hashes/search
690 // for the query parameter format.
691 for (uint32_t i = 0; i < aHashPrefixes.Length(); i++) {
692 aRequest.AppendLiteral("hashPrefixes=");
693 aRequest.Append(aHashPrefixes[i]);
694 if (i != aHashPrefixes.Length() - 1) {
695 aRequest.AppendLiteral("&");
696 }
697 }
698
699 return NS_OK;
700}
701
702// Remove ref, query, userpass, anypart which may contain sensitive data
703static nsresult GetSpecWithoutSensitiveData(nsIURI* aUri, nsACString& aSpec) {
704 if (NS_WARN_IF(!aUri)NS_warn_if_impl(!aUri, "!aUri", "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 704)
) {
705 return NS_ERROR_INVALID_ARG;
706 }
707
708 nsresult rv;
709 nsCOMPtr<nsIURL> url(do_QueryInterface(aUri));
710 if (url) {
711 nsCOMPtr<nsIURI> clone;
712 rv = NS_MutateURI(url)
713 .SetQuery(""_ns)
714 .SetRef(""_ns)
715 .SetUserPass(""_ns)
716 .Finalize(clone);
717 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 717); return rv; } } while (false)
;
718 rv = clone->GetAsciiSpec(aSpec);
719 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 719); return rv; } } while (false)
;
720 }
721 return NS_OK;
722}
723
724static nsresult AddThreatSourceFromChannel(ThreatHit& aHit,
725 nsIChannel* aChannel,
726 ThreatHit_ThreatSourceType aType) {
727 if (NS_WARN_IF(!aChannel)NS_warn_if_impl(!aChannel, "!aChannel", "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 727)
) {
728 return NS_ERROR_INVALID_ARG;
729 }
730
731 nsresult rv;
732
733 auto matchingSource = aHit.add_resources();
734 matchingSource->set_type(aType);
735
736 nsCOMPtr<nsIURI> uri;
737 rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
738 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 738); return rv; } } while (false)
;
739
740 nsCString spec;
741 rv = GetSpecWithoutSensitiveData(uri, spec);
742 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 742); return rv; } } while (false)
;
743 matchingSource->set_url(spec.get());
744
745 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
746 if (httpChannel) {
747 nsCOMPtr<nsIReferrerInfo> referrerInfo = httpChannel->GetReferrerInfo();
748 if (referrerInfo) {
749 nsAutoCString referrerSpec;
750 nsCOMPtr<nsIURI> referrer = referrerInfo->GetComputedReferrer();
751 if (referrer) {
752 rv = GetSpecWithoutSensitiveData(referrer, referrerSpec);
753 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 753); return rv; } } while (false)
;
754 matchingSource->set_referrer(referrerSpec.get());
755 }
756 }
757 }
758
759 nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal =
760 do_QueryInterface(aChannel);
761 if (httpChannelInternal) {
762 nsCString remoteIp;
763 rv = httpChannelInternal->GetRemoteAddress(remoteIp);
764 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !remoteIp.IsEmpty()) {
765 matchingSource->set_remote_ip(remoteIp.get());
766 }
767 }
768 return NS_OK;
769}
770static nsresult AddThreatSourceFromRedirectEntry(
771 ThreatHit& aHit, nsIRedirectHistoryEntry* aRedirectEntry,
772 ThreatHit_ThreatSourceType aType) {
773 if (NS_WARN_IF(!aRedirectEntry)NS_warn_if_impl(!aRedirectEntry, "!aRedirectEntry", "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 773)
) {
774 return NS_ERROR_INVALID_ARG;
775 }
776
777 nsresult rv;
778
779 nsCOMPtr<nsIPrincipal> principal;
780 rv = aRedirectEntry->GetPrincipal(getter_AddRefs(principal));
781 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 781); return rv; } } while (false)
;
782 nsCString spec;
783 rv = principal->GetExposableSpec(spec);
784 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 784); return rv; } } while (false)
;
785 auto source = aHit.add_resources();
786 source->set_url(spec.get());
787 source->set_type(aType);
788
789 nsCOMPtr<nsIURI> referrer;
790 rv = aRedirectEntry->GetReferrerURI(getter_AddRefs(referrer));
791 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && referrer) {
792 nsCString referrerSpec;
793 rv = GetSpecWithoutSensitiveData(referrer, referrerSpec);
794 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 794); return rv; } } while (false)
;
795 source->set_referrer(referrerSpec.get());
796 }
797
798 nsCString remoteIp;
799 rv = aRedirectEntry->GetRemoteAddress(remoteIp);
800 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !remoteIp.IsEmpty()) {
801 source->set_remote_ip(remoteIp.get());
802 }
803 return NS_OK;
804}
805
806// Add top level tab url and redirect threatsources to threatHit message
807static nsresult AddTabThreatSources(ThreatHit& aHit, nsIChannel* aChannel) {
808 if (NS_WARN_IF(!aChannel)NS_warn_if_impl(!aChannel, "!aChannel", "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 808)
) {
809 return NS_ERROR_INVALID_ARG;
810 }
811
812 nsresult rv;
813 nsCOMPtr<mozIDOMWindowProxy> win;
814 nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
815 do_GetService(THIRDPARTYUTIL_CONTRACTID"@mozilla.org/thirdpartyutil;1", &rv);
816 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 816); return rv; } } while (false)
;
817
818 rv = thirdPartyUtil->GetTopWindowForChannel(aChannel, nullptr,
819 getter_AddRefs(win));
820 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 820); return rv; } } while (false)
;
821
822 auto* pwin = nsPIDOMWindowOuter::From(win);
823 nsCOMPtr<nsIDocShell> docShell = pwin->GetDocShell();
824 if (!docShell) {
825 return NS_OK;
826 }
827
828 nsCOMPtr<nsIChannel> topChannel;
829 docShell->GetCurrentDocumentChannel(getter_AddRefs(topChannel));
830 if (!topChannel) {
831 return NS_OK;
832 }
833
834 nsCOMPtr<nsIURI> uri;
835 rv = aChannel->GetURI(getter_AddRefs(uri));
836 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 836); return rv; } } while (false)
;
837
838 nsCOMPtr<nsIURI> topUri;
839 rv = topChannel->GetURI(getter_AddRefs(topUri));
840 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 840); return rv; } } while (false)
;
841
842 bool isTopUri = false;
843 rv = topUri->Equals(uri, &isTopUri);
844 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !isTopUri) {
845 nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
846 if (loadInfo->RedirectChain().Length()) {
847 AddThreatSourceFromRedirectEntry(aHit, loadInfo->RedirectChain()[0],
848 ThreatHit_ThreatSourceType_TAB_RESOURCE);
849 }
850 }
851
852 // Set top level tab_url threat source
853 rv = AddThreatSourceFromChannel(aHit, topChannel,
854 ThreatHit_ThreatSourceType_TAB_URL);
855 (void)NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 855)
;
856
857 // Set tab_redirect threat sources if there's any
858 nsCOMPtr<nsILoadInfo> topLoadInfo = topChannel->LoadInfo();
859 nsIRedirectHistoryEntry* redirectEntry;
860 size_t length = topLoadInfo->RedirectChain().Length();
861 for (size_t i = 0; i < length; i++) {
862 redirectEntry = topLoadInfo->RedirectChain()[i];
863 AddThreatSourceFromRedirectEntry(aHit, redirectEntry,
864 ThreatHit_ThreatSourceType_TAB_REDIRECT);
865 }
866
867 return NS_OK;
868}
869
870NS_IMETHODIMPnsresult
871nsUrlClassifierUtils::MakeThreatHitReport(nsIChannel* aChannel,
872 const nsACString& aListName,
873 const nsACString& aHashBase64,
874 nsACString& aRequest) {
875 if (NS_WARN_IF(aListName.IsEmpty())NS_warn_if_impl(aListName.IsEmpty(), "aListName.IsEmpty()", "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 875)
|| NS_WARN_IF(aHashBase64.IsEmpty())NS_warn_if_impl(aHashBase64.IsEmpty(), "aHashBase64.IsEmpty()"
, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 875)
||
876 NS_WARN_IF(!aChannel)NS_warn_if_impl(!aChannel, "!aChannel", "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 876)
) {
877 return NS_ERROR_INVALID_ARG;
878 }
879
880 ThreatHit hit;
881 nsresult rv;
882
883 uint32_t threatType;
884 rv = ConvertListNameToThreatType(aListName, &threatType);
885 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 885); return rv; } } while (false)
;
886 hit.set_threat_type(static_cast<ThreatType>(threatType));
887
888 hit.set_platform_type(GetPlatformType());
889
890 nsCString hash;
891 rv = Base64Decode(aHashBase64, hash);
892 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || hash.Length() != COMPLETE_SIZE32) {
893 return NS_ERROR_FAILURE;
894 }
895
896 auto threatEntry = hit.mutable_entry();
897 threatEntry->set_hash(hash.get(), hash.Length());
898
899 // Set matching source
900 rv = AddThreatSourceFromChannel(hit, aChannel,
901 ThreatHit_ThreatSourceType_MATCHING_URL);
902 (void)NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 902)
;
903 // Set tab url, tab resource url and redirect sources
904 rv = AddTabThreatSources(hit, aChannel);
905 (void)NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 905)
;
906
907 hit.set_allocated_client_info(CreateClientInfo());
908
909 std::string s;
910 (void)hit.SerializeToString(&s);
911
912 nsCString out;
913 rv = Base64URLEncode(s.size(), reinterpret_cast<const uint8_t*>(s.c_str()),
914 Base64URLEncodePaddingPolicy::Include, out);
915 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 915); return rv; } } while (false)
;
916
917 aRequest = std::move(out);
918
919 return NS_OK;
920}
921
922static uint32_t DurationToMs(const Duration& aDuration) {
923 // Seconds precision is good enough. Ignore nanoseconds like Chrome does.
924 return aDuration.seconds() * 1000;
925}
926
927NS_IMETHODIMPnsresult
928nsUrlClassifierUtils::ParseFindFullHashResponseV4(
929 const nsACString& aResponse,
930 nsIUrlClassifierParseFindFullHashCallback* aCallback) {
931 enum CompletionErrorType {
932 SUCCESS = 0,
933 PARSING_FAILURE = 1,
934 UNKNOWN_THREAT_TYPE = 2,
935 };
936
937 FindFullHashesResponse r;
938 if (!r.ParseFromArray(aResponse.BeginReading(), aResponse.Length())) {
939 NS_WARNING("Invalid response")NS_DebugBreak(NS_DEBUG_WARNING, "Invalid response", nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 939)
;
940 glean::urlclassifier::completion_error.AccumulateSingleSample(
941 PARSING_FAILURE);
942 return NS_ERROR_FAILURE;
943 }
944
945 bool hasUnknownThreatType = false;
946
947 for (auto& m : r.matches()) {
948 nsCString tableNames;
949 nsresult rv = ConvertThreatTypeToListNames(m.threat_type(), tableNames);
950 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
951 hasUnknownThreatType = true;
952 continue; // Ignore un-convertable threat type.
953 }
954 auto& hash = m.threat().hash();
955 auto cacheDurationSec = m.cache_duration().seconds();
956 aCallback->OnCompleteHashFound(
957 nsDependentCString(hash.c_str(), hash.length()), tableNames,
958 cacheDurationSec);
959 }
960
961 auto minWaitDuration = DurationToMs(r.minimum_wait_duration());
962 auto negCacheDurationSec = r.negative_cache_duration().seconds();
963
964 aCallback->OnResponseParsed(minWaitDuration, negCacheDurationSec);
965
966 glean::urlclassifier::completion_error.AccumulateSingleSample(
967 hasUnknownThreatType ? UNKNOWN_THREAT_TYPE : SUCCESS);
968 return NS_OK;
969}
970
971NS_IMETHODIMPnsresult
972nsUrlClassifierUtils::ParseFindFullHashResponseV5(
973 const nsACString& aResponse,
974 nsIUrlClassifierParseFindFullHashCallback* aCallback) {
975 v5::SearchHashesResponse response;
976
977 if (!response.ParseFromArray(aResponse.BeginReading(), aResponse.Length())) {
978 NS_WARNING("Invalid V5 find full hash response")NS_DebugBreak(NS_DEBUG_WARNING, "Invalid V5 find full hash response"
, nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 978)
;
979 return NS_ERROR_FAILURE;
980 }
981
982 auto cacheDurationSec = response.cache_duration().seconds();
983
984 for (auto& fullHash : response.full_hashes()) {
985 auto& hash = fullHash.full_hash();
986
987 nsAutoCString tableNames;
988
989 for (auto& fullHashDetail : fullHash.full_hash_details()) {
990 const auto& threatType = fullHashDetail.threat_type();
991
992 nsresult rv = ConvertThreatTypeToListNamesV5(threatType, tableNames);
993 // Ignore un-convertable threat type.
994 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
995 continue;
996 }
997 }
998
999 aCallback->OnCompleteHashFound(
1000 nsDependentCString(hash.c_str(), hash.length()), tableNames,
1001 cacheDurationSec);
1002 }
1003
1004 // In V5, the hashes::search API use the single cache duration for all. There
1005 // is no negative_cache_duration field in the response. In addition, the field
1006 // 'minimum_wait_duration' is not present in the response, which means the
1007 // client can always issue a new request on an as-needed basis. Therefore, we
1008 // set the value to 0.
1009 aCallback->OnResponseParsed(0, cacheDurationSec);
1010
1011 return NS_OK;
1012}
1013
1014//////////////////////////////////////////////////////////
1015// nsIObserver
1016
1017NS_IMETHODIMPnsresult
1018nsUrlClassifierUtils::Observe(nsISupports* aSubject, const char* aTopic,
1019 const char16_t* aData) {
1020 if (0 == strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID"nsPref:changed")) {
1021 MutexAutoLock lock(mProviderDictLock);
1022 return ReadProvidersFromPrefs(mProviderDict);
1023 }
1024
1025 if (0 == strcmp(aTopic, "xpcom-shutdown-threads")) {
1026 nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID"@mozilla.org/preferences-service;1");
1027 NS_ENSURE_TRUE(prefs, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(prefs)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "prefs" ") failed", nullptr
, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 1027); return NS_ERROR_FAILURE; } } while (false)
;
1028 return prefs->RemoveObserver("browser.safebrowsing", this);
1029 }
1030
1031 return NS_ERROR_UNEXPECTED;
1032}
1033
1034/////////////////////////////////////////////////////////////////////////////
1035// non-interface methods
1036
1037nsresult nsUrlClassifierUtils::ReadProvidersFromPrefs(ProviderDictType& aDict) {
1038 MOZ_ASSERT(NS_IsMainThread(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "ReadProvidersFromPrefs must be on main thread" ")", "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 1039); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "ReadProvidersFromPrefs must be on main thread" ")"); do
{ MOZ_CrashSequence(__null, 1039); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
1039 "ReadProvidersFromPrefs must be on main thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "ReadProvidersFromPrefs must be on main thread" ")", "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 1039); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "ReadProvidersFromPrefs must be on main thread" ")"); do
{ MOZ_CrashSequence(__null, 1039); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
1040
1041 nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID"@mozilla.org/preferences-service;1");
1042 NS_ENSURE_TRUE(prefs, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(prefs)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "prefs" ") failed", nullptr
, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 1042); return NS_ERROR_FAILURE; } } while (false)
;
1043 nsCOMPtr<nsIPrefBranch> prefBranch;
1044 nsresult rv = prefs->GetBranch("browser.safebrowsing.provider.",
1045 getter_AddRefs(prefBranch));
1046 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 1046); return rv; } } while (false)
;
1047
1048 // We've got a pref branch for "browser.safebrowsing.provider.".
1049 // Enumerate all children prefs and parse providers.
1050 nsTArray<nsCString> childArray;
1051 rv = prefBranch->GetChildList("", childArray);
1052 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/nsUrlClassifierUtils.cpp"
, 1052); return rv; } } while (false)
;
1053
1054 // Collect providers from childArray.
1055 nsTHashSet<nsCString> providers;
1056 for (auto& child : childArray) {
1057 auto dotPos = child.FindChar('.');
1058 if (dotPos < 0) {
1059 continue;
1060 }
1061
1062 nsDependentCSubstring provider = Substring(child, 0, dotPos);
1063
1064 providers.Insert(provider);
1065 }
1066
1067 // Sort the providers to ensure the google5 provider is always after the
1068 // google4 provider.
1069 nsTArray<nsCString> sortedProviders;
1070 for (auto& provider : providers) {
1071 sortedProviders.AppendElement(provider);
1072 }
1073 sortedProviders.Sort();
1074
1075 bool isGoogle5Enabled = mozilla::Preferences::GetBool(
1076 "browser.safebrowsing.provider.google5.enabled");
1077
1078 // Now we have all providers. Check which one owns |aTableName|.
1079 // e.g. The owning lists of provider "google" is defined in
1080 // "browser.safebrowsing.provider.google.lists".
1081 for (const auto& provider : sortedProviders) {
1082 nsPrintfCString owninListsPref("%s.lists", provider.get());
1083
1084 nsAutoCString owningLists;
1085 nsresult rv = prefBranch->GetCharPref(owninListsPref.get(), owningLists);
1086 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1087 continue;
1088 }
1089
1090 // We've got the owning lists (represented as string) of |provider|.
1091 // Build the dictionary for the owning list and the current provider.
1092 nsTArray<nsCString> tables;
1093 Classifier::SplitTables(owningLists, tables);
1094 nsAutoCString providerToUse(provider);
1095 for (const auto& tableName : tables) {
1096 // If the Safe Browsing V5 is disabled, we will use V4 instead. This means
1097 // that we will put the V5 lists to the V4 provider to instruct using
1098 // Safe Browsing V4 for those tables.
1099 if (!isGoogle5Enabled && providerToUse.EqualsLiteral("google5")) {
1100 providerToUse.AssignLiteral("google4");
1101 }
1102 aDict.InsertOrUpdate(tableName, MakeUnique<nsCString>(providerToUse));
1103 }
1104 }
1105
1106 return NS_OK;
1107}
1108
1109nsresult nsUrlClassifierUtils::CanonicalizeHostname(const nsACString& hostname,
1110 nsACString& _retval) {
1111 nsAutoCString unescaped;
1112 if (!NS_UnescapeURL(PromiseFlatCStringTPromiseFlatString<char>(hostname).get(),
1113 PromiseFlatCStringTPromiseFlatString<char>(hostname).Length(), 0, unescaped)) {
1114 unescaped.Assign(hostname);
1115 }
1116
1117 nsAutoCString cleaned;
1118 CleanupHostname(unescaped, cleaned);
1119
1120 nsAutoCString temp;
1121 ParseIPAddress(cleaned, temp);
1122 if (!temp.IsEmpty()) {
1123 cleaned.Assign(temp);
1124 }
1125
1126 ToLowerCase(cleaned);
1127 SpecialEncode(cleaned, false, _retval);
1128
1129 return NS_OK;
1130}
1131
1132nsresult nsUrlClassifierUtils::CanonicalizePath(const nsACString& path,
1133 nsACString& _retval) {
1134 _retval.Truncate();
1135
1136 nsAutoCString decodedPath(path);
1137 nsAutoCString temp;
1138 while (NS_UnescapeURL(decodedPath.get(), decodedPath.Length(), 0, temp)) {
1139 decodedPath.Assign(temp);
1140 temp.Truncate();
1141 }
1142
1143 SpecialEncode(decodedPath, true, _retval);
1144 // XXX: lowercase the path?
1145
1146 return NS_OK;
1147}
1148
1149nsresult nsUrlClassifierUtils::CanonicalizeQuery(const nsACString& query,
1150 nsACString& _retval) {
1151 _retval.Truncate();
1152 _retval.Append('?');
1153
1154 // Unescape the query
1155 nsAutoCString unescaped;
1156 if (!NS_UnescapeURL(PromiseFlatCStringTPromiseFlatString<char>(query).get(),
1157 PromiseFlatCStringTPromiseFlatString<char>(query).Length(), 0, unescaped)) {
1158 unescaped.Assign(query);
1159 }
1160
1161 // slash folding does not apply to the query parameters, but we need to
1162 // percent-escape all characters that are <= ASCII 32, >= 127, "#", or "%"
1163 SpecialEncode(unescaped, false, _retval);
1164
1165 return NS_OK;
1166}
1167
1168void nsUrlClassifierUtils::CleanupHostname(const nsACString& hostname,
1169 nsACString& _retval) {
1170 _retval.Truncate();
1171
1172 const char* curChar = hostname.BeginReading();
1173 const char* end = hostname.EndReading();
1174 char lastChar = '\0';
1175 while (curChar != end) {
1176 unsigned char c = static_cast<unsigned char>(*curChar);
1177 if (c == '.' && (lastChar == '\0' || lastChar == '.')) {
1178 // skip
1179 } else {
1180 _retval.Append(*curChar);
1181 }
1182 lastChar = c;
1183 ++curChar;
1184 }
1185
1186 // cut off trailing dots
1187 while (_retval.Length() > 0 && _retval[_retval.Length() - 1] == '.') {
1188 _retval.SetLength(_retval.Length() - 1);
1189 }
1190}
1191
1192void nsUrlClassifierUtils::ParseIPAddress(const nsACString& host,
1193 nsACString& _retval) {
1194 _retval.Truncate();
1195 nsACString::const_iterator iter, end;
1196 host.BeginReading(iter);
1197 host.EndReading(end);
1198
1199 if (host.Length() <= 15) {
1200 // The Windows resolver allows a 4-part dotted decimal IP address to
1201 // have a space followed by any old rubbish, so long as the total length
1202 // of the string doesn't get above 15 characters. So, "10.192.95.89 xy"
1203 // is resolved to 10.192.95.89.
1204 // If the string length is greater than 15 characters, e.g.
1205 // "10.192.95.89 xy.wildcard.example.com", it will be resolved through
1206 // DNS.
1207
1208 if (FindCharInReadable(' ', iter, end)) {
1209 end = iter;
1210 }
1211 }
1212
1213 for (host.BeginReading(iter); iter != end; iter++) {
1214 if (!(mozilla::IsAsciiHexDigit(*iter) || *iter == 'x' || *iter == 'X' ||
1215 *iter == '.')) {
1216 // not an IP
1217 return;
1218 }
1219 }
1220
1221 host.BeginReading(iter);
1222 nsTArray<nsCString> parts;
1223 ParseString(PromiseFlatCStringTPromiseFlatString<char>(Substring(iter, end)), '.', parts);
1224 if (parts.Length() > 4) {
1225 return;
1226 }
1227
1228 // If any potentially-octal numbers (start with 0 but not hex) have
1229 // non-octal digits, no part of the ip can be in octal
1230 // XXX: this came from the old javascript implementation, is it really
1231 // supposed to be like this?
1232 bool allowOctal = true;
1233 uint32_t i;
1234
1235 for (i = 0; i < parts.Length(); i++) {
1236 const nsCString& part = parts[i];
1237 if (part[0] == '0') {
1238 for (uint32_t j = 1; j < part.Length(); j++) {
1239 if (part[j] == 'x') {
1240 break;
1241 }
1242 if (part[j] == '8' || part[j] == '9') {
1243 allowOctal = false;
1244 break;
1245 }
1246 }
1247 }
1248 }
1249
1250 for (i = 0; i < parts.Length(); i++) {
1251 nsAutoCString canonical;
1252
1253 if (i == parts.Length() - 1) {
1254 CanonicalNum(parts[i], 5 - parts.Length(), allowOctal, canonical);
1255 } else {
1256 CanonicalNum(parts[i], 1, allowOctal, canonical);
1257 }
1258
1259 if (canonical.IsEmpty()) {
1260 _retval.Truncate();
1261 return;
1262 }
1263
1264 if (_retval.IsEmpty()) {
1265 _retval.Assign(canonical);
1266 } else {
1267 _retval.Append('.');
1268 _retval.Append(canonical);
1269 }
1270 }
1271}
1272
1273void nsUrlClassifierUtils::CanonicalNum(const nsACString& num, uint32_t bytes,
1274 bool allowOctal, nsACString& _retval) {
1275 _retval.Truncate();
1276
1277 if (num.Length() < 1) {
1278 return;
1279 }
1280
1281 uint32_t val;
1282 if (allowOctal && IsOctal(num)) {
1283 if (PR_sscanf(PromiseFlatCStringTPromiseFlatString<char>(num).get(), "%o", &val) != 1) {
1284 return;
1285 }
1286 } else if (IsDecimal(num)) {
1287 if (PR_sscanf(PromiseFlatCStringTPromiseFlatString<char>(num).get(), "%u", &val) != 1) {
1288 return;
1289 }
1290 } else if (IsHex(num)) {
1291 if (PR_sscanf(PromiseFlatCStringTPromiseFlatString<char>(num).get(),
1292 num[1] == 'X' ? "0X%x" : "0x%x", &val) != 1) {
1293 return;
1294 }
1295 } else {
1296 return;
1297 }
1298
1299 while (bytes--) {
1300 char buf[20];
1301 SprintfLiteral(buf, "%u", val & 0xff);
1302 if (_retval.IsEmpty()) {
1303 _retval.Assign(buf);
1304 } else {
1305 _retval = nsDependentCString(buf) + "."_ns + _retval;
1306 }
1307 val >>= 8;
1308 }
1309}
1310
1311// This function will encode all "special" characters in typical url
1312// encoding, that is %hh where h is a valid hex digit. It will also fold
1313// any duplicated slashes.
1314bool nsUrlClassifierUtils::SpecialEncode(const nsACString& url,
1315 bool foldSlashes,
1316 nsACString& _retval) {
1317 bool changed = false;
1318 const char* curChar = url.BeginReading();
1319 const char* end = url.EndReading();
1320
1321 unsigned char lastChar = '\0';
1322 while (curChar != end) {
1323 unsigned char c = static_cast<unsigned char>(*curChar);
1324 if (ShouldURLEscape(c)) {
1325 _retval.Append('%');
1326 _retval.Append(int_to_hex_digit(c / 16));
1327 _retval.Append(int_to_hex_digit(c % 16));
1328
1329 changed = true;
1330 } else if (foldSlashes && (c == '/' && lastChar == '/')) {
1331 // skip
1332 } else {
1333 _retval.Append(*curChar);
1334 }
1335 lastChar = c;
1336 curChar++;
1337 }
1338 return changed;
1339}
1340
1341bool nsUrlClassifierUtils::ShouldURLEscape(const unsigned char c) const {
1342 return c <= 32 || c == '%' || c == '#' || c >= 127;
1343}
1344
1345// moztest- tables are built-in created in LookupCache, they contain hardcoded
1346// url entries in it. moztest tables don't support updates.
1347// static
1348bool nsUrlClassifierUtils::IsMozTestTable(const nsACString& aTableName) {
1349 return StringBeginsWith(aTableName, "moztest-"_ns);
1350}
1351
1352// test- tables are used by testcases and can add custom test entries
1353// through update API.
1354// static
1355bool nsUrlClassifierUtils::IsTestTable(const nsACString& aTableName) {
1356 return IsMozTestTable(aTableName) || StringBeginsWith(aTableName, "test"_ns);
1357}
1358
1359bool nsUrlClassifierUtils::IsInSafeMode() {
1360 static Maybe<bool> sIsInSafeMode;
1361
1362 if (!sIsInSafeMode.isSome()) {
1363 nsCOMPtr<nsIXULRuntime> appInfo =
1364 do_GetService("@mozilla.org/xre/runtime;1");
1365 if (appInfo) {
1366 bool inSafeMode = false;
1367 appInfo->GetInSafeMode(&inSafeMode);
1368 sIsInSafeMode.emplace(inSafeMode);
1369 }
1370 }
1371
1372 return sIsInSafeMode.value();
1373}