Bug 697401 - Heap buffer overflow write in jsrun.c: js_stackoverflow()
Summary: Heap buffer overflow write in jsrun.c: js_stackoverflow()
Status: RESOLVED FIXED
Alias: None
Product: MuJS
Classification: Unclassified
Component: general (show other bugs)
Version: unspecified
Hardware: PC All
: P4 normal
Assignee: Tor Andersson
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-12-01 04:52 UTC by DD
Modified: 2017-01-12 06:33 UTC (History)
1 user (show)

See Also:
Customer:
Word Size: ---


Attachments
PFA the javascript that is causing the crash (31 bytes, application/x-javascript)
2016-12-01 04:52 UTC, DD
Details

Note You need to log in before you can comment on or make changes to this bug.
Description DD 2016-12-01 04:52:07 UTC
Created attachment 13184 [details]
PFA the javascript that is causing the crash

# Address Sanitizer Output:

==30225== ERROR: AddressSanitizer: heap-buffer-overflow on address 0xb5b0352f at pc 0x8049777 bp 0xbf9c07c8 sp 0xbf9c07bc
WRITE of size 1 at 0xb5b0352f thread T0
    #0 0x8049776 in js_stackoverflow jsrun.c:18
    #1 0x805747f in js_pushundefined jsrun.c:84
    #2 0x805f04a in jsR_calllwfunction jsrun.c:944
    #3 0x805f04a in js_call jsrun.c:1055
    #4 0x805ae19 in jsR_run jsrun.c:1468
    #5 0x805f06e in jsR_calllwfunction jsrun.c:946
    #6 0x805f06e in js_call jsrun.c:1055
    #7 0x805ae19 in jsR_run jsrun.c:1468
    #8 0x805f06e in jsR_calllwfunction jsrun.c:946
    #9 0x805f06e in js_call jsrun.c:1055
    #10 0x805ae19 in jsR_run jsrun.c:1468
    #11 0x805f06e in jsR_calllwfunction jsrun.c:946
    #12 0x805f06e in js_call jsrun.c:1055
    #13 0x805ae19 in jsR_run jsrun.c:1468
    #14 0x805f06e in jsR_calllwfunction jsrun.c:946
    #15 0x805f06e in js_call jsrun.c:1055
    #16 0x805ae19 in jsR_run jsrun.c:1468
    #17 0x805f06e in jsR_calllwfunction jsrun.c:946
    #18 0x805f06e in js_call jsrun.c:1055
    #19 0x805ae19 in jsR_run jsrun.c:1468
    #20 0x805f06e in jsR_calllwfunction jsrun.c:946
    #21 0x805f06e in js_call jsrun.c:1055
    #22 0x805ae19 in jsR_run jsrun.c:1468
    #23 0x805f06e in jsR_calllwfunction jsrun.c:946
    #24 0x805f06e in js_call jsrun.c:1055
    #25 0x805ae19 in jsR_run jsrun.c:1468
    #26 0x805f06e in jsR_calllwfunction jsrun.c:946
    #27 0x805f06e in js_call jsrun.c:1055
    #28 0x805ae19 in jsR_run jsrun.c:1468
    #29 0x805f06e in jsR_calllwfunction jsrun.c:946
    #30 0x805f06e in js_call jsrun.c:1055
    #31 0x805ae19 in jsR_run jsrun.c:1468
    #32 0x805f06e in jsR_calllwfunction jsrun.c:946
    #33 0x805f06e in js_call jsrun.c:1055
    #34 0x805ae19 in jsR_run jsrun.c:1468
    #35 0x805f06e in jsR_calllwfunction jsrun.c:946
    #36 0x805f06e in js_call jsrun.c:1055
    #37 0x805ae19 in jsR_run jsrun.c:1468
    #38 0x805f06e in jsR_calllwfunction jsrun.c:946
    #39 0x805f06e in js_call jsrun.c:1055
    #40 0x805ae19 in jsR_run jsrun.c:1468
    #41 0x805f06e in jsR_calllwfunction jsrun.c:946
    #42 0x805f06e in js_call jsrun.c:1055
    #43 0x805ae19 in jsR_run jsrun.c:1468
    #44 0x805f06e in jsR_calllwfunction jsrun.c:946
    #45 0x805f06e in js_call jsrun.c:1055
    #46 0x805ae19 in jsR_run jsrun.c:1468
    #47 0x805f06e in jsR_calllwfunction jsrun.c:946
    #48 0x805f06e in js_call jsrun.c:1055
    #49 0x805ae19 in jsR_run jsrun.c:1468
    #50 0x805f06e in jsR_calllwfunction jsrun.c:946
    #51 0x805f06e in js_call jsrun.c:1055
    #52 0x805ae19 in jsR_run jsrun.c:1468
    #53 0x805f06e in jsR_calllwfunction jsrun.c:946
    #54 0x805f06e in js_call jsrun.c:1055
    #55 0x805ae19 in jsR_run jsrun.c:1468
    #56 0x805f06e in jsR_calllwfunction jsrun.c:946
    #57 0x805f06e in js_call jsrun.c:1055
    #58 0x805ae19 in jsR_run jsrun.c:1468
    #59 0x805f06e in jsR_calllwfunction jsrun.c:946
    #60 0x805f06e in js_call jsrun.c:1055
    #61 0x805ae19 in jsR_run jsrun.c:1468
    #62 0x805f06e in jsR_calllwfunction jsrun.c:946
    #63 0x805f06e in js_call jsrun.c:1055
    #64 0x805ae19 in jsR_run jsrun.c:1468
    #65 0x805f06e in jsR_calllwfunction jsrun.c:946
    #66 0x805f06e in js_call jsrun.c:1055
    #67 0x805ae19 in jsR_run jsrun.c:1468
    #68 0x805f06e in jsR_calllwfunction jsrun.c:946
    #69 0x805f06e in js_call jsrun.c:1055
    #70 0x805ae19 in jsR_run jsrun.c:1468
    #71 0x805f06e in jsR_calllwfunction jsrun.c:946
    #72 0x805f06e in js_call jsrun.c:1055
    #73 0x805ae19 in jsR_run jsrun.c:1468
    #74 0x805f06e in jsR_calllwfunction jsrun.c:946
    #75 0x805f06e in js_call jsrun.c:1055
    #76 0x805ae19 in jsR_run jsrun.c:1468
    #77 0x805f06e in jsR_calllwfunction jsrun.c:946
    #78 0x805f06e in js_call jsrun.c:1055
    #79 0x805ae19 in jsR_run jsrun.c:1468
    #80 0x805f06e in jsR_calllwfunction jsrun.c:946
    #81 0x805f06e in js_call jsrun.c:1055
    #82 0x805ae19 in jsR_run jsrun.c:1468
    #83 0x805f06e in jsR_calllwfunction jsrun.c:946
    #84 0x805f06e in js_call jsrun.c:1055
    #85 0x805ae19 in jsR_run jsrun.c:1468
    #86 0x805f06e in jsR_calllwfunction jsrun.c:946
    #87 0x805f06e in js_call jsrun.c:1055
    #88 0x805ae19 in jsR_run jsrun.c:1468
    #89 0x805eb3c in jsR_callscript jsrun.c:1006
    #90 0x805eb3c in js_call jsrun.c:1061
    #91 0x80626af in js_dofile jsstate.c:152
    #92 0x8049df9 in main main.c:175
    #93 0xb5f11a82 (/lib/i386-linux-gnu/libc.so.6+0x19a82)
    #94 0x804a421 in _start (build/mujs+0x804a421)
0xb5b0352f is located 47 bytes to the right of 4096-byte region [0xb5b02500,0xb5b03500)
allocated by thread T0 here:
    #0 0xb6104854 (/usr/lib/i386-linux-gnu/libasan.so.0+0x16854)
    #1 0x806297e in js_newstate jsstate.c:201
    #2 0x8049c59 in main main.c:148
    #3 0xb5f11a82 (/lib/i386-linux-gnu/libc.so.6+0x19a82)
SUMMARY: AddressSanitizer: heap-buffer-overflow jsrun.c:18 js_stackoverflow

# PoC Javascript input that is causing the crash:

See attachment poc.js

# Steps to reproduce:

Build Mujs with Asan and do ./mujs poc.js

# Preliminary analysis:

      I believe this crash may be difficult to exploit since the heap overflow write is happening with this statement "STACK[TOP].type = JS_TLITSTR" in js_stackoverflow function of jsrun.c

      The program has allocated 4096 bytes or 256 virtual stack frames size { this can be confirmed from Asan output quoted "0xb5b0352f is located 47 bytes to the right of 4096-byte region [0xb5b02500,0xb5b03500)", Also in the code "./jsi.h:72 #define JS_STACKSIZE 256" } and when I give the poc.js as an input to mujs, it is bypassing the stack size checking { Which I believe is primarly through  " ./jsrun.c:73:#define CHECKSTACK(n) if (TOP + n >= JS_STACKSIZE)" } and writing into unallocated virtual stack space { as can be seen in Asan output "0xb5b0352f is located 47 bytes to the right of 4096-byte region [0xb5b02500,0xb5b03500)", i can see that the value of TOP is 258 in js_stackoverflow when the program crashed }

      I believe there is some point in the code where we are incrementing the stack TOP without doing the CHECKSTACK(n) which should have something to do with unbalanced number of parameters in function definition and function call. Will post more analysis and suggest resolution if I get time to analyze this completely.
Comment 1 DD 2016-12-12 03:04:14 UTC
Hi,

Any update on this?
Comment 2 DD 2016-12-20 01:03:42 UTC
Hi,

The bug must be at line 940 in jsR_calllwfunction function in jsrun.c which is:

if (n > F->numparams) {
    js_pop(J, F->numparams - n);

Essentially in the above code, "F->numparams - n" will return a negative value and once we pass it to js_pop function, we are doing something equivalent to "TOP -= (F->numparams - n)" which is incrementing the value of TOP instead of decrementing it which is aiding in the heap overflow.

Fix can be to modify the line 940 in jsrun.c to: js_pop(J, n - F->numparams);

Let me know if this works.
Comment 3 Tor Andersson 2017-01-12 06:33:27 UTC
Sorry for the late response.

This has been fixed in commit 77ab465f1c394bb77f00966cd950650f3f53cb24
Author: Tor Andersson <tor.andersson@gmail.com>
Date:   Thu Jan 12 14:47:01 2017 +0100

    Fix 697401: Error when dropping extra arguments to lightweight functions.