Making splat argument objects invisible from Ruby side - #6356
Merged
Conversation
The `mrb_get_argv()` function and the `*` specifier of `mrb_get_args()` get the address of the argument. At this time, if it is passed in the form of a splat argument, it will be an address to an element of an array object. After getting the pointer to the array object, the caller may call `mrb_vm_exec()` directly or indirectly. At this time, a splat argument with the class set can be retrieved as an array object by searching with `ObjectSpace.each_object`. If changes are made as array objects, addresses on the heap as arrays may become invalid, or objects in the array may be recycled by the GC. When the caller references the changed address in a subsequent operation, use-after-free is established. This patch assigns `NULL` as the class of the array object so that it cannot be detected by `ObjectSpace.each_object` from the Ruby side.
Contributor
Author
|
Use-after-free with the $wolf = Object.new
hh = Hash.new { |h, k|
ObjectSpace.each_object(Array) { |o|
if o[-1] == $wolf
o.clear
GC.start
end
}
}
hh.values_at(*%w(sheep1 sheep2 sheep3 sheep4 sheep5), $wolf)% valgrind -- build/host/bin/mruby uaf-splat1.rb
==93446== Memcheck, a memory error detector
==93446== Copyright (C) 2002-2024, and GNU GPL'd, by Julian Seward et al.
==93446== Using Valgrind-3.23.0 and LibVEX; rerun with -h for copyright info
==93446== Command: build/host/bin/mruby uaf-splat1.rb
==93446==
==93446== Invalid read of size 8
==93446== at 0x2D8614: hash_values_at (hash-ext.c:36)
==93446== by 0x2952EF: mrb_vm_exec (vm.c:0)
==93446== by 0x2BA223: mrb_load_exec (parse.y:6912)
==93446== by 0x2BA543: mrb_load_detect_file_cxt (parse.y:6955)
==93446== by 0x260A23: main (mruby.c:353)
==93446== Address 0x54e1d78 is 8 bytes inside a block of size 80 free'd
==93446== at 0x484F2EC: free (vg_replace_malloc.c:993)
==93446== by 0x283DD8: mrb_default_allocf (allocf.c:22)
==93446== by 0x264AF1: mrb_ary_clear (array.c:1265)
==93446== by 0x264AF1: mrb_ary_clear_m (array.c:1281)
==93446== by 0x2952EF: mrb_vm_exec (vm.c:0)
==93446== by 0x290D48: mrb_yield (vm.c:1086)
==93446== by 0x2D9958: os_each_object_cb (mruby_objectspace.c:149)
==93446== by 0x27126C: gc_each_objects (gc.c:1506)
==93446== by 0x27126C: mrb_objspace_each_objects (gc.c:1529)
==93446== by 0x2D9883: os_each_object (mruby_objectspace.c:173)
==93446== by 0x2952EF: mrb_vm_exec (vm.c:0)
==93446== by 0x28F546: mrb_run (vm.c:3058)
==93446== by 0x28F546: mrb_funcall_with_block (vm.c:750)
==93446== by 0x28EFD4: mrb_funcall_argv (vm.c:761)
==93446== by 0x28EFD4: mrb_funcall_id (vm.c:559)
==93446== by 0x2733F8: hash_default (hash.c:1162)
==93446== by 0x2733F8: mrb_hash_get (hash.c:1221)
==93446== Block was alloc'd at
==93446== at 0x4852321: realloc (vg_replace_malloc.c:1806)
==93446== by 0x2703A9: mrb_realloc_simple (gc.c:197)
==93446== by 0x2703A9: mrb_realloc (gc.c:211)
==93446== by 0x261437: ary_expand_capa (array.c:227)
==93446== by 0x261ADB: mrb_ary_push (array.c:551)
==93446== by 0x2A2D13: mrb_vm_exec (vm.c:2666)
==93446== by 0x2BA223: mrb_load_exec (parse.y:6912)
==93446== by 0x2BA543: mrb_load_detect_file_cxt (parse.y:6955)
==93446== by 0x260A23: main (mruby.c:353)
==93446==
==93446==
==93446== HEAP SUMMARY:
==93446== in use at exit: 0 bytes in 0 blocks
==93446== total heap usage: 802 allocs, 802 frees, 230,914 bytes allocated
==93446==
==93446== All heap blocks were freed -- no leaks are possible
==93446==
==93446== For lists of detected and suppressed errors, rerun with: -s
==93446== ERROR SUMMARY: 5 errors from 1 contexts (suppressed: 0 from 0)Similar results can be obtained with |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The
mrb_get_argv()function and the*specifier ofmrb_get_args()get the address of the argument. At this time, if it is passed in the form of a splat argument, it will be an address to an element of an array object.After getting the pointer to the array object, the caller may call
mrb_vm_exec()directly or indirectly. At this time, a splat argument with the class set can be retrieved as an array object by searching withObjectSpace.each_object. If changes are made as array objects, addresses on the heap as arrays may become invalid, or objects in the array may be recycled by the GC. When the caller references the changed address in a subsequent operation, use-after-free is established.This patch assigns
NULLas the class of the array object so that it cannot be detected byObjectSpace.each_objectfrom the Ruby side.