From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Andrey Belenko <anbelen@microsoft.com>
Date: Thu, 10 Dec 2020 18:03:59 +0100
Subject: Chromium backport: crbug.com/1142331

M87-1
Clipboard: Fix UaP in ClipboardWriter/FileReaderLoader
https://chromium-review.googlesource.com/c/chromium/src/+/2536946
CVE-2020-16037

diff --git a/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc b/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc
index 47bd085c92ff97e30b82f48b99bece2d3f8ffbd7..5b9d059291a8c60e33c15f5d981cea06045f4044 100644
--- a/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc
+++ b/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc
@@ -101,7 +101,7 @@ ScriptPromise ClipboardPromise::CreateForWriteText(ExecutionContext* context,
 
 ClipboardPromise::ClipboardPromise(ExecutionContext* context,
                                    ScriptState* script_state)
-    : ExecutionContextClient(context),
+    : ExecutionContextLifecycleObserver(context),
       script_state_(script_state),
       script_promise_resolver_(
           MakeGarbageCollected<ScriptPromiseResolver>(script_state)),
@@ -396,12 +396,19 @@ scoped_refptr<base::SingleThreadTaskRunner> ClipboardPromise::GetTaskRunner() {
   return GetExecutionContext()->GetTaskRunner(TaskType::kUserInteraction);
 }
 
+// ExecutionContextLifecycleObserver implementation.
+void ClipboardPromise::ContextDestroyed() {
+  script_promise_resolver_->Reject(MakeGarbageCollected<DOMException>(
+      DOMExceptionCode::kNotAllowedError, "Document detached."));
+  clipboard_writer_.Clear();
+}
+
 void ClipboardPromise::Trace(Visitor* visitor) {
   visitor->Trace(script_state_);
   visitor->Trace(script_promise_resolver_);
   visitor->Trace(clipboard_writer_);
   visitor->Trace(clipboard_item_data_);
-  ExecutionContextClient::Trace(visitor);
+  ExecutionContextLifecycleObserver::Trace(visitor);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/clipboard/clipboard_promise.h b/third_party/blink/renderer/modules/clipboard/clipboard_promise.h
index c2c7286149238db914087af743cc4c0042da95ba..65f4797b2e3eb45dd4c6f1ba8fda608d1488edef 100644
--- a/third_party/blink/renderer/modules/clipboard/clipboard_promise.h
+++ b/third_party/blink/renderer/modules/clipboard/clipboard_promise.h
@@ -24,7 +24,7 @@ class LocalFrame;
 class ExecutionContext;
 
 class ClipboardPromise final : public GarbageCollected<ClipboardPromise>,
-                               public ExecutionContextClient {
+                               public ExecutionContextLifecycleObserver {
   USING_GARBAGE_COLLECTED_MIXIN(ClipboardPromise);
 
  public:
@@ -74,6 +74,9 @@ class ClipboardPromise final : public GarbageCollected<ClipboardPromise>,
   LocalFrame* GetLocalFrame() const;
   scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner();
 
+  // ExecutionContextLifecycleObserver
+  void ContextDestroyed() override;
+
   Member<ScriptState> script_state_;
   Member<ScriptPromiseResolver> script_promise_resolver_;
 
diff --git a/third_party/blink/renderer/modules/clipboard/clipboard_writer.cc b/third_party/blink/renderer/modules/clipboard/clipboard_writer.cc
index 625934d39c613f2fce0f6a55b15f8e4a8ca604b6..7ae1f48e9dd9dac609b263462eeb15d30452ac2b 100644
--- a/third_party/blink/renderer/modules/clipboard/clipboard_writer.cc
+++ b/third_party/blink/renderer/modules/clipboard/clipboard_writer.cc
@@ -181,9 +181,12 @@ ClipboardWriter::ClipboardWriter(SystemClipboard* system_clipboard,
       file_reading_task_runner_(promise->GetExecutionContext()->GetTaskRunner(
           TaskType::kFileReading)),
       system_clipboard_(system_clipboard),
-      raw_system_clipboard_(raw_system_clipboard) {}
+      raw_system_clipboard_(raw_system_clipboard),
+      self_keep_alive_(PERSISTENT_FROM_HERE, this) {}
 
-ClipboardWriter::~ClipboardWriter() = default;
+ClipboardWriter::~ClipboardWriter() {
+  DCHECK(!file_reader_);
+}
 
 // static
 bool ClipboardWriter::IsValidType(const String& type) {
@@ -209,7 +212,9 @@ void ClipboardWriter::DidFinishLoading() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DOMArrayBuffer* array_buffer = file_reader_->ArrayBufferResult();
   DCHECK(array_buffer);
+
   file_reader_.reset();
+  self_keep_alive_.Clear();
 
   worker_pool::PostTask(
       FROM_HERE, CrossThreadBindOnce(&ClipboardWriter::DecodeOnBackgroundThread,
@@ -219,6 +224,8 @@ void ClipboardWriter::DidFinishLoading() {
 }
 
 void ClipboardWriter::DidFail(FileErrorCode error_code) {
+  file_reader_.reset();
+  self_keep_alive_.Clear();
   promise_->RejectFromReadOrDecodeFailure();
 }
 
diff --git a/third_party/blink/renderer/modules/clipboard/clipboard_writer.h b/third_party/blink/renderer/modules/clipboard/clipboard_writer.h
index 45eb4bd91c0b7db4fc3648518e62f4071945a9e7..5241032714512405aaa0135ffa081ea4fa702851 100644
--- a/third_party/blink/renderer/modules/clipboard/clipboard_writer.h
+++ b/third_party/blink/renderer/modules/clipboard/clipboard_writer.h
@@ -10,6 +10,7 @@
 #include "third_party/blink/renderer/core/fileapi/blob.h"
 #include "third_party/blink/renderer/core/fileapi/file_reader_loader_client.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/heap/self_keep_alive.h"
 #include "third_party/skia/include/core/SkImage.h"
 
 namespace blink {
@@ -27,6 +28,11 @@ class RawSystemClipboard;
 // (2) Decoding the blob's contents to avoid RCE in native applications that may
 //     take advantage of vulnerabilities in their decoders.
 // (3) Writing the blob's decoded contents to the system clipboard.
+//
+// ClipboardWriter is owned only by itself and ClipboardPromise. It keeps
+// itself alive for the duration of FileReaderLoader's async operations using
+// SelfKeepAlive, and keeps itself alive afterwards during cross-thread
+// operations by using WrapCrossThreadPersistent.
 class ClipboardWriter : public GarbageCollected<ClipboardWriter>,
                         public FileReaderLoaderClient {
  public:
@@ -80,6 +86,10 @@ class ClipboardWriter : public GarbageCollected<ClipboardWriter>,
   Member<SystemClipboard> system_clipboard_;
   // Access to the global unsanitized system clipboard.
   Member<RawSystemClipboard> raw_system_clipboard_;
+
+  // Oilpan: ClipboardWriter must remain alive until Member<T>::Clear() is
+  // called, to keep the FileReaderLoader alive and avoid unexpected UaPs.
+  SelfKeepAlive<ClipboardWriter> self_keep_alive_;
 };
 
 }  // namespace blink
