$SAFE = 3.5?

  • Thread starter Guillaume Marcais
  • Start date
G

Guillaume Marcais

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.
 
G

gabriele renzi

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)
 
M

Mark Hubbart

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)


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
 
T

Tim Bates

Mark said:
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.
 
T

ts

G> Is there anyway to have the same restriction that $SAFE=4 would give
G> 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
 
H

Hidetoshi NAGAI

Hi,

From: Tim Bates <[email protected]>
Subject: Re: $SAFE = 3.5?
Date: Tue, 4 May 2004 07:58:42 +0900
Message-ID: said:
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")
===============================================================
 
T

ts

H> ###################
H> # sample part 2
H> ###################

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
 
H

Hidetoshi NAGAI

Hi,

From: ts <[email protected]>
Subject: Re: $SAFE = 3.5?
Date: Thu, 6 May 2004 17:07:19 +0900
Message-ID: said:
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. :)
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)
 
T

ts

H> 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
 
H

Hidetoshi NAGAI

Hi,

From: ts <[email protected]>
Subject: Re: $SAFE = 3.5?
Date: Thu, 6 May 2004 18:54:59 +0900
Message-ID: said:
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?
 
T

ts

H> 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
 
H

Hidetoshi NAGAI

From: ts <[email protected]>
Subject: Re: $SAFE = 3.5?
Date: Thu, 6 May 2004 22:27:04 +0900
Message-ID: said:
H> 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?
 
T

ts

H> Well, under $SAFE==4, I must check that return value of
H> to_s method is a String and the String object has no
H> 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
 
H

Hidetoshi NAGAI

From: ts <[email protected]>
Subject: Re: $SAFE = 3.5?
Date: Thu, 6 May 2004 23:23:18 +0900
Message-ID: said:
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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,145
Messages
2,570,826
Members
47,371
Latest member
Brkaa

Latest Threads

Top