From 36051ec92bb2e0ec2f455fba9290b79e60902e07 Mon Sep 17 00:00:00 2001 From: Zoltan Herczeg Date: Thu, 1 Feb 2018 15:09:53 +0100 Subject: [PATCH] Limit maximum number of arguments for apply(). (#2183) The length*sizeof(ecma_value_t) may overflow on 32 bit systems which cause a memory corruption when the values are filled. Fixes #2182. JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com --- .../ecma-builtin-function-prototype.c | 76 +++++++++++-------- tests/jerry/regression-test-issue-2182.js | 28 +++++++ 2 files changed, 72 insertions(+), 32 deletions(-) create mode 100644 tests/jerry/regression-test-issue-2182.js diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-function-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-function-prototype.c index 0f78cc68d..9603f358d 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-function-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-function-prototype.c @@ -43,6 +43,11 @@ * @{ */ +/** + * Maximum number of arguments for an apply function. + */ +#define ECMA_FUNCTION_APPLY_ARGUMENT_COUNT_LIMIT 65535 + /** * The Function.prototype object's 'toString' routine * @@ -122,43 +127,50 @@ ecma_builtin_function_prototype_object_apply (ecma_value_t this_arg, /**< this a /* 5. */ const uint32_t length = ecma_number_to_uint32 (length_number); - /* 6. */ - JMEM_DEFINE_LOCAL_ARRAY (arguments_list_p, length, ecma_value_t); - uint32_t last_index = 0; - - /* 7. */ - for (uint32_t index = 0; - index < length && ecma_is_value_empty (ret_value); - index++) + if (length >= ECMA_FUNCTION_APPLY_ARGUMENT_COUNT_LIMIT) { - ecma_string_t *curr_idx_str_p = ecma_new_ecma_string_from_uint32 (index); - - ECMA_TRY_CATCH (get_value, - ecma_op_object_get (obj_p, curr_idx_str_p), - ret_value); - - arguments_list_p[index] = ecma_copy_value (get_value); - last_index = index + 1; - - ECMA_FINALIZE (get_value); - ecma_deref_ecma_string (curr_idx_str_p); + ret_value = ecma_raise_range_error (ECMA_ERR_MSG ("Too many arguments declared for Function.apply().")); } - - if (ecma_is_value_empty (ret_value)) + else { - JERRY_ASSERT (last_index == length); - ret_value = ecma_op_function_call (func_obj_p, - arg1, - arguments_list_p, - length); - } + /* 6. */ + JMEM_DEFINE_LOCAL_ARRAY (arguments_list_p, length, ecma_value_t); + uint32_t last_index = 0; - for (uint32_t index = 0; index < last_index; index++) - { - ecma_free_value (arguments_list_p[index]); - } + /* 7. */ + for (uint32_t index = 0; + index < length && ecma_is_value_empty (ret_value); + index++) + { + ecma_string_t *curr_idx_str_p = ecma_new_ecma_string_from_uint32 (index); - JMEM_FINALIZE_LOCAL_ARRAY (arguments_list_p); + ECMA_TRY_CATCH (get_value, + ecma_op_object_get (obj_p, curr_idx_str_p), + ret_value); + + arguments_list_p[index] = ecma_copy_value (get_value); + last_index = index + 1; + + ECMA_FINALIZE (get_value); + ecma_deref_ecma_string (curr_idx_str_p); + } + + if (ecma_is_value_empty (ret_value)) + { + JERRY_ASSERT (last_index == length); + ret_value = ecma_op_function_call (func_obj_p, + arg1, + arguments_list_p, + length); + } + + for (uint32_t index = 0; index < last_index; index++) + { + ecma_free_value (arguments_list_p[index]); + } + + JMEM_FINALIZE_LOCAL_ARRAY (arguments_list_p); + } ECMA_OP_TO_NUMBER_FINALIZE (length_number); ECMA_FINALIZE (length_value); diff --git a/tests/jerry/regression-test-issue-2182.js b/tests/jerry/regression-test-issue-2182.js new file mode 100644 index 000000000..96e11ed31 --- /dev/null +++ b/tests/jerry/regression-test-issue-2182.js @@ -0,0 +1,28 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function test(len) +{ + function applyTest() { } + try { + applyTest.apply(null, { length : len }); + assert(false); + } catch (e) { + assert(e instanceof RangeError); + } +} + +test(65536); +test(0x40000001); +test(0xffffffff);