Low chrome Authorization Error 🔧 Commit mapped

Overview

Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactIncorrect authorization in Chromoting
DescriptionIncorrect authorization in Chromoting
ComponentChromoting
Sub-componentRemoting
Bug ClassAuthorization Error
Tracker553930843
Fix commitab0cd1a251b8 (chromium/src) +262/-3
CISA KEVNot listed
CreditedGoogle
Disclosed2026-10-06

Changed Functions

FunctionChangeNotes
LocalKeyboardInputMonitorMac
remoting/host/input_monitor/local_keyboard_input_monitor_mac.mm
modified
EventHandler
remoting/host/input_monitor/local_keyboard_input_monitor_mac.mm
modified
Core
remoting/host/input_monitor/local_keyboard_input_monitor_mac.mm
modified
if
remoting/host/input_monitor/local_keyboard_input_monitor_mac.mm
modified

Files Changed

  • remoting/host/input_monitor/local_keyboard_input_monitor_mac.mm
From ab0cd1a251b81bc89cac0417e8c54843adc571ff Mon Sep 17 00:00:00 2001
From: Joe Downing <[email protected]>
Date: Thu, 17 Sep 2026 15:04:14 -0700
Subject: [PATCH] [remoting] Implement local keyboard input monitor on macOS

LocalKeyboardInputMonitor::Create previously returned nullptr on
macOS. Because of this, local physical keystrokes and modifier key
presses were never delivered to ClientSessionControl::OnLocalKeyPressed
or RemoteInputFilter::LocalKeyPressed, preventing local keystrokes from
triggering the 2-second remote input suppression window or un-hiding
the disconnect window.

This change:
- Implements LocalKeyboardInputMonitorMac and
  LocalKeyboardInputMonitorManager using CGEventTapCreate.
- Listens to kCGEventKeyDown, kCGEventKeyUp, and kCGEventFlagsChanged
  to capture both key presses/releases and modifier key transitions.
- Converts macOS native keycodes to USB keycodes via
  ui::KeycodeConverter::NativeKeycodeToUsbKeycode.
- Filters out CRD's own injected key events by checking
  kCGEventSourceUnixProcessID != getpid().
- Re-enables the event tap when kCGEventTapDisabledByTimeout is received.

Bug: 553930843
Change-Id: I9d7b7cabe3fdc1ff3d0b8372945c09f004bfd57c
Fixed: 553930843
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8391909
Reviewed-by: Yuwei Huang <[email protected]>
Commit-Queue: Joe Downing <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1700154}
---
diff --git a/remoting/host/input_monitor/local_keyboard_input_monitor_mac.mm b/remoting/host/input_monitor/local_keyboard_input_monitor_mac.mm
index be37d37..d1caae1 100644
--- a/remoting/host/input_monitor/local_keyboard_input_monitor_mac.mm
+++ b/remoting/host/input_monitor/local_keyboard_input_monitor_mac.mm
@@ -4,21 +4,280 @@
 
 #include "remoting/host/input_monitor/local_keyboard_input_monitor.h"
 
+#import <AppKit/AppKit.h>
+#include <unistd.h>
+
+#include <memory>
 #include <utility>
 
+#include "base/apple/scoped_cftyperef.h"
+#include "base/compiler_specific.h"
+#include "base/functional/bind.h"
 #include "base/functional/callback.h"
-#import "base/task/single_thread_task_runner.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/memory/raw_ptr.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/sequence_checker.h"
+#include "base/task/bind_post_task.h"
 #include "base/task/single_thread_task_runner.h"
+#include "ui/events/keycodes/dom/keycode_converter.h"
 
 namespace remoting {
+namespace {
+
+class LocalKeyboardInputMonitorMac : public LocalKeyboardInputMonitor {
+ public:
+  // Invoked by LocalKeyboardInputMonitorManager.
+  class EventHandler {
+   public:
+    virtual ~EventHandler() = default;
+
+    virtual void OnLocalKeyPressed(uint32_t usb_keycode) = 0;
+  };
+
+  LocalKeyboardInputMonitorMac(
+      scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
+      scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+      LocalInputMonitor::KeyPressedCallback on_key_event_callback,
+      base::OnceClosure disconnect_callback);
+
+  LocalKeyboardInputMonitorMac(const LocalKeyboardInputMonitorMac&) = delete;
+  LocalKeyboardInputMonitorMac& operator=(const LocalKeyboardInputMonitorMac&) =
+      delete;
+
+  ~LocalKeyboardInputMonitorMac() override;
+
+ private:
+  // The actual implementation resides in LocalKeyboardInputMonitorMac::Core.
+  class Core;
+  scoped_refptr<Core> core_;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+};
+
+}  // namespace
+}  // namespace remoting
+
+@interface LocalKeyboardInputMonitorManager : NSObject {
+ @private
+  base::apple::ScopedCFTypeRef<CFRunLoopSourceRef> _keyboardRunLoopSource;
+  base::apple::ScopedCFTypeRef<CFMachPortRef> _keyboardMachPort;
+  raw_ptr<remoting::LocalKeyboardInputMonitorMac::EventHandler> _monitor;
+}
+
+- (instancetype)initWithMonitor:
+    (remoting::LocalKeyboardInputMonitorMac::EventHandler*)monitor;
+
+// Called when a local key event is detected.
+- (void)localKeyPressed:(uint32_t)usb_keycode;
+
+// Re-enables the event tap if disabled by timeout.
+- (void)reEnableEventTap;
+
+// Must be called when the LocalKeyboardInputMonitorManager is no longer needed.
+- (void)invalidate;
+
+@end
+
+static CGEventRef LocalKeyboardEvent([[maybe_unused]] CGEventTapProxy proxy,
+                                     CGEventType type,
+                                     CGEventRef event,
+                                     void* context) {
+  LocalKeyboardInputMonitorManager* manager =
+      (__bridge LocalKeyboardInputMonitorManager*)context;
+  if (type == kCGEventTapDisabledByTimeout) {
+    [manager reEnableEventTap];
+    return event;
+  }
+  if (type == kCGEventTapDisabledByUserInput) {
+    return event;
+  }
+
+  // Filter out events injected by the CRD host process, while capturing
+  // hardware events (pid == 0) and synthetic events from other local software
+  // (e.g. accessibility and assistive tools).
+  int64_t pid = CGEventGetIntegerValueField(event, kCGEventSourceUnixProcessID);
+  if (pid != getpid()) {
+    int mac_keycode = static_cast<int>(
+        CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode));
+    uint32_t usb_keycode =
+        ui::KeycodeConverter::NativeKeycodeToUsbKeycode(mac_keycode);
+    [manager localKeyPressed:usb_keycode];
+  }
+  return event;
+}
+
+@implementation LocalKeyboardInputMonitorManager
+
+- (instancetype)initWithMonitor:
+    (remoting::LocalKeyboardInputMonitorMac::EventHandler*)monitor {
+  if ((self = [super init])) {
+    _monitor = monitor;
+
+    const CGEventMask keyboard_mask = CGEventMaskBit(kCGEventKeyDown) |
+                                      CGEventMaskBit(kCGEventKeyUp) |
+                                      CGEventMaskBit(kCGEventFlagsChanged);
+
+    _keyboardMachPort.reset(CGEventTapCreate(
+        kCGSessionEventTap, kCGHeadInsertEventTap, kCGEventTapOptionListenOnly,
+        keyboard_mask, LocalKeyboardEvent, (__bridge void*)self));
+    if (_keyboardMachPort) {
+      _keyboardRunLoopSource.reset(
+          CFMachPortCreateRunLoopSource(nullptr, _keyboardMachPort.get(), 0));
+      CFRunLoopAddSource(CFRunLoopGetMain(), _keyboardRunLoopSource.get(),
+                         kCFRunLoopCommonModes);
+    } else {
+      LOG(ERROR) << "CGEventTapCreate failed for keyboard.";
+      self = nil;
+      return nil;
+    }
+  }
+  return self;
+}
+
+- (void)localKeyPressed:(uint32_t)usb_keycode {
+  _monitor->OnLocalKeyPressed(usb_keycode);
+}
+
+- (void)reEnableEventTap {
+  if (_keyboardMachPort) {
+    CGEventTapEnable(_keyboardMachPort.get(), true);
+  }
+}
+
+- (void)invalidate {
+  if (_keyboardRunLoopSource) {
+    CFMachPortInvalidate(_keyboardMachPort.get());
+    CFRunLoopRemoveSource(CFRunLoopGetMain(), _keyboardRunLoopSource.get(),
+                          kCFRunLoopCommonModes);
+    _keyboardMachPort.reset();
+    _keyboardRunLoopSource.reset();
+  }
+}
+
+- (void)dealloc {
+  [self invalidate];
+}
+
+@end
+
+namespace remoting {
+namespace {
+
+class LocalKeyboardInputMonitorMac::Core
+    : public base::RefCountedThreadSafe<Core>,
+      public EventHandler {
+ public:
+  Core(scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
+       scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+       LocalInputMonitor::KeyPressedCallback on_key_event_callback,
+       base::OnceClosure disconnect_callback);
+
+  Core(const Core&) = delete;
+  Core& operator=(const Core&) = delete;
+
+  void Start();
+  void Stop();
+
+ private:
+  friend class base::RefCountedThreadSafe<Core>;
+  ~Core() override;
+
+  void StartOnUiThread();
+  void StopOnUiThread();
+
+  // EventHandler interface.
+  void OnLocalKeyPressed(uint32_t usb_keycode) override;
+
+  scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
+
+  LocalKeyboardInputMonitorManager* __strong manager_ = nil;
+
+  LocalInputMonitor::KeyPressedCallback on_key_event_callback_;
+  base::OnceClosure disconnect_callback_;
+};
+
+LocalKeyboardInputMonitorMac::LocalKeyboardInputMonitorMac(
+    scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
+    scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+    LocalInputMonitor::KeyPressedCallback on_key_event_callback,
+    base::OnceClosure disconnect_callback)
+    : core_(base::MakeRefCounted<Core>(std::move(caller_task_runner),
+                                       std::move(ui_task_runner),
+                                       std::move(on_key_event_callback),
+                                       std::move(disconnect_callback))) {
+  core_->Start();
+}
+
+LocalKeyboardInputMonitorMac::~LocalKeyboardInputMonitorMac() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  core_->Stop();
+}
+
+LocalKeyboardInputMonitorMac::Core::Core(
+    scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
+    scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+    LocalInputMonitor::KeyPressedCallback on_key_event_callback,
+    base::OnceClosure disconnect_callback)
+    : ui_task_runner_(std::move(ui_task_runner)),
+      on_key_event_callback_(
+          base::BindPostTask(caller_task_runner,
+                             std::move(on_key_event_callback))),
+      disconnect_callback_(
+          disconnect_callback
+              ? base::BindPostTask(caller_task_runner,
+                                   std::move(disconnect_callback))
+              : base::OnceClosure()) {}
+
+void LocalKeyboardInputMonitorMac::Core::Start() {
+  ui_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&Core::StartOnUiThread, base::WrapRefCounted(this)));
+}
+
+void LocalKeyboardInputMonitorMac::Core::Stop() {
+  ui_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&Core::StopOnUiThread, base::WrapRefCounted(this)));
+}
+
+LocalKeyboardInputMonitorMac::Core::~Core() = default;
+
+void LocalKeyboardInputMonitorMac::Core::StartOnUiThread() {
+  DCHECK(ui_task_runner_->BelongsToCurrentThread());
+
+  manager_ = [[LocalKeyboardInputMonitorManager alloc] initWithMonitor:this];
+  if (!manager_ && disconnect_callback_) {
+    std::move(disconnect_callback_).Run();
+  }
+}
+
+void LocalKeyboardInputMonitorMac::Core::StopOnUiThread() {
+  DCHECK(ui_task_runner_->BelongsToCurrentThread());
+
+  [manager_ invalidate];
+  manager_ = nil;
+  disconnect_callback_.Reset();
+}
+
+void LocalKeyboardInputMonitorMac::Core::OnLocalKeyPressed(
+    uint32_t usb_keycode) {
+  on_key_event_callback_.Run(usb_keycode);
+}
+
+}  // namespace
 
 std::unique_ptr<LocalKeyboardInputMonitor> LocalKeyboardInputMonitor::Create(
     scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
-    scoped_refptr<base::SingleThreadTaskRunner> input_task_runner,
+    scoped_refptr<base::SingleThreadTaskRunner> /* input_task_runner */,
     scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
     LocalInputMonitor::KeyPressedCallback on_key_event_callback,
     base::OnceClosure disconnect_callback) {
-  return nullptr;
+  return std::make_unique<LocalKeyboardInputMonitorMac>(
+      std::move(caller_task_runner), std::move(ui_task_runner),
+      std::move(on_key_event_callback), std::move(disconnect_callback));
 }
 
 }  // namespace remoting
Loading diff…

Original Bug Report

The reporter's bug is still restricted on the tracker. Chrome de-restricts security bugs ~30–90 days after the fix ships; a later run will backfill it here.