Bug #21977
closedRuby::Box crash with `RUBY_BOX=1` via `Binding` refinement, `UnboundMethod#bind_call`, and `Symbol#to_proc`
Description
Summary¶
I found a reproducible interpreter crash when Ruby is run with RUBY_BOX=1.
A refinement on Binding, combined with UnboundMethod#bind_call and Symbol#to_proc, causes Ruby to abort with:
I reproduced this on:
Follow-up validation confirmed an important discriminator: replacing map(&:to_s) with an explicit block such as map { _1.to_s } avoids the crash. The currently available evidence therefore points to a box/frame bookkeeping bug in the Symbol#to_proc path that reaches an explicit internal rb_bug(...) assertion, not to confirmed memory corruption.
PoC¶
using Module.new {
refine ::Binding do
def eval_methods
::Kernel.instance_method(:methods).bind_call(receiver)
end
end
}
p binding.eval_methods.map(&:to_s)
Run:
RUBY_BOX=1 ./miniruby -e '
using Module.new {
refine ::Binding do
def eval_methods
::Kernel.instance_method(:methods).bind_call(receiver)
end
end
}
p binding.eval_methods.map(&:to_s)
'
Observed result:
[BUG] BUG: Local ep without cme/box, flags: 66660087
ruby 4.1.0dev (2026-03-24T21:47:14Z master 30dcc2a082) +PRISM [x86_64-linux]
Crashed while printing bug report
Important discriminator:
Replacing map(&:to_s) with an explicit block avoids the crash, which strongly suggests that the failure depends specifically on the Symbol#to_proc path rather than map in general.
Impact¶
The currently confirmed impact is denial of service in processes using Ruby::Box with RUBY_BOX=1.
Confirmed claim:
- reliable interpreter abort
- trigger requires
RUBY_BOX=1 - trigger depends specifically on the
Symbol#to_procpath in this setup
Current non-claims:
- no confirmed memory corruption
- no confirmed sandbox escape
- no confirmed privilege escalation
- no confirmed arbitrary code execution
This report should remain separate from the Ruby::Box double-free issue, because the trigger path, failure mode, and currently demonstrated impact are different.
Updated by mame (Yusuke Endoh) 5 months ago
- Status changed from Open to Assigned
- Assignee set to tagomoris (Satoshi Tagomori)
Updated by hsbt (Hiroshi SHIBATA) 7 days ago
- Related to Misc #22275: Ruby::Box support plan for RubyGems and Bundler added
Updated by niku (niku _) about 15 hours ago
- Status changed from Assigned to Closed
Applied in changeset git|1fe4fcf1852fe9887f2903e800d026b3a952b5c0.
Fix Box resolution crash with IFUNC frames
[Bug #21977]
When RUBY_BOX=1 is set, combining binding with Symbol#to_proc causes a crash ([BUG] BUG: Local ep without cme/box).
This occurs because escaping an IFUNC frame via binding adds the VM_ENV_FLAG_LOCAL flag. VM_EP_RUBY_LEP previously relied on VM_EP_LEP, which blindly stopped at this flag. This caused it to return the IFUNC itself instead of its caller, and since IFUNC lacks cme/box data, the Box resolution crashed.
This commit fixes the issue by traversing current_cfp backwards to skip IFUNC frames directly, instead of relying on VM_EP_LEP and the local flag.