diff --git a/build/patches/00Internal-firewall.patch b/build/patches/00Internal-firewall.patch new file mode 100644 index 00000000..faa92500 --- /dev/null +++ b/build/patches/00Internal-firewall.patch @@ -0,0 +1,1753 @@ +From: uazo +Date: Sat, 15 Apr 2023 11:48:49 +0000 +Subject: Internal firewall + +Introduces a kind of firewall on http calls made by the +browser that allows selective blocking via the NetworkTrafficAnnotationTag. +allowed or explicitly blocked calls are defined +in services/firewall/tools/rules.xml +--- + chrome/browser/BUILD.gn | 1 + + chrome/browser/about_flags.cc | 6 + + .../downloads/offline_page_download_bridge.cc | 32 +- + .../content/internal/context_menu_download.cc | 32 +- + .../android/webapk/webapk_icon_hasher.cc | 32 +- + net/BUILD.gn | 1 + + .../network_traffic_annotation.h | 4 - + net/url_request/url_request_http_job.cc | 15 + + net/url_request/url_request_http_job.h | 3 + + services/firewall/public/BUILD.gn | 70 +++ + services/firewall/public/firewall_features.cc | 28 ++ + services/firewall/public/firewall_features.h | 31 ++ + services/firewall/public/firewall_service.cc | 46 ++ + services/firewall/public/firewall_service.h | 57 +++ + services/firewall/tools/annotation_model.py | 49 ++ + services/firewall/tools/annotations.xml | 448 ++++++++++++++++++ + services/firewall/tools/builders_template.py | 72 +++ + services/firewall/tools/codegen.py | 82 ++++ + services/firewall/tools/decode_template.py | 85 ++++ + services/firewall/tools/gen_builders.py | 65 +++ + services/firewall/tools/rules.xml | 70 +++ + services/firewall/tools/rules_model.py | 35 ++ + .../network/public/cpp/simple_url_loader.cc | 18 + + .../network/public/cpp/simple_url_loader.h | 3 + + .../loader/fetch/url_loader/url_loader.cc | 145 +++++- + .../scripts/auditor/auditor.py | 1 + + .../scripts/auditor/util.py | 1 + + 27 files changed, 1416 insertions(+), 16 deletions(-) + create mode 100644 services/firewall/public/BUILD.gn + create mode 100644 services/firewall/public/firewall_features.cc + create mode 100644 services/firewall/public/firewall_features.h + create mode 100644 services/firewall/public/firewall_service.cc + create mode 100644 services/firewall/public/firewall_service.h + create mode 100644 services/firewall/tools/annotation_model.py + create mode 100644 services/firewall/tools/annotations.xml + create mode 100644 services/firewall/tools/builders_template.py + create mode 100644 services/firewall/tools/codegen.py + create mode 100644 services/firewall/tools/decode_template.py + create mode 100644 services/firewall/tools/gen_builders.py + create mode 100644 services/firewall/tools/rules.xml + create mode 100644 services/firewall/tools/rules_model.py + +diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn +--- a/chrome/browser/BUILD.gn ++++ b/chrome/browser/BUILD.gn +@@ -2427,6 +2427,7 @@ static_library("browser") { + "//third_party/ungoogled:switches", + "//services/device/public/mojom", + "//services/device/public/mojom:usb", ++ "//services/firewall/public:firewall_builders", + "//services/image_annotation:service", + "//services/media_session/public/mojom", + "//services/metrics/public/cpp:ukm_builders", +diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc +--- a/chrome/browser/about_flags.cc ++++ b/chrome/browser/about_flags.cc +@@ -194,6 +194,7 @@ + #include "sandbox/policy/switches.h" + #include "services/device/public/cpp/device_features.h" + #include "services/device/public/cpp/serial/serial_switches.h" ++#include "services/firewall/public/firewall_service.h" + #include "services/media_session/public/cpp/features.h" + #include "services/network/public/cpp/features.h" + #include "services/network/public/cpp/network_switches.h" +@@ -7308,6 +7309,11 @@ const FeatureEntry kFeatureEntries[] = { + FEATURE_VALUE_TYPE(page_info::kPageInfoHideSiteSettings)}, + #endif // !BUILDFLAG(IS_ANDROID) + ++ {"enable-firewall", ++ "Enable internal firewall", ++ "Enable internal firewall", kOsDesktop | kOsAndroid, ++ FEATURE_VALUE_TYPE(firewall::features::kEnableFirewall)}, ++ + #if BUILDFLAG(IS_ANDROID) + {"page-info-about-this-site-improved-bottomsheet", + flag_descriptions::kPageInfoAboutThisSiteImprovedBottomSheetName, +diff --git a/chrome/browser/offline_pages/android/downloads/offline_page_download_bridge.cc b/chrome/browser/offline_pages/android/downloads/offline_page_download_bridge.cc +--- a/chrome/browser/offline_pages/android/downloads/offline_page_download_bridge.cc ++++ b/chrome/browser/offline_pages/android/downloads/offline_page_download_bridge.cc +@@ -268,13 +268,43 @@ content::WebContents::Getter GetWebContentsGetter( + web_contents->GetPrimaryMainFrame()->GetRoutingID()); + } + ++const net::NetworkTrafficAnnotationTag traffic_annotation = ++ net::DefineNetworkTrafficAnnotation("offline_pages_download_file", R"( ++ semantics { ++ sender: "Bromite" ++ description: ++ "Offline pages download file" ++ trigger: "Manual from user." ++ data: ++ "binary format" ++ destination: LOCAL ++ internal { ++ contacts { ++ email: "uazo@users.noreply.github.com" ++ } ++ contacts { ++ email: "uazo@users.noreply.github.com" ++ } ++ } ++ user_data { ++ type: NONE ++ } ++ last_reviewed: "2023-01-01" ++ } ++ policy { ++ cookies_allowed: NO ++ setting: ++ "No setting." ++ policy_exception_justification: "Not implemented." ++ })"); ++ + void DownloadAsFile(content::WebContents* web_contents, const GURL& url) { + content::DownloadManager* dlm = + web_contents->GetBrowserContext()->GetDownloadManager(); + std::unique_ptr dl_params( + content::DownloadRequestUtils::CreateDownloadForWebContentsMainFrame( + web_contents, url, +- TRAFFIC_ANNOTATION_WITHOUT_PROTO("Offline pages download file"))); ++ traffic_annotation)); + + content::NavigationEntry* entry = + web_contents->GetController().GetLastCommittedEntry(); +diff --git a/components/download/content/internal/context_menu_download.cc b/components/download/content/internal/context_menu_download.cc +--- a/components/download/content/internal/context_menu_download.cc ++++ b/components/download/content/internal/context_menu_download.cc +@@ -15,6 +15,36 @@ + + namespace download { + ++const net::NetworkTrafficAnnotationTag traffic_annotation = ++ net::DefineNetworkTrafficAnnotation("download_via_context_menu", R"( ++ semantics { ++ sender: "Bromite" ++ description: ++ "Download from context menu" ++ trigger: "Manual from user." ++ data: ++ "binary format" ++ destination: LOCAL ++ internal { ++ contacts { ++ email: "uazo@users.noreply.github.com" ++ } ++ contacts { ++ email: "uazo@users.noreply.github.com" ++ } ++ } ++ user_data { ++ type: NONE ++ } ++ last_reviewed: "2023-01-01" ++ } ++ policy { ++ cookies_allowed: NO ++ setting: ++ "No setting." ++ policy_exception_justification: "Not implemented." ++ })"); ++ + void CreateContextMenuDownload(content::WebContents* web_contents, + const content::ContextMenuParams& params, + const std::string& origin, +@@ -27,7 +57,7 @@ void CreateContextMenuDownload(content::WebContents* web_contents, + std::unique_ptr dl_params( + content::DownloadRequestUtils::CreateDownloadForWebContentsMainFrame( + web_contents, url, +- TRAFFIC_ANNOTATION_WITHOUT_PROTO("Download via context menu"))); ++ traffic_annotation)); + content::Referrer referrer = content::Referrer::SanitizeForRequest( + url, + content::Referrer(referring_url.GetAsReferrer(), params.referrer_policy)); +diff --git a/components/webapps/browser/android/webapk/webapk_icon_hasher.cc b/components/webapps/browser/android/webapk/webapk_icon_hasher.cc +--- a/components/webapps/browser/android/webapk/webapk_icon_hasher.cc ++++ b/components/webapps/browser/android/webapk/webapk_icon_hasher.cc +@@ -121,6 +121,36 @@ void WebApkIconHasher::DownloadAndComputeMurmur2HashWithTimeout( + std::move(callback)); + } + ++const net::NetworkTrafficAnnotationTag traffic_annotation = ++ net::DefineNetworkTrafficAnnotation("webapk_icon_hasher", R"( ++ semantics { ++ sender: "webapk icon hasher" ++ description: ++ "webapk icon hasher" ++ trigger: "Manual or automatic." ++ data: ++ " binary format" ++ destination: WEBSITE ++ internal { ++ contacts { ++ email: "uazo@users.noreply.github.com" ++ } ++ contacts { ++ email: "uazo@users.noreply.github.com" ++ } ++ } ++ user_data { ++ type: NONE ++ } ++ last_reviewed: "2023-01-01" ++ } ++ policy { ++ cookies_allowed: NO ++ setting: ++ "No setting." ++ policy_exception_justification: "Not implemented." ++ })"); ++ + WebApkIconHasher::WebApkIconHasher( + network::mojom::URLLoaderFactory* url_loader_factory, + base::WeakPtr web_contents, +@@ -145,7 +175,7 @@ WebApkIconHasher::WebApkIconHasher( + resource_request->url = icon_url; + simple_url_loader_ = network::SimpleURLLoader::Create( + std::move(resource_request), +- TRAFFIC_ANNOTATION_WITHOUT_PROTO("webapk icon hasher")); ++ traffic_annotation); + simple_url_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie( + url_loader_factory, + base::BindOnce(&WebApkIconHasher::OnSimpleLoaderComplete, +diff --git a/net/BUILD.gn b/net/BUILD.gn +--- a/net/BUILD.gn ++++ b/net/BUILD.gn +@@ -1079,6 +1079,7 @@ component("net") { + "//build:chromeos_buildflags", + "//net/data/ssl/chrome_root_store:gen_root_store_inc", + "//net/http:transport_security_state_generated_files", ++ "//services/firewall/public:firewall_builders", + "//components/network_session_configurator/common" + ] + +diff --git a/net/traffic_annotation/network_traffic_annotation.h b/net/traffic_annotation/network_traffic_annotation.h +--- a/net/traffic_annotation/network_traffic_annotation.h ++++ b/net/traffic_annotation/network_traffic_annotation.h +@@ -373,10 +373,6 @@ struct MutablePartialNetworkTrafficAnnotationTag { + } // namespace net + + // Placeholder for unannotated usages. +-#if !BUILDFLAG(IS_WIN) && !BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CHROMEOS) +-#define TRAFFIC_ANNOTATION_WITHOUT_PROTO(ANNOTATION_ID) \ +- net::DefineNetworkTrafficAnnotation(ANNOTATION_ID, "No proto yet.") +-#endif + + // These annotations are unavailable on desktop Linux + Windows. They are + // available on other platforms, since we only audit network annotations on +diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc +--- a/net/url_request/url_request_http_job.cc ++++ b/net/url_request/url_request_http_job.cc +@@ -239,6 +239,9 @@ URLRequestHttpJob::URLRequestHttpJob( + throttling_entry_ = manager->RegisterRequestUrl(request->url()); + + ResetTimer(); ++ ++ if (base::FeatureList::IsEnabled(firewall::features::kEnableFirewall)) ++ firewall_service_ = std::make_unique(nullptr); + } + + URLRequestHttpJob::~URLRequestHttpJob() { +@@ -545,6 +548,18 @@ void URLRequestHttpJob::MaybeStartTransactionInternal(int result) { + void URLRequestHttpJob::StartTransactionInternal() { + DCHECK(!override_response_headers_); + ++ if (firewall_service_ && ++ !firewall_service_->IsAllowed(request_->traffic_annotation().unique_id_hash_code)) { ++ auto entry = firewall_service_->GetEntry(request_->traffic_annotation().unique_id_hash_code); ++ LOG(INFO) << "---ABORTED URLRequestHttpJob: " ++ << (entry.has_value() ? entry->name : "no-name") ++ << "(" << request_->traffic_annotation().unique_id_hash_code << ")" ++ << " url: " << request_->original_url().possibly_invalid_spec() ++ << " path: " << (entry.has_value() ? entry->path : "no-path"); ++ Kill(); ++ return; ++ } ++ + // NOTE: This method assumes that request_info_ is already setup properly. + + // If we already have a transaction, then we should restart the transaction +diff --git a/net/url_request/url_request_http_job.h b/net/url_request/url_request_http_job.h +--- a/net/url_request/url_request_http_job.h ++++ b/net/url_request/url_request_http_job.h +@@ -31,6 +31,7 @@ + #include "net/url_request/url_request_job.h" + #include "net/url_request/url_request_throttler_entry_interface.h" + #include "third_party/abseil-cpp/absl/types/optional.h" ++#include "services/firewall/public/firewall_service.h" + + namespace net { + +@@ -79,6 +80,8 @@ class NET_EXPORT_PRIVATE URLRequestHttpJob : public URLRequestJob { + return priority_; + } + ++ std::unique_ptr firewall_service_; ++ + private: + // For CookieRequestScheme histogram enum. + FRIEND_TEST_ALL_PREFIXES(URLRequestHttpJobTest, +diff --git a/services/firewall/public/BUILD.gn b/services/firewall/public/BUILD.gn +new file mode 100644 +--- /dev/null ++++ b/services/firewall/public/BUILD.gn +@@ -0,0 +1,70 @@ ++# This file is part of Bromite. ++# Bromite is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++# Bromite is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# You should have received a copy of the GNU General Public License ++# along with Bromite. If not, see . ++ ++component("firewall_cpp") { ++ sources = [ ++ "firewall_service.h", ++ "firewall_service.cc", ++ "firewall_features.h", ++ "firewall_features.cc", ++ ] ++ ++ defines = [ "FIREWALL_IMPLEMENTATION" ] ++ ++ public_deps = [ ++ "//base", ++ "//third_party/abseil-cpp:absl" ++ ] ++} ++ ++action("gen_firewall_builders") { ++ script = "//services/firewall/tools/gen_builders.py" ++ ++ inputs = [ ++ "//services/firewall/tools/gen_builders.py", ++ "//services/firewall/tools/builders_template.py", ++ "//services/firewall/tools/rules.xml", ++ "//services/firewall/tools/annotations.xml", ++ ] ++ sources = [ ++ "//services/firewall/tools/annotations.xml", ++ "//services/firewall/tools/rules.xml", ++ ] ++ ++ outdir = "$target_gen_dir" ++ ++ outputs = [ ++ outdir + "/firewall_builders.cc", ++ outdir + "/firewall_builders.h", ++ outdir + "/annotation_decode.cc", ++ outdir + "/annotation_decode.h", ++ ] ++ ++ args = [ ++ "--input", ++ rebase_path(sources[0], root_build_dir), ++ "--rules", ++ rebase_path(sources[1], root_build_dir), ++ "--output", ++ rebase_path(outdir, root_build_dir), ++ ] ++} ++ ++static_library("firewall_builders") { ++ sources = get_target_outputs(":gen_firewall_builders") ++ ++ deps = [ ++ ":gen_firewall_builders", ++ ":firewall_cpp", ++ "//base", ++ ] ++} +diff --git a/services/firewall/public/firewall_features.cc b/services/firewall/public/firewall_features.cc +new file mode 100644 +--- /dev/null ++++ b/services/firewall/public/firewall_features.cc +@@ -0,0 +1,28 @@ ++/* ++ This file is part of Bromite. ++ ++ Bromite is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ Bromite is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with Bromite. If not, see . ++*/ ++ ++#include "firewall_features.h" ++ ++namespace firewall { ++namespace features { ++ ++BASE_FEATURE(kEnableFirewall, ++ "EnableFirewall", ++ base::FEATURE_DISABLED_BY_DEFAULT); ++ ++} // namespace features ++} // namespace firewall +diff --git a/services/firewall/public/firewall_features.h b/services/firewall/public/firewall_features.h +new file mode 100644 +--- /dev/null ++++ b/services/firewall/public/firewall_features.h +@@ -0,0 +1,31 @@ ++/* ++ This file is part of Bromite. ++ ++ Bromite is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ Bromite is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with Bromite. If not, see . ++*/ ++ ++#ifndef COMPONENTS_FIREWALL_FIREWALL_FEATURES_H_ ++#define COMPONENTS_FIREWALL_FIREWALL_FEATURES_H_ ++ ++#include "base/feature_list.h" ++ ++namespace firewall { ++namespace features { ++ ++BASE_DECLARE_FEATURE(kEnableFirewall); ++ ++} // namespace features ++} // namespace firewall ++ ++#endif // COMPONENTS_FIREWALL_FIREWALL_FEATURES_H_ +diff --git a/services/firewall/public/firewall_service.cc b/services/firewall/public/firewall_service.cc +new file mode 100644 +--- /dev/null ++++ b/services/firewall/public/firewall_service.cc +@@ -0,0 +1,46 @@ ++/* ++ This file is part of Bromite. ++ ++ Bromite is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ Bromite is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with Bromite. If not, see . ++*/ ++ ++#include "firewall_service.h" ++ ++namespace firewall { ++ ++FirewallService::FirewallService(PrefService* pref_service) ++ : pref_service_(pref_service) { ++ decode_map_ = builders::CreateDecodeMap(); ++} ++ ++FirewallService::~FirewallService() = default; ++ ++bool FirewallService::IsAllowed(int32_t unique_id_hash_code) { ++ const auto it = decode_map_.find(unique_id_hash_code); ++ if (it == decode_map_.end()) ++ return false; ++ ++ return it->second.allowed; ++} ++ ++absl::optional FirewallService::GetEntry( ++ int32_t unique_id_hash_code) const { ++ const auto it = decode_map_.find(unique_id_hash_code); ++ if (it == decode_map_.end()) ++ return absl::nullopt; ++ ++ return absl::optional(it->second); ++} ++ ++} +diff --git a/services/firewall/public/firewall_service.h b/services/firewall/public/firewall_service.h +new file mode 100644 +--- /dev/null ++++ b/services/firewall/public/firewall_service.h +@@ -0,0 +1,57 @@ ++/* ++ This file is part of Bromite. ++ ++ Bromite is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ Bromite is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with Bromite. If not, see . ++*/ ++ ++#ifndef COMPONENTS_FIREWALL_FIREWALL_SERVICE_H_ ++#define COMPONENTS_FIREWALL_FIREWALL_SERVICE_H_ ++ ++#include ++#include ++ ++#include "base/memory/raw_ptr.h" ++#include "base/memory/weak_ptr.h" ++#include "services/firewall/public/firewall_builders.h" ++#include "services/firewall/public/annotation_decode.h" ++#include "third_party/abseil-cpp/absl/types/optional.h" ++ ++#include "firewall_features.h" ++ ++class PrefService; ++ ++namespace firewall { ++ ++class FirewallService { ++ public: ++ FirewallService(PrefService* pref_service); ++ ++ FirewallService(const FirewallService&) = delete; ++ FirewallService& operator=(const FirewallService&) = delete; ++ ++ ~FirewallService(); ++ ++ bool IsAllowed(int32_t unique_id_hash_code); ++ absl::optional GetEntry(int32_t unique_id_hash_code) const; ++ ++ private: ++ raw_ptr pref_service_; ++ firewall::builders::DecodeMap decode_map_; ++ ++ base::WeakPtrFactory self_ptr_factory_{this}; ++}; ++ ++} // namespace firewall ++ ++#endif // COMPONENTS_FIREWALL_FIREWALL_SERVICE_H_ +diff --git a/services/firewall/tools/annotation_model.py b/services/firewall/tools/annotation_model.py +new file mode 100644 +--- /dev/null ++++ b/services/firewall/tools/annotation_model.py +@@ -0,0 +1,49 @@ ++# This file is part of Bromite. ++# Bromite is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++# Bromite is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# You should have received a copy of the GNU General Public License ++# along with Bromite. If not, see . ++ ++import os ++import sys ++ ++sys.path.append(os.path.join(os.path.dirname(__file__), '..', '../../tools/metrics/common')) ++import models ++ ++_ITEM_TYPE = models.ObjectNodeType('item', ++ attributes=[ ++ ('id', str, r'^[_A-Za-z0-9.]+$'), ++ ('hash_code', str, r'^[0-9.]+$'), ++ ('file_path', str, r'^[_/A-Za-z0-9.]*$'), ++ ('allowed', str, r'^[_/A-Za-z0-9.]*$'), ++ ], ++ extra_newlines=(1, 1, 1)) ++ ++ ++_ANNOTATION_CONFIGURATION_TYPE = models.ObjectNodeType( ++ 'annotations', ++ extra_newlines=(2, 1, 1), ++ indent=False, ++ children=[ ++ models.ChildType(_ITEM_TYPE.tag, _ITEM_TYPE, multiple=True), ++ ]) ++ ++ANNOTATION_XML_TYPE = models.DocumentType(_ANNOTATION_CONFIGURATION_TYPE) ++ ++def PrettifyXML(original_xml): ++ """Parses the original xml and return a pretty printed version. ++ ++ Args: ++ original_xml: A string containing the original xml file contents. ++ ++ Returns: ++ A pretty-printed xml string, or None if the config contains errors. ++ """ ++ config = ANNOTATION_XML_TYPE.Parse(original_xml) ++ return ANNOTATION_XML_TYPE.PrettyPrint(config) +diff --git a/services/firewall/tools/annotations.xml b/services/firewall/tools/annotations.xml +new file mode 100644 +--- /dev/null ++++ b/services/firewall/tools/annotations.xml +@@ -0,0 +1,448 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/services/firewall/tools/builders_template.py b/services/firewall/tools/builders_template.py +new file mode 100644 +--- /dev/null ++++ b/services/firewall/tools/builders_template.py +@@ -0,0 +1,72 @@ ++# This file is part of Bromite. ++# Bromite is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++# Bromite is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# You should have received a copy of the GNU General Public License ++# along with Bromite. If not, see . ++ ++"""Templates for generating builder classes for UKM entries.""" ++ ++import codegen ++ ++HEADER = codegen.Template(basename="firewall_builders.h", ++ file_template=""" ++// Generated from //services/firewall/tools/gen_builders.py. DO NOT EDIT! ++// source: annotations.xml ++ ++#ifndef {file.guard_path} ++#define {file.guard_path} ++ ++#include ++ ++//#include "services/metrics/public/cpp/ukm_entry_builder_base.h" ++#include "net/traffic_annotation/network_traffic_annotation.h" ++ ++namespace firewall {{ ++namespace builders {{ ++ ++{event_code} ++ ++}} // namespace builders ++}} // namespace firewall ++ ++#endif // {file.guard_path} ++""", ++ event_template=""" ++ extern const char k{event.name}EntryName[]; ++ extern const uint64_t k{event.name}EntryNameHash; ++""", ++ metric_template=""" ++""") ++ ++IMPL = codegen.Template(basename="firewall_builders.cc", ++ file_template=""" ++// Generated from //services/firewall/tools/gen_builders.py. DO NOT EDIT! ++// source: annotations.xml ++ ++#include "{file.dir_path}firewall_builders.h" ++ ++namespace firewall {{ ++namespace builders {{ ++ ++{event_code} ++ ++}} // namespace builders ++}} // namespace firewall ++""", ++ event_template=""" ++const char k{event.name}EntryName[] = "{event.raw_name}"; ++constexpr uint64_t k{event.name}EntryNameHash = COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("{event.raw_name}"); ++""", ++ metric_template=""" ++""") ++ ++ ++def WriteFiles(outdir, relpath, data): ++ HEADER.WriteFile(outdir, relpath, data) ++ IMPL.WriteFile(outdir, relpath, data) +diff --git a/services/firewall/tools/codegen.py b/services/firewall/tools/codegen.py +new file mode 100644 +--- /dev/null ++++ b/services/firewall/tools/codegen.py +@@ -0,0 +1,82 @@ ++# This file is part of Bromite. ++# Bromite is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++# Bromite is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# You should have received a copy of the GNU General Public License ++# along with Bromite. If not, see . ++ ++import hashlib ++import os ++import re ++import struct ++from annotation_model import _ITEM_TYPE ++ ++def to_pascal_case(text): ++ s = text.replace("-", " ").replace("_", " ") ++ s = s.split() ++ if len(text) == 0: ++ return text ++ return ''.join(i.capitalize() for i in s[0:]) ++ ++def sanitize_name(name): ++ s = re.sub('[^0-9a-zA-Z_]', '_', name) ++ return s ++ ++class FileInfo(object): ++ def __init__(self, relpath, basename): ++ self.dir_path = relpath ++ self.guard_path = sanitize_name(os.path.join(relpath, basename)).upper() ++ ++ ++class ItemInfo(object): ++ def __init__(self, json_obj): ++ self.raw_name = json_obj['id'] ++ self.name = to_pascal_case(json_obj['id']) ++ self.hash = json_obj['hash_code'] ++ self.file_path = json_obj['file_path'] ++ self.allowed = "false" ++ if "allowed" in json_obj and json_obj['allowed'] == "1": ++ self.allowed = "true" ++ ++class Template(object): ++ """Template for producing code from annotations.xml.""" ++ ++ def __init__(self, basename, file_template, event_template, metric_template): ++ self.basename = basename ++ self.file_template = file_template ++ self.event_template = event_template ++ self.metric_template = metric_template ++ ++ def _StampEventCode(self, file_info, item): ++ event_info = ItemInfo(item) ++ metric_code = "" ++ return self.event_template.format( ++ file=file_info, ++ event=event_info, ++ metric_code=metric_code) ++ ++ def _StampFileCode(self, relpath, data): ++ file_info = FileInfo(relpath, self.basename) ++ event_code = "".join( ++ self._StampEventCode(file_info, item) ++ for item in data[_ITEM_TYPE.tag]) ++ return self.file_template.format( ++ file=file_info, ++ event_code=event_code) ++ ++ def WriteFile(self, outdir, relpath, data): ++ """Generates code and writes it to a file. ++ ++ Args: ++ relpath: The path to the file in the source tree. ++ rootdir: The root of the path the file should be written to. ++ data: The parsed data. ++ """ ++ output = open(os.path.join(outdir, self.basename), 'w') ++ output.write(self._StampFileCode(relpath, data)) ++ output.close() +diff --git a/services/firewall/tools/decode_template.py b/services/firewall/tools/decode_template.py +new file mode 100644 +--- /dev/null ++++ b/services/firewall/tools/decode_template.py +@@ -0,0 +1,85 @@ ++# This file is part of Bromite. ++# Bromite is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++# Bromite is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# You should have received a copy of the GNU General Public License ++# along with Bromite. If not, see . ++ ++"""A template for generating hash decoding code.""" ++ ++import codegen ++ ++HEADER = codegen.Template( ++basename="annotation_decode.h", ++file_template=""" ++// Generated from //services/firewall/tools/gen_builders.py. DO NOT EDIT! ++// source: annotations.xml ++ ++#ifndef {file.guard_path} ++#define {file.guard_path} ++ ++#include ++#include ++ ++namespace firewall {{ ++namespace builders {{ ++ ++struct EntryDecoder {{ ++ const char* name; ++ bool allowed; ++ const char* path; ++}}; ++typedef std::map DecodeMap; ++DecodeMap CreateDecodeMap(); ++ ++}} // namespace builders ++}} // namespace ukm ++ ++#endif // {file.guard_path} ++""", ++event_template="", ++metric_template="") ++ ++IMPL = codegen.Template( ++basename="annotation_decode.cc", ++file_template=""" ++// Generated from //services/firewall/tools/gen_builders.py. DO NOT EDIT! ++// source: annotations.xml ++ ++#include "{file.dir_path}annotation_decode.h" ++#include "{file.dir_path}firewall_builders.h" ++ ++namespace firewall {{ ++namespace builders {{ ++ ++std::map CreateDecodeMap() {{ ++ return {{ ++ {event_code} ++ }}; ++}} ++ ++}} // namespace builders ++}} // namespace firewall ++""", ++event_template=""" ++ {{ ++ k{event.name}EntryNameHash, ++ {{ ++ k{event.name}EntryName, ++ {event.allowed}, ++ "{event.file_path}", ++ }} ++ }}, ++""", ++metric_template=""" ++""") ++ ++ ++def WriteFiles(outdir, relpath, data): ++ HEADER.WriteFile(outdir, relpath, data) ++ IMPL.WriteFile(outdir, relpath, data) +diff --git a/services/firewall/tools/gen_builders.py b/services/firewall/tools/gen_builders.py +new file mode 100644 +--- /dev/null ++++ b/services/firewall/tools/gen_builders.py +@@ -0,0 +1,65 @@ ++#!/usr/bin/env python ++# This file is part of Bromite. ++# Bromite is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++# Bromite is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# You should have received a copy of the GNU General Public License ++# along with Bromite. If not, see . ++ ++"""A utility for generating builder classes for firewall entries. ++ ++It takes as input a rules.xml file describing all of the network annotation entries, ++and produces a c++ header and implementation file exposing builders for those ++entries. ++""" ++ ++import argparse ++import sys ++ ++import rules_model ++import annotation_model ++import builders_template ++import decode_template ++ ++parser = argparse.ArgumentParser(description='Generate network annotation entries') ++parser.add_argument('--input', help='Path to annotations.xml') ++parser.add_argument('--rules', help='Path to rules.xml') ++parser.add_argument('--output', help='Path to generated files.') ++ ++ ++def main(argv): ++ args = parser.parse_args() ++ data = ReadFilteredData(args.input) ++ rules = ReadRulesData(args.rules) ++ ++ for key in rules[rules_model._ITEM_TYPE.tag]: ++ key_id = key["id"] ++ ++ for f in data[annotation_model._ITEM_TYPE.tag]: ++ if f["id"] == key_id: ++ f["allowed"] = key["allowed"] ++ #print(f) ++ ++ relpath = 'services/firewall/public/' ++ builders_template.WriteFiles(args.output, relpath, data) ++ decode_template.WriteFiles(args.output, relpath, data) ++ return 0 ++ ++def ReadRulesData(path): ++ with open(path) as rules_file: ++ data = rules_model.RULES_XML_TYPE.Parse(rules_file.read()) ++ return data ++ ++def ReadFilteredData(path): ++ with open(path) as ukm_file: ++ data = annotation_model.ANNOTATION_XML_TYPE.Parse(ukm_file.read()) ++ return data ++ ++ ++if '__main__' == __name__: ++ sys.exit(main(sys.argv)) +diff --git a/services/firewall/tools/rules.xml b/services/firewall/tools/rules.xml +new file mode 100644 +--- /dev/null ++++ b/services/firewall/tools/rules.xml +@@ -0,0 +1,70 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/services/firewall/tools/rules_model.py b/services/firewall/tools/rules_model.py +new file mode 100644 +--- /dev/null ++++ b/services/firewall/tools/rules_model.py +@@ -0,0 +1,35 @@ ++# This file is part of Bromite. ++# Bromite is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++# Bromite is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# You should have received a copy of the GNU General Public License ++# along with Bromite. If not, see . ++ ++import os ++import sys ++ ++sys.path.append(os.path.join(os.path.dirname(__file__), '..', '../../tools/metrics/common')) ++import models ++ ++_ITEM_TYPE = models.ObjectNodeType('item', ++ attributes=[ ++ ('id', str, r'^[_A-Za-z0-9.]+$'), ++ ('allowed', str, r'^[0-9.]+$'), ++ ], ++ extra_newlines=(1, 1, 1)) ++ ++ ++_RULES_CONFIGURATION_TYPE = models.ObjectNodeType( ++ 'rules', ++ extra_newlines=(2, 1, 1), ++ indent=False, ++ children=[ ++ models.ChildType(_ITEM_TYPE.tag, _ITEM_TYPE, multiple=True), ++ ]) ++ ++RULES_XML_TYPE = models.DocumentType(_RULES_CONFIGURATION_TYPE) +diff --git a/services/network/public/cpp/simple_url_loader.cc b/services/network/public/cpp/simple_url_loader.cc +--- a/services/network/public/cpp/simple_url_loader.cc ++++ b/services/network/public/cpp/simple_url_loader.cc +@@ -1244,6 +1244,8 @@ SimpleURLLoaderImpl::SimpleURLLoaderImpl( + timeout_timer_(timeout_tick_clock_) { + // Allow creation and use on different threads. + DETACH_FROM_SEQUENCE(sequence_checker_); ++ if (base::FeatureList::IsEnabled(firewall::features::kEnableFirewall)) ++ firewall_service_ = std::make_unique(nullptr); + #if DCHECK_IS_ON() + if (resource_request_->request_body) { + for (const DataElement& element : +@@ -1679,6 +1681,22 @@ void SimpleURLLoaderImpl::StartRequest( + resource_request_->request_body->AppendDataPipe( + string_upload_data_pipe_getter_->GetRemoteForNewUpload()); + } ++ if (firewall_service_ && ++ !firewall_service_->IsAllowed(annotation_tag_.unique_id_hash_code)) { ++ auto entry = firewall_service_->GetEntry(annotation_tag_.unique_id_hash_code); ++ LOG(INFO) << "---ABORTED SimpleURLLoaderImpl: " ++ << (entry.has_value() ? entry->name : "no-name") ++ << "(" << annotation_tag_.unique_id_hash_code << ")" ++ << " url: " << resource_request_->url.possibly_invalid_spec() ++ << " path: " << (entry.has_value() ? entry->path : "no-path"); ++ ++ timeout_timer_.Start( ++ FROM_HERE, base::Seconds(1), ++ base::BindOnce(&SimpleURLLoaderImpl::FinishWithResult, ++ weak_ptr_factory_.GetWeakPtr(), net::ERR_TIMED_OUT)); ++ return; ++ } ++ + url_loader_factory->CreateLoaderAndStart( + url_loader_.BindNewPipeAndPassReceiver(), request_id_, + url_loader_factory_options_, *resource_request_, +diff --git a/services/network/public/cpp/simple_url_loader.h b/services/network/public/cpp/simple_url_loader.h +--- a/services/network/public/cpp/simple_url_loader.h ++++ b/services/network/public/cpp/simple_url_loader.h +@@ -17,6 +17,7 @@ + #include "services/network/public/cpp/url_loader_completion_status.h" + #include "services/network/public/mojom/url_response_head.mojom-forward.h" + #include "third_party/abseil-cpp/absl/types/optional.h" ++#include "services/firewall/public/firewall_service.h" + + class GURL; + +@@ -405,6 +406,8 @@ class COMPONENT_EXPORT(NETWORK_CPP) SimpleURLLoader { + + protected: + SimpleURLLoader(); ++ ++ std::unique_ptr firewall_service_; + }; + + } // namespace network +diff --git a/third_party/blink/renderer/platform/loader/fetch/url_loader/url_loader.cc b/third_party/blink/renderer/platform/loader/fetch/url_loader/url_loader.cc +--- a/third_party/blink/renderer/platform/loader/fetch/url_loader/url_loader.cc ++++ b/third_party/blink/renderer/platform/loader/fetch/url_loader/url_loader.cc +@@ -677,23 +677,150 @@ net::NetworkTrafficAnnotationTag URLLoader::Context::GetTrafficAnnotationTag( + NOTREACHED(); + [[fallthrough]]; + ++ // Split destination with new annotations ++ case network::mojom::RequestDestination::kServiceWorker: ++ case network::mojom::RequestDestination::kSharedWorker: ++ case network::mojom::RequestDestination::kWorker: ++ return net::DefineNetworkTrafficAnnotation("blink_resource_loader_workers", R"( ++ semantics { ++ sender: "Blink Resource Loader" ++ description: ++ "Blink-initiated request, which includes all resources for " ++ "normal page loads, chrome URLs, and downloads." ++ trigger: ++ "The user navigates to a URL or downloads a file. Also when a " ++ "webpage, ServiceWorker, or chrome:// uses any network communication." ++ data: "Anything the initiator wants to send." ++ destination: OTHER ++ } ++ policy { ++ cookies_allowed: YES ++ cookies_store: "user" ++ setting: "These requests cannot be disabled in settings." ++ policy_exception_justification: ++ "Not implemented. Without these requests, Chrome will be unable " ++ "to load any webpage." ++ })"); ++ ++ case network::mojom::RequestDestination::kReport: ++ return net::DefineNetworkTrafficAnnotation("blink_resource_loader_report", R"( ++ semantics { ++ sender: "Blink Resource Loader" ++ description: ++ "Blink-initiated request, which includes all resources for " ++ "normal page loads, chrome URLs, and downloads." ++ trigger: ++ "The user navigates to a URL or downloads a file. Also when a " ++ "webpage, ServiceWorker, or chrome:// uses any network communication." ++ data: "Anything the initiator wants to send." ++ destination: OTHER ++ } ++ policy { ++ cookies_allowed: YES ++ cookies_store: "user" ++ setting: "These requests cannot be disabled in settings." ++ policy_exception_justification: ++ "Not implemented. Without these requests, Chrome will be unable " ++ "to load any webpage." ++ })"); ++ ++ case network::mojom::RequestDestination::kAudioWorklet: ++ case network::mojom::RequestDestination::kPaintWorklet: ++ return net::DefineNetworkTrafficAnnotation("blink_resource_loader_worklet", R"( ++ semantics { ++ sender: "Blink Resource Loader" ++ description: ++ "Blink-initiated request, which includes all resources for " ++ "normal page loads, chrome URLs, and downloads." ++ trigger: ++ "The user navigates to a URL or downloads a file. Also when a " ++ "webpage, ServiceWorker, or chrome:// uses any network communication." ++ data: "Anything the initiator wants to send." ++ destination: OTHER ++ } ++ policy { ++ cookies_allowed: YES ++ cookies_store: "user" ++ setting: "These requests cannot be disabled in settings." ++ policy_exception_justification: ++ "Not implemented. Without these requests, Chrome will be unable " ++ "to load any webpage." ++ })"); ++ ++ case network::mojom::RequestDestination::kWebBundle: ++ return net::DefineNetworkTrafficAnnotation("blink_resource_loader_webbundle", R"( ++ semantics { ++ sender: "Blink Resource Loader" ++ description: ++ "Blink-initiated request, which includes all resources for " ++ "normal page loads, chrome URLs, and downloads." ++ trigger: ++ "The user navigates to a URL or downloads a file. Also when a " ++ "webpage, ServiceWorker, or chrome:// uses any network communication." ++ data: "Anything the initiator wants to send." ++ destination: OTHER ++ } ++ policy { ++ cookies_allowed: YES ++ cookies_store: "user" ++ setting: "These requests cannot be disabled in settings." ++ policy_exception_justification: ++ "Not implemented. Without these requests, Chrome will be unable " ++ "to load any webpage." ++ })"); ++ ++ case network::mojom::RequestDestination::kManifest: ++ return net::DefineNetworkTrafficAnnotation("blink_resource_loader_manifest", R"( ++ semantics { ++ sender: "Blink Resource Loader" ++ description: ++ "Blink-initiated request, which includes all resources for " ++ "normal page loads, chrome URLs, and downloads." ++ trigger: ++ "The user navigates to a URL or downloads a file. Also when a " ++ "webpage, ServiceWorker, or chrome:// uses any network communication." ++ data: "Anything the initiator wants to send." ++ destination: OTHER ++ } ++ policy { ++ cookies_allowed: YES ++ cookies_store: "user" ++ setting: "These requests cannot be disabled in settings." ++ policy_exception_justification: ++ "Not implemented. Without these requests, Chrome will be unable " ++ "to load any webpage." ++ })"); ++ ++ case network::mojom::RequestDestination::kXslt: ++ return net::DefineNetworkTrafficAnnotation("blink_resource_loader_xslt", R"( ++ semantics { ++ sender: "Blink Resource Loader" ++ description: ++ "Blink-initiated request, which includes all resources for " ++ "normal page loads, chrome URLs, and downloads." ++ trigger: ++ "The user navigates to a URL or downloads a file. Also when a " ++ "webpage, ServiceWorker, or chrome:// uses any network communication." ++ data: "Anything the initiator wants to send." ++ destination: OTHER ++ } ++ policy { ++ cookies_allowed: YES ++ cookies_store: "user" ++ setting: "These requests cannot be disabled in settings." ++ policy_exception_justification: ++ "Not implemented. Without these requests, Chrome will be unable " ++ "to load any webpage." ++ })"); ++ + case network::mojom::RequestDestination::kEmpty: + case network::mojom::RequestDestination::kAudio: +- case network::mojom::RequestDestination::kAudioWorklet: + case network::mojom::RequestDestination::kFont: + case network::mojom::RequestDestination::kImage: +- case network::mojom::RequestDestination::kManifest: +- case network::mojom::RequestDestination::kPaintWorklet: +- case network::mojom::RequestDestination::kReport: + case network::mojom::RequestDestination::kScript: +- case network::mojom::RequestDestination::kServiceWorker: +- case network::mojom::RequestDestination::kSharedWorker: + case network::mojom::RequestDestination::kStyle: + case network::mojom::RequestDestination::kTrack: + case network::mojom::RequestDestination::kVideo: +- case network::mojom::RequestDestination::kWebBundle: +- case network::mojom::RequestDestination::kWorker: +- case network::mojom::RequestDestination::kXslt: + return net::DefineNetworkTrafficAnnotation("blink_resource_loader", R"( + semantics { + sender: "Blink Resource Loader" +diff --git a/tools/traffic_annotation/scripts/auditor/auditor.py b/tools/traffic_annotation/scripts/auditor/auditor.py +--- a/tools/traffic_annotation/scripts/auditor/auditor.py ++++ b/tools/traffic_annotation/scripts/auditor/auditor.py +@@ -829,6 +829,7 @@ class ArchivedAnnotation: + # the XML. This is used to serialize/deserialize the XML. + FIELDS = [ + "id", "added_in_milestone", "type", "second_id", "reserved", ++ "hash_code", + "content_hash_code", "os_list", "semantics_fields", "policy_fields", + "file_path" + ] +diff --git a/tools/traffic_annotation/scripts/auditor/util.py b/tools/traffic_annotation/scripts/auditor/util.py +--- a/tools/traffic_annotation/scripts/auditor/util.py ++++ b/tools/traffic_annotation/scripts/auditor/util.py +@@ -73,6 +73,7 @@ def get_current_platform(build_path: Optional[Path] = None) -> str: + # It's probably not Android/ChromeOS in that case. + pass + ++ current_platform = "android" + return current_platform + + +-- +2.25.1 diff --git a/build/patches/00Remove-ChromiumNetworkAdapter.patch b/build/patches/00Remove-ChromiumNetworkAdapter.patch new file mode 100644 index 00000000..9d7d5f6c --- /dev/null +++ b/build/patches/00Remove-ChromiumNetworkAdapter.patch @@ -0,0 +1,285 @@ +From: uazo +Date: Sat, 15 Apr 2023 11:46:48 +0000 +Subject: Remove ChromiumNetworkAdapter + +Removes from java code the ability to make http connections +without asking the native code +--- + .../browser/download/OMADownloadHandler.java | 38 ------------- + .../browser/feedback/ConnectivityChecker.java | 37 +------------ + .../ConnectivityDetector.java | 54 ------------------- + .../chrome/browser/omaha/OmahaBase.java | 3 +- + .../util/HttpURLConnectionFactoryImpl.java | 7 +-- + .../firstrun/VariationsSeedFetcher.java | 27 +--------- + .../chromium/net/ChromiumNetworkAdapter.java | 12 ----- + 7 files changed, 4 insertions(+), 174 deletions(-) + +diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/OMADownloadHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/download/OMADownloadHandler.java +--- a/chrome/android/java/src/org/chromium/chrome/browser/download/OMADownloadHandler.java ++++ b/chrome/android/java/src/org/chromium/chrome/browser/download/OMADownloadHandler.java +@@ -969,44 +969,6 @@ public class OMADownloadHandler extends BroadcastReceiver { + protected Boolean doInBackground() { + HttpURLConnection urlConnection = null; + boolean success = false; +- try { +- URL url = new URL(mOMAInfo.getValue(OMA_INSTALL_NOTIFY_URI)); +- urlConnection = (HttpURLConnection) ChromiumNetworkAdapter.openConnection( +- url, TRAFFIC_ANNOTATION); +- urlConnection.setDoOutput(true); +- urlConnection.setUseCaches(false); +- urlConnection.setRequestMethod("POST"); +- String userAgent = mDownloadInfo.getUserAgent(); +- if (TextUtils.isEmpty(userAgent)) { +- userAgent = ContentUtils.getBrowserUserAgent(); +- } +- urlConnection.setRequestProperty("User-Agent", userAgent); +- urlConnection.setRequestProperty("cookie", mDownloadInfo.getCookie()); +- +- DataOutputStream dos = new DataOutputStream(urlConnection.getOutputStream()); +- try { +- dos.writeBytes(mStatusMessage); +- dos.flush(); +- } catch (IOException e) { +- Log.w(TAG, "Cannot write status message.", e); +- } finally { +- dos.close(); +- } +- int responseCode = urlConnection.getResponseCode(); +- if (responseCode == HttpURLConnection.HTTP_OK || responseCode == -1) { +- success = true; +- } else { +- success = false; +- } +- } catch (MalformedURLException e) { +- Log.w(TAG, "Invalid notification URL.", e); +- } catch (IOException e) { +- Log.w(TAG, "Cannot connect to server.", e); +- } catch (IllegalStateException e) { +- Log.w(TAG, "Cannot connect to server.", e); +- } finally { +- if (urlConnection != null) urlConnection.disconnect(); +- } + + if (success) { + String path = mDownloadInfo.getFilePath(); +diff --git a/chrome/android/java/src/org/chromium/chrome/browser/feedback/ConnectivityChecker.java b/chrome/android/java/src/org/chromium/chrome/browser/feedback/ConnectivityChecker.java +--- a/chrome/android/java/src/org/chromium/chrome/browser/feedback/ConnectivityChecker.java ++++ b/chrome/android/java/src/org/chromium/chrome/browser/feedback/ConnectivityChecker.java +@@ -137,42 +137,7 @@ public final class ConnectivityChecker { + postResult(callback, ConnectivityCheckResult.ERROR); + return; + } +- new AsyncTask() { +- @Override +- protected Integer doInBackground() { +- try { +- HttpURLConnection conn = +- (HttpURLConnection) ChromiumNetworkAdapter.openConnection( +- url, TRAFFIC_ANNOTATION); +- conn.setInstanceFollowRedirects(false); +- conn.setRequestMethod("GET"); +- conn.setDoInput(false); +- conn.setDoOutput(false); +- conn.setConnectTimeout(timeoutMs); +- conn.setReadTimeout(timeoutMs); +- +- conn.connect(); +- int responseCode = conn.getResponseCode(); +- if (responseCode == HttpURLConnection.HTTP_NO_CONTENT) { +- return ConnectivityCheckResult.CONNECTED; +- } else { +- return ConnectivityCheckResult.NOT_CONNECTED; +- } +- } catch (SocketTimeoutException e) { +- return ConnectivityCheckResult.TIMEOUT; +- } catch (ProtocolException e) { +- return ConnectivityCheckResult.ERROR; +- } catch (IOException e) { +- return ConnectivityCheckResult.NOT_CONNECTED; +- } +- } +- +- @Override +- protected void onPostExecute(Integer result) { +- callback.onResult(result); +- } +- } +- .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); ++ postResult(callback, ConnectivityCheckResult.ERROR); + } + + /** +diff --git a/chrome/android/java/src/org/chromium/chrome/browser/net/connectivitydetector/ConnectivityDetector.java b/chrome/android/java/src/org/chromium/chrome/browser/net/connectivitydetector/ConnectivityDetector.java +--- a/chrome/android/java/src/org/chromium/chrome/browser/net/connectivitydetector/ConnectivityDetector.java ++++ b/chrome/android/java/src/org/chromium/chrome/browser/net/connectivitydetector/ConnectivityDetector.java +@@ -389,60 +389,6 @@ public class ConnectivityDetector implements NetworkChangeNotifier.ConnectionTyp + new AsyncTask() { + @Override + protected Integer doInBackground() { +- HttpURLConnection urlConnection = null; +- try { +- RecordHistogram.recordCount1MHistogram( +- "ConnectivityDetector.SentHttpProbe." + mClientName, 1); +- Log.i(TAG, "Sending HTTP Probe now to url:" + urlString); +- +- URL url = new URL(urlString); +- urlConnection = (HttpURLConnection) ChromiumNetworkAdapter.openConnection( +- url, NetworkTrafficAnnotationTag.MISSING_TRAFFIC_ANNOTATION); +- urlConnection.setInstanceFollowRedirects(false); +- urlConnection.setRequestMethod(sProbeMethod); +- urlConnection.setConnectTimeout(timeoutMs); +- urlConnection.setReadTimeout(timeoutMs); +- urlConnection.setUseCaches(false); +- urlConnection.setRequestProperty(USER_AGENT_HEADER_NAME, mUserAgentString); +- +- long requestTimestamp = SystemClock.elapsedRealtime(); +- urlConnection.connect(); +- long responseTimestamp = SystemClock.elapsedRealtime(); +- int responseCode = urlConnection.getResponseCode(); +- +- Log.i(TAG, +- "Probe " + urlString + " time=" + (responseTimestamp - requestTimestamp) +- + "ms ret=" + responseCode +- + " headers=" + urlConnection.getHeaderFields()); +- +- if (responseCode == HttpURLConnection.HTTP_NO_CONTENT) { +- return ProbeResult.VALIDATED_WITH_NO_CONTENT; +- } else if (responseCode >= 400) { +- return ProbeResult.SERVER_ERROR; +- } else if (responseCode == HttpURLConnection.HTTP_OK) { +- // Treat 200 response with zero content length to not be a captive portal +- // because the user cannot sign in to an empty page. Probably this is due to +- // a broken transparent proxy. +- if (urlConnection.getContentLength() == 0) { +- return ProbeResult.VALIDATED_WITH_OK_BUT_ZERO_CONTENT_LENGTH; +- } else if (urlConnection.getContentLength() == -1) { +- // When no Content-length (default value == -1), attempt to read a byte +- // from the response. +- if (urlConnection.getInputStream().read() == -1) { +- return ProbeResult.VALIDATED_WITH_OK_BUT_NO_CONTENT_LENGTH; +- } +- } +- } +- } catch (IOException e) { +- Log.i(TAG, "Probe " + urlString + " failed w/ exception " + e); +- // Most likely the exception is thrown due to host name not resolved or socket +- // timeout. +- return ProbeResult.NO_INTERNET; +- } finally { +- if (urlConnection != null) { +- urlConnection.disconnect(); +- } +- } + // The result returned from a well-known URL doesn't match the expected result, + // probably due to that the traffic is intercepted by the captive portal. + return ProbeResult.NOT_VALIDATED; +diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/OmahaBase.java b/chrome/android/java/src/org/chromium/chrome/browser/omaha/OmahaBase.java +--- a/chrome/android/java/src/org/chromium/chrome/browser/omaha/OmahaBase.java ++++ b/chrome/android/java/src/org/chromium/chrome/browser/omaha/OmahaBase.java +@@ -471,8 +471,7 @@ public class OmahaBase { + + "}"); + try { + URL url = new URL(getRequestGenerator().getServerUrl()); +- HttpURLConnection connection = +- (HttpURLConnection) ChromiumNetworkAdapter.openConnection(url, annotation); ++ HttpURLConnection connection = null; + connection.setConnectTimeout(MS_CONNECTION_TIMEOUT); + connection.setReadTimeout(MS_CONNECTION_TIMEOUT); + return connection; +diff --git a/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/util/HttpURLConnectionFactoryImpl.java b/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/util/HttpURLConnectionFactoryImpl.java +--- a/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/util/HttpURLConnectionFactoryImpl.java ++++ b/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/util/HttpURLConnectionFactoryImpl.java +@@ -37,11 +37,6 @@ public class HttpURLConnectionFactoryImpl implements HttpURLConnectionFactory { + + @Override + public HttpURLConnection createHttpURLConnection(String url) { +- try { +- return (HttpURLConnection) ChromiumNetworkAdapter.openConnection( +- new URL(url), TRAFFIC_ANNOTATION); +- } catch (IOException e) { +- return null; +- } ++ return null; + } + } +diff --git a/components/variations/android/java/src/org/chromium/components/variations/firstrun/VariationsSeedFetcher.java b/components/variations/android/java/src/org/chromium/components/variations/firstrun/VariationsSeedFetcher.java +--- a/components/variations/android/java/src/org/chromium/components/variations/firstrun/VariationsSeedFetcher.java ++++ b/components/variations/android/java/src/org/chromium/components/variations/firstrun/VariationsSeedFetcher.java +@@ -181,15 +181,6 @@ public class VariationsSeedFetcher { + sInstance = fetcher; + } + +- @VisibleForTesting +- protected HttpURLConnection getServerConnection( +- @VariationsPlatform int platform, String restrictMode, String milestone, String channel) +- throws MalformedURLException, IOException { +- String urlString = getConnectionString(platform, restrictMode, milestone, channel); +- URL url = new URL(urlString); +- return (HttpURLConnection) ChromiumNetworkAdapter.openConnection(url, TRAFFIC_ANNOTATION); +- } +- + @VisibleForTesting + protected List getAvailableInstanceManipulations() { + List compressions = new ArrayList(); +@@ -391,24 +382,8 @@ public class VariationsSeedFetcher { + HttpURLConnection connection = null; + try { + long startTimeMillis = SystemClock.elapsedRealtime(); +- connection = getServerConnection(platform, restrictMode, milestone, channel); +- connection.setReadTimeout(READ_TIMEOUT); +- connection.setConnectTimeout(REQUEST_TIMEOUT); +- connection.setDoInput(true); +- if (curSeedInfo != null) { +- VariationsSeed currentVariationsSeed = curSeedInfo.getParsedVariationsSeed(); +- if (currentVariationsSeed != null) { +- String serialNumber = currentVariationsSeed.getSerialNumber(); +- if (!serialNumber.isEmpty()) { +- connection.setRequestProperty("If-None-Match", serialNumber); +- } +- } +- } + List requestedInstanceManipulations = getAvailableInstanceManipulations(); +- connection.setRequestProperty("A-IM", String.join(",", requestedInstanceManipulations)); +- connection.connect(); +- int responseCode = connection.getResponseCode(); +- fetchInfo.seedFetchResult = responseCode; ++ int responseCode = 400; + if (responseCode == HttpURLConnection.HTTP_OK) { + recordSeedConnectTime(SystemClock.elapsedRealtime() - startTimeMillis); + +diff --git a/net/android/java/src/org/chromium/net/ChromiumNetworkAdapter.java b/net/android/java/src/org/chromium/net/ChromiumNetworkAdapter.java +--- a/net/android/java/src/org/chromium/net/ChromiumNetworkAdapter.java ++++ b/net/android/java/src/org/chromium/net/ChromiumNetworkAdapter.java +@@ -25,10 +25,6 @@ public final class ChromiumNetworkAdapter { + * what data gets sent, what triggers it, etc. + * @return a URLConnection linking to the URL. + */ +- public static URLConnection openConnection( +- URL url, NetworkTrafficAnnotationTag trafficAnnotation) throws IOException { +- return url.openConnection(); +- } + + /** + * Wrapper around URL#openConnection(Proxy), with an extra argument for static analysis/privacy +@@ -40,10 +36,6 @@ public final class ChromiumNetworkAdapter { + * what data gets sent, what triggers it, etc. + * @return a URLConnection linking to the URL. + */ +- public static URLConnection openConnection(URL url, Proxy proxy, +- NetworkTrafficAnnotationTag trafficAnnotation) throws IOException { +- return url.openConnection(proxy); +- } + + /** + * Wrapper around URL#openStream(), with an extra argument for static analysis/privacy +@@ -54,8 +46,4 @@ public final class ChromiumNetworkAdapter { + * what data gets sent, what triggers it, etc. + * @return an InputStream linking to the URL. + */ +- public static InputStream openStream(URL url, NetworkTrafficAnnotationTag trafficAnnotation) +- throws IOException { +- return url.openStream(); +- } + } +-- +2.25.1