DEC private sequences use '?' as a parameter prefix byte (e.g.  ESC[?25h
to show the cursor).

The CSI state machine treats any non-digit, non-separator as a final
byte and dispatches fbc_parse_csi(), but '?' is only a prefix with
the real final byte ('h' or 'l') following later.

fbc_parse_csi() handles this by recording '?' in csi_cmd and
transitioning to CSI_CNT, which resumes CSI parameter accumulation
for the digits and final byte that follow.

This introduces a subtle bug: The character directly after the ? is not
saved into the priv->csi buffer. This didn't matter so far, because we
only handle h and l without regard to the number before it.

By simplifying the code and removing that extra state, we also fix this
bug by not having that incomplete CSI_CNT state in-between.

Signed-off-by: Ahmad Fatoum <[email protected]>
---
 drivers/video/fbconsole.c | 30 +++++++++---------------------
 1 file changed, 9 insertions(+), 21 deletions(-)

diff --git a/drivers/video/fbconsole.c b/drivers/video/fbconsole.c
index 7946d013b24d..60e9783266b6 100644
--- a/drivers/video/fbconsole.c
+++ b/drivers/video/fbconsole.c
@@ -17,7 +17,6 @@ enum state_t {
        LIT,                            /* Literal input */
        ESC,                            /* Start of escape sequence */
        CSI,                            /* Reading arguments in "CSI Pn ;...*/
-       CSI_CNT,
 };
 
 enum fbconsole_rotation {
@@ -555,10 +554,6 @@ static void fbc_parse_csi(struct fbc_priv *priv)
        case 'm':
                fbc_parse_colors(priv);
                return;
-       case '?': /* vt100: show/hide cursor */
-               priv->csi_cmd = last;
-               priv->state = CSI_CNT;
-               return;
        case 'h':
                /* suffix for vt100 "[?25h" */
                switch (priv->csi_cmd) {
@@ -674,29 +669,22 @@ static void fbc_putc(struct console_device *cdev, char c)
                }
 
                switch (c) {
-               case '0':
-               case '1':
-               case '2':
-               case '3':
-               case '4':
-               case '5':
-               case '6':
-               case '7':
-               case '8':
-               case '9':
+               case '?':
+                       /* DEC private sequences use '?' as a parameter prefix 
byte.
+                        * Record '?' in csi_cmd and continue CSI parameter
+                        * accumulation for digits and the final byte that 
follows.
+                        */
+                       priv->csi_cmd = c;
+                       break;
+               case '0' ... '9':
                case ';':
                case ':':
                        break;
                default:
                        fbc_parse_csi(priv);
-                       if (priv->state != CSI_CNT)
-                               priv->state = LIT;
+                       priv->state = LIT;
                }
                break;
-       case CSI_CNT:
-               priv->state = CSI;
-               break;
-
        }
        priv->in_console = 0;
 
-- 
2.47.3


Reply via email to