Project

General

Profile

Actions

Bug #20427

closed

Backport: Heap buffer overflow in `Array#sort!` when block modifies target array

Added by zack.ref@gmail.com (Zack Deveau) 7 months ago. Updated 5 months ago.

Status:
Closed
Assignee:
-
Target version:
-
ruby -v:
ruby 3.3.0 (2024-01-05 revision 634d4e29ef) [x86_64-darwin22]
[ruby-core:117510]

Description

(note: It was decided we should handle this in the public issue tracker in security ticket #2327648)

The attached patch has been applied to master and should apply to latest 3.3.0 for backport.

Could not reproduce on the following builds:

  • ruby 3.2.3 (2024-01-18 revision 52bb2ac0a6) [x86_64-linux]
  • ruby 3.1.4p249 (2024-01-11 revision 2b608349bb) [x86_64-linux]

In cases where rb_ary_sort_bang is called with a block and tmp is an embedded array, we need to account for the block potentially impacting the capacity of ary.

Reproduction script for x86 targets:

var_0 = (1..70).to_a
var_0.sort! do |var_0_block_129, var_1_block_129|
  var_0.pop
  var_1_block_129 <=> var_0_block_129
end.shift(3)

Reproduction script for ARM targets:

10.times do
  var_0 = (1..70).to_a
  var_0.sort! do |var_0_block_129, var_1_block_129|
    var_0.pop
    var_1_block_129 <=> var_0_block_129
  end.shift(3)
end

The above example can put the array into a corrupted state (ary after block has len=0 and capa=14) :

================== ary ===================
ary: BD99908
is_embedded?: 0
is_shared?: 0
heap.len: 0
heap.capa: 14
heap.shared_root: 14
================== tmp ===================
ary: BD1EB18
is_embedded?: 1
is_shared?: 0
embed_len: 70
embed_capa: 78
heap.len: 141
heap.capa: 139
heap.shared_root: 139

This results in a heap buffer overflow and possible segfault:

==19964==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60b0000034f0 at pc 0x00010c35ee6c bp 0x0003070fb290 sp 0x0003070faa50
WRITE of size 560 at 0x60b0000034f0 thread T0
    #0 0x10c35ee6b in wrap_memcpy+0x2ab (libclang_rt.asan_osx_dynamic.dylib:x86_64+0x18e6b)
    #1 0x100e0b085 in ruby_nonempty_memcpy memory.h:671
    #2 0x100e0e43e in ary_memcpy0 array.c:335
    #3 0x100e0cb00 in ary_memcpy array.c:352
    #4 0x100e1426c in rb_ary_sort_bang array.c:3519
    [ ... ]

Was able to reproduce on the following builds:

  • ruby 3.4.0dev (2024-01-17T14:48:46Z ef4a08eb65) [x86_64-linux]
  • ruby 3.3.0 (2024-01-05 revision 634d4e29ef) [x86_64-darwin23]
  • ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [arm64-darwin23]

This patch adds a conditional to determine when the capacity of ary has been modified by the provided block. If this is the case, ensure that the capacity of ary is adjusted to handle at minimum the len of tmp.

test-all passes locally:

Finished tests in 70.194526s, 369.6727 tests/s, 89373.2939 assertions/s.
25949 tests, 6273516 assertions, 0 failures, 0 errors, 292 skips

Files

rb_ary_sort_bang_heap_overflow.patch (2.06 KB) rb_ary_sort_bang_heap_overflow.patch patch zack.ref@gmail.com (Zack Deveau), 04/14/2024 12:43 AM
Actions #1

Updated by zack.ref@gmail.com (Zack Deveau) 7 months ago

  • ruby -v set to ruby 3.3.0 (2024-01-05 revision 634d4e29ef) [x86_64-darwin22]
Actions #2

Updated by zack.ref@gmail.com (Zack Deveau) 7 months ago

  • Subject changed from Heap buffer overflow in `Array#sort!` when block modifies target array to Backport: Heap buffer overflow in `Array#sort!` when block modifies target array

Updated by nobu (Nobuyoshi Nakada) 7 months ago

  • Status changed from Open to Closed
  • Backport changed from 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN to 3.0: DONTNEED, 3.1: DONTNEED, 3.2: DONTNEED, 3.3: REQUIRED

Updated by k0kubun (Takashi Kokubun) 5 months ago

  • Backport changed from 3.0: DONTNEED, 3.1: DONTNEED, 3.2: DONTNEED, 3.3: REQUIRED to 3.0: DONTNEED, 3.1: DONTNEED, 3.2: DONTNEED, 3.3: DONE
Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0