Project

General

Profile

Actions

Bug #20932

closed

Socket fast_fallback segfaults when fds are > FD_SETSIZE

Added by jhawthorn (John Hawthorn) 16 days ago. Updated 10 days ago.

Status:
Closed
Target version:
ruby -v:
ruby 3.4.0dev (2024-12-04T21:46:02Z master bf225feb26) +PRISM [x86_64-linux]
[ruby-core:120114]

Description

When Socket.tcp_fast_fallback = true and a socket ends up with an FD over FD_SETSIZE (typically 1024), it results in a buffer overflow and crashes when running FD_SET before select.

It may be necessary to update ulimits to be above 1024 before reproducing (ulimit -n 2048)

require "socket"

open_fds = []
loop do
  file = open(__FILE__)
  open_fds << file
  break if file.fileno >= 1010
end

#Socket.tcp_fast_fallback=false

TCPServer.open("localhost", 0) do |server|
  port = server.addr[1]
  sockets = []
  50.times do |i|
    socket = TCPSocket.open("localhost", port)
    p socket
    sockets << socket
  end
end
$ ulimit -n 2048
$ ruby test.rb
#<TCPSocket:fd 1015, AF_INET6, ::1, 40622>
#<TCPSocket:fd 1014, AF_INET6, ::1, 40628>
#<TCPSocket:fd 1016, AF_INET6, ::1, 40630>
#<TCPSocket:fd 1017, AF_INET6, ::1, 40632>
#<TCPSocket:fd 1018, AF_INET6, ::1, 40644>
#<TCPSocket:fd 1020, AF_INET6, ::1, 40658>
#<TCPSocket:fd 1021, AF_INET6, ::1, 40668>
#<TCPSocket:fd 1019, AF_INET6, ::1, 40674>
#<TCPSocket:fd 1022, AF_INET6, ::1, 40678>
#<TCPSocket:fd 1023, AF_INET6, ::1, 40694>
=================================================================
==3180778==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ae35aadc580 at pc 0x7ae35b1b7449 bp 0x7fffc9af1af0 sp 0x7fffc9af1ae8
READ of size 8 at 0x7ae35aadc580 thread T0
    #0 0x7ae35b1b7448 in init_fast_fallback_inetsock_internal /home/jhawthorn/src/ruby/ext/socket/ipsocket.c:912:17
    #1 0x60462ff14879 in rb_ensure /home/jhawthorn/src/ruby/eval.c:1053:18
    #2 0x7ae35b1b41b9 in rsock_init_inetsock /home/jhawthorn/src/ruby/ext/socket/ipsocket.c:1315:20
    #3 0x7ae35b1bae9a in tcp_init /home/jhawthorn/src/ruby/ext/socket/tcpsocket.c:91:12
    #4 0x604630178944 in vm_call0_cfunc_with_frame /home/jhawthorn/src/ruby/./vm_eval.c:164:15
    #5 0x604630176ade in vm_call0_body /home/jhawthorn/src/ruby/./vm_eval.c:229:15
    #6 0x604630146e46 in vm_call0_cc /home/jhawthorn/src/ruby/./vm_eval.c:101:12
    #7 0x604630178ffd in rb_call0 /home/jhawthorn/src/ruby/./vm_eval.c:554:12
    #8 0x604630147e3a in rb_call /home/jhawthorn/src/ruby/./vm_eval.c:873:12
    #9 0x60462ffe15cd in rb_class_new_instance_kw /home/jhawthorn/src/ruby/object.c:2187:5
    #10 0x60462ff6c39c in rb_io_s_open /home/jhawthorn/src/ruby/io.c:8126:16
    #11 0x604630166e9c in vm_call_cfunc_with_frame_ /home/jhawthorn/src/ruby/./vm_insnhelper.c:3801:11
    #12 0x604630134dad in vm_sendish /home/jhawthorn/src/ruby/./vm_insnhelper.c
    #13 0x60463013c68b in vm_exec_core /home/jhawthorn/src/ruby/insns.def:898:11
    #14 0x604630135327 in rb_vm_exec /home/jhawthorn/src/ruby/vm.c:2585:22
    #15 0x60463017ba7c in invoke_iseq_block_from_c /home/jhawthorn/src/ruby/vm.c:1615:12
    #16 0x60463017ba7c in invoke_block_from_c_bh /home/jhawthorn/src/ruby/vm.c:1629:20
    #17 0x60463014b477 in vm_yield_with_cref /home/jhawthorn/src/ruby/vm.c:1666:12
    #18 0x604630148937 in rb_yield /home/jhawthorn/src/ruby/./vm_eval.c
    #19 0x60462ff14879 in rb_ensure /home/jhawthorn/src/ruby/eval.c:1053:18
    #20 0x604630166e9c in vm_call_cfunc_with_frame_ /home/jhawthorn/src/ruby/./vm_insnhelper.c:3801:11
    #21 0x604630159de6 in vm_call_method_each_type /home/jhawthorn/src/ruby/./vm_insnhelper.c:4779:16
    #22 0x604630159afe in vm_call_method /home/jhawthorn/src/ruby/./vm_insnhelper.c
    #23 0x604630134dad in vm_sendish /home/jhawthorn/src/ruby/./vm_insnhelper.c
    #24 0x60463013ba52 in vm_exec_core /home/jhawthorn/src/ruby/insns.def:851:11
    #25 0x60463015113b in vm_exec_loop /home/jhawthorn/src/ruby/vm.c:2612:22
    #26 0x60463013533a in rb_vm_exec /home/jhawthorn/src/ruby/vm.c
    #27 0x60462ff12f0c in rb_ec_exec_node /home/jhawthorn/src/ruby/eval.c:281:9
    #28 0x60462ff12d12 in ruby_run_node /home/jhawthorn/src/ruby/eval.c:319:30
    #29 0x60462ff0ed73 in rb_main /home/jhawthorn/src/ruby/./main.c:43:12
    #30 0x60462ff0ec47 in main /home/jhawthorn/src/ruby/./main.c:68:12
    #31 0x7ae35c5e7e07 in __libc_start_call_main /usr/src/debug/glibc/glibc/csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #32 0x7ae35c5e7ecb in __libc_start_main /usr/src/debug/glibc/glibc/csu/../csu/libc-start.c:360:3
    #33 0x60462fe2f334 in _start (/home/jhawthorn/.rubies/ruby-asan/bin/ruby+0x174334)

Address 0x7ae35aadc580 is located in stack of thread T0 at offset 384 in frame
    #0 0x7ae35b1b44df in init_fast_fallback_inetsock_internal /home/jhawthorn/src/ruby/ext/socket/ipsocket.c:537

  This frame has 14 object(s):
    [32, 36) 'status' (line 544)
    [48, 50) 'resolved_type' (line 555)
    [64, 72) 'pipefd' (line 558)
    [96, 224) 'readfds' (line 559)
    [256, 384) 'writefds' (line 559) <== Memory access at offset 384 overflows this variable
    [416, 456) 'wait_arg' (line 561)
    [496, 512) 'delay' (line 563)
    [528, 568) 'resolution_store' (line 567)
    [608, 624) 'resolution_delay_storage' (line 604)
    [640, 656) 'connection_attempt_delay_strage' (line 606)
    [672, 688) 'user_specified_resolv_timeout_storage' (line 608)
    [704, 720) 'user_specified_connect_timeout_storage' (line 610)
    [736, 740) 'err' (line 953)
    [752, 756) 'len' (line 954)
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow /home/jhawthorn/src/ruby/ext/socket/ipsocket.c:912:17 in init_fast_fallback_inetsock_internal
Shadow bytes around the buggy address:
  0x7ae35aadc300: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x7ae35aadc380: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x7ae35aadc400: f1 f1 f1 f1 04 f2 02 f2 00 f2 f2 f2 00 00 00 00
  0x7ae35aadc480: 00 00 00 00 00 00 00 00 00 00 00 00 f2 f2 f2 f2
  0x7ae35aadc500: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x7ae35aadc580:[f2]f2 f2 f2 00 00 00 00 00 f2 f2 f2 f2 f2 00 00
  0x7ae35aadc600: f2 f2 00 00 00 00 00 f2 f2 f2 f2 f2 00 00 f2 f2
  0x7ae35aadc680: 00 00 f2 f2 00 00 f2 f2 00 00 f2 f2 f8 f2 f8 f3
  0x7ae35aadc700: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7ae35aadc780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7ae35aadc800: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==3180778==ABORTING
Actions

Also available in: Atom PDF

Like0
Like0Like1Like0