Skip to content

Do not trust argument_end to select the shared frame layout (#5302) - #5310

Open
1820893135-pixel wants to merge 1 commit into
jerryscript-project:masterfrom
1820893135-pixel:fix-vm-init-arg-list
Open

1820893135-pixel wants to merge 1 commit into
jerryscript-project:masterfrom
1820893135-pixel:fix-vm-init-arg-list

Conversation

@1820893135-pixel

Copy link
Copy Markdown

vm_init_exec() decides whether shared_p carries an argument list by looking
at argument_end, a field taken from the bytecode header, and then casts
shared_p to vm_frame_ctx_shared_args_t (vm.c:5190):

if (argument_end > 0)
{
  JERRY_ASSERT (shared_p->status_flags & VM_FRAME_CTX_SHARED_HAS_ARG_LIST);

  const ecma_value_t *arg_list_p = ((vm_frame_ctx_shared_args_t *) shared_p)->arg_list_p;
  arg_list_len = ((vm_frame_ctx_shared_args_t *) shared_p)->arg_list_len;

The assert is compiled out with NDEBUG, and vm_run_global() only ever passes
a plain vm_frame_ctx_shared_t (24 bytes), so a snapshot whose bytecode declares
arguments makes this read go past the struct:

==ERROR: AddressSanitizer: stack-buffer-overflow
READ of size 8
    #0 vm_init_exec     vm.c:5190
    #1 vm_run           vm.c:5330
    #2 vm_run_global    vm.c:286
    #3 jerry_exec_snapshot jerry-snapshot.c:1024
  This frame has 1 object(s):
    [32, 56) 'shared' (line 272) <== Memory access at offset 56 overflows

A 122-byte malformed snapshot is enough to trigger it. The read lands 8 bytes
past a stack object that also holds the frame's saved pointers, so the adjacent
arg_list_len load is the same defect.

Fix

The layout is described by VM_FRAME_CTX_SHARED_HAS_ARG_LIST, which is set by
the callers that actually build the args variant
(ecma-function-object.c:1088), so test that flag rather than the untrusted
argument_end:

if (argument_end > 0 && (shared_p->status_flags & VM_FRAME_CTX_SHARED_HAS_ARG_LIST))

A snapshot that cannot provide an argument list now leaves the registers
undefined, exactly as it does when argument_end is zero.

Fixes #5302.

vm_init_exec() decided whether shared_p carries an argument list by
looking at argument_end, a field taken from the bytecode header, and then
cast shared_p to vm_frame_ctx_shared_args_t:

    if (argument_end > 0)
    {
      JERRY_ASSERT (shared_p->status_flags & VM_FRAME_CTX_SHARED_HAS_ARG_LIST);
      const ecma_value_t *arg_list_p = ((vm_frame_ctx_shared_args_t *) shared_p)->arg_list_p;
      arg_list_len = ((vm_frame_ctx_shared_args_t *) shared_p)->arg_list_len;

The assert is compiled out with NDEBUG, and vm_run_global() only ever
passes a plain vm_frame_ctx_shared_t, so a snapshot whose bytecode
declares arguments makes this read go past the 24-byte shared struct:

    ==ERROR: AddressSanitizer: stack-buffer-overflow
    READ of size 8
        #0 vm_init_exec vm.c:5190
        jerryscript-project#1 vm_run vm.c:5330
        jerryscript-project#2 vm_run_global vm.c:286
        jerryscript-project#3 jerry_exec_snapshot jerry-snapshot.c:1024
      [32, 56) 'shared' (line 272) <== Memory access at offset 56 overflows

The layout is described by VM_FRAME_CTX_SHARED_HAS_ARG_LIST, which is set
by the callers that actually build the args variant, so test that flag
instead of argument_end.  A snapshot that cannot provide an argument list
now leaves the registers undefined, exactly as it does when argument_end
is zero.

JerryScript-DCO-1.0-Signed-off-by: 1820893135-pixel <1820893135@qq.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]Malformed snapshot bytecode drives VM-init stack-buffer-overflow (vm_init_exec, vm.c:5190) (CWE-125)

1 participant