CVE-2021-45005: Out-of-bounds Write (CWE-787)
value: Artifex MuJS v1.1.3 was discovered to contain a heap buffer overflow which is caused by conflicting JumpList of nested try/finally statements.
CWE description: The product writes data past the end, or before the beginning, of the intended buffer.
CVSS v3 base score: 9.8
Published: 2022-02-14T22:15Z
Repository: https://github.com/ccxvii/mujs
Language: C
Files changed: jscompile.c
Commit date: 2021-12-06 11:48:32 +0100
Commit message: Bug 704749: Clear jump list after patching jump addresses.

Since we can emit a statement multiple times when compiling try/finally
we have to use a new patch list for each instance.

Diff: diff --git a/jscompile.c b/jscompile.c
index dcdee05..a915903 100644
--- a/jscompile.c
+++ b/jscompile.c
@@ -792,19 +792,23 @@ static void addjump(JF, enum js_AstType type, js_Ast *target, int inst)
 	jump->inst = inst;
 	jump->next = target->jumps;
 	target->jumps = jump;
 }
 
-static void labeljumps(JF, js_JumpList *jump, int baddr, int caddr)
+static void labeljumps(JF, js_Ast *stm, int baddr, int caddr)
 {
+	js_JumpList *jump = stm->jumps;
 	while (jump) {
+		js_JumpList *next = jump->next;
 		if (jump->type == STM_BREAK)
 			labelto(J, F, jump->inst, baddr);
 		if (jump->type == STM_CONTINUE)
 			labelto(J, F, jump->inst, caddr);
-		jump = jump->next;
+		js_free(J, jump);
+		jump = next;
 	}
+	stm->jumps = NULL;
 }
 
 static int isloop(enum js_AstType T)
 {
 	return T == STM_DO || T == STM_WHILE ||
@@ -1119,11 +1123,11 @@ static void cstm(JF, js_Ast *stm)
 		cstm(J, F, stm->a);
 		cont = here(J, F);
 		cexp(J, F, stm->b);
 		emitline(J, F, stm);
 		emitjumpto(J, F, OP_JTRUE, loop);
-		labeljumps(J, F, stm->jumps, here(J,F), cont);
+		labeljumps(J, F, stm, here(J,F), cont);
 		break;
 
 	case STM_WHILE:
 		loop = here(J, F);
 		cexp(J, F, stm->a);
@@ -1131,11 +1135,11 @@ static void cstm(JF, js_Ast *stm)
 		end = emitjump(J, F, OP_JFALSE);
 		cstm(J, F, stm->b);
 		emitline(J, F, stm);
 		emitjumpto(J, F, OP_JUMP, loop);
 		label(J, F, end);
-		labeljumps(J, F, stm->jumps, here(J,F), loop);
+		labeljumps(J, F, stm, here(J,F), loop);
 		break;
 
 	case STM_FOR:
 	case STM_FOR_VAR:
 		if (stm->type == STM_FOR_VAR) {
@@ -1162,11 +1166,11 @@ static void cstm(JF, js_Ast *stm)
 		}
 		emitline(J, F, stm);
 		emitjumpto(J, F, OP_JUMP, loop);
 		if (end)
 			label(J, F, end);
-		labeljumps(J, F, stm->jumps, here(J,F), cont);
+		labeljumps(J, F, stm, here(J,F), cont);
 		break;
 
 	case STM_FOR_IN:
 	case STM_FOR_IN_VAR:
 		cexp(J, F, stm->b);
@@ -1187,26 +1191,26 @@ static void cstm(JF, js_Ast *stm)
 			}
 			emitline(J, F, stm);
 			emitjumpto(J, F, OP_JUMP, loop);
 		}
 		label(J, F, end);
-		labeljumps(J, F, stm->jumps, here(J,F), loop);
+		labeljumps(J, F, stm, here(J,F), loop);
 		break;
 
 	case STM_SWITCH:
 		cswitch(J, F, stm->a, stm->b);
-		labeljumps(J, F, stm->jumps, here(J,F), 0);
+		labeljumps(J, F, stm, here(J,F), 0);
 		break;
 
 	case STM_LABEL:
 		cstm(J, F, stm->b);
 		/* skip consecutive labels */
 		while (stm->type == STM_LABEL)
 			stm = stm->b;
 		/* loops and switches have already been labelled */
 		if (!isloop(stm->type) && stm->type != STM_SWITCH)
-			labeljumps(J, F, stm->jumps, here(J,F), 0);
+			labeljumps(J, F, stm, here(J,F), 0);
 		break;
 
 	case STM_BREAK:
 		if (stm->a) {
 			checkfutureword(J, F, stm->a);

Vulnerable code: static void labeljumps(JF, js_JumpList *jump, int baddr, int caddr)
		jump = jump->next;
		labeljumps(J, F, stm->jumps, here(J,F), cont);
		labeljumps(J, F, stm->jumps, here(J,F), loop);
		labeljumps(J, F, stm->jumps, here(J,F), cont);
		labeljumps(J, F, stm->jumps, here(J,F), loop);
		labeljumps(J, F, stm->jumps, here(J,F), 0);
			labeljumps(J, F, stm->jumps, here(J,F), 0);
Fixed code: static void labeljumps(JF, js_Ast *stm, int baddr, int caddr)
	js_JumpList *jump = stm->jumps;
		js_JumpList *next = jump->next;
		js_free(J, jump);
		jump = next;
	stm->jumps = NULL;
		labeljumps(J, F, stm, here(J,F), cont);
		labeljumps(J, F, stm, here(J,F), loop);
		labeljumps(J, F, stm, here(J,F), cont);
		labeljumps(J, F, stm, here(J,F), loop);
		labeljumps(J, F, stm, here(J,F), 0);
			labeljumps(J, F, stm, here(J,F), 0);