Skip to content

Commit c8be383

Browse files
committed
Prevent JS_SetOpaque from overriding internal class state
Fixes: #657
1 parent e30da0e commit c8be383

File tree

2 files changed

+38
-20
lines changed

2 files changed

+38
-20
lines changed

quickjs.c

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1302,6 +1302,8 @@ static void js_new_callsite_data(JSContext *ctx, JSCallSiteData *csd, JSStackFra
13021302
static void js_new_callsite_data2(JSContext *ctx, JSCallSiteData *csd, const char *filename, int line_num, int col_num);
13031303
static void _JS_AddIntrinsicCallSite(JSContext *ctx);
13041304

1305+
static void JS_SetOpaqueInternal(JSValue obj, void *opaque);
1306+
13051307
static const JSClassExoticMethods js_arguments_exotic_methods;
13061308
static const JSClassExoticMethods js_string_exotic_methods;
13071309
static const JSClassExoticMethods js_proxy_exotic_methods;
@@ -5226,7 +5228,7 @@ JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func,
52265228
s->magic = magic;
52275229
for(i = 0; i < data_len; i++)
52285230
s->data[i] = js_dup(data[i]);
5229-
JS_SetOpaque(func_obj, s);
5231+
JS_SetOpaqueInternal(func_obj, s);
52305232
js_function_set_properties(ctx, func_obj,
52315233
JS_ATOM_empty_string, length);
52325234
return func_obj;
@@ -10072,13 +10074,29 @@ void JS_ResetUncatchableError(JSContext *ctx)
1007210074
JS_SetUncatchableError(ctx, ctx->rt->current_exception, FALSE);
1007310075
}
1007410076

10075-
void JS_SetOpaque(JSValue obj, void *opaque)
10077+
JS_BOOL JS_SetOpaque(JSValue obj, void *opaque)
1007610078
{
10077-
JSObject *p;
10079+
JSObject *p;
1007810080
if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
1007910081
p = JS_VALUE_GET_OBJ(obj);
10080-
p->u.opaque = opaque;
10082+
// User code can't set the opaque of internal objects.
10083+
if (p->class_id >= JS_CLASS_INIT_COUNT) {
10084+
p->u.opaque = opaque;
10085+
return 0;
10086+
}
1008110087
}
10088+
10089+
return 1;
10090+
}
10091+
10092+
/* |obj| must be a JSObject of an internal class. */
10093+
static void JS_SetOpaqueInternal(JSValue obj, void *opaque)
10094+
{
10095+
JSObject *p;
10096+
assert(JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT);
10097+
p = JS_VALUE_GET_OBJ(obj);
10098+
assert(p->class_id < JS_CLASS_INIT_COUNT);
10099+
p->u.opaque = opaque;
1008210100
}
1008310101

1008410102
/* return NULL if not an object of class class_id */
@@ -17807,7 +17825,7 @@ static JSValue js_generator_function_call(JSContext *ctx, JSValue func_obj,
1780717825
obj = js_create_from_ctor(ctx, func_obj, JS_CLASS_GENERATOR);
1780817826
if (JS_IsException(obj))
1780917827
goto fail;
17810-
JS_SetOpaque(obj, s);
17828+
JS_SetOpaqueInternal(obj, s);
1781117829
return obj;
1781217830
fail:
1781317831
free_generator_stack_rt(ctx->rt, s);
@@ -18438,7 +18456,7 @@ static JSValue js_async_generator_function_call(JSContext *ctx, JSValue func_obj
1843818456
if (JS_IsException(obj))
1843918457
goto fail;
1844018458
s->generator = JS_VALUE_GET_OBJ(obj);
18441-
JS_SetOpaque(obj, s);
18459+
JS_SetOpaqueInternal(obj, s);
1844218460
return obj;
1844318461
fail:
1844418462
js_async_generator_free(ctx->rt, s);
@@ -39862,7 +39880,7 @@ static JSValue js_create_array_iterator(JSContext *ctx, JSValue this_val,
3986239880
it->obj = arr;
3986339881
it->kind = kind;
3986439882
it->idx = 0;
39865-
JS_SetOpaque(enum_obj, it);
39883+
JS_SetOpaqueInternal(enum_obj, it);
3986639884
return enum_obj;
3986739885
fail1:
3986839886
JS_FreeValue(ctx, enum_obj);
@@ -43862,7 +43880,7 @@ static JSValue js_regexp_Symbol_matchAll(JSContext *ctx, JSValue this_val,
4386243880
it->global = string_indexof_char(strp, 'g', 0) >= 0;
4386343881
it->unicode = string_indexof_char(strp, 'u', 0) >= 0;
4386443882
it->done = FALSE;
43865-
JS_SetOpaque(iter, it);
43883+
JS_SetOpaqueInternal(iter, it);
4386643884

4386743885
JS_FreeValue(ctx, C);
4386843886
JS_FreeValue(ctx, flags);
@@ -46112,7 +46130,7 @@ static JSValue js_proxy_constructor(JSContext *ctx, JSValue this_val,
4611246130
s->handler = js_dup(handler);
4611346131
s->is_func = JS_IsFunction(ctx, target);
4611446132
s->is_revoked = FALSE;
46115-
JS_SetOpaque(obj, s);
46133+
JS_SetOpaqueInternal(obj, s);
4611646134
JS_SetConstructorBit(ctx, obj, JS_IsConstructor(ctx, target));
4611746135
return obj;
4611846136
}
@@ -46345,7 +46363,7 @@ static JSValue js_map_constructor(JSContext *ctx, JSValue new_target,
4634546363
goto fail;
4634646364
init_list_head(&s->records);
4634746365
s->is_weak = is_weak;
46348-
JS_SetOpaque(obj, s);
46366+
JS_SetOpaqueInternal(obj, s);
4634946367
s->hash_size = 1;
4635046368
s->hash_table = js_malloc(ctx, sizeof(s->hash_table[0]) * s->hash_size);
4635146369
if (!s->hash_table)
@@ -46993,7 +47011,7 @@ static JSValue js_create_map_iterator(JSContext *ctx, JSValue this_val,
4699347011
it->obj = js_dup(this_val);
4699447012
it->kind = kind;
4699547013
it->cur_record = NULL;
46996-
JS_SetOpaque(enum_obj, it);
47014+
JS_SetOpaqueInternal(enum_obj, it);
4699747015
return enum_obj;
4699847016
fail:
4699947017
return JS_EXCEPTION;
@@ -48091,7 +48109,7 @@ static int js_create_resolving_functions(JSContext *ctx,
4809148109
sr->ref_count++;
4809248110
s->presolved = sr;
4809348111
s->promise = js_dup(promise);
48094-
JS_SetOpaque(obj, s);
48112+
JS_SetOpaqueInternal(obj, s);
4809548113
js_function_set_properties(ctx, obj, JS_ATOM_empty_string, 1);
4809648114
resolving_funcs[i] = obj;
4809748115
}
@@ -48236,7 +48254,7 @@ static JSValue js_promise_constructor(JSContext *ctx, JSValue new_target,
4823648254
for(i = 0; i < 2; i++)
4823748255
init_list_head(&s->promise_reactions[i]);
4823848256
s->promise_result = JS_UNDEFINED;
48239-
JS_SetOpaque(obj, s);
48257+
JS_SetOpaqueInternal(obj, s);
4824048258
if (js_create_resolving_functions(ctx, args, obj))
4824148259
goto fail;
4824248260
ret = JS_Call(ctx, executor, JS_UNDEFINED, 2, args);
@@ -48991,7 +49009,7 @@ static JSValue JS_CreateAsyncFromSyncIterator(JSContext *ctx,
4899149009
}
4899249010
s->sync_iter = js_dup(sync_iter);
4899349011
s->next_method = next_method;
48994-
JS_SetOpaque(async_iter, s);
49012+
JS_SetOpaqueInternal(async_iter, s);
4899549013
return async_iter;
4899649014
}
4899749015

@@ -51202,7 +51220,7 @@ static JSValue js_array_buffer_constructor3(JSContext *ctx,
5120251220
abuf->free_func = free_func;
5120351221
if (alloc_flag && buf)
5120451222
memcpy(abuf->data, buf, len);
51205-
JS_SetOpaque(obj, abuf);
51223+
JS_SetOpaqueInternal(obj, abuf);
5120651224
return obj;
5120751225
fail:
5120851226
JS_FreeValue(ctx, obj);
@@ -54771,7 +54789,7 @@ static JSValue js_weakref_constructor(JSContext *ctx, JSValue new_target, int ar
5477154789
wr->u.weak_ref_data = wrd;
5477254790
insert_weakref_record(arg, wr);
5477354791

54774-
JS_SetOpaque(obj, wrd);
54792+
JS_SetOpaqueInternal(obj, wrd);
5477554793
return obj;
5477654794
}
5477754795

@@ -54881,7 +54899,7 @@ static JSValue js_finrec_constructor(JSContext *ctx, JSValue new_target, int arg
5488154899
init_list_head(&frd->entries);
5488254900
frd->ctx = ctx;
5488354901
frd->cb = js_dup(cb);
54884-
JS_SetOpaque(obj, frd);
54902+
JS_SetOpaqueInternal(obj, frd);
5488554903
return obj;
5488654904
}
5488754905

@@ -55039,7 +55057,7 @@ static void reset_weak_ref(JSRuntime *rt, JSWeakRefRecord **first_weak_ref)
5503955057
break;
5504055058
case JS_WEAK_REF_KIND_WEAK_REF:
5504155059
wrd = wr->u.weak_ref_data;
55042-
JS_SetOpaque(wrd->obj, &js_weakref_sentinel);
55060+
JS_SetOpaqueInternal(wrd->obj, &js_weakref_sentinel);
5504355061
js_free_rt(rt, wrd);
5504455062
break;
5504555063
case JS_WEAK_REF_KIND_FINALIZATION_REGISTRY_ENTRY: {
@@ -55271,7 +55289,7 @@ static JSValue js_new_callsite(JSContext *ctx, JSCallSiteData *csd) {
5527155289

5527255290
memcpy(csd1, csd, sizeof(*csd));
5527355291

55274-
JS_SetOpaque(obj, csd1);
55292+
JS_SetOpaqueInternal(obj, csd1);
5527555293

5527655294
return obj;
5527755295
}

quickjs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -755,7 +755,7 @@ JS_EXTERN int JS_DefinePropertyValueStr(JSContext *ctx, JSValue this_obj,
755755
JS_EXTERN int JS_DefinePropertyGetSet(JSContext *ctx, JSValue this_obj,
756756
JSAtom prop, JSValue getter, JSValue setter,
757757
int flags);
758-
JS_EXTERN void JS_SetOpaque(JSValue obj, void *opaque);
758+
JS_EXTERN JS_BOOL JS_SetOpaque(JSValue obj, void *opaque);
759759
JS_EXTERN void *JS_GetOpaque(JSValue obj, JSClassID class_id);
760760
JS_EXTERN void *JS_GetOpaque2(JSContext *ctx, JSValue obj, JSClassID class_id);
761761
JS_EXTERN void *JS_GetAnyOpaque(JSValue obj, JSClassID *class_id);

0 commit comments

Comments
 (0)