]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
vt: fix spurious modifier in CSI/cursor key sequences
authorNicolas Pitre <npitre@baylibre.com>
Fri, 26 Jun 2026 02:48:33 +0000 (22:48 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 10 Jul 2026 12:46:00 +0000 (14:46 +0200)
csi_modifier_param() builds the xterm modifier parameter from
shift_state, counting KG_SHIFTL/KG_SHIFTR as Shift, KG_ALTGR as Alt
and KG_CTRLL/KG_CTRLR as Ctrl in addition to the canonical KG_SHIFT,
KG_ALT and KG_CTRL.

That is wrong when those weights are not plain modifiers. Keymaps
derived from XKB layouts (by kbd's xkbsupport, and by the
console-setup used in Debian, Ubuntu and others) encode the active
layout group using KG_SHIFTL/KG_SHIFTR:

group 1: -
group 2: shiftl
group 3: shiftr
group 4: shiftl | shiftr

So while a non-default layout group is selected, KG_SHIFTL and/or
KG_SHIFTR are set in shift_state with no Shift key held.
csi_modifier_param() then adds a spurious Shift to every cursor and
CSI key: pressing Up while group 2 is active emits ESC[1;2A (Shift+Up)
instead of ESC[A. KG_ALTGR has the same problem since it is the
standard third-level selector.

Normal keymaps bind the physical Shift/Ctrl/Alt keys to KG_SHIFT,
KG_CTRL and KG_ALT, leaving the left/right and AltGr weights free for
layout and level selection. Count only those canonical weights, so
genuine modifiers are still encoded while layout/level selectors are
not.

Fixes: 4af70f151671 ("vt: add modifier support to cursor keys")
Reported-by: Alexey Gladkov <legion@kernel.org>
Closes: https://lore.kernel.org/kbd/aj2gR0Y7sM6i9s2G@example.org/
Cc: stable <stable@kernel.org>
Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
Link: https://patch.msgid.link/20260626024833.3419086-1-nico@fluxnic.net
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/vt/keyboard.c

index dfdea0842149500e70ff328002f60d3177fdf11b..763a3f1b7be08ac43953c7fe6083b5e19c412328 100644 (file)
@@ -765,16 +765,22 @@ static void k_fn(struct vc_data *vc, unsigned char value, char up_flag)
 /*
  * Compute xterm-style modifier parameter for CSI sequences.
  * Returns 1 + (shift ? 1 : 0) + (alt ? 2 : 0) + (ctrl ? 4 : 0)
+ *
+ * Only the canonical modifier weights are counted. The left/right variants
+ * (KG_SHIFTL, KG_SHIFTR, KG_CTRLL, KG_CTRLR) and KG_ALTGR are commonly
+ * repurposed as keymap layout-group or level selectors rather than as plain
+ * modifiers (for instance XKB-derived keymaps select the layout group with
+ * KG_SHIFTL/KG_SHIFTR), so counting them would encode a spurious modifier.
  */
 static int csi_modifier_param(void)
 {
        int mod = 1;
 
-       if (shift_state & (BIT(KG_SHIFT) | BIT(KG_SHIFTL) | BIT(KG_SHIFTR)))
+       if (shift_state & BIT(KG_SHIFT))
                mod += 1;
-       if (shift_state & (BIT(KG_ALT) | BIT(KG_ALTGR)))
+       if (shift_state & BIT(KG_ALT))
                mod += 2;
-       if (shift_state & (BIT(KG_CTRL) | BIT(KG_CTRLL) | BIT(KG_CTRLR)))
+       if (shift_state & BIT(KG_CTRL))
                mod += 4;
        return mod;
 }