details: https://hg.nginx.org/njs/rev/06d4768b37d8 branches: changeset: 1708:06d4768b37d8 user: Dmitry Volyntsev <xei...@nginx.com> date: Wed Sep 29 13:45:26 2021 +0000 description: Fixed function constructor for cloned VMs.
Previously a shared "keywords_hash" and "values_hash" were used while compiling functions in runtime. This led to populating a shared hash with elements allocated in a cloned VM. Which resulted in heap-use-after-free when next cloned VM accesses the shared hashes. diffstat: src/njs_function.c | 4 +++- src/njs_generator.c | 24 ++++++++++++++---------- src/njs_lexer.c | 5 +++-- src/njs_lexer.h | 2 +- src/njs_module.c | 2 +- src/njs_vm.c | 6 ++++-- src/njs_vm.h | 1 + src/test/njs_unit_test.c | 11 +++++++++++ 8 files changed, 38 insertions(+), 17 deletions(-) diffs (200 lines): diff -r 6feba0e602ee -r 06d4768b37d8 src/njs_function.c --- a/src/njs_function.c Fri Sep 17 18:29:40 2021 +0000 +++ b/src/njs_function.c Wed Sep 29 13:45:26 2021 +0000 @@ -1156,7 +1156,8 @@ njs_function_constructor(njs_vm_t *vm, n file = njs_str_value("runtime"); - ret = njs_lexer_init(vm, &lexer, &file, str.start, str.start + str.length); + ret = njs_lexer_init(vm, &lexer, &file, str.start, str.start + str.length, + 1); if (njs_slow_path(ret != NJS_OK)) { return ret; } @@ -1206,6 +1207,7 @@ njs_function_constructor(njs_vm_t *vm, n } njs_memzero(&generator, sizeof(njs_generator_t)); + generator.runtime = 1; code = njs_generate_scope(vm, &generator, scope, &njs_entry_anonymous); if (njs_slow_path(code == NULL)) { diff -r 6feba0e602ee -r 06d4768b37d8 src/njs_generator.c --- a/src/njs_generator.c Fri Sep 17 18:29:40 2021 +0000 +++ b/src/njs_generator.c Wed Sep 29 13:45:26 2021 +0000 @@ -277,8 +277,8 @@ static njs_int_t njs_generate_inc_dec_op static njs_int_t njs_generate_function_declaration(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node); static njs_int_t njs_generate_function_scope(njs_vm_t *vm, - njs_function_lambda_t *lambda, njs_parser_node_t *node, - const njs_str_t *name, njs_uint_t depth); + njs_generator_t *generator, njs_function_lambda_t *lambda, + njs_parser_node_t *node, const njs_str_t *name); static njs_int_t njs_generate_scope_end(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node); static int64_t njs_generate_lambda_variables(njs_vm_t *vm, @@ -3056,8 +3056,8 @@ njs_generate_function_expression(njs_vm_ return NJS_ERROR; } - ret = njs_generate_function_scope(vm, lambda, node, &lex_entry->name, - generator->depth); + ret = njs_generate_function_scope(vm, generator, lambda, node, + &lex_entry->name); if (njs_slow_path(ret != NJS_OK)) { return ret; } @@ -3093,7 +3093,7 @@ njs_generate_function(njs_vm_t *vm, njs_ name = module ? &njs_entry_module : &njs_entry_anonymous; - ret = njs_generate_function_scope(vm, lambda, node, name, generator->depth); + ret = njs_generate_function_scope(vm, generator, lambda, node, name); if (njs_slow_path(ret != NJS_OK)) { return ret; } @@ -3594,8 +3594,8 @@ njs_generate_function_declaration(njs_vm return NJS_ERROR; } - ret = njs_generate_function_scope(vm, lambda, node, &lex_entry->name, - generator->depth); + ret = njs_generate_function_scope(vm, generator, lambda, node, + &lex_entry->name); if (njs_slow_path(ret != NJS_OK)) { return ret; } @@ -3617,23 +3617,27 @@ njs_generate_function_declaration(njs_vm static njs_int_t -njs_generate_function_scope(njs_vm_t *vm, njs_function_lambda_t *lambda, - njs_parser_node_t *node, const njs_str_t *name, njs_uint_t depth) +njs_generate_function_scope(njs_vm_t *vm, njs_generator_t *prev, + njs_function_lambda_t *lambda, njs_parser_node_t *node, + const njs_str_t *name) { njs_arr_t *arr; njs_bool_t module; + njs_uint_t depth; njs_vm_code_t *code; njs_generator_t generator; njs_parser_node_t *file_node; - njs_memzero(&generator, sizeof(njs_generator_t)); + depth = prev->depth; if (++depth >= NJS_FUNCTION_MAX_DEPTH) { njs_range_error(vm, "Maximum function nesting depth exceeded"); return NJS_ERROR; } + njs_memzero(&generator, sizeof(njs_generator_t)); generator.depth = depth; + generator.runtime = prev->runtime; node = node->right; diff -r 6feba0e602ee -r 06d4768b37d8 src/njs_lexer.c --- a/src/njs_lexer.c Fri Sep 17 18:29:40 2021 +0000 +++ b/src/njs_lexer.c Wed Sep 29 13:45:26 2021 +0000 @@ -290,7 +290,7 @@ static const njs_lexer_multi_t njs_assi njs_int_t njs_lexer_init(njs_vm_t *vm, njs_lexer_t *lexer, njs_str_t *file, - u_char *start, u_char *end) + u_char *start, u_char *end, njs_uint_t runtime) { njs_memzero(lexer, sizeof(njs_lexer_t)); @@ -298,7 +298,8 @@ njs_lexer_init(njs_vm_t *vm, njs_lexer_t lexer->start = start; lexer->end = end; lexer->line = 1; - lexer->keywords_hash = &vm->shared->keywords_hash; + lexer->keywords_hash = (runtime) ? &vm->keywords_hash + : &vm->shared->keywords_hash; lexer->mem_pool = vm->mem_pool; njs_queue_init(&lexer->preread); diff -r 6feba0e602ee -r 06d4768b37d8 src/njs_lexer.h --- a/src/njs_lexer.h Fri Sep 17 18:29:40 2021 +0000 +++ b/src/njs_lexer.h Wed Sep 29 13:45:26 2021 +0000 @@ -271,7 +271,7 @@ typedef struct { njs_int_t njs_lexer_init(njs_vm_t *vm, njs_lexer_t *lexer, njs_str_t *file, - u_char *start, u_char *end); + u_char *start, u_char *end, njs_uint_t runtime); njs_lexer_token_t *njs_lexer_token(njs_lexer_t *lexer, njs_bool_t with_end_line); diff -r 6feba0e602ee -r 06d4768b37d8 src/njs_module.c --- a/src/njs_module.c Fri Sep 17 18:29:40 2021 +0000 +++ b/src/njs_module.c Wed Sep 29 13:45:26 2021 +0000 @@ -185,7 +185,7 @@ njs_parser_module(njs_parser_t *parser, } ret = njs_lexer_init(parser->vm, &temp->lexer, &info.file, text.start, - text.start + text.length); + text.start + text.length, 0); if (njs_slow_path(ret != NJS_OK)) { return NJS_ERROR; } diff -r 6feba0e602ee -r 06d4768b37d8 src/njs_vm.c --- a/src/njs_vm.c Fri Sep 17 18:29:40 2021 +0000 +++ b/src/njs_vm.c Wed Sep 29 13:45:26 2021 +0000 @@ -138,7 +138,7 @@ njs_vm_compile(njs_vm_t *vm, u_char **st njs_module_reset(vm); } - ret = njs_lexer_init(vm, &lexer, &vm->options.file, *start, end); + ret = njs_lexer_init(vm, &lexer, &vm->options.file, *start, end, 0); if (njs_slow_path(ret != NJS_OK)) { return NJS_ERROR; } @@ -317,9 +317,11 @@ njs_vm_init(njs_vm_t *vm) return NJS_ERROR; } + njs_lvlhsh_init(&vm->values_hash); + njs_lvlhsh_init(&vm->keywords_hash); njs_lvlhsh_init(&vm->modules_hash); + njs_lvlhsh_init(&vm->events_hash); - njs_lvlhsh_init(&vm->events_hash); njs_queue_init(&vm->posted_events); njs_queue_init(&vm->promise_events); diff -r 6feba0e602ee -r 06d4768b37d8 src/njs_vm.h --- a/src/njs_vm.h Fri Sep 17 18:29:40 2021 +0000 +++ b/src/njs_vm.h Wed Sep 29 13:45:26 2021 +0000 @@ -147,6 +147,7 @@ struct njs_vm_s { njs_frame_t *active_frame; njs_rbtree_t *variables_hash; + njs_lvlhsh_t keywords_hash; njs_lvlhsh_t values_hash; njs_arr_t *modules; diff -r 6feba0e602ee -r 06d4768b37d8 src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Fri Sep 17 18:29:40 2021 +0000 +++ b/src/test/njs_unit_test.c Wed Sep 29 13:45:26 2021 +0000 @@ -21028,6 +21028,17 @@ static njs_unit_test_t njs_shared_test[ njs_str("TypeError: \"path\" must be a string or Buffer\n" " at fs.readFileSync (native)\n" " at main (:1)\n") }, + + { njs_str("var f = new Function('return 1;'); f();"), + njs_str("1") }, + + { njs_str("var sum = new Function('a', 'b', 'return a + b');" + "sum(2, 4);"), + njs_str("6") }, + + { njs_str("var sum = new Function('a, b', 'return a + b');" + "sum(2, 4);"), + njs_str("6") }, }; _______________________________________________ nginx-devel mailing list nginx-devel@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx-devel