Public bug reported:

## Problem Description

On systems running GNOME on X11 with the Brazilian Portuguese keyboard layout 
(`br` or `br+thinkpad`), users experience severe session instability 
immediately upon login:
1. **Random multi-minute login freezes:** The session stalls on a black screen 
displaying only the default X11 "X" cursor (`XC_X_cursor`) for minutes before 
(or without ever) drawing the desktop.
2. **Severe key response delays:** Even when login succeeds, keypresses and 
desktop shortcut reactions suffer massive latency and sluggishness.

### Root Cause Analysis

In `/usr/share/X11/xkb/symbols/br`, line 41 explicitly binds `Scroll_Lock` to 
`Mod3`:
```xkb
modifier_map Mod3   { Scroll_Lock };
```
No other standard keyboard layout in XKB assigns `Scroll_Lock` to `Mod3`.

When Mutter initializes keybindings for an X11 session:

1. `reload_modmap()` queries the XKB keymap for virtual modifiers. On
standard layouts, `Scroll_Lock` is not mapped to any real modifier
(`0x0`). On the Brazilian layout, it resolves to `Mod3` (`0x20`).

2. Mutter computes `keys->ignored_modifier_mask`:
   $$\text{ignored\_modifier\_mask} = \text{LockMask } (0x02) \mid 
\text{Mod2Mask } (0x10) \mid \text{Mod3Mask } (0x20) = 0x32$$
   On standard layouts, this mask is only `0x12` (`NumLock | CapsLock`).

3. Mutter's `calc_grab_modifiers()` function contains a logic flaw:
   ```c
   for (ignored_mask = 1;
        ignored_mask <= keys->ignored_modifier_mask;
        ++ignored_mask)
     {
       if (ignored_mask & keys->ignored_modifier_mask)
         {
           mods = (XIGrabModifiers) { modmask | ignored_mask, 0 };
           g_array_append_val (mods_array, mods);
         }
     }
   ```
   Instead of iterating over the power set of active bits (subsets), the 
bitwise AND matches any number sharing *at least one bit* with the mask:
   - For `0x12` (2 bits), it generates **12 combinations** per keybinding.
   - For `0x32` (3 bits), it generates **44 combinations** per keybinding.

4. GNOME Shell registers ~251 keybindings. With multiple connected input
devices (laptop keyboard, external keyboard, ThinkPad extra buttons,
YubiKey), Mutter issues **over 40,000 passive grabs** via
`XIGrabKeycode`.

5. In Xorg, all passive grabs are stored in a single flat linked list
(`grabList`). Every single insertion traverses the entire list to check
for conflicting grabs ($O(N^2)$ algorithmic complexity).

6. Inserting 40,000 grabs requires approximately **$\mathbf{1 \times
10^9}$ (one billion) linked-list node traversals**, completely starving
the X server and locking the Mutter main event loop. Furthermore,
whenever any USB device is detected or the keymap is reloaded during
session startup, Mutter ungrabs and regrabs everything, repeatedly re-
triggering the multi-minute freeze.

## State of the Grabs Table (Before vs. After)

Live telemetry measured directly from Xorg's client resource table
(`RT_PASSIVEGRAB`) and `gnome-shell` process memory on Ubuntu 24.04:

| Metric | Before (with line 41 active) | After (line 41 commented out) | 
Improvement |
| :--- | :--- | :--- | :--- |
| **`mod3` in `xmodmap -pm`** | `Scroll_Lock (0x4e), ISO_Level5_Shift (0xcb)` | 
`ISO_Level5_Shift (0xcb)` | `Scroll_Lock` unmapped |
| **Mutter `ignored_modifier_mask`** | `0x32` (`Lock \| Mod2 \| Mod3`) | `0x12` 
(`Lock \| Mod2`) | Restored to standard 2-bit mask |
| **Combinations generated per keybinding** | **44** | **12** | **72.7% 
reduction** per binding |
| **Total passive grabs (`gnome-shell`)** | **~10,793** (over 40,000 across 
devices) | **1,822** | **83.1% fewer grabs** |
| **Xorg linked-list collision checks** | $\approx 116,488,000$ (per device) | 
$\approx 3,319,000$ | **97.15% reduction (~35x faster)** |

## User Testimony & Behavioral Impact

Commenting out line 41 in `/usr/share/X11/xkb/symbols/br`:
- **Completely resolved the login freeze:** The desktop session now loads 
immediately and consistently upon entering credentials in GDM, eliminating the 
black screen with the "X" cursor.
- **Eliminated keypress delays:** Desktop latency and massive delays in 
reacting to hotkeys and keyboard input inside the running session disappeared 
entirely. The desktop is responsive and snappy.
- **Zero regressions:** Standard Brazilian ABNT2 keys and layouts (including 
`รง`, `?`, `/`, dead accents, and AltGr third-level symbols) continue to 
function identically without any loss of functionality.

## Suggested Fixes

### 1. Primary Fix: `xkeyboard-config` (`xkb-data`)

In `/usr/share/X11/xkb/symbols/br`, remove or comment out line 41:

```diff
--- a/symbols/br
+++ b/symbols/br
@@ -38,7 +38,7 @@
     // The ABNT-2 keyboard has this special key:
     key <AB11> { [        slash,       question,        degree,    
questiondown ] };
 
-    modifier_map Mod3   { Scroll_Lock };
+    // modifier_map Mod3   { Scroll_Lock };
 
     include "kpdl(comma)"
```

### 2. Secondary Fix: `mutter`

In `src/core/keybindings.c`, fix `calc_grab_modifiers()` so that it
generates true subsets ($2^N$ combinations) rather than performing a
linear loop with `if (ignored_mask & keys->ignored_modifier_mask)`. This
will prevent accidental combinatorial explosions if any other layout
defines additional modifiers in the future.

** Affects: xkeyboard-config (Ubuntu)
     Importance: Undecided
         Status: New

-- 
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/2166723

Title:
  [Bug] Brazilian layout (symbols/br) assigns Scroll_Lock to Mod3,
  causing massive X11 passive grab storm (40,000+ grabs), login freezes,
  and severe key latency in GNOME X11

To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/xkeyboard-config/+bug/2166723/+subscriptions


-- 
ubuntu-bugs mailing list
[email protected]
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs

Reply via email to