Add a few missing bounds checks when processing terminal escape sequences.
authormiod <miod@openbsd.org>
Sun, 26 Feb 2023 15:09:53 +0000 (15:09 +0000)
committermiod <miod@openbsd.org>
Sun, 26 Feb 2023 15:09:53 +0000 (15:09 +0000)
Without them, the kernel could be made to crash or reboot after receiving some
specially crafted terminal escape sequences.

Reported by David Leadbeater (dgl, dgl dot cx)

sys/dev/wscons/wsemul_vt100.c
sys/dev/wscons/wsemul_vt100_subr.c

index e38cb54..7796bab 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: wsemul_vt100.c,v 1.42 2023/01/12 20:39:37 nicm Exp $ */
+/* $OpenBSD: wsemul_vt100.c,v 1.43 2023/02/26 15:09:53 miod Exp $ */
 /* $NetBSD: wsemul_vt100.c,v 1.13 2000/04/28 21:56:16 mycroft Exp $ */
 
 /*
@@ -191,7 +191,7 @@ wsemul_vt100_cnattach(const struct wsscreen_descr *type, void *cookie, int ccol,
        edp->dblwid = NULL;
        edp->dw = 0;
 #endif
-       edp->dcsarg = 0;
+       edp->dcsarg = NULL;
        edp->isolatin1tab = edp->decgraphtab = edp->dectechtab = NULL;
        edp->nrctab = NULL;
        wsemul_vt100_reset(edp);
@@ -584,12 +584,15 @@ wsemul_vt100_output_esc(struct wsemul_vt100_emuldata *edp,
                edp->sschartab = 3;
                break;
        case 'M': /* RI */
-               if (ROWS_ABOVE > 0) {
-                       edp->crow--;
+               i = ROWS_ABOVE;
+               if (i > 0) {
+                       if (edp->crow > 0)
+                               edp->crow--;
                        CHECK_DW;
-                       break;
+               } else if (i == 0) {
+                       /* Top of scroll region. */
+                       rc = wsemul_vt100_scrolldown(edp, 1);
                }
-               rc = wsemul_vt100_scrolldown(edp, 1);
                break;
        case 'P': /* DCS */
                edp->nargs = 0;
@@ -817,7 +820,7 @@ int
 wsemul_vt100_output_string(struct wsemul_vt100_emuldata *edp,
     struct wsemul_inputstate *instate)
 {
-       if (edp->dcstype && edp->dcspos < DCS_MAXLEN) {
+       if (edp->dcsarg && edp->dcstype && edp->dcspos < DCS_MAXLEN) {
                if (instate->inchar & ~0xff) {
 #ifdef VT100_PRINTUNKNOWN
                        printf("unknown char %x in DCS\n", instate->inchar);
index e63d90d..9c04ce3 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: wsemul_vt100_subr.c,v 1.29 2023/01/12 20:39:37 nicm Exp $ */
+/* $OpenBSD: wsemul_vt100_subr.c,v 1.30 2023/02/26 15:09:53 miod Exp $ */
 /* $NetBSD: wsemul_vt100_subr.c,v 1.7 2000/04/28 21:56:16 mycroft Exp $ */
 
 /*
@@ -457,11 +457,15 @@ wsemul_vt100_handle_csi(struct wsemul_vt100_emuldata *edp,
                    ERASECOLS(edp->ccol, n, edp->bkgdattr));
                break;
        case 'A': /* CUU */
-               edp->crow -= min(DEF1_ARG(0), ROWS_ABOVE);
+               n = ROWS_ABOVE;
+               if (n > 0)
+                       edp->crow -= min(DEF1_ARG(0), n);
                CHECK_DW;
                break;
        case 'B': /* CUD */
-               edp->crow += min(DEF1_ARG(0), ROWS_BELOW);
+               n = ROWS_BELOW;
+               if (n > 0)
+                       edp->crow += min(DEF1_ARG(0), n);
                CHECK_DW;
                break;
        case 'C': /* CUF */
@@ -488,21 +492,22 @@ wsemul_vt100_handle_csi(struct wsemul_vt100_emuldata *edp,
                break;
        case 'L': /* IL insert line */
        case 'M': /* DL delete line */
-           {
-               int savscrstartrow, savscrnrows;
-
-               n = min(DEF1_ARG(0), ROWS_BELOW + 1);
-               savscrstartrow = edp->scrreg_startrow;
-               savscrnrows = edp->scrreg_nrows;
-               edp->scrreg_nrows -= ROWS_ABOVE;
-               edp->scrreg_startrow = edp->crow;
-               if (c == 'L')
-                       rc = wsemul_vt100_scrolldown(edp, n);
-               else
-                       rc = wsemul_vt100_scrollup(edp, n);
-               edp->scrreg_startrow = savscrstartrow;
-               edp->scrreg_nrows = savscrnrows;
-           }
+               if (edp->crow >= edp->scrreg_startrow &&
+                   edp->crow < edp->scrreg_startrow + edp->scrreg_nrows) {
+                       int savscrstartrow, savscrnrows;
+
+                       n = min(DEF1_ARG(0), ROWS_BELOW + 1);
+                       savscrstartrow = edp->scrreg_startrow;
+                       savscrnrows = edp->scrreg_nrows;
+                       edp->scrreg_nrows -= ROWS_ABOVE;
+                       edp->scrreg_startrow = edp->crow;
+                       if (c == 'L')
+                               rc = wsemul_vt100_scrolldown(edp, n);
+                       else
+                               rc = wsemul_vt100_scrollup(edp, n);
+                       edp->scrreg_startrow = savscrstartrow;
+                       edp->scrreg_nrows = savscrnrows;
+               } /* else not within scrolling region, ignore the sequence */
                break;
        case 'P': /* DCH delete character */
                n = min(DEF1_ARG(0), COLS_LEFT + 1);
@@ -676,9 +681,11 @@ wsemul_vt100_handle_csi(struct wsemul_vt100_emuldata *edp,
                    {
                        char buf[20];
                        int row;
-                       if (edp->flags & VTFL_DECOM)
+                       if (edp->flags & VTFL_DECOM) {
                                row = ROWS_ABOVE;
-                       else
+                               if (row < 0)
+                                       row = 0;
+                       } else
                                row = edp->crow;
                        n = snprintf(buf, sizeof buf, "\033[%d;%dR",
                                    row + 1, edp->ccol + 1);
@@ -839,13 +846,17 @@ wsemul_vt100_handle_dcs(struct wsemul_vt100_emuldata *edp)
                if (edp->tabs != NULL) {
                        memset(edp->tabs, 0, edp->ncols);
                        pos = 0;
+                       if (edp->dcsarg == NULL)
+                               goto out;
                        for (i = 0; i < edp->dcspos; i++) {
                                char c = edp->dcsarg[i];
                                switch (c) {
                                case '0': case '1': case '2': case '3':
                                case '4': case '5': case '6': case '7':
                                case '8': case '9':
-                                       pos = pos * 10 + (edp->dcsarg[i] - '0');
+                                       pos = pos * 10 + (c - '0');
+                                       if (pos > edp->ncols)
+                                               goto out;
                                        break;
                                case '/':
                                        if (pos > 0)
@@ -869,6 +880,7 @@ wsemul_vt100_handle_dcs(struct wsemul_vt100_emuldata *edp)
 #endif
                break;
        }
+out:
        edp->dcstype = 0;
 }