|
GC.disable
|
|
|
|
# This class holds a reference to the duplicated sym proc
|
|
module Warden
|
|
class SessionSerializer
|
|
end
|
|
end
|
|
|
|
# This class duplicates the sym proc when defines a method
|
|
# the duplicated sym proc references the ep of the original sym proc
|
|
module Warden
|
|
class Manager
|
|
class << self
|
|
def serialize_into_session(scope = nil, &block)
|
|
puts 'lets define the method'
|
|
method_name = scope.nil? ? :serialize : "#{scope}_serialize"
|
|
Warden::SessionSerializer.send :define_method, method_name, &block
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
# our config file creates the original sym proc
|
|
# the original proc is a cfunc_proc_t which self-contains its block.env as part of the struct
|
|
Warden::Manager.serialize_into_session(&:to_h)
|
|
|
|
# at this point we have 2 different &:to_h procs
|
|
# both has the same block.ep pointer
|
|
# which points to the cfunc_proc_t struct of the original &:to_h
|
|
# proc_memsize(original_ptr) => 64
|
|
# proc_memsize(duplicated_ptr) => 40 (because it uses the ep of the original)
|
|
|
|
|
|
# we wont get rid of the original sym proc until the sym_proc_cache loses the reference
|
|
# to the original sym_proc
|
|
# To destroy the cache for &to_h I just need another sym proc with the same module
|
|
# (id % SYM_PROC_CACHE_SIZE) to have a cache collision
|
|
# since I don't want to calculate that magic number, let's convert to proc all our symbols!
|
|
p "let's fill the sym proc cache!"
|
|
Symbol.all_symbols.each(&:to_proc)
|
|
|
|
# this will start the GC. destroying our original reference.
|
|
p 'destroy the original reference to the &to_h proc'
|
|
GC.start
|
|
GC.enable
|
|
|
|
# now we only keep the duplicated sym_proc which references a ep which is not in use.
|
|
p 'fill the heap with garbage'
|
|
require 'rails'
|
|
# with little luck, the block->ep[1] will have a number that is not 0 nor a valid VALUE
|
|
# KABOOM!!
|
|
|