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