Skip to content
  • dearblue's avatar
    be9431a9
    Fix use-after-free by `mrb_gc_unregistor()` · be9431a9
    dearblue authored
    Calling `mrb_gc_unregistor()` from `mrb_data_type::dfree` caused a use-after-free deep inside `mrb_close()`.
    The impetus to investigate was <https://github.com/mruby/mruby/pull/6342#pullrequestreview-2292747530>.
    
    Currently, when `mrb_close()` is called, all objects are destroyed first.
    The process is done heap page by heap page, and when all objects belonging to a heap page are destroyed, the heap page is released.
    If the next heap page contains `RData` objects, the `mrb_gc_unregistor()` function may be called from the `mrb_data_type::dfree` function.
    At this time, the `mrb_gc_unregistor()` function gets an array object from a Ruby global variable.
    If the array object belongs to a freed heap page, use-after-free is established by referencing this array object.
    
    About the fixes.
    
    First of all, there is the fact that the `mrb_gv_get()` function returns `nil` if `mrb->globals` is `NULL`.
    Therefore, before destroying all objects, free `mrb->globals` and set `mrb->globals` to `NULL` at the same time.
    Now the `mrb_gv_get()` function will return `nil` to the calling `mrb_gc_unregistor()` function and `mrb_gc_unregistor()` will do nothing more.
    
    ref. https://github.com/mruby/mruby/issues/4618
    be9431a9
    Fix use-after-free by `mrb_gc_unregistor()`
    dearblue authored
    Calling `mrb_gc_unregistor()` from `mrb_data_type::dfree` caused a use-after-free deep inside `mrb_close()`.
    The impetus to investigate was <https://github.com/mruby/mruby/pull/6342#pullrequestreview-2292747530>.
    
    Currently, when `mrb_close()` is called, all objects are destroyed first.
    The process is done heap page by heap page, and when all objects belonging to a heap page are destroyed, the heap page is released.
    If the next heap page contains `RData` objects, the `mrb_gc_unregistor()` function may be called from the `mrb_data_type::dfree` function.
    At this time, the `mrb_gc_unregistor()` function gets an array object from a Ruby global variable.
    If the array object belongs to a freed heap page, use-after-free is established by referencing this array object.
    
    About the fixes.
    
    First of all, there is the fact that the `mrb_gv_get()` function returns `nil` if `mrb->globals` is `NULL`.
    Therefore, before destroying all objects, free `mrb->globals` and set `mrb->globals` to `NULL` at the same time.
    Now the `mrb_gv_get()` function will return `nil` to the calling `mrb_gc_unregistor()` function and `mrb_gc_unregistor()` will do nothing more.
    
    ref. https://github.com/mruby/mruby/issues/4618
Loading