fix_harden_blink_scriptstate_maybefrom.patch 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
  2. From: deepak1556 <[email protected]>
  3. Date: Wed, 28 Jun 2023 21:11:40 +0900
  4. Subject: fix: harden blink::ScriptState::MaybeFrom
  5. This is needed as side effect of https://chromium-review.googlesource.com/c/chromium/src/+/4609446
  6. which now gets blink::ExecutionContext from blink::ScriptState
  7. and there are isolate callbacks which get entered from Node.js
  8. environment that has v8::Context not associated with blink::ScriptState.
  9. Some examples are ModifyCodeGenerationFromStrings in node_bindings.cc,
  10. blink::UseCounterCallback etc.
  11. Without this patch when blink::ScriptState::MaybeFrom tries to extract
  12. blink::ScriptState from the provided v8::Context and since Node.js has context
  13. embedder data fields with index greater than blink (see node_context_data.h)
  14. leading to the following CHECK failure.
  15. ```
  16. script_state.h(169)] Security Check Failed: script_state
  17. ```
  18. This patch adds a new tag in the context associated with ScriptState
  19. to uniquely identify. It is based on what Node.js does to identify the
  20. context created by it in `node_context_data.h`.
  21. PS: We are not performing a check like
  22. ```
  23. ScriptState* script_state =
  24. static_cast<ScriptState*>(context->GetAlignedPointerFromEmbedderData(
  25. kV8ContextPerContextDataIndex));
  26. if (!script_state) {
  27. return nullptr;
  28. }
  29. ```
  30. since in 32-bit builds which does not have v8 sandbox enabled unlike 64-bit builds,
  31. the embedder data slot will not lazy initialize indexes in the former. This means
  32. accessing uninitialized lower indexes can return garbage values that cannot be null checked.
  33. Refer to v8::EmbedderDataSlot::store_aligned_pointer for context.
  34. diff --git a/gin/public/gin_embedders.h b/gin/public/gin_embedders.h
  35. index 8d7c5631fd8f1499c67384286f0e3c4037673b32..99b2e2f63be8a46c5546dd53bc9b05e8c54e857c 100644
  36. --- a/gin/public/gin_embedders.h
  37. +++ b/gin/public/gin_embedders.h
  38. @@ -18,6 +18,8 @@ namespace gin {
  39. enum GinEmbedder : uint16_t {
  40. kEmbedderNativeGin,
  41. kEmbedderBlink,
  42. + kEmbedderElectron,
  43. + kEmbedderBlinkTag,
  44. kEmbedderPDFium,
  45. kEmbedderFuchsia,
  46. };
  47. diff --git a/third_party/blink/renderer/platform/bindings/script_state.cc b/third_party/blink/renderer/platform/bindings/script_state.cc
  48. index 7ff8785cd64c1264a88f91f7bd3292c6943f58ea..bc14ad8cab9fa3ec45bcb9f670b198970ecbeb92 100644
  49. --- a/third_party/blink/renderer/platform/bindings/script_state.cc
  50. +++ b/third_party/blink/renderer/platform/bindings/script_state.cc
  51. @@ -13,6 +13,10 @@ namespace blink {
  52. ScriptState::CreateCallback ScriptState::s_create_callback_ = nullptr;
  53. +int const ScriptState::kScriptStateTag = 0x6e6f64;
  54. +void* const ScriptState::kScriptStateTagPtr = const_cast<void*>(
  55. + static_cast<const void*>(&ScriptState::kScriptStateTag));
  56. +
  57. // static
  58. void ScriptState::SetCreateCallback(CreateCallback create_callback) {
  59. DCHECK(create_callback);
  60. @@ -37,6 +41,8 @@ ScriptState::ScriptState(v8::Local<v8::Context> context,
  61. DCHECK(world_);
  62. context_.SetWeak(this, &OnV8ContextCollectedCallback);
  63. context->SetAlignedPointerInEmbedderData(kV8ContextPerContextDataIndex, this);
  64. + context->SetAlignedPointerInEmbedderData(
  65. + kV8ContextPerContextDataTagIndex, ScriptState::kScriptStateTagPtr);
  66. RendererResourceCoordinator::Get()->OnScriptStateCreated(this,
  67. execution_context);
  68. }
  69. @@ -78,6 +84,8 @@ void ScriptState::DissociateContext() {
  70. // Cut the reference from V8 context to ScriptState.
  71. GetContext()->SetAlignedPointerInEmbedderData(kV8ContextPerContextDataIndex,
  72. nullptr);
  73. + GetContext()->SetAlignedPointerInEmbedderData(
  74. + kV8ContextPerContextDataTagIndex, nullptr);
  75. reference_from_v8_context_.Clear();
  76. // Cut the reference from ScriptState to V8 context.
  77. diff --git a/third_party/blink/renderer/platform/bindings/script_state.h b/third_party/blink/renderer/platform/bindings/script_state.h
  78. index 7109852950cde0a6553000421faacefb39366b41..79be73cb660839d6074b11cd7491dc3d5e876345 100644
  79. --- a/third_party/blink/renderer/platform/bindings/script_state.h
  80. +++ b/third_party/blink/renderer/platform/bindings/script_state.h
  81. @@ -178,7 +178,12 @@ class PLATFORM_EXPORT ScriptState : public GarbageCollected<ScriptState> {
  82. static ScriptState* MaybeFrom(v8::Local<v8::Context> context) {
  83. DCHECK(!context.IsEmpty());
  84. if (context->GetNumberOfEmbedderDataFields() <=
  85. - kV8ContextPerContextDataIndex) {
  86. + kV8ContextPerContextDataTagIndex) {
  87. + return nullptr;
  88. + }
  89. + if (context->GetAlignedPointerFromEmbedderData(
  90. + kV8ContextPerContextDataTagIndex) !=
  91. + ScriptState::kScriptStateTagPtr) {
  92. return nullptr;
  93. }
  94. return From(context);
  95. @@ -249,9 +254,15 @@ class PLATFORM_EXPORT ScriptState : public GarbageCollected<ScriptState> {
  96. static void SetCreateCallback(CreateCallback);
  97. friend class ScriptStateImpl;
  98. + static void* const kScriptStateTagPtr;
  99. + static int const kScriptStateTag;
  100. static constexpr int kV8ContextPerContextDataIndex =
  101. static_cast<int>(gin::kPerContextDataStartIndex) +
  102. static_cast<int>(gin::kEmbedderBlink);
  103. + static constexpr int kV8ContextPerContextDataTagIndex =
  104. + static_cast<int>(gin::kPerContextDataStartIndex) +
  105. + static_cast<int>(gin::kEmbedderBlink) +
  106. + static_cast<int>(gin::kEmbedderBlinkTag);
  107. };
  108. // ScriptStateProtectingContext keeps the context associated with the