CVE-2023-40216: Missing Authorization (CWE-862)
value: OpenBSD 7.3 before errata 014 is missing an argument-count bounds check in console terminal emulation. This could cause incorrect memory access and a kernel crash after receiving crafted DCS or CSI terminal escape sequences.
CWE description: The product does not perform an authorization check when an actor attempts to access a resource or perform an action.
CVSS v3 base score: 5.5
Published: 2023-08-10T16:15Z
Repository: https://github.com/openbsd/src
Language: C
Files changed: sys/dev/wscons/wsemul_sun.c, sys/dev/wscons/wsemul_vt100.c
Commit date: 2023-07-24 17:03:32 +0000
Commit message: Make sure we do not increase the escape sequence argument count beyond usable
bounds, in case escape sequences end up with too many semicolons.
Without this, the kernel could be made to access random memory after receiving
some specially crafted DCS or CSI terminal escape sequences.

Reported by David Leadbeater (dgl, dgl dot cx)

Diff: diff --git a/sys/dev/wscons/wsemul_sun.c b/sys/dev/wscons/wsemul_sun.c
index 40871af462b76..e14c32dae3fff 100644
--- a/sys/dev/wscons/wsemul_sun.c
+++ b/sys/dev/wscons/wsemul_sun.c
@@ -1,6 +1,6 @@
-/* $OpenBSD: wsemul_sun.c,v 1.36 2023/03/06 20:34:35 miod Exp $ */
+/* $OpenBSD: wsemul_sun.c,v 1.37 2023/07/24 17:03:32 miod Exp $ */
 /* $NetBSD: wsemul_sun.c,v 1.11 2000/01/05 11:19:36 drochner Exp $ */
 
 /*
  * Copyright (c) 2007, 2013 Miodrag Vallat.
  *
@@ -615,17 +615,18 @@ wsemul_sun_output_control(struct wsemul_sun_emuldata *edp,
 		edp->args[edp->nargs] = (edp->args[edp->nargs] * 10) +
 		    (instate->inchar - '0');
 		break;
 
 	case ';':		/* argument terminator */
-		edp->nargs++;
+		if (edp->nargs < SUN_EMUL_NARGS)
+			edp->nargs++;
 		break;
 
 	default:		/* end of escape sequence */
-		oargs = edp->nargs++;
-		if (edp->nargs > SUN_EMUL_NARGS)
-			edp->nargs = SUN_EMUL_NARGS;
+		oargs = edp->nargs;
+		if (edp->nargs < SUN_EMUL_NARGS)
+			edp->nargs++;
 		rc = wsemul_sun_control(edp, instate);
 		if (rc != 0) {
 			/* undo nargs progress */
 			edp->nargs = oargs;
 
diff --git a/sys/dev/wscons/wsemul_vt100.c b/sys/dev/wscons/wsemul_vt100.c
index 1f976bd823194..afea00b469a84 100644
--- a/sys/dev/wscons/wsemul_vt100.c
+++ b/sys/dev/wscons/wsemul_vt100.c
@@ -1,6 +1,6 @@
-/* $OpenBSD: wsemul_vt100.c,v 1.45 2023/03/06 20:34:35 miod Exp $ */
+/* $OpenBSD: wsemul_vt100.c,v 1.46 2023/07/24 17:03:32 miod Exp $ */
 /* $NetBSD: wsemul_vt100.c,v 1.13 2000/04/28 21:56:16 mycroft Exp $ */
 
 /*
  * Copyright (c) 2007, 2013 Miodrag Vallat.
  *
@@ -866,20 +866,16 @@ wsemul_vt100_output_dcs(struct wsemul_vt100_emuldata *edp,
 			break;
 		edp->args[edp->nargs] = (edp->args[edp->nargs] * 10) +
 		    (instate->inchar - '0');
 		break;
 	case ';': /* argument terminator */
-		edp->nargs++;
+		if (edp->nargs < VT100_EMUL_NARGS)
+			edp->nargs++;
 		break;
 	default:
-		edp->nargs++;
-		if (edp->nargs > VT100_EMUL_NARGS) {
-#ifdef VT100_DEBUG
-			printf("vt100: too many arguments\n");
-#endif
-			edp->nargs = VT100_EMUL_NARGS;
-		}
+		if (edp->nargs < VT100_EMUL_NARGS)
+			edp->nargs++;
 		newstate = VT100_EMUL_STATE_STRING;
 		switch (instate->inchar) {
 		case '$':
 			newstate = VT100_EMUL_STATE_DCS_DOLLAR;
 			break;
@@ -1067,11 +1063,12 @@ wsemul_vt100_output_csi(struct wsemul_vt100_emuldata *edp,
 			break;
 		edp->args[edp->nargs] = (edp->args[edp->nargs] * 10) +
 		    (instate->inchar - '0');
 		break;
 	case ';': /* argument terminator */
-		edp->nargs++;
+		if (edp->nargs < VT100_EMUL_NARGS)
+			edp->nargs++;
 		break;
 	case '?': /* DEC specific */
 	case '>': /* DA query */
 		edp->modif1 = (char)instate->inchar;
 		break;
@@ -1080,17 +1077,13 @@ wsemul_vt100_output_csi(struct wsemul_vt100_emuldata *edp,
 	case '$':
 	case '&':
 		edp->modif2 = (char)instate->inchar;
 		break;
 	default: /* end of escape sequence */
-		oargs = edp->nargs++;
-		if (edp->nargs > VT100_EMUL_NARGS) {
-#ifdef VT100_DEBUG
-			printf("vt100: too many arguments\n");
-#endif
-			edp->nargs = VT100_EMUL_NARGS;
-		}
+		oargs = edp->nargs;
+		if (edp->nargs < VT100_EMUL_NARGS)
+			edp->nargs++;
 		rc = wsemul_vt100_handle_csi(edp, instate);
 		if (rc != 0) {
 			edp->nargs = oargs;
 			return rc;
 		}

Vulnerable code: /* $OpenBSD: wsemul_sun.c,v 1.36 2023/03/06 20:34:35 miod Exp $ */
		edp->nargs++;
		oargs = edp->nargs++;
		if (edp->nargs > SUN_EMUL_NARGS)
			edp->nargs = SUN_EMUL_NARGS;
/* $OpenBSD: wsemul_vt100.c,v 1.45 2023/03/06 20:34:35 miod Exp $ */
		edp->nargs++;
		edp->nargs++;
		if (edp->nargs > VT100_EMUL_NARGS) {
#ifdef VT100_DEBUG
			printf("vt100: too many arguments\n");
#endif
			edp->nargs = VT100_EMUL_NARGS;
		}
		edp->nargs++;
		oargs = edp->nargs++;
		if (edp->nargs > VT100_EMUL_NARGS) {
#ifdef VT100_DEBUG
			printf("vt100: too many arguments\n");
#endif
			edp->nargs = VT100_EMUL_NARGS;
		}
Fixed code: /* $OpenBSD: wsemul_sun.c,v 1.37 2023/07/24 17:03:32 miod Exp $ */
		if (edp->nargs < SUN_EMUL_NARGS)
			edp->nargs++;
		oargs = edp->nargs;
		if (edp->nargs < SUN_EMUL_NARGS)
			edp->nargs++;
/* $OpenBSD: wsemul_vt100.c,v 1.46 2023/07/24 17:03:32 miod Exp $ */
		if (edp->nargs < VT100_EMUL_NARGS)
			edp->nargs++;
		if (edp->nargs < VT100_EMUL_NARGS)
			edp->nargs++;
		if (edp->nargs < VT100_EMUL_NARGS)
			edp->nargs++;
		oargs = edp->nargs;
		if (edp->nargs < VT100_EMUL_NARGS)
			edp->nargs++;