mirror of
https://github.com/bellard/quickjs.git
synced 2025-11-15 10:12:14 +03:00
Fix use-after-free in ArrayBuffer.prototype.transfer (bnoordhuis) (#450) - use js_array_buffer_update_typed_arrays() in JS_DetachArrayBuffer()
This commit is contained in:
82
quickjs.c
82
quickjs.c
@@ -55344,10 +55344,47 @@ static JSValue js_array_buffer_get_resizable(JSContext *ctx,
|
|||||||
return JS_NewBool(ctx, array_buffer_is_resizable(abuf));
|
return JS_NewBool(ctx, array_buffer_is_resizable(abuf));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void js_array_buffer_update_typed_arrays(JSArrayBuffer *abuf)
|
||||||
|
{
|
||||||
|
uint32_t size_log2, size_elem;
|
||||||
|
struct list_head *el;
|
||||||
|
JSTypedArray *ta;
|
||||||
|
JSObject *p;
|
||||||
|
uint8_t *data;
|
||||||
|
int64_t len;
|
||||||
|
|
||||||
|
len = abuf->byte_length;
|
||||||
|
data = abuf->data;
|
||||||
|
// update lengths of all typed arrays backed by this array buffer
|
||||||
|
list_for_each(el, &abuf->array_list) {
|
||||||
|
ta = list_entry(el, JSTypedArray, link);
|
||||||
|
p = ta->obj;
|
||||||
|
if (p->class_id == JS_CLASS_DATAVIEW) {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
p->u.array.count = 0;
|
||||||
|
p->u.array.u.ptr = NULL;
|
||||||
|
size_log2 = typed_array_size_log2(p->class_id);
|
||||||
|
size_elem = 1 << size_log2;
|
||||||
|
if (ta->track_rab) {
|
||||||
|
if (len >= (int64_t)ta->offset + size_elem) {
|
||||||
|
p->u.array.count = (len - ta->offset) >> size_log2;
|
||||||
|
p->u.array.u.ptr = &data[ta->offset];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (len >= (int64_t)ta->offset + ta->length) {
|
||||||
|
p->u.array.count = ta->length >> size_log2;
|
||||||
|
p->u.array.u.ptr = &data[ta->offset];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void JS_DetachArrayBuffer(JSContext *ctx, JSValueConst obj)
|
void JS_DetachArrayBuffer(JSContext *ctx, JSValueConst obj)
|
||||||
{
|
{
|
||||||
JSArrayBuffer *abuf = JS_GetOpaque(obj, JS_CLASS_ARRAY_BUFFER);
|
JSArrayBuffer *abuf = JS_GetOpaque(obj, JS_CLASS_ARRAY_BUFFER);
|
||||||
struct list_head *el;
|
|
||||||
|
|
||||||
if (!abuf || abuf->detached)
|
if (!abuf || abuf->detached)
|
||||||
return;
|
return;
|
||||||
@@ -55356,19 +55393,7 @@ void JS_DetachArrayBuffer(JSContext *ctx, JSValueConst obj)
|
|||||||
abuf->data = NULL;
|
abuf->data = NULL;
|
||||||
abuf->byte_length = 0;
|
abuf->byte_length = 0;
|
||||||
abuf->detached = TRUE;
|
abuf->detached = TRUE;
|
||||||
|
js_array_buffer_update_typed_arrays(abuf);
|
||||||
list_for_each(el, &abuf->array_list) {
|
|
||||||
JSTypedArray *ta;
|
|
||||||
JSObject *p;
|
|
||||||
|
|
||||||
ta = list_entry(el, JSTypedArray, link);
|
|
||||||
p = ta->obj;
|
|
||||||
/* Note: the typed array length and offset fields are not modified */
|
|
||||||
if (p->class_id != JS_CLASS_DATAVIEW) {
|
|
||||||
p->u.array.count = 0;
|
|
||||||
p->u.array.u.ptr = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get an ArrayBuffer or SharedArrayBuffer */
|
/* get an ArrayBuffer or SharedArrayBuffer */
|
||||||
@@ -55483,6 +55508,7 @@ static JSValue js_array_buffer_transfer(JSContext *ctx,
|
|||||||
abuf->data = NULL;
|
abuf->data = NULL;
|
||||||
abuf->byte_length = 0;
|
abuf->byte_length = 0;
|
||||||
abuf->detached = TRUE;
|
abuf->detached = TRUE;
|
||||||
|
js_array_buffer_update_typed_arrays(abuf);
|
||||||
return js_array_buffer_constructor3(ctx, JS_UNDEFINED, new_len, pmax_len,
|
return js_array_buffer_constructor3(ctx, JS_UNDEFINED, new_len, pmax_len,
|
||||||
JS_CLASS_ARRAY_BUFFER,
|
JS_CLASS_ARRAY_BUFFER,
|
||||||
bs, free_func,
|
bs, free_func,
|
||||||
@@ -55493,11 +55519,7 @@ static JSValue js_array_buffer_transfer(JSContext *ctx,
|
|||||||
static JSValue js_array_buffer_resize(JSContext *ctx, JSValueConst this_val,
|
static JSValue js_array_buffer_resize(JSContext *ctx, JSValueConst this_val,
|
||||||
int argc, JSValueConst *argv, int class_id)
|
int argc, JSValueConst *argv, int class_id)
|
||||||
{
|
{
|
||||||
uint32_t size_log2, size_elem;
|
|
||||||
struct list_head *el;
|
|
||||||
JSArrayBuffer *abuf;
|
JSArrayBuffer *abuf;
|
||||||
JSTypedArray *ta;
|
|
||||||
JSObject *p;
|
|
||||||
uint8_t *data;
|
uint8_t *data;
|
||||||
int64_t len;
|
int64_t len;
|
||||||
|
|
||||||
@@ -55540,29 +55562,7 @@ static JSValue js_array_buffer_resize(JSContext *ctx, JSValueConst this_val,
|
|||||||
abuf->byte_length = len;
|
abuf->byte_length = len;
|
||||||
abuf->data = data;
|
abuf->data = data;
|
||||||
}
|
}
|
||||||
data = abuf->data;
|
js_array_buffer_update_typed_arrays(abuf);
|
||||||
// update lengths of all typed arrays backed by this array buffer
|
|
||||||
list_for_each(el, &abuf->array_list) {
|
|
||||||
ta = list_entry(el, JSTypedArray, link);
|
|
||||||
p = ta->obj;
|
|
||||||
if (p->class_id == JS_CLASS_DATAVIEW)
|
|
||||||
continue;
|
|
||||||
p->u.array.count = 0;
|
|
||||||
p->u.array.u.ptr = NULL;
|
|
||||||
size_log2 = typed_array_size_log2(p->class_id);
|
|
||||||
size_elem = 1 << size_log2;
|
|
||||||
if (ta->track_rab) {
|
|
||||||
if (len >= (int64_t)ta->offset + size_elem) {
|
|
||||||
p->u.array.count = (len - ta->offset) >> size_log2;
|
|
||||||
p->u.array.u.ptr = &data[ta->offset];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (len >= (int64_t)ta->offset + ta->length) {
|
|
||||||
p->u.array.count = ta->length >> size_log2;
|
|
||||||
p->u.array.u.ptr = &data[ta->offset];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return JS_UNDEFINED;
|
return JS_UNDEFINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -511,6 +511,14 @@ function test_typed_array()
|
|||||||
assert(a.toString(), "1,2,3,4");
|
assert(a.toString(), "1,2,3,4");
|
||||||
a.set([10, 11], 2);
|
a.set([10, 11], 2);
|
||||||
assert(a.toString(), "1,2,10,11");
|
assert(a.toString(), "1,2,10,11");
|
||||||
|
|
||||||
|
// https://github.com/quickjs-ng/quickjs/issues/1208
|
||||||
|
buffer = new ArrayBuffer(16);
|
||||||
|
a = new Uint8Array(buffer);
|
||||||
|
a.fill(42);
|
||||||
|
assert(a[0], 42);
|
||||||
|
buffer.transfer();
|
||||||
|
assert(a[0], undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return [s, line_num, col_num] where line_num and col_num are the
|
/* return [s, line_num, col_num] where line_num and col_num are the
|
||||||
|
|||||||
Reference in New Issue
Block a user