Memory leak in JS_ReadBigInt when a bjson payload is truncated inside a BigInt
I maintainer di solito rispondono entro 2 giorni
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 2/5
- Tempo stimato
- 1-3 ore
- Idoneità per principianti
- 88/100
Direzione di ricerca
Leggi JS_ReadBigInt in quickjs.c e segui come viene liberata la sua allocazione nel percorso fail. Riproduci il problema con il payload bjson troncato fornito sotto AddressSanitizer, quindi verifica che la perdita sia risolta per ogni troncamento; il risultato atteso è lo stesso SyntaxError, senza oggetti JSBigInt persi. L’issue riporta che la suite di test esistente passa senza modifiche.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Summary
JS_ReadBigInt allocates the JSBigInt before it reads the limbs. When the
payload ends in the middle of the limbs, the function jumps to its fail label,
which releases obj but never the bigint — so the JSBigInt is leaked.
Found while fuzzing the bjson reader with a locally built AddressSanitizer
binary. The reproducer below is plain JavaScript, no C code required.
Steps to reproduce
import * as bjson from "qjs:bjson";
const buf = bjson.write({ v: 123456789012345678901234567890n });
// Set the checksum to the "no checksum" escape value, so the reader does not
// reject the payload before it reaches the bigint.
new DataView(buf).setUint32(1, 0xFFFFFFFF, true);
for (let cut = 1; cut <= 6; cut++) {
bjson.read(buf, 0, buf.byteLength - cut); // throws SyntaxError
}
Expected: each call throws SyntaxError: read after the end of the buffer
and nothing is leaked.
Actual: each call throws the same error and leaks a JSBigInt
(28 bytes each on x86-64).
ASan output
Built with gcc -g -O1 -fsanitize=address, running the script above:
=================================================================
==7905==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 168 byte(s) in 6 object(s) allocated from:
#1 0x5f7094d3e8b9 in js_def_malloc quickjs.c:2409
#2 0x5f7094d36000 in arena_malloc_large quickjs.c:1780
#3 0x5f7094d52516 in js_arena_malloc quickjs.c:1836
#4 0x5f7094d52516 in js_malloc_rt quickjs.c:2018
#5 0x5f7094d8a3a6 in js_malloc quickjs.c:2106
#6 0x5f7094dc3f82 in js_bigint_new quickjs.c:12666
#7 0x5f7094e92f00 in JS_ReadBigInt quickjs.c:39655
#8 0x5f7094e92f00 in JS_ReadObjectRec quickjs.c:40452
#9 0x5f7094e91048 in JS_ReadObjectTag quickjs.c:40092
#10 0x5f7094e91048 in JS_ReadObjectRec quickjs.c:40425
#11 0x5f7094e94229 in JS_ReadObject2 quickjs.c:40603
#12 0x5f7094e94ac9 in JS_ReadObject quickjs.c:40618
#13 0x5f7094ec2a77 in js_bjson_read quickjs-libc.c:5008
Six truncations leak 168 bytes in total.
Root cause
JS_ReadBigInt in quickjs.c:
p = js_bigint_new(s->ctx, (len - 1) / (JS_LIMB_BITS / 8) + 1);
if (!p)
goto fail;
for (i = 0; i < len / (JS_LIMB_BITS / 8); i++) {
if (bc_get_u32(s, &v))
goto fail; /* <-- p is leaked here */
p->tab[i] = v;
}
n = len % (JS_LIMB_BITS / 8);
if (n != 0) {
...
for (i = 0; i < n; i++) {
if (bc_get_u8(s, &v8))
goto fail; /* <-- and here */
...
}
}
...
fail:
JS_FreeValue(s->ctx, obj);
return JS_EXCEPTION;
obj is released, p is not.
Suggested fix
- JSBigInt *p;
+ JSBigInt *p = NULL;
...
fail:
+ if (p)
+ js_free_rt(s->ctx->rt, p);
JS_FreeValue(s->ctx, obj);
return JS_EXCEPTION;
js_free_rt() is the counterpart of the js_malloc() call inside
js_bigint_new() (js_malloc(ctx, …) forwards to js_malloc_rt(ctx->rt, …)).
p must be initialised to NULL because the first goto fail happens before
js_bigint_new().
With this change the reproducer above leaks nothing, and the existing local
test suite still passes unchanged (run-test262 -c tests.conf → 0/121 errors).
Notes
- The
failpath is reachable from two places: the limb loop
(bc_get_u32) and the sign-extension loop (bc_get_u8). - This may be specific to the current BigInt implementation: the allocation
pattern was introduced together with it (git log -S "js_bigint_new" -- quickjs.cpoints at the "New BigInt implementation" commit), so the older
libbf-based code may not have had this path. - This is a leak, not memory corruption, so per SECURITY.md it should be a
normal bug report. Reaching it requires deliberately malformed input; with
the checksum left enabled, the reader rejects the payload before it reaches
the BigInt.
- Lingua principale
- C
- Stelle
- 3.9k
- Fork
- 389
- Merge medio
- 4g 1h
- PR unite (30g)
- 24
Preparare l'ambiente
Questo progetto non fornisce container di sviluppo, Dockerfile né guida per i contributori, quindi l'ambiente è a tuo carico: parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di quickjs-ng/quickjs
-
Array.prototype.find frees an element twice when interrupted between iterationsForse già presa @josefguenther l’ha presa 14 giorni fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 73/100
quickjs-ng/quickjs#1792 · 1 commento ·
I maintainer di solito rispondono entro 2 giorni
-
Object.prototype.propertyIsEnumerable converts `this` before the property keyForse già presa @SomSamantray l’ha presa 10 giorni fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
quickjs-ng/quickjs#1772 ·
I maintainer di solito rispondono entro 2 giorni
-
Deserialization corrupts data or returns `undefined` when a RegExp precedes a shared object referenceForse già presa @Sree24-ui l’ha presa 13 giorni fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
quickjs-ng/quickjs#1771 · 2 commenti ·
I maintainer di solito rispondono entro 2 giorni
-
Difficoltà 3/5 1-2 giorni Idoneità per principianti 72/100
quickjs-ng/quickjs#1835 · 1 reazione ·
I maintainer di solito rispondono entro 2 giorni
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 45/100
quickjs-ng/quickjs#1833 ·
I maintainer di solito rispondono entro 2 giorni
Tutte le issue di quickjs-ng/quickjs
Issue simili
-
area:docs kind:docs-drift
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
InauguralSystems/EigenScript#1887 ·
I maintainer di solito rispondono entro 1 giorno
-
[WinReg] update to v12.0.0Apertacategory:port-update
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
I maintainer di solito rispondono entro 2 giorni
-
type-bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
zephyrproject-rtos/zephyr#122906 ·
I maintainer di solito rispondono entro 2 giorni
-
feat(palindrome): add C solutionForse già presa @aadiitya2007 l’ha presa oggi. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
techcsispit/code-corner#58 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno