CVE-2019-11413 (C, published 2019-04-22T11:29Z)
Description: value: An issue was discovered in Artifex MuJS 1.0.5. It has unlimited recursion because the match function in regexp.c lacks a depth check.
Severity: MEDIUM (CVSS v3 base score: 7.5)
Weakness: CWE-674 \u2014 Uncontrolled Recursion
The product does not properly control the amount of recursion that takes place,  consuming excessive resources, such as allocated memory or the program stack.
Repository: https://github.com/ccxvii/mujs
Files changed:
jsregexp.c
jsstring.c
regexp.c
Commit message: Bug 700937: Limit recursion in regexp matcher.

Also handle negative return code as an error in the JS bindings.


Vulnerable code:
	if (!js_regexec(re->prog, text, &m, opts)) {
	if (!js_regexec(re->prog, text, &m, opts)) {
		if (js_regexec(re->prog, a, &m, a > text ? REG_NOTBOL : 0))
	if (!js_regexec(re->prog, text, &m, 0))
	if (js_regexec(re->prog, source, &m, 0)) {
		if (!js_regexec(re->prog, source, &m, REG_NOTBOL))
		if (js_regexec(re->prog, text, &m, 0)) {
		if (js_regexec(re->prog, a, &m, a > text ? REG_NOTBOL : 0))
static int match(Reinst *pc, const char *sp, const char *bol, int flags, Resub *out)
			return 1;
			if (match(pc->x, sp, bol, flags, &scratch)) {
				return 1;
			if (!match(pc->x, sp, bol, flags, out))
				return 0;
			if (match(pc->x, sp, bol, flags, &scratch))
				return 0;
				return 0;
				return 0;
				return 0;
				return 0;
				return 0;
				return 0;
					return 0;
					return 0;
				return 0;
					return 0;
					return 0;
					return 0;
					return 0;
			return 0;
			return 0;
				return 0;
				return 0;
			return 0;
	return !match(prog->start, sp, sp, prog->flags | eflags, sub);

Fixed code:
	int result;
	result = js_regexec(re->prog, text, &m, opts);
	if (result < 0)
		js_error(J, "regexec failed");
	if (result == 0) {
	int result;
	result = js_regexec(re->prog, text, &m, opts);
	if (result < 0)
		js_error(J, "regexec failed");
	if (result == 0) {
static int js_doregexec(js_State *J, Reprog *prog, const char *string, Resub *sub, int eflags)
{
	int result = js_regexec(prog, string, sub, eflags);
	if (result < 0)
		js_error(J, "regexec failed");
	return result;
}

		if (js_doregexec(J, re->prog, a, &m, a > text ? REG_NOTBOL : 0))
	if (!js_doregexec(J, re->prog, text, &m, 0))
	if (js_doregexec(J, re->prog, source, &m, 0)) {
		if (!js_doregexec(J, re->prog, source, &m, REG_NOTBOL))
		if (js_doregexec(J, re->prog, text, &m, 0)) {
		if (js_doregexec(J, re->prog, a, &m, a > text ? REG_NOTBOL : 0))
#define MAXREC 1024
static int match(Reinst *pc, const char *sp, const char *bol, int flags, Resub *out, int depth)
	int result;
	/* stack overflow */
	if (depth > MAXREC)
		return -1;

			return 0;
			result = match(pc->x, sp, bol, flags, &scratch, depth+1);
			if (result == -1)
				return -1;
			if (result == 0) {
				return 0;
			result = match(pc->x, sp, bol, flags, out, depth+1);
			if (result == -1)
				return -1;
			if (result == 1)
				return 1;
			result = match(pc->x, sp, bol, flags, &scratch, depth+1);
			if (result == -1)
				return -1;
			if (result == 0)
				return 1;
				return 1;
				return 1;
				return 1;
				return 1;
				return 1;
				return 1;
					return 1;
					return 1;
				return 1;
					return 1;
					return 1;
					return 1;
					return 1;
			return 1;
			return 1;
				return 1;
				return 1;
			return 1;
	return match(prog->start, sp, sp, prog->flags | eflags, sub, 0);