CVE-2024-29489: Insufficient Information (NVD-CWE-noinfo)
value: Jerryscript 2.4.0 has SEGV at ./jerry-core/ecma/base/ecma-helpers.c:238:58 in ecma_get_object_type.
CWE description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
Published: 2024-03-28T23:15Z
Repository: https://github.com/jerryscript-project/jerryscript
Language: C
Files changed: .github/workflows/gh-actions.yml, jerry-core/ecma/operations/ecma-function-object.c, jerry-core/ecma/operations/ecma-proxy-object.c, tests/jerry/regression-test-issue-5101.js
Commit date: 2024-03-13 12:08:41 +0100
Commit message: Fix rare crash caused by get method of proxy object (#5129)

This fixes #5101
In rare cases the proxy object could get used after
being incorrectly removed by the gc

Add stack checks to the start of all function calls

JerryScript-DCO-1.0-Signed-off-by: Máté Tokodi mate.tokodi@szteszoftver.hu
Diff: diff --git a/.github/workflows/gh-actions.yml b/.github/workflows/gh-actions.yml
index 41c45021f..f2db5d11c 100644
--- a/.github/workflows/gh-actions.yml
+++ b/.github/workflows/gh-actions.yml
@@ -169,11 +169,11 @@ jobs:
       - run: sudo apt update
       - run: sudo apt install gcc-multilib
       - run: >-
           $RUNNER -q --jerry-tests
           --buildoptions=--stack-limit=0,--compile-flag=-fsanitize=address,--compile-flag=-m32,--compile-flag=-fno-omit-frame-pointer,--compile-flag=-fno-common,--compile-flag=-O2,--debug,--system-allocator=on,--linker-flag=-fuse-ld=gold
-          --skip-list=parser-oom.js,parser-oom2.js,stack-limit.js,regression-test-issue-4901.js,regression-test-issue-4848.js,regression-test-issue-4890.js,regression-test-issue-2190.js,regression-test-issue-2258-2963.js,regression-test-issue-2448.js,regression-test-issue-2905.js,regression-test-issue-3785.js,proxy-evil-recursion.js
+          --skip-list=parser-oom.js,parser-oom2.js,stack-limit.js,regression-test-issue-4901.js,regression-test-issue-4848.js,regression-test-issue-4890.js,regression-test-issue-2190.js,regression-test-issue-2258-2963.js,regression-test-issue-2448.js,regression-test-issue-2905.js,regression-test-issue-3785.js,proxy-evil-recursion.js,regression-test-issue-5101.js
 
   ASAN_Tests_Debug:
     runs-on: ubuntu-latest
     env:
       ASAN_OPTIONS: detect_stack_use_after_return=1:check_initialization_order=true:strict_init_order=true
@@ -185,11 +185,11 @@ jobs:
       - run: sudo apt update
       - run: sudo apt install gcc-multilib
       - run: >-
           $RUNNER -q --jerry-tests --build-debug
           --buildoptions=--stack-limit=0,--compile-flag=-fsanitize=address,--compile-flag=-m32,--compile-flag=-fno-omit-frame-pointer,--compile-flag=-fno-common,--compile-flag=-O2,--debug,--system-allocator=on,--linker-flag=-fuse-ld=gold
-          --skip-list=parser-oom.js,parser-oom2.js,stack-limit.js,regression-test-issue-4901.js,regression-test-issue-4848.js,regression-test-issue-4890.js,regression-test-issue-2190.js,regression-test-issue-2258-2963.js,regression-test-issue-2448.js,regression-test-issue-2905.js,regression-test-issue-3785.js,proxy-evil-recursion.js
+          --skip-list=parser-oom.js,parser-oom2.js,stack-limit.js,regression-test-issue-4901.js,regression-test-issue-4848.js,regression-test-issue-4890.js,regression-test-issue-2190.js,regression-test-issue-2258-2963.js,regression-test-issue-2448.js,regression-test-issue-2905.js,regression-test-issue-3785.js,proxy-evil-recursion.js,regression-test-issue-5101.js
 
   UBSAN_Tests:
     runs-on: ubuntu-latest
     env:
       UBSAN_OPTIONS: print_stacktrace=1
diff --git a/jerry-core/ecma/operations/ecma-function-object.c b/jerry-core/ecma/operations/ecma-function-object.c
index 1e24384c9..2905d4abe 100644
--- a/jerry-core/ecma/operations/ecma-function-object.c
+++ b/jerry-core/ecma/operations/ecma-function-object.c
@@ -1008,10 +1008,12 @@ ecma_op_get_prototype_from_constructor (ecma_object_t *ctor_obj_p, /**< construc
 static ecma_value_t JERRY_ATTR_NOINLINE
 ecma_op_function_call_constructor (vm_frame_ctx_shared_args_t *shared_args_p, /**< shared data */
                                    ecma_object_t *scope_p, /**< lexical environment to use */
                                    ecma_value_t this_binding) /**< value of 'ThisBinding' */
 {
+  ECMA_CHECK_STACK_USAGE ();
+
   shared_args_p->header.status_flags |= VM_FRAME_CTX_SHARED_NON_ARROW_FUNC;
 
   ecma_value_t ret_value;
 
   if (JERRY_CONTEXT (current_new_target_p) == NULL)
@@ -1078,10 +1080,12 @@ ecma_op_function_call_simple (ecma_object_t *func_obj_p, /**< Function object */
                               const ecma_value_t *arguments_list_p, /**< arguments list */
                               uint32_t arguments_list_len) /**< length of arguments list */
 {
   JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_FUNCTION);
 
+  ECMA_CHECK_STACK_USAGE ();
+
   vm_frame_ctx_shared_args_t shared_args;
   shared_args.header.status_flags = VM_FRAME_CTX_SHARED_HAS_ARG_LIST;
   shared_args.header.function_object_p = func_obj_p;
   shared_args.arg_list_p = arguments_list_p;
   shared_args.arg_list_len = arguments_list_len;
@@ -1203,10 +1207,12 @@ ecma_op_function_call_native_built_in (ecma_object_t *func_obj_p, /**< Function
                                        const ecma_value_t *arguments_list_p, /**< arguments list */
                                        uint32_t arguments_list_len) /**< length of arguments list */
 {
   JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION);
 
+  ECMA_CHECK_STACK_USAGE ();
+
 #if JERRY_BUILTIN_REALMS
   ecma_global_object_t *saved_global_object_p = JERRY_CONTEXT (global_object_p);
 
   ecma_extended_object_t *ext_func_obj_p = (ecma_extended_object_t *) func_obj_p;
   JERRY_CONTEXT (global_object_p) =
@@ -1233,10 +1239,12 @@ ecma_op_function_call_native (ecma_object_t *func_obj_p, /**< Function object */
                               const ecma_value_t *arguments_list_p, /**< arguments list */
                               uint32_t arguments_list_len) /**< length of arguments list */
 {
   JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_NATIVE_FUNCTION);
 
+  ECMA_CHECK_STACK_USAGE ();
+
   ecma_native_function_t *native_function_p = (ecma_native_function_t *) func_obj_p;
 
 #if JERRY_BUILTIN_REALMS
   ecma_global_object_t *saved_global_object_p = JERRY_CONTEXT (global_object_p);
   JERRY_CONTEXT (global_object_p) =
diff --git a/jerry-core/ecma/operations/ecma-proxy-object.c b/jerry-core/ecma/operations/ecma-proxy-object.c
index 35ff2bf00..df864651d 100644
--- a/jerry-core/ecma/operations/ecma-proxy-object.c
+++ b/jerry-core/ecma/operations/ecma-proxy-object.c
@@ -1168,11 +1168,13 @@ ecma_proxy_object_get (ecma_object_t *obj_p, /**< proxy object */
   ecma_object_t *func_obj_p = ecma_get_object_from_value (trap);
   ecma_value_t prop_value = ecma_make_prop_name_value (prop_name_p);
   ecma_value_t args[] = { proxy_obj_p->target, prop_value, receiver };
 
   /* 9. */
+  ecma_ref_object (obj_p);
   ecma_value_t trap_result = ecma_op_function_call (func_obj_p, handler, args, 3);
+  ecma_deref_object (obj_p);
 
   ecma_deref_object (func_obj_p);
 
   /* 10. */
   if (ECMA_IS_VALUE_ERROR (trap_result) || (obj_p->u2.prototype_cp & JERRY_PROXY_SKIP_RESULT_VALIDATION))
diff --git a/tests/jerry/regression-test-issue-5101.js b/tests/jerry/regression-test-issue-5101.js
new file mode 100644
index 000000000..6ee4f30af
--- /dev/null
+++ b/tests/jerry/regression-test-issue-5101.js
@@ -0,0 +1,32 @@
+// 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.
+
+var iter = 100;
+async function f0() {
+    iter--;
+    function f6() {
+        return f0;
+    }
+    var proxy_handler = {
+        "get": f0,
+    };
+
+    f0.__proto__ = new Proxy(f6, proxy_handler);
+
+    if ((iter >= 0)) {
+        var v12 = f0();
+    }
+    return f0;
+}
+f0();

Vulnerable code:           --skip-list=parser-oom.js,parser-oom2.js,stack-limit.js,regression-test-issue-4901.js,regression-test-issue-4848.js,regression-test-issue-4890.js,regression-test-issue-2190.js,regression-test-issue-2258-2963.js,regression-test-issue-2448.js,regression-test-issue-2905.js,regression-test-issue-3785.js,proxy-evil-recursion.js
          --skip-list=parser-oom.js,parser-oom2.js,stack-limit.js,regression-test-issue-4901.js,regression-test-issue-4848.js,regression-test-issue-4890.js,regression-test-issue-2190.js,regression-test-issue-2258-2963.js,regression-test-issue-2448.js,regression-test-issue-2905.js,regression-test-issue-3785.js,proxy-evil-recursion.js
Fixed code:           --skip-list=parser-oom.js,parser-oom2.js,stack-limit.js,regression-test-issue-4901.js,regression-test-issue-4848.js,regression-test-issue-4890.js,regression-test-issue-2190.js,regression-test-issue-2258-2963.js,regression-test-issue-2448.js,regression-test-issue-2905.js,regression-test-issue-3785.js,proxy-evil-recursion.js,regression-test-issue-5101.js
          --skip-list=parser-oom.js,parser-oom2.js,stack-limit.js,regression-test-issue-4901.js,regression-test-issue-4848.js,regression-test-issue-4890.js,regression-test-issue-2190.js,regression-test-issue-2258-2963.js,regression-test-issue-2448.js,regression-test-issue-2905.js,regression-test-issue-3785.js,proxy-evil-recursion.js,regression-test-issue-5101.js
  ECMA_CHECK_STACK_USAGE ();

  ECMA_CHECK_STACK_USAGE ();

  ECMA_CHECK_STACK_USAGE ();

  ECMA_CHECK_STACK_USAGE ();

  ecma_ref_object (obj_p);
  ecma_deref_object (obj_p);
// 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.

var iter = 100;
async function f0() {
    iter--;
    function f6() {
        return f0;
    }
    var proxy_handler = {
        "get": f0,
    };

    f0.__proto__ = new Proxy(f6, proxy_handler);

    if ((iter >= 0)) {
        var v12 = f0();
    }
    return f0;
}
f0();