$safe = 3.5?

Is there anyway to have the same restriction that $SAFE=4 would give
except the right to write to already opened IO?

More generally, would it make sense to have a more flexible way to
cherry pick what limitation to impose on a thread? Like:

Thread.new(:safe_no_eval => true) { eval(rm -rf /) } # => error

Is it usefull enough to justify the implementation time investment?
Would it have an unbearable performance hit?

Guillaume.

Would’nt make sense to remove $SAFE and introduce a SAFE module ?
This module could contain a getter/setter couple for every restriction
allowed by safe levels plus a convenient Safe.level=(anInteger)

···

il Tue, 4 May 2004 04:14:06 +0900, Guillaume Marcais guslist@free.fr ha scritto::

Is there anyway to have the same restriction that $SAFE=4 would give
except the right to write to already opened IO?

More generally, would it make sense to have a more flexible way to
cherry pick what limitation to impose on a thread? Like:

Is there anyway to have the same restriction that $SAFE=4 would give
except the right to write to already opened IO?

Use 2 threads :

   * one which open the file and write in
   * other which run with $SAFE = 4

communication between the 2 threads is made via a queue

Guy Decoux

That’s an interesting idea… perhaps even:

Safe.level(2) do
# unsafe code here
end

or

Safe.flags(:no_filesystem, :no_redefine_core) do
load “untrusted_code.rb”
end

I always thought that $SAFE was rather perlish, and hoped that it could
eventually be gotten rid of. I think a Safe module would be a great way
to get rid of the $SAFE global entirely (eventually).

cheers,
–Mark

···

On May 3, 2004, at 1:08 PM, gabriele renzi wrote:

il Tue, 4 May 2004 04:14:06 +0900, Guillaume Marcais guslist@free.fr > ha scritto::

Is there anyway to have the same restriction that $SAFE=4 would give
except the right to write to already opened IO?

More generally, would it make sense to have a more flexible way to
cherry pick what limitation to impose on a thread? Like:

Would’nt make sense to remove $SAFE and introduce a SAFE module ?
This module could contain a getter/setter couple for every restriction
allowed by safe levels plus a convenient Safe.level=(anInteger)

Mark Hubbart wrote:

Safe.level(2) do
# unsafe code here
end

class Safe
def level(lvl)
th = Thread.new do
$SAFE = lvl.to_i
yield
end
th.join
end
end

Does exactly what you’d expect.

Also, for the original poster’s question: one way around the problem is
to use a setup like the one above, and have the SAFE thread pass the
content to be written out to another, non-SAFE thread which can sanity
check it and then write it to the IO.

If you’re still confused I could dig up some code where I did some
playing around with something like this once.

Tim.

···


Tim Bates
tim@bates.id.au

Hi,

···

From: Tim Bates tim@bates.id.au
Subject: Re: $SAFE = 3.5?
Date: Tue, 4 May 2004 07:58:42 +0900
Message-ID: 4096CE96.7000702@bates.id.au

class Safe
def level(lvl)
th = Thread.new do
$SAFE = lvl.to_i
yield
end
th.join
end
end

A proc object can be used as a safe-level wrapper.
Please try the following script.

###################

sample part 1

###################
class Safe
def self.level(lvl)
proc{$SAFE=lvl.to_i; yield}.call
end
end

p $SAFE
p Safe.level(2){puts ‘----’;p $SAFE; puts ‘-----’; $SAFE}
p $SAFE
puts ‘=========================’

###################

sample part 2

###################
fp = open(‘hoge’, ‘w’)
wp = proc{|s| p $SAFE; fp.print(s)}

puts ‘=========================’
$SAFE = 4
wp.call(“hoge hoge\n”)
fp.print(“fuge fuge\n”)


Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)

###################
# sample part 2
###################

svg% cat b.rb
#!/usr/bin/ruby
fp = open('hoge', 'w')
wp = proc{|s| p $SAFE; fp.print(s)}

puts '========================='
$SAFE = 4
class << a = [12]
   def to_s
      $stderr.puts "coucou :-)"
      super
   end
end
wp.call(a)
svg%

Guy Decoux

Hi,

···

From: ts decoux@moulon.inra.fr
Subject: Re: $SAFE = 3.5?
Date: Thu, 6 May 2004 17:07:19 +0900
Message-ID: 200405060807.i4687Dx16666@moulon.inra.fr

svg% cat b.rb
#!/usr/bin/ruby
fp = open(‘hoge’, ‘w’)
wp = proc{|s| p $SAFE; fp.print(s)}

puts ‘=========================’
$SAFE = 4
class << a = [12]
def to_s
$stderr.puts “coucou :-)”
super
end
end
wp.call(a)
svg%

Ok. You are a nice cracker. :slight_smile:
Well, how about this?

def foo(fp)
wp = proc{|s| p $SAFE; fp.print(s)}
proc{|s| $SAFE=4; wp.call(s.to_s)}
end
wp = foo(open(‘hoge’, ‘w’))

puts ‘=========================’
$SAFE = 4
class << a = [12]
def to_s
$stderr.puts “coucou :-)”
super
end
end
wp.call([12])
wp.call(a)


Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)

Well, how about this?

If I can read the source

svg% cat b.rb
#!/usr/bin/ruby
def foo(fp)
  wp = proc{|s| p $SAFE; fp.print(s)}
  proc{|s| $SAFE=4; wp.call(s.to_s)}
end
wp = foo(open('hoge', 'w'))

puts '========================='

$SAFE = 4
eval('wp.call(eval(%q{class << a = [12]
                       def to_s
                          $stderr.puts "coucou :-)"
                          super
                       end
                    end
                    a}))', wp.binding)

svg%

Guy Decoux

Hi,

···

From: ts decoux@moulon.inra.fr
Subject: Re: $SAFE = 3.5?
Date: Thu, 6 May 2004 18:54:59 +0900
Message-ID: 200405060939.i469dpo21931@moulon.inra.fr

eval(‘wp.call(eval(%q{class << a = [12]
def to_s
$stderr.puts “coucou :-)”
super
end
end
a}))’, wp.binding)

Oops! I didn’t think about Proc#binding.
If wp.binding method is undefined, how do you crack it?

                              Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)

If wp.binding method is undefined, how do you crack it?

You make the common error to think that #to_s return a String

svg% cat b.rb
#!/usr/bin/ruby
def foo(fp)
  wp = proc{|s| p $SAFE; fp.print(s)}
  proc{|s| $SAFE=4; wp.call(s.to_s)}
end
wp = foo(open('hoge', 'w'))

puts '========================='

$SAFE = 4
class << a =
   def to_s
      class << a =
         def to_s
            $stderr.puts "coucou :-)"
         end
      end
      a
   end
end

wp.call(a)
svg%

Guy Decoux

Message-ID: 200405061326.i46DQxS28056@moulon.inra.fr

If wp.binding method is undefined, how do you crack it?
You make the common error to think that #to_s return a String

Hmmm…
Well, under $SAFE==4, I must check that return value of
to_s method is a String and the String object has no
singleton methods. However, I cannto trust all methods
of the object because those methods may be overrided.
It means that I cannot know the class of the object which
passed to the safe-level capsule, doesn’t it?
That is, if I allow that a safe-level capsule proc accesses
an untrust object, I cannot deny to give the right of the
safe-level of the proc to the caller.
Am I right? Or are there any way to avoid security holes?

···

From: ts decoux@moulon.inra.fr
Subject: Re: $SAFE = 3.5?
Date: Thu, 6 May 2004 22:27:04 +0900

                              Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)

Well, under $SAFE==4, I must check that return value of
to_s method is a String and the String object has no
singleton methods.

No need for this, you just need to use a method that you can trust like
String::new

   proc{|s| $SAFE=4; wp.call(String.new(s.to_s))}

Guy Decoux

Message-ID: 200405061423.i46ENB000686@moulon.inra.fr

No need for this, you just need to use a method that you can trust like
String::new
proc{|s| $SAFE=4; wp.call(String.new(s.to_s))}

How foolish I am!
I was mistaken it is a problem that String.new(obj) calls obj.to_str
if obj is not a String.
It is NOT a problem because obj.to_str is called under $SAFE==4.
I need more practice for Ruby programing. :-<
Thank you.

···

From: ts decoux@moulon.inra.fr
Subject: Re: $SAFE = 3.5?
Date: Thu, 6 May 2004 23:23:18 +0900

                              Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)