Browse Source

chore: cherry-pick 11 changes from 3-M126 (#43141)

* chore: [30-x-y] cherry-pick 11 changes from 3-M126

* d54105311590 from chromium
* 43b8b682d05c from chromium
* c5dd8839bfaf from chromium
* cdbc1d9684a3 from v8
* 38e4483e47f9 from chromium
* 70d2fe6b7c47 from v8
* 901377bb2f3b from v8
* 1b9040817119 from chromium
* bb28367eed73 from v8
* 99cafbf4b4b9 from chromium
* bc545b15a0ee from v8

* chore: update patches

* 5639725: [wasm] Fix scanning of wasm-to-js params | https://chromium-review.googlesource.com/c/v8/v8/+/5639725

* 5672472: [M120-LTS] Prevent script injection on reload when racing with a navigation | https://chromium-review.googlesource.com/c/chromium/src/+/5672472
Keeley Hammond 8 months ago
parent
commit
1ec867c8a1

+ 6 - 0
patches/chromium/.patches

@@ -137,3 +137,9 @@ fix_font_face_resolution_when_renderer_is_blocked.patch
 x11_use_localized_display_label_only_for_browser_process.patch
 feat_enable_passing_exit_code_on_service_process_crash.patch
 feat_enable_customizing_symbol_color_in_framecaptionbutton.patch
+cherry-pick-d54105311590.patch
+cherry-pick-43b8b682d05c.patch
+cherry-pick-c5dd8839bfaf.patch
+cherry-pick-38e4483e47f9.patch
+cherry-pick-1b9040817119.patch
+cherry-pick-99cafbf4b4b9.patch

+ 84 - 0
patches/chromium/cherry-pick-1b9040817119.patch

@@ -0,0 +1,84 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Bryant Chandler <[email protected]>
+Date: Mon, 24 Jun 2024 17:28:53 +0000
+Subject: Fix pointer tear down order problem
+
+Holding a RenderFrameHost* in the `OnceBinding` isn't safe,
+because the `RenderFrameHost` can be destroyed before the
+binding. This CL changes the task strategy so that the
+RenderFrameHost* doesn't need to be bound in a callback.
+
+Tested using the repro steps in the bug and this change stops
+it from reproducing.
+
+Fixed: 347373236
+Change-Id: Id639f317b0f37a508833aba9fe52ffc5c0ed590c
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5640501
+Reviewed-by: Dave Tapuska <[email protected]>
+Commit-Queue: Bryant Chandler <[email protected]>
+Reviewed-by: Guido Urdaneta <[email protected]>
+Cr-Commit-Position: refs/heads/main@{#1318653}
+
+diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc
+index 65bee7132f6583cb64d774756423942382c8eed6..2c27db7ee49193cbf91158d576e29bb255378a3e 100644
+--- a/content/browser/renderer_host/media/media_stream_manager.cc
++++ b/content/browser/renderer_host/media/media_stream_manager.cc
+@@ -2887,25 +2887,19 @@ void MediaStreamManager::GetRawDeviceIdsOpenedForFrame(
+     RenderFrameHost* render_frame_host,
+     blink::mojom::MediaStreamType type,
+     GetRawDeviceIdsOpenedForFrameCallback callback) const {
+-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+-  CHECK(render_frame_host);
+-  auto collect_all_render_frame_host_ids = base::BindOnce(
+-      [](RenderFrameHost* render_frame_host) {
+-        base::flat_set<GlobalRenderFrameHostId> all_render_frame_host_ids;
+-        render_frame_host->ForEachRenderFrameHost(
+-            [&all_render_frame_host_ids](RenderFrameHost* render_frame_host) {
+-              all_render_frame_host_ids.insert(
+-                  render_frame_host->GetGlobalId());
+-            });
+-        return all_render_frame_host_ids;
+-      },
+-      render_frame_host);
+-
+-  GetUIThreadTaskRunner()->PostTaskAndReplyWithResult(
+-      FROM_HERE, std::move(collect_all_render_frame_host_ids),
+-      base::BindPostTaskToCurrentDefault(
+-          base::BindOnce(&MediaStreamManager::GetRawDeviceIdsOpenedForFrameIds,
+-                         base::Unretained(this), type, std::move(callback))));
++  DCHECK_CURRENTLY_ON(BrowserThread::UI);
++
++  base::flat_set<GlobalRenderFrameHostId> all_render_frame_host_ids;
++  render_frame_host->ForEachRenderFrameHost(
++      [&all_render_frame_host_ids](RenderFrameHost* render_frame_host) {
++        all_render_frame_host_ids.insert(render_frame_host->GetGlobalId());
++      });
++
++  GetIOThreadTaskRunner()->PostTask(
++      FROM_HERE,
++      base::BindOnce(&MediaStreamManager::GetRawDeviceIdsOpenedForFrameIds,
++                     base::Unretained(this), type, std::move(callback),
++                     all_render_frame_host_ids));
+ }
+ 
+ void MediaStreamManager::GetRawDeviceIdsOpenedForFrameIds(
+diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
+index b0b1d0aea5bf251411d0cab06562fd77d8d7c549..819c73370d6e6fc5e6ab24e78646a206b6a5873d 100644
+--- a/content/browser/web_contents/web_contents_impl.cc
++++ b/content/browser/web_contents/web_contents_impl.cc
+@@ -10808,12 +10808,9 @@ void WebContentsImpl::GetMediaCaptureRawDeviceIdsOpened(
+     return;
+   }
+ 
+-  GetIOThreadTaskRunner({})->PostTask(
+-      FROM_HERE,
+-      base::BindOnce(&MediaStreamManager::GetRawDeviceIdsOpenedForFrame,
+-                     base::Unretained(media_stream_manager),
+-                     GetPrimaryMainFrame(), type,
+-                     base::BindPostTaskToCurrentDefault(std::move(callback))));
++  media_stream_manager->GetRawDeviceIdsOpenedForFrame(
++      GetPrimaryMainFrame(), type,
++      base::BindPostTaskToCurrentDefault(std::move(callback)));
+ }
+ 
+ }  // namespace content

+ 88 - 0
patches/chromium/cherry-pick-38e4483e47f9.patch

@@ -0,0 +1,88 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Johannes Kron <[email protected]>
+Date: Wed, 19 Jun 2024 20:59:48 +0000
+Subject: Use BindPostTask() + weak pointer in callback handler
+
+The callback handler incorrectly accessed member objects directly which may
+cause UAF. Avoid this by using BindPostTask() together with a weak pointer.
+
+Fixed: 346898524
+Change-Id: I9d03d6decfd0212af88d3d0d8d70f83f1081d2e3
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5639016
+Reviewed-by: Avi Drissman <[email protected]>
+Reviewed-by: Mark Foltz <[email protected]>
+Commit-Queue: Johannes Kron <[email protected]>
+Cr-Commit-Position: refs/heads/main@{#1317142}
+
+diff --git a/content/browser/media/capture/screen_capture_kit_device_mac.mm b/content/browser/media/capture/screen_capture_kit_device_mac.mm
+index 4fb3e8eb5f34a7ee9e8b0f22a7c842129cdc31eb..e2710fba1a8d7a4cee6023558898c74706a9c189 100644
+--- a/content/browser/media/capture/screen_capture_kit_device_mac.mm
++++ b/content/browser/media/capture/screen_capture_kit_device_mac.mm
+@@ -326,13 +326,18 @@ void OnStreamSample(gfx::ScopedInUseIOSurface io_surface,
+                                destRectInFrame:dest_rect_in_frame
+                                      frameRate:requested_capture_format_->
+                                                frame_rate];
++
++          __block base::OnceCallback<void()> on_update_configuration_error =
++              base::BindPostTask(
++                  device_task_runner_,
++                  base::BindOnce(
++                      &ScreenCaptureKitDeviceMac::OnUpdateConfigurationError,
++                      weak_factory_.GetWeakPtr()));
+           [stream_
+               updateConfiguration:config
+                 completionHandler:^(NSError* _Nullable error) {
+                   if (error) {
+-                    client()->OnError(
+-                        media::VideoCaptureError::kScreenCaptureKitStreamError,
+-                        FROM_HERE, "Error on updateConfiguration");
++                    std::move(on_update_configuration_error).Run();
+                   }
+                 }];
+         }
+@@ -361,6 +366,21 @@ void OnStreamError() {
+                         FROM_HERE, "Stream delegate called didStopWithError");
+     }
+   }
++  void OnUpdateContentFilterCompleted(NSError* _Nullable error) {
++    DCHECK(device_task_runner_->RunsTasksInCurrentSequence());
++    is_resetting_ = false;
++
++    if (error) {
++      client()->OnError(media::VideoCaptureError::kScreenCaptureKitStreamError,
++                        FROM_HERE,
++                        "Error on updateContentFilter (fullscreen window).");
++    }
++  }
++  void OnUpdateConfigurationError() {
++    DCHECK(device_task_runner_->RunsTasksInCurrentSequence());
++    client()->OnError(media::VideoCaptureError::kScreenCaptureKitStreamError,
++                      FROM_HERE, "Error on updateConfiguration");
++  }
+ 
+   // IOSurfaceCaptureDeviceBase:
+   void OnStart() override {
+@@ -411,15 +431,16 @@ void ResetStreamTo(SCWindow* window) override {
+     SCContentFilter* filter =
+         [[SCContentFilter alloc] initWithDesktopIndependentWindow:window];
+ 
++    __block base::OnceCallback<void(NSError*)>
++        on_update_content_filter_completed = base::BindPostTask(
++            device_task_runner_,
++            base::BindOnce(
++                &ScreenCaptureKitDeviceMac::OnUpdateContentFilterCompleted,
++                weak_factory_.GetWeakPtr()));
++
+     [stream_ updateContentFilter:filter
+                completionHandler:^(NSError* _Nullable error) {
+-                 is_resetting_ = false;
+-                 if (error) {
+-                   client()->OnError(
+-                       media::VideoCaptureError::kScreenCaptureKitStreamError,
+-                       FROM_HERE,
+-                       "Error on updateContentFilter (fullscreen window).");
+-                 }
++                 std::move(on_update_content_filter_completed).Run(error);
+                }];
+   }
+ 

+ 264 - 0
patches/chromium/cherry-pick-43b8b682d05c.patch

@@ -0,0 +1,264 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Philip Pfaffe <[email protected]>
+Date: Tue, 18 Jun 2024 10:04:45 +0000
+Subject: Prevent script injection on reload when racing with a navigation
+
+DevTools passes the loaderId now when calling Page.reload, in order to
+prevent accidentally reloading the wrong page when a navigation occurred
+concurrently. It can still happen that the navigation kicks in in between the reload iniated in the browser and the script injection that happens in the renderer, which would run the injected script on the wrong target. We need to check the loaderId also on the renderer side.
+
+Fixed: 341136300
+Change-Id: I891fb37fa10e6789c8697a0f29bf7118788a9319
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5625857
+Reviewed-by: Andrey Kosyakov <[email protected]>
+Commit-Queue: Philip Pfaffe <[email protected]>
+Cr-Commit-Position: refs/heads/main@{#1316330}
+
+diff --git a/third_party/blink/renderer/core/inspector/build.gni b/third_party/blink/renderer/core/inspector/build.gni
+index 2e9feebe066f938506d63d157be65828aa2a27c9..39de006f5f97f9e2a84ee4d38f7bb98e99c41924 100644
+--- a/third_party/blink/renderer/core/inspector/build.gni
++++ b/third_party/blink/renderer/core/inspector/build.gni
+@@ -138,6 +138,7 @@ blink_core_tests_inspector = [
+   "inspector_emulation_agent_test.cc",
+   "inspector_highlight_test.cc",
+   "inspector_history_test.cc",
++  "inspector_page_agent_unittest.cc",
+   "inspector_preload_agent_unittest.cc",
+   "inspector_media_context_impl_unittest.cc",
+   "inspector_session_state_test.cc",
+diff --git a/third_party/blink/renderer/core/inspector/inspector_page_agent.cc b/third_party/blink/renderer/core/inspector/inspector_page_agent.cc
+index 1825080b32ab6d7adb86236a389c08caf0b90c5c..f17565a6178c3f47037378faf965cd0f52cb0d26 100644
+--- a/third_party/blink/renderer/core/inspector/inspector_page_agent.cc
++++ b/third_party/blink/renderer/core/inspector/inspector_page_agent.cc
+@@ -479,6 +479,42 @@ String InspectorPageAgent::CachedResourceTypeJson(
+   return ResourceTypeJson(ToResourceType(cached_resource.GetType()));
+ }
+ 
++InspectorPageAgent::PageReloadScriptInjection::PageReloadScriptInjection(
++    InspectorAgentState& agent_state)
++    : pending_script_to_evaluate_on_load_once_(&agent_state,
++                                               /*default_value=*/{}),
++      target_url_for_pending_script_(&agent_state,
++                                     /*default_value=*/{}) {}
++
++void InspectorPageAgent::PageReloadScriptInjection::clear() {
++  script_to_evaluate_on_load_once_ = {};
++  pending_script_to_evaluate_on_load_once_.Set({});
++  target_url_for_pending_script_.Set({});
++}
++
++void InspectorPageAgent::PageReloadScriptInjection::SetPending(
++    String script,
++    const KURL& target_url) {
++  pending_script_to_evaluate_on_load_once_.Set(script);
++  target_url_for_pending_script_.Set(target_url.GetString().GetString());
++}
++
++void InspectorPageAgent::PageReloadScriptInjection::PromoteToLoadOnce() {
++  script_to_evaluate_on_load_once_ =
++      pending_script_to_evaluate_on_load_once_.Get();
++  target_url_for_active_script_ = target_url_for_pending_script_.Get();
++  pending_script_to_evaluate_on_load_once_.Set({});
++  target_url_for_pending_script_.Set({});
++}
++
++String InspectorPageAgent::PageReloadScriptInjection::GetScriptForInjection(
++    const KURL& target_url) {
++  if (target_url_for_active_script_ == target_url.GetString()) {
++    return script_to_evaluate_on_load_once_;
++  }
++  return {};
++}
++
+ InspectorPageAgent::InspectorPageAgent(
+     InspectedFrames* inspected_frames,
+     Client* client,
+@@ -495,8 +531,6 @@ InspectorPageAgent::InspectorPageAgent(
+       screencast_enabled_(&agent_state_, /*default_value=*/false),
+       lifecycle_events_enabled_(&agent_state_, /*default_value=*/false),
+       bypass_csp_enabled_(&agent_state_, /*default_value=*/false),
+-      pending_script_to_evaluate_on_load_once_(&agent_state_,
+-                                               /*default_value=*/String()),
+       scripts_to_evaluate_on_load_(&agent_state_,
+                                    /*default_value=*/String()),
+       worlds_to_evaluate_on_load_(&agent_state_,
+@@ -506,7 +540,8 @@ InspectorPageAgent::InspectorPageAgent(
+           /*default_value=*/false),
+       standard_font_size_(&agent_state_, /*default_value=*/0),
+       fixed_font_size_(&agent_state_, /*default_value=*/0),
+-      script_font_families_cbor_(&agent_state_, std::vector<uint8_t>()) {}
++      script_font_families_cbor_(&agent_state_, std::vector<uint8_t>()),
++      script_injection_on_load_(agent_state_) {}
+ 
+ void InspectorPageAgent::Restore() {
+   if (enabled_.Get())
+@@ -545,8 +580,7 @@ protocol::Response InspectorPageAgent::enable() {
+ protocol::Response InspectorPageAgent::disable() {
+   agent_state_.ClearAllFields();
+   pending_isolated_worlds_.clear();
+-  script_to_evaluate_on_load_once_ = String();
+-  pending_script_to_evaluate_on_load_once_.Set(String());
++  script_injection_on_load_.clear();
+   instrumenting_agents_->RemoveInspectorPageAgent(this);
+   inspector_resource_content_loader_->Cancel(
+       resource_content_loader_client_id_);
+@@ -672,8 +706,9 @@ protocol::Response InspectorPageAgent::setAdBlockingEnabled(bool enable) {
+ protocol::Response InspectorPageAgent::reload(
+     Maybe<bool> optional_bypass_cache,
+     Maybe<String> optional_script_to_evaluate_on_load) {
+-  pending_script_to_evaluate_on_load_once_.Set(
+-      optional_script_to_evaluate_on_load.value_or(""));
++  script_injection_on_load_.SetPending(
++      optional_script_to_evaluate_on_load.value_or(""),
++      inspected_frames_->Root()->Loader().GetDocumentLoader()->Url());
+   v8_session_->setSkipAllPauses(true);
+   v8_session_->resume(true /* terminate on resume */);
+   return protocol::Response::Success();
+@@ -989,7 +1024,9 @@ void InspectorPageAgent::DidCreateMainWorldContext(LocalFrame* frame) {
+     EvaluateScriptOnNewDocument(*frame, key);
+   }
+ 
+-  if (script_to_evaluate_on_load_once_.empty()) {
++  String script = script_injection_on_load_.GetScriptForInjection(
++      frame->Loader().GetDocumentLoader()->Url());
++  if (script.empty()) {
+     return;
+   }
+   ScriptState* script_state = ToScriptStateForMainWorld(frame);
+@@ -997,9 +1034,8 @@ void InspectorPageAgent::DidCreateMainWorldContext(LocalFrame* frame) {
+     return;
+   }
+ 
+-  v8_session_->evaluate(
+-      script_state->GetContext(),
+-      ToV8InspectorStringView(script_to_evaluate_on_load_once_));
++  v8_session_->evaluate(script_state->GetContext(),
++                        ToV8InspectorStringView(script));
+ }
+ 
+ void InspectorPageAgent::EvaluateScriptOnNewDocument(
+@@ -1049,9 +1085,7 @@ void InspectorPageAgent::LoadEventFired(LocalFrame* frame) {
+ 
+ void InspectorPageAgent::WillCommitLoad(LocalFrame*, DocumentLoader* loader) {
+   if (loader->GetFrame() == inspected_frames_->Root()) {
+-    script_to_evaluate_on_load_once_ =
+-        pending_script_to_evaluate_on_load_once_.Get();
+-    pending_script_to_evaluate_on_load_once_.Set(String());
++    script_injection_on_load_.PromoteToLoadOnce();
+   }
+   GetFrontend()->frameNavigated(BuildObjectForFrame(loader->GetFrame()),
+                                 protocol::Page::NavigationTypeEnum::Navigation);
+diff --git a/third_party/blink/renderer/core/inspector/inspector_page_agent.h b/third_party/blink/renderer/core/inspector/inspector_page_agent.h
+index 6e6263beee810946d03934e7f707bb49a3177a2f..e7003baa895494bf61ad06f875d825ac9f53aec2 100644
+--- a/third_party/blink/renderer/core/inspector/inspector_page_agent.h
++++ b/third_party/blink/renderer/core/inspector/inspector_page_agent.h
+@@ -94,6 +94,22 @@ class CORE_EXPORT InspectorPageAgent final
+     kOtherResource
+   };
+ 
++  class CORE_EXPORT PageReloadScriptInjection {
++   private:
++    String script_to_evaluate_on_load_once_;
++    String target_url_for_active_script_;
++    InspectorAgentState::String pending_script_to_evaluate_on_load_once_;
++    InspectorAgentState::String target_url_for_pending_script_;
++
++   public:
++    explicit PageReloadScriptInjection(InspectorAgentState&);
++
++    void clear();
++    void SetPending(String script, const KURL& target_url);
++    void PromoteToLoadOnce();
++    String GetScriptForInjection(const KURL& target_url);
++  };
++
+   static bool CachedResourceContent(const Resource*,
+                                     String* result,
+                                     bool* base64_encoded);
+@@ -307,7 +323,6 @@ class CORE_EXPORT InspectorPageAgent final
+       ad_script_identifiers_;
+   v8_inspector::V8InspectorSession* v8_session_;
+   Client* client_;
+-  String script_to_evaluate_on_load_once_;
+   Member<InspectorResourceContentLoader> inspector_resource_content_loader_;
+   int resource_content_loader_client_id_;
+   InspectorAgentState::Boolean intercept_file_chooser_;
+@@ -315,7 +330,6 @@ class CORE_EXPORT InspectorPageAgent final
+   InspectorAgentState::Boolean screencast_enabled_;
+   InspectorAgentState::Boolean lifecycle_events_enabled_;
+   InspectorAgentState::Boolean bypass_csp_enabled_;
+-  InspectorAgentState::String pending_script_to_evaluate_on_load_once_;
+   InspectorAgentState::StringMap scripts_to_evaluate_on_load_;
+   InspectorAgentState::StringMap worlds_to_evaluate_on_load_;
+   InspectorAgentState::BooleanMap
+@@ -323,6 +337,7 @@ class CORE_EXPORT InspectorPageAgent final
+   InspectorAgentState::Integer standard_font_size_;
+   InspectorAgentState::Integer fixed_font_size_;
+   InspectorAgentState::Bytes script_font_families_cbor_;
++  PageReloadScriptInjection script_injection_on_load_;
+ };
+ 
+ }  // namespace blink
+diff --git a/third_party/blink/renderer/core/inspector/inspector_page_agent_unittest.cc b/third_party/blink/renderer/core/inspector/inspector_page_agent_unittest.cc
+new file mode 100644
+index 0000000000000000000000000000000000000000..b81f6b4735392f3f542ccbb2a114c2def185be1c
+--- /dev/null
++++ b/third_party/blink/renderer/core/inspector/inspector_page_agent_unittest.cc
+@@ -0,0 +1,57 @@
++// Copyright 2024 The Chromium Authors
++// Use of this source code is governed by a BSD-style license that can be
++// found in the LICENSE file.
++
++#include "third_party/blink/renderer/core/inspector/inspector_page_agent.h"
++
++#include "testing/gtest/include/gtest/gtest.h"
++#include "third_party/blink/renderer/core/inspector/inspector_session_state.h"
++#include "third_party/blink/renderer/platform/weborigin/kurl.h"
++
++class PageReloadScriptInjectionTest : public testing::Test {
++ protected:
++  blink::mojom::blink::DevToolsSessionStatePtr session_state_cookie_;
++  blink::InspectorAgentState agent_state_;
++  blink::InspectorPageAgent::PageReloadScriptInjection injection_;
++  blink::InspectorSessionState state_;
++
++ public:
++  PageReloadScriptInjectionTest()
++      : agent_state_("page"),
++        injection_(agent_state_),
++        state_(session_state_cookie_.Clone()) {}
++
++  void SetUp() override { agent_state_.InitFrom(&state_); }
++};
++
++TEST_F(PageReloadScriptInjectionTest, PromotesScript) {
++  blink::KURL url("http://example.com");
++  injection_.SetPending("script", url);
++  ASSERT_TRUE(injection_.GetScriptForInjection(url).empty());
++  injection_.PromoteToLoadOnce();
++  ASSERT_EQ(injection_.GetScriptForInjection(url), "script");
++  injection_.PromoteToLoadOnce();
++  ASSERT_TRUE(injection_.GetScriptForInjection(url).empty());
++}
++
++TEST_F(PageReloadScriptInjectionTest, ClearsScript) {
++  blink::KURL url("http://example.com");
++  injection_.SetPending("script", url);
++  injection_.clear();
++  injection_.PromoteToLoadOnce();
++  ASSERT_TRUE(injection_.GetScriptForInjection(url).empty());
++
++  injection_.SetPending("script", url);
++  injection_.PromoteToLoadOnce();
++  ASSERT_EQ(injection_.GetScriptForInjection(url), "script");
++  injection_.clear();
++  ASSERT_TRUE(injection_.GetScriptForInjection(url).empty());
++}
++
++TEST_F(PageReloadScriptInjectionTest, ChecksLoaderId) {
++  blink::KURL url("http://example.com");
++  blink::KURL url2("about:blank");
++  injection_.SetPending("script", url);
++  injection_.PromoteToLoadOnce();
++  ASSERT_TRUE(injection_.GetScriptForInjection(url2).empty());
++}

+ 166 - 0
patches/chromium/cherry-pick-99cafbf4b4b9.patch

@@ -0,0 +1,166 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Yann Dago <[email protected]>
+Date: Mon, 8 Jul 2024 16:20:32 +0000
+Subject: Ensure chrome://policy/test messages ignored when not supported
+
+It was possible to go to chrome://policy and in the dev tools and send
+the right message to set test policies even if the policy test page was disabled and/or unavailable because both pages share the same handler.
+
+Bug: 338248595
+Change-Id: If689325999cb108b2b71b2821d905e42efd3390d
+Low-Coverage-Reason: TRIVIAL_CHANGE
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5679162
+Auto-Submit: Yann Dago <[email protected]>
+Reviewed-by: Rohit Rao <[email protected]>
+Reviewed-by: Sergey Poromov <[email protected]>
+Commit-Queue: Rohit Rao <[email protected]>
+Cr-Commit-Position: refs/heads/main@{#1324277}
+
+diff --git a/chrome/browser/ui/webui/policy/policy_test_ui_browsertest.cc b/chrome/browser/ui/webui/policy/policy_test_ui_browsertest.cc
+index e27325a18087c8a01d21111f2fa0dd6e6da60023..a03c639b8654a5cbedccc3c38de4007dba084bf8 100644
+--- a/chrome/browser/ui/webui/policy/policy_test_ui_browsertest.cc
++++ b/chrome/browser/ui/webui/policy/policy_test_ui_browsertest.cc
+@@ -8,6 +8,7 @@
+ #include "base/test/scoped_feature_list.h"
+ #include "build/build_config.h"
+ #include "build/chromeos_buildflags.h"
++#include "chrome/browser/enterprise/browser_management/browser_management_service.h"
+ #include "chrome/browser/enterprise/browser_management/management_service_factory.h"
+ #include "chrome/browser/lifetime/application_lifetime.h"
+ #include "chrome/browser/policy/chrome_browser_policy_connector.h"
+@@ -270,6 +271,57 @@ class PolicyTestHandlerTest : public PlatformBrowserTest {
+ #endif
+ };
+ 
++IN_PROC_BROWSER_TEST_F(PolicyTestHandlerTest,
++                       HandleSetLocalTestPoliciesNotSupported) {
++  // Ensure chrome://policy/test not supported.
++  policy::ScopedManagementServiceOverrideForTesting profile_management(
++      policy::ManagementServiceFactory::GetForProfile(GetProfile()),
++      policy::EnterpriseManagementAuthority::CLOUD);
++  std::unique_ptr<PolicyUIHandler> handler = SetUpHandler();
++  const std::string jsonString =
++      R"([
++      {"level": 0,"scope": 0,"source": 0, "namespace": "chrome",
++       "name": "AutofillAddressEnabled","value": false},
++      {"level": 1,"scope": 1,"source": 2, "namespace": "chrome",
++       "name": "CloudReportingEnabled","value": true}
++      ])";
++  const std::string revertAppliedPoliciesButtonDisabledJs =
++      R"(
++        document
++          .querySelector('#revert-applied-policies')
++          .disabled;
++      )";
++
++  base::Value::List list_args;
++
++  list_args.Append("setLocalTestPolicies");
++  list_args.Append(jsonString);
++  list_args.Append("{}");
++
++  // Open chrome://policy
++  ASSERT_TRUE(
++      content::NavigateToURL(web_contents(), GURL(chrome::kChromeUIPolicyURL)));
++  web_ui()->HandleReceivedMessage("setLocalTestPolicies", list_args);
++
++  base::RunLoop().RunUntilIdle();
++
++  const policy::PolicyNamespace chrome_namespace(policy::POLICY_DOMAIN_CHROME,
++                                                 std::string());
++  policy::PolicyService* policy_service =
++      GetProfile()->GetProfilePolicyConnector()->policy_service();
++
++  // Check policies not applied
++  const policy::PolicyMap* policy_map =
++      &policy_service->GetPolicies(chrome_namespace);
++  ASSERT_TRUE(policy_map);
++
++  {
++    const policy::PolicyMap::Entry* entry =
++        policy_map->Get(policy::key::kAutofillAddressEnabled);
++    ASSERT_FALSE(entry);
++  }
++}
++
+ IN_PROC_BROWSER_TEST_F(PolicyTestHandlerTest,
+                        HandleSetAndRevertLocalTestPolicies) {
+   if (!policy::utils::IsPolicyTestingEnabled(/*pref_service=*/nullptr,
+diff --git a/chrome/browser/ui/webui/policy/policy_ui_handler.cc b/chrome/browser/ui/webui/policy/policy_ui_handler.cc
+index 0d13979009fc4df379432d5eea1a394607203615..1dc6ecc6bed91115be10021c0661f8d81456161b 100644
+--- a/chrome/browser/ui/webui/policy/policy_ui_handler.cc
++++ b/chrome/browser/ui/webui/policy/policy_ui_handler.cc
+@@ -49,6 +49,7 @@
+ #include "chrome/browser/ui/chrome_select_file_policy.h"
+ #include "chrome/browser/ui/webui/policy/policy_ui.h"
+ #include "chrome/browser/ui/webui/webui_util.h"
++#include "chrome/common/channel_info.h"
+ #include "chrome/grit/branded_strings.h"
+ #include "components/crx_file/id_util.h"
+ #include "components/enterprise/browser/controller/browser_dm_token_storage.h"
+@@ -69,6 +70,7 @@
+ #include "components/policy/core/common/policy_pref_names.h"
+ #include "components/policy/core/common/policy_scheduler.h"
+ #include "components/policy/core/common/policy_types.h"
++#include "components/policy/core/common/policy_utils.h"
+ #include "components/policy/core/common/remote_commands/remote_commands_service.h"
+ #include "components/policy/core/common/schema.h"
+ #include "components/policy/core/common/schema_map.h"
+@@ -316,6 +318,12 @@ void PolicyUIHandler::HandleCopyPoliciesJson(const base::Value::List& args) {
+ void PolicyUIHandler::HandleSetLocalTestPolicies(
+     const base::Value::List& args) {
+   std::string policies = args[1].GetString();
++  AllowJavascript();
++
++  if (!PolicyUI::ShouldLoadTestPage(Profile::FromWebUI(web_ui()))) {
++    ResolveJavascriptCallback(args[0], true);
++    return;
++  }
+ 
+   policy::LocalTestPolicyProvider* local_test_provider =
+       static_cast<policy::LocalTestPolicyProvider*>(
+@@ -338,12 +346,14 @@ void PolicyUIHandler::HandleSetLocalTestPolicies(
+       ->UseLocalTestPolicyProvider();
+ 
+   local_test_provider->LoadJsonPolicies(policies);
+-  AllowJavascript();
+   ResolveJavascriptCallback(args[0], true);
+ }
+ 
+ void PolicyUIHandler::HandleRevertLocalTestPolicies(
+     const base::Value::List& args) {
++  if (!PolicyUI::ShouldLoadTestPage(Profile::FromWebUI(web_ui()))) {
++    return;
++  }
+ #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS)
+   Profile::FromWebUI(web_ui())->GetPrefs()->ClearPref(
+       prefs::kUserCloudSigninPolicyResponseFromPolicyTestPage);
+diff --git a/ios/chrome/browser/webui/ui_bundled/policy/policy_ui_handler.mm b/ios/chrome/browser/webui/ui_bundled/policy/policy_ui_handler.mm
+index 577caf2012e0cdcdcf5baa4c5a288119da40cabd..94466842c2faeb13fd0ae33ba619362f8a43cd06 100644
+--- a/ios/chrome/browser/webui/ui_bundled/policy/policy_ui_handler.mm
++++ b/ios/chrome/browser/webui/ui_bundled/policy/policy_ui_handler.mm
+@@ -220,6 +220,12 @@
+     const base::Value::List& args) {
+   std::string json_policies_string = args[1].GetString();
+ 
++  if (!PolicyUI::ShouldLoadTestPage(
++          ChromeBrowserState::FromWebUIIOS(web_ui()))) {
++    web_ui()->ResolveJavascriptCallback(args[0], true);
++    return;
++  }
++
+   policy::LocalTestPolicyProvider* local_test_provider =
+       static_cast<policy::LocalTestPolicyProvider*>(
+           GetApplicationContext()
+@@ -238,6 +244,11 @@
+ 
+ void PolicyUIHandler::HandleRevertLocalTestPolicies(
+     const base::Value::List& args) {
++  if (!PolicyUI::ShouldLoadTestPage(
++          ChromeBrowserState::FromWebUIIOS(web_ui()))) {
++    return;
++  }
++
+   ChromeBrowserState::FromWebUIIOS(web_ui())
+       ->GetPolicyConnector()
+       ->RevertUseLocalTestPolicyProvider();

+ 32 - 0
patches/chromium/cherry-pick-c5dd8839bfaf.patch

@@ -0,0 +1,32 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Rakina Zata Amni <[email protected]>
+Date: Wed, 19 Jun 2024 02:49:58 +0000
+Subject: Destruct controller before referenced WebUI in CreateWebUIIfNeeded
+
+Reset `controller` first before resetting `web_ui_`, since the
+controller still has a pointer to `web_ui_`, to avoid referencing to
+the already deleted `web_ui_` object from `controller`'s destructor.
+
+Bug: 345640549
+Change-Id: Ie9c193436b593845d8269605f68bf94bc75beed7
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5624749
+Commit-Queue: Rakina Zata Amni <[email protected]>
+Reviewed-by: Nasko Oskov <[email protected]>
+Cr-Commit-Position: refs/heads/main@{#1316830}
+
+diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
+index 8a9beaf3bfb9fe5eca8ca6675c7c45b4b880db03..85041c38c8d2e84d780948a4dab94013ce39dfbe 100644
+--- a/content/browser/renderer_host/navigation_request.cc
++++ b/content/browser/renderer_host/navigation_request.cc
+@@ -10268,6 +10268,11 @@ void NavigationRequest::CreateWebUIIfNeeded(RenderFrameHostImpl* frame_host) {
+       bindings() != web_ui_->GetBindings()) {
+     RecordAction(base::UserMetricsAction("ProcessSwapBindingsMismatch_RVHM"));
+     base::WeakPtr<NavigationRequest> self = GetWeakPtr();
++    // Reset `controller` first before resetting `web_ui_`, since the controller
++    // still has a pointer to `web_ui_`, to avoid referencing to the already
++    // deleted  `web_ui_` object from `controller`'s destructor. See also
++    // https://crbug.com/345640549.
++    controller.reset();
+     web_ui_.reset();
+     // Resetting the WebUI may indirectly call content's embedders and delete
+     // `this`. There are no known occurrences of it, so we assume this never

+ 37 - 0
patches/chromium/cherry-pick-d54105311590.patch

@@ -0,0 +1,37 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "mark a. foltz" <[email protected]>
+Date: Mon, 17 Jun 2024 23:07:32 +0000
+Subject: Retain refptr to shared helper to prevent UAF.
+
+Capture a reference to the shared helper in the onerror handler to
+prevent a UAF that can occur when the browser drops the mojo
+connection.
+
+Bug: 346692546
+Change-Id: Ifb264488a6fa8417c134a34d902605d2c141720b
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5634908
+Reviewed-by: Avi Drissman <[email protected]>
+Commit-Queue: Mark Foltz <[email protected]>
+Cr-Commit-Position: refs/heads/main@{#1316145}
+
+diff --git a/media/audio/mac/audio_loopback_input_mac_impl.mm b/media/audio/mac/audio_loopback_input_mac_impl.mm
+index 7b301492f17a3f1da96b8ff990f6deeb4a19b6e3..f90c00e668f58c2389e622466422ae7aa237c94d 100644
+--- a/media/audio/mac/audio_loopback_input_mac_impl.mm
++++ b/media/audio/mac/audio_loopback_input_mac_impl.mm
+@@ -394,12 +394,15 @@ - (void)stream:(SCStream*)stream
+       base::BindRepeating(&SCKAudioInputStream::OnStreamError,
+                           base::Unretained(this)));
+ 
++  // Make a local copy of the shared_refptr in case the error handler is called
++  // after `this` is destroyed.
++  auto local_shared_helper = shared_helper_;
+   [stream_ startCaptureWithCompletionHandler:^(NSError* error) {
+     if (!error) {
+       return;
+     }
+ 
+-    shared_helper_->OnStreamError(error);
++    local_shared_helper->OnStreamError(error);
+   }];
+ }
+ 

+ 5 - 0
patches/v8/.patches

@@ -3,3 +3,8 @@ deps_add_v8_object_setinternalfieldfornodecore.patch
 cherry-pick-8b400f9b7d66.patch
 cherry-pick-ba6cab40612d.patch
 merged_wasm_add_missing_type_canonicalization_for_exceptions_js.patch
+cherry-pick-cdbc1d9684a3.patch
+cherry-pick-70d2fe6b7c47.patch
+cherry-pick-901377bb2f3b.patch
+cherry-pick-bb28367eed73.patch
+cherry-pick-bc545b15a0ee.patch

+ 32 - 0
patches/v8/cherry-pick-70d2fe6b7c47.patch

@@ -0,0 +1,32 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Leszek Swirski <[email protected]>
+Date: Fri, 21 Jun 2024 15:11:40 +0200
+Subject: Allow reduced hasInstance to abort
+
+Fixed: 343507800
+Change-Id: I579041fe82e975d83a72e4744013cb04c4d3dc70
+Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5644891
+Commit-Queue: Toon Verwaest <[email protected]>
+Commit-Queue: Leszek Swirski <[email protected]>
+Auto-Submit: Leszek Swirski <[email protected]>
+Reviewed-by: Toon Verwaest <[email protected]>
+Cr-Commit-Position: refs/heads/main@{#94585}
+
+diff --git a/src/maglev/maglev-graph-builder.cc b/src/maglev/maglev-graph-builder.cc
+index efcdd6d2028a5e0f0ec1149925ab2e1fe5f90412..78f4dd57d339eaad8b265721ef37137291da7940 100644
+--- a/src/maglev/maglev-graph-builder.cc
++++ b/src/maglev/maglev-graph-builder.cc
+@@ -8639,10 +8639,9 @@ ReduceResult MaglevGraphBuilder::TryBuildFastInstanceOf(
+ 
+       if (has_instance_field->IsJSFunction()) {
+         SaveCallSpeculationScope saved(this);
+-        ReduceResult result =
+-            ReduceCallForConstant(has_instance_field->AsJSFunction(), args);
+-        DCHECK(!result.IsDoneWithAbort());
+-        call_result = result.value();
++        GET_VALUE_OR_ABORT(
++            call_result,
++            ReduceCallForConstant(has_instance_field->AsJSFunction(), args));
+       } else {
+         call_result = BuildGenericCall(GetConstant(*has_instance_field),
+                                        Call::TargetType::kAny, args);

+ 221 - 0
patches/v8/cherry-pick-901377bb2f3b.patch

@@ -0,0 +1,221 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Thibaud Michaud <[email protected]>
+Date: Fri, 21 Jun 2024 16:31:15 +0200
+Subject: Fix scanning of wasm-to-js params
+
+Wasm-to-js wrappers are sometimes compiled as on-heap Code objects, for
+example when tiering-up from a WasmFuncRef call origin. The frames of
+these functions are mapped to a subclass of TypedFrame, however
+TypedFrame::Iterate() only supports iterating the generic wasm-to-js
+wrapper.
+
+Add support for iterating the tagged parameters of optimized wasm-to-js
+wrappers in TypedFrame::Iterate. For this we also add two 16-bit fields
+in the Code object to encode the incoming tagged parameter region, which
+we would normally find in the WasmCode data.
+
[email protected]
+
+Fixed: 346597059
+Change-Id: I425619fca86c38f91f1ca9cbeb70e7b5a7b2d6c1
+Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5639725
+Reviewed-by: Jakob Kummerow <[email protected]>
+Commit-Queue: Thibaud Michaud <[email protected]>
+Cr-Commit-Position: refs/heads/main@{#94589}
+
+diff --git a/src/compiler/pipeline.cc b/src/compiler/pipeline.cc
+index 0181588337df73bfa97220d895733c40b92bd40b..033469e626ffb35846ae5114632f3dc000400935 100644
+--- a/src/compiler/pipeline.cc
++++ b/src/compiler/pipeline.cc
+@@ -2295,6 +2295,14 @@ CompilationJob::Status FinalizeWrapperCompilation(
+                                        Handle<AbstractCode>::cast(code),
+                                        info->GetDebugName().get()));
+     }
++    // Set the wasm-to-js specific code fields needed to scan the incoming stack
++    // parameters.
++    if (code->kind() == CodeKind::WASM_TO_JS_FUNCTION) {
++      code->set_wasm_js_tagged_parameter_count(
++          call_descriptor->GetTaggedParameterSlots() & 0xffff);
++      code->set_wasm_js_first_tagged_parameter(
++          call_descriptor->GetTaggedParameterSlots() >> 16);
++    }
+     return CompilationJob::SUCCEEDED;
+   }
+   return CompilationJob::FAILED;
+diff --git a/src/diagnostics/objects-printer.cc b/src/diagnostics/objects-printer.cc
+index 7677022ce31c1b8ead0cc2eb37fb505b750639be..12bd5b8fd27f67c73938550acc4af1857eace59a 100644
+--- a/src/diagnostics/objects-printer.cc
++++ b/src/diagnostics/objects-printer.cc
+@@ -2102,7 +2102,14 @@ void Code::CodePrint(std::ostream& os, const char* name, Address current_pc) {
+   os << "\n - instruction_size: " << instruction_size();
+   os << "\n - metadata_size: " << metadata_size();
+ 
+-  os << "\n - inlined_bytecode_size: " << inlined_bytecode_size();
++  if (kind() != CodeKind::WASM_TO_JS_FUNCTION) {
++    os << "\n - inlined_bytecode_size: " << inlined_bytecode_size();
++  } else {
++    os << "\n - wasm_js_tagged_parameter_count: "
++       << wasm_js_tagged_parameter_count();
++    os << "\n - wasm_js_first_tagged_parameter: "
++       << wasm_js_first_tagged_parameter();
++  }
+   os << "\n - osr_offset: " << osr_offset();
+   os << "\n - handler_table_offset: " << handler_table_offset();
+   os << "\n - unwinding_info_offset: " << unwinding_info_offset();
+diff --git a/src/execution/frames.cc b/src/execution/frames.cc
+index 92dff2f7e8c8f72e38eef4feb5b10ace9fe2535c..2693fb2a859dc7489ef802c3064beace88608415 100644
+--- a/src/execution/frames.cc
++++ b/src/execution/frames.cc
+@@ -1562,7 +1562,7 @@ void WasmFrame::Iterate(RootVisitor* v) const {
+                        frame_header_limit);
+ }
+ 
+-void TypedFrame::IterateParamsOfWasmToJSWrapper(RootVisitor* v) const {
++void TypedFrame::IterateParamsOfGenericWasmToJSWrapper(RootVisitor* v) const {
+   Tagged<Object> maybe_signature = Tagged<Object>(
+       Memory<Address>(fp() + WasmToJSWrapperConstants::kSignatureOffset));
+   if (IsSmi(maybe_signature)) {
+@@ -1678,6 +1678,18 @@ void TypedFrame::IterateParamsOfWasmToJSWrapper(RootVisitor* v) const {
+     }
+   }
+ }
++
++void TypedFrame::IterateParamsOfOptimizedWasmToJSWrapper(RootVisitor* v) const {
++  Tagged<GcSafeCode> code = GcSafeLookupCode();
++  if (code->wasm_js_tagged_parameter_count() > 0) {
++    FullObjectSlot tagged_parameter_base(&Memory<Address>(caller_sp()));
++    tagged_parameter_base += code->wasm_js_first_tagged_parameter();
++    FullObjectSlot tagged_parameter_limit =
++        tagged_parameter_base + code->wasm_js_tagged_parameter_count();
++    v->VisitRootPointers(Root::kStackRoots, nullptr, tagged_parameter_base,
++                         tagged_parameter_limit);
++  }
++}
+ #endif  // V8_ENABLE_WEBASSEMBLY
+ 
+ void TypedFrame::Iterate(RootVisitor* v) const {
+@@ -1709,10 +1721,13 @@ void TypedFrame::Iterate(RootVisitor* v) const {
+   CHECK(entry->code.has_value());
+   Tagged<GcSafeCode> code = entry->code.value();
+ #if V8_ENABLE_WEBASSEMBLY
+-  bool is_wasm_to_js =
++  bool is_generic_wasm_to_js =
+       code->is_builtin() && code->builtin_id() == Builtin::kWasmToJsWrapperCSA;
+-  if (is_wasm_to_js) {
+-    IterateParamsOfWasmToJSWrapper(v);
++  bool is_optimized_wasm_to_js = this->type() == WASM_TO_JS_FUNCTION;
++  if (is_generic_wasm_to_js) {
++    IterateParamsOfGenericWasmToJSWrapper(v);
++  } else if (is_optimized_wasm_to_js) {
++    IterateParamsOfOptimizedWasmToJSWrapper(v);
+   }
+ #endif  // V8_ENABLE_WEBASSEMBLY
+   DCHECK(code->is_turbofanned());
+@@ -1745,10 +1760,14 @@ void TypedFrame::Iterate(RootVisitor* v) const {
+   // wrapper switched to before pushing the outgoing stack parameters and
+   // calling the target. It marks the limit of the stack param area, and is
+   // distinct from the beginning of the spill area.
+-  Address central_stack_sp =
+-      Memory<Address>(fp() + WasmToJSWrapperConstants::kCentralStackSPOffset);
++  int central_stack_sp_offset =
++      is_generic_wasm_to_js
++          ? WasmToJSWrapperConstants::kCentralStackSPOffset
++          : WasmImportWrapperFrameConstants::kCentralStackSPOffset;
++  Address central_stack_sp = Memory<Address>(fp() + central_stack_sp_offset);
+   FullObjectSlot parameters_limit(
+-      is_wasm_to_js && central_stack_sp != kNullAddress
++      (is_generic_wasm_to_js || is_optimized_wasm_to_js) &&
++              central_stack_sp != kNullAddress
+           ? central_stack_sp
+           : frame_header_base.address() - spill_slots_size);
+ #else
+diff --git a/src/execution/frames.h b/src/execution/frames.h
+index 081c74bf124ccfa57e4b40f75cbe42b00c771b2e..908239b4161235aeda04fe5526ddea8d56b09425 100644
+--- a/src/execution/frames.h
++++ b/src/execution/frames.h
+@@ -634,7 +634,8 @@ class TypedFrame : public CommonFrame {
+   Tagged<HeapObject> unchecked_code() const override { return {}; }
+   void Iterate(RootVisitor* v) const override;
+ 
+-  void IterateParamsOfWasmToJSWrapper(RootVisitor* v) const;
++  void IterateParamsOfGenericWasmToJSWrapper(RootVisitor* v) const;
++  void IterateParamsOfOptimizedWasmToJSWrapper(RootVisitor* v) const;
+ 
+  protected:
+   inline explicit TypedFrame(StackFrameIteratorBase* iterator);
+diff --git a/src/objects/code-inl.h b/src/objects/code-inl.h
+index baaced29afdbc87eae1c34b8df779e17e41410c4..1e1d66a87ee633cbdb49265444f53b5db790d9dd 100644
+--- a/src/objects/code-inl.h
++++ b/src/objects/code-inl.h
+@@ -48,6 +48,8 @@ GCSAFE_CODE_FWD_ACCESSOR(bool, has_tagged_outgoing_params)
+ GCSAFE_CODE_FWD_ACCESSOR(bool, marked_for_deoptimization)
+ GCSAFE_CODE_FWD_ACCESSOR(Tagged<Object>, raw_instruction_stream)
+ GCSAFE_CODE_FWD_ACCESSOR(int, stack_slots)
++GCSAFE_CODE_FWD_ACCESSOR(uint16_t, wasm_js_tagged_parameter_count)
++GCSAFE_CODE_FWD_ACCESSOR(uint16_t, wasm_js_first_tagged_parameter)
+ GCSAFE_CODE_FWD_ACCESSOR(Address, constant_pool)
+ GCSAFE_CODE_FWD_ACCESSOR(Address, safepoint_table_address)
+ #undef GCSAFE_CODE_FWD_ACCESSOR
+@@ -428,6 +430,31 @@ void Code::set_inlined_bytecode_size(unsigned size) {
+   RELAXED_WRITE_UINT_FIELD(*this, kInlinedBytecodeSizeOffset, size);
+ }
+ 
++// For optimized on-heap wasm-js wrappers, we repurpose the (otherwise unused)
++// 32-bit InlinedBytecodeSize field to encode two 16 values needed for scanning
++// the frame: the count and starting offset of incoming tagged parameters.
++// TODO(wasm): Eventually the wrappers should be managed off-heap by the wasm
++// engine. Remove these accessors when that is the case.
++void Code::set_wasm_js_tagged_parameter_count(uint16_t count) {
++  DCHECK_EQ(kind(), CodeKind::WASM_TO_JS_FUNCTION);
++  RELAXED_WRITE_UINT16_FIELD(*this, kInlinedBytecodeSizeOffset, count);
++}
++
++uint16_t Code::wasm_js_tagged_parameter_count() const {
++  DCHECK_EQ(kind(), CodeKind::WASM_TO_JS_FUNCTION);
++  return RELAXED_READ_UINT16_FIELD(*this, kInlinedBytecodeSizeOffset);
++}
++
++void Code::set_wasm_js_first_tagged_parameter(uint16_t count) {
++  DCHECK_EQ(kind(), CodeKind::WASM_TO_JS_FUNCTION);
++  RELAXED_WRITE_UINT16_FIELD(*this, kInlinedBytecodeSizeOffset + 2, count);
++}
++
++uint16_t Code::wasm_js_first_tagged_parameter() const {
++  DCHECK_EQ(kind(), CodeKind::WASM_TO_JS_FUNCTION);
++  return RELAXED_READ_UINT16_FIELD(*this, kInlinedBytecodeSizeOffset + 2);
++}
++
+ BytecodeOffset Code::osr_offset() const {
+   return BytecodeOffset(RELAXED_READ_INT32_FIELD(*this, kOsrOffsetOffset));
+ }
+diff --git a/src/objects/code.h b/src/objects/code.h
+index 9a079a94ba0126b24532362a0ce233477f42c221..1da011899807125d6dc9ffb6d56622f5f15ad465 100644
+--- a/src/objects/code.h
++++ b/src/objects/code.h
+@@ -124,6 +124,15 @@ class Code : public ExposedTrustedObject {
+   // [deoptimization_data]: Array containing data for deopt for non-baseline
+   // code.
+   DECL_ACCESSORS(deoptimization_data, Tagged<TrustedFixedArray>)
++  // [parameter_count]: The number of formal parameters, including the
++  // receiver. Currently only available for optimized functions.
++  // TODO(saelo): make this always available. This is just a matter of figuring
++  // out how to obtain the parameter count during code generation when no
++  // BytecodeArray is available from which it can be copied.
++  DECL_PRIMITIVE_ACCESSORS(parameter_count, uint16_t)
++  inline uint16_t parameter_count_without_receiver() const;
++  DECL_PRIMITIVE_ACCESSORS(wasm_js_tagged_parameter_count, uint16_t)
++  DECL_PRIMITIVE_ACCESSORS(wasm_js_first_tagged_parameter, uint16_t)
+ 
+   // Whether this type of Code uses deoptimization data, in which case the
+   // deoptimization_data field will be populated.
+@@ -503,6 +512,10 @@ class GcSafeCode : public HeapObject {
+   inline bool CanDeoptAt(Isolate* isolate, Address pc) const;
+   inline Tagged<Object> raw_instruction_stream(
+       PtrComprCageBase code_cage_base) const;
++  // The two following accessors repurpose the InlinedBytecodeSize field, see
++  // comment in code-inl.h.
++  inline uint16_t wasm_js_tagged_parameter_count() const;
++  inline uint16_t wasm_js_first_tagged_parameter() const;
+ 
+  private:
+   OBJECT_CONSTRUCTORS(GcSafeCode, HeapObject);

+ 64 - 0
patches/v8/cherry-pick-bb28367eed73.patch

@@ -0,0 +1,64 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Olivier=20Fl=C3=BCckiger?= <[email protected]>
+Date: Mon, 24 Jun 2024 16:22:09 +0200
+Subject: Fix skipped smi check due to phi hoisting
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Given we have a phi (29) assumed to be smi at graph building time, we
+must not untag it's input phis (10,12) to float64.
+
+    ╭─────►Block b2
+    │       10: φᵀ r0 (n4, n29) (compressed) → (x), 3 uses
+    │       12: φᵀ r2 (n6, n39) (compressed) → (x), 6 uses
+        ...
+    │       13: CheckedSmiUntag [n10:(x)] → (x), 2 uses
+    │       14: CheckedSmiUntag [n12:(x)] → (x), 1 uses
+        ...
+    │╭──────17: BranchIfToBooleanTrue [n16:(x)] b3 b9
+        ...
+    ││ │    29: φᵀ <accumulator> (n10, n12) (compressed) → (x), 4 uses
+        ...
+    ││ │    33: UnsafeSmiUntag [n29:(x)] → (x), 1 uses
+
+Doing so could invalidate the `UnsafeSmiUntag` instruction.
+
+This can only happen when hoisting the untagging out of the loop, as
+this will remove the original `CheckedSmiUntag` instruction.
+
+Fixed: 348567825
+Change-Id: I2d7f2c3b544f991be9850d44bf11c3f632a0bb46
+Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5645901
+Reviewed-by: Darius Mercadier <[email protected]>
+Commit-Queue: Darius Mercadier <[email protected]>
+Auto-Submit: Olivier Flückiger <[email protected]>
+Cr-Commit-Position: refs/heads/main@{#94615}
+
+diff --git a/src/maglev/maglev-phi-representation-selector.cc b/src/maglev/maglev-phi-representation-selector.cc
+index 02e030bcb543287433c944e5f298998cdc5b7ce9..cabe3a29383b111fc0f1568a40d439e1513bc154 100644
+--- a/src/maglev/maglev-phi-representation-selector.cc
++++ b/src/maglev/maglev-phi-representation-selector.cc
+@@ -285,6 +285,14 @@ MaglevPhiRepresentationSelector::ProcessPhi(Phi* node) {
+                                ValueRepresentation::kHoleyFloat64};
+   }
+ 
++  // When hoisting we must ensure that we don't turn a tagged flowing into
++  // CheckedSmiUntag into a float64. This would cause us to loose the smi check
++  // which in turn can invalidate assumptions on aliasing values.
++  if (hoist_untagging.size() && node->uses_require_31_bit_value()) {
++    allowed_inputs_for_uses.Remove(
++        {ValueRepresentation::kFloat64, ValueRepresentation::kHoleyFloat64});
++  }
++
+   auto intersection = possible_inputs & allowed_inputs_for_uses;
+ 
+   TRACE_UNTAGGING("  + intersection reprs: " << intersection);
+@@ -615,6 +623,7 @@ void MaglevPhiRepresentationSelector::ConvertTaggedPhiTo(
+                                    TaggedToFloat64ConversionType::kOnlyNumber),
+                                block, NewNodePosition::kEnd);
+           } else {
++            DCHECK(!phi->uses_require_31_bit_value());
+             untagged = AddNode(NodeBase::New<CheckedNumberOrOddballToFloat64>(
+                                    builder_->zone(), {input},
+                                    TaggedToFloat64ConversionType::kOnlyNumber),

+ 39 - 0
patches/v8/cherry-pick-bc545b15a0ee.patch

@@ -0,0 +1,39 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Jakob Kummerow <[email protected]>
+Date: Thu, 11 Jul 2024 16:34:00 +0200
+Subject: Fix cast of memory index
+
+"uint8_t" must have been a typo.
+
+Fixed: 351327767
+Bug: 42203854
+Change-Id: I196c961ec2f2ed16acfe16bf304d7eae6551aacc
+Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5695665
+Reviewed-by: Matthias Liedtke <[email protected]>
+Commit-Queue: Matthias Liedtke <[email protected]>
+Auto-Submit: Jakob Kummerow <[email protected]>
+Commit-Queue: Jakob Kummerow <[email protected]>
+Cr-Commit-Position: refs/heads/main@{#94981}
+
+diff --git a/src/compiler/wasm-compiler.cc b/src/compiler/wasm-compiler.cc
+index 16f1f1470b782ce3584ba4bb6626501c9f9551b7..02364fdf5d3d17fa0f03fd48d21523a4bae3f21e 100644
+--- a/src/compiler/wasm-compiler.cc
++++ b/src/compiler/wasm-compiler.cc
+@@ -3395,7 +3395,7 @@ Node* WasmGraphBuilder::MemStart(uint32_t mem_index) {
+   DCHECK_NOT_NULL(instance_cache_);
+   V8_ASSUME(cached_memory_index_ == kNoCachedMemoryIndex ||
+             cached_memory_index_ >= 0);
+-  if (mem_index == static_cast<uint8_t>(cached_memory_index_)) {
++  if (mem_index == static_cast<uint32_t>(cached_memory_index_)) {
+     return instance_cache_->mem_start;
+   }
+   return LoadMemStart(mem_index);
+@@ -3405,7 +3405,7 @@ Node* WasmGraphBuilder::MemSize(uint32_t mem_index) {
+   DCHECK_NOT_NULL(instance_cache_);
+   V8_ASSUME(cached_memory_index_ == kNoCachedMemoryIndex ||
+             cached_memory_index_ >= 0);
+-  if (mem_index == static_cast<uint8_t>(cached_memory_index_)) {
++  if (mem_index == static_cast<uint32_t>(cached_memory_index_)) {
+     return instance_cache_->mem_size;
+   }
+ 

+ 112 - 0
patches/v8/cherry-pick-cdbc1d9684a3.patch

@@ -0,0 +1,112 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Darius Mercadier <[email protected]>
+Date: Tue, 18 Jun 2024 16:10:26 +0200
+Subject: Lower LoadStackArgument to a Tagged load
+
+If we start with a graph that looks like
+
+```
+x = LoadStackArgument(a, 40)
+...
+Allocate()
+...
+y = LoadStackArgument(a, 40)
+```
+
+This used to be lowered to
+
+```
+x1 = Load<WordPtr>(a, 40)
+x2 = TaggedBitcast(x1, WordPtr->Tagged)
+...
+Allocate()
+...
+y1 = Load<WordPtr>(a, 40)
+y2 = TaggedBitcast(y1, WordPtr->Tagged)
+```
+
+And then, Load Elimination would remove the second Load, and we'd get:
+
+```
+x1 = Load<WordPtr>(a, 40)
+x2 = TaggedBitcast(x1, WordPtr->Tagged)
+...
+Allocate()
+...
+y2 = TaggedBitcast(x1, WordPtr->Tagged)
+```
+
+And now we would be in trouble: if the allocation in the middle
+triggers a GC, then `x1` could move, and thus `y2` could refer to a
+stale pointer. In theory, Turbofan knows where tagged values are, and
+can thus update them when the GC moves things, but here, `x1` is not
+marked as Tagged (but rather as a raw WordPtr).
+
+This CL fixes this issue by doing a Tagged load from the start, since
+the value we're loading is clearly tagged.
+
+Fixed: chromium:347724915
+Change-Id: Ia659155fbc602907ab9a50fb992c79df6ccdaa44
+Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5630530
+Reviewed-by: Nico Hartmann <[email protected]>
+Auto-Submit: Darius Mercadier <[email protected]>
+Commit-Queue: Nico Hartmann <[email protected]>
+Cr-Commit-Position: refs/heads/main@{#94527}
+
+diff --git a/src/compiler/turboshaft/machine-lowering-reducer-inl.h b/src/compiler/turboshaft/machine-lowering-reducer-inl.h
+index 8f37ef00f7edc1395586439fad4c39f426520d87..1f8ecb428f7d53d20369b82d958b2309ab09d2eb 100644
+--- a/src/compiler/turboshaft/machine-lowering-reducer-inl.h
++++ b/src/compiler/turboshaft/machine-lowering-reducer-inl.h
+@@ -2372,9 +2372,17 @@ class MachineLoweringReducer : public Next {
+   }
+ 
+   V<Object> REDUCE(LoadStackArgument)(V<WordPtr> base, V<WordPtr> index) {
+-    V<WordPtr> argument = __ template LoadNonArrayBufferElement<WordPtr>(
+-        base, AccessBuilder::ForStackArgument(), index);
+-    return __ BitcastWordPtrToTagged(argument);
++    // Note that this is a load of a Tagged value
++    // (MemoryRepresentation::TaggedPointer()), but since it's on the stack
++    // where stack slots are all kSystemPointerSize, we use kSystemPointerSize
++    // for element_size_log2. On 64-bit plateforms with pointer compression,
++    // this means that we're kinda loading a 32-bit value from an array of
++    // 64-bit values.
++    return __ Load(
++        base, index, LoadOp::Kind::RawAligned(),
++        MemoryRepresentation::TaggedPointer(),
++        CommonFrameConstants::kFixedFrameSizeAboveFp - kSystemPointerSize,
++        kSystemPointerSizeLog2);
+   }
+ 
+   OpIndex REDUCE(StoreTypedElement)(OpIndex buffer, V<Object> base,
+diff --git a/test/mjsunit/compiler/regress-347724915.js b/test/mjsunit/compiler/regress-347724915.js
+new file mode 100644
+index 0000000000000000000000000000000000000000..4a5d1a9a2e3dd7674bf0872c94a971b5f28ddf72
+--- /dev/null
++++ b/test/mjsunit/compiler/regress-347724915.js
+@@ -0,0 +1,26 @@
++// Copyright 2024 the V8 project authors. All rights reserved.
++// Use of this source code is governed by a BSD-style license that can be
++// found in the LICENSE file.
++
++// Flags: --allow-natives-syntax
++
++function f(...args) {
++  let arr1 = [ undefined, undefined, undefined ];
++  %SimulateNewspaceFull();
++  arr1[0] = args[0];
++  // The following allocation will trigger a full GC, which will move the
++  // argument passed to the function (because it was a young object).
++  let arr2 = [ arr1 ];
++  // Here we're accessing `args[0]` again. This might be load-eliminated with
++  // the `args[0]` load from a few lines above, which has been moved by the GC
++  // since then. This should be fine though, as the loaded value should be
++  // marked as Tagged, which means that it shouldn't point to the stale value
++  // but instead have been updated during GC.
++  arr1[1] = args[0]
++  return arr2;
++}
++
++%PrepareFunctionForOptimization(f);
++let expected = f({ x : 42 });
++%OptimizeFunctionOnNextCall(f);
++assertEquals(expected, f({x : 42}));