Not just $SAFE, but damn $SAFE

The string:

str = "
s = 'blue eyes'
def s.class
  puts `ruby -v`
  String
end
s"

puts(safe_to_s(safe_eval(str)))

Outputs:

ruby 1.8.2 (2004-07-29) [i386-mswin32]
blue eyes
Made it!

···

-----Original Message-----
From: Aredridel [mailto:aredridel@nbtsc.org]
Sent: Thursday, 2 September 2004 4:48 PM
To: ruby-talk ML
Subject: Not just $SAFE, but damn $SAFE

I've been toying with an IRC bot that takes input from users in channel,
evals it, and returns the result.

Doing so safely has proved to be a challenge -- the biggest problem
being that you can't trust any method on the returned object.

Here's our solution, and I'd love to know if anyone can break it.

module Safe
  def class
    super
  end
end

def safe_to_s(obj)
  t = Thread.new {
    $SAFE = 4
    obj.to_s
  }
  o = t.value
  class << o
    include Safe
  end
  if String == o.class
    o
  else
    raise SecurityError
  end
end

def safe_eval(code)
  t = Thread.new {
     $SAFE = 4
     eval(code)
  }
  t.value
end

puts(safe_to_s(safe_eval("exit! # or variations")))

puts "Made it!"

Consider this a challenge. The ways I broke simpler variants was to try
to trick safe_to_s into calling methods outside of the safe Thread.

Ari

Augh. It worked in the testbed.

Try this variation:

def safe_to_s(obj)
  t = Thread.new {
    $SAFE = 4
    obj.to_s
  }
  o = t.value
  def o.class
    super
  end
  if String == o.class
    o
  else
    raise SecurityError
  end
end

Ari

···

On Thu, 2004-09-02 at 16:11 +0900, Mehr, Assaph (Assaph) wrote:

The string:

str = "
s = 'blue eyes'
def s.class
  puts `ruby -v`
  String
end
s"

puts(safe_to_s(safe_eval(str)))

Outputs:

ruby 1.8.2 (2004-07-29) [i386-mswin32]
blue eyes
Made it!

o = Object.new
def o.to_s
   Class.new(Class.new { def class; puts '5'; String; end }).new
end
o

I'd suggest using Object.instance_method(:class).bind(obj).call instead of your singleton class approach.

Regards,
Florian Gross