Security problems

I’m having problems with controlling what can and can’t be done in a certain
piece of code. As some of you will be aware, I’m working on a Ruby
implementation of RoboCode, the ephemeral programming game. The robots and
controller are being written in Ruby (what else?) and I’m loading the robots
into the controller’s code directly by use of eval. To prevent the robots
doing anything nasty to the controller, the other robots or the system the
program is running on, all robot code is being executed with $SAFE == 4. This
is necessary as, among other things, it prevents them from modifying
untainted objects. So reducing $SAFE is not an option.

As Ruby is an extremely object-oriented language, and as part of the aim of
the program is to provide a teaching tool for Ruby and/or OOP, the robot API
is planned to be simple - extend a pre-written Robot class and add some
pre-defined methods (eg MyRobot#run) to do whatever you want.

The problem is that with $SAFE == 4, it doesn’t allow the robot programmer to
create new classes (“SecurityError: Insecure: can’t set constant”), and I
can’t just create the class for them first and give it to them to modify
either (“SecurityError: extending class prohibited”)

The only way I can get around this is by creating a temporary module and
extending the robot with it outside of $SAFE == 4:
eval <<-END
module Ex#{id}
self.taint
@f = File.readlines(sourcefile).join.untaint
safe(4) { eval(@f, binding, sourcefile) }
end

self.extend Ex#{__id__}

END

However this destroys the OOP-style extend-the-robot-class API, and thus
removes some of its usefulness as a Ruby teaching tool.

Can anyone else see a way around this? Running the code in a separate process
(like RealTimeBattle does) is not really an option either, because it would
still allow malicious code to damage the system on which it is run, and it
would reduce the ability run tournaments etc safely.

Tim Bates

···


tim@bates.id.au

The problem is that with $SAFE == 4, it doesn't allow the robot programmer to
create new classes ("SecurityError: Insecure: can't set constant"), and I
can't just create the class for them first and give it to them to modify
either ("SecurityError: extending class prohibited")

Can you work with singleton methods ? Something like this

pigeon% cat b.rb
#!/usr/bin/ruby
module M
   class A
   end
end
$SAFE = 4
a = M::a::new
def a.run
   puts "run"
end
a.run
pigeon%

pigeon% b.rb
./b.rb:10:in `write': Insecure operation `write' at level 4 (SecurityError)
        from ./b.rb:10:in `puts'
        from ./b.rb:10:in `run'
        from ./b.rb:12
pigeon%

Create *only* the class in non-safe mode after verification

Guy Decoux

I would still argue for separate processes and the client/server model.
What you are trying to do is exactly separating a robot controlling code
from the world controlling code.
If your server implements the hardware part of robots with a well defined
interface and the software part is left for clients then every robot writer
can change the world status only via the virtual hardware provided by the
server.

Why do you think that separate processes would break the security?

What I imagine is something like this:

Server:
class Robot

def turnLeft(howmuch)
check_and_do_something
end

…etc

end

Server accepts connection and for every connection makes an instance of the
Robot class (the connection is connected to the class).
When the server gets “turnLeft(34)” from the connection it can translate it
to appropriate_instance.turnLeft(34).
In other words the client can use just a defined set of methods.

Client
There are many ways to write a client for the described server.

Anyway I hope that you work on the robot game will quickly lead to some
interesting battles.

Regards,

Dalibor Sramek

···

On Fri, Jan 10, 2003 at 05:42:11PM +0900, Tim Bates wrote:

Can anyone else see a way around this? Running the code in a separate process
(like RealTimeBattle does) is not really an option either, because it would
still allow malicious code to damage the system on which it is run, and it
would reduce the ability run tournaments etc safely.


Dalibor Sramek insula.cz | In the eyes of cats,
dalibor.sramek@insula.cz | all things belong to cats.

That’s not terribly dissimilar from what I am already doing. Ideally, I want
the robot programmer to be able to do something like this:

class MyRobot < Robot
def run
# …
end
end

Anything less than that and it’s not really demonstrating OOP.
So I guess what I really want to do is give a piece of code all the
restrictions of $SAFE == 4 with one exception - permission to extend one
particular class. I can’t see a simple way to do this, but maybe I’m missing
something.

Tim Bates

···

On Fri, 10 Jan 2003 08:49 pm, ts wrote:

Can you work with singleton methods ? Something like this


tim@bates.id.au

That's not terribly dissimilar from what I am already doing. Ideally, I want
the robot programmer to be able to do something like this:

Well, no good idea (eow? == true)

class MyRobot < Robot
  def run
    # ...
  end
end

Warning 1.8.0

pigeon% cat b.rb
#!./ruby
Tmp = module R
   class << self
      class Robot
      end
      self
   end
end
R.taint
$SAFE = 4
class << R
   class MyRobot < Robot
      def run
         # ...
      end
   end
end
a = Tmp::MyRobot.new
a.run
pigeon%

pigeon% b.rb
pigeon%

Guy Decoux

Hi,

Anything less than that and it’s not really demonstrating OOP.
So I guess what I really want to do is give a piece of code all the
restrictions of $SAFE == 4 with one exception - permission to extend one
particular class. I can’t see a simple way to do this, but maybe I’m missing
something.

There’s no restriction to create subclass in $SAFE level 4.
The point is constant assignment. Wrap with a tainted module for
example.

class Foo
end

module XXX
self.taint
Thread.start do
$SAFE=4
class Bar<Foo
end
end.join
end

						matz.
···

In message “Re: Security problems” on 03/01/10, Tim Bates tim@bates.id.au writes:

What does that mean? I’m not familiar with the ‘eow?’ method…

You say your code sample is 1.8.0 - I have 1.6.7 and I just get

marvin:~$ ruby b.rb
b.rb:7: void value expression
b.rb:7: void value expression
marvin:~$

I don’t quite understand how this code sample works anyway - what is the
difference between doing

class << R
class MyRobot < Robot
def run
# …
end
end
end

and

module R
class MyRobot < Robot
def run
# …
end
end
end

which gives me an error telling me I can’t extend a class with $SAFE == 4 …

Tim Bates

···

On Fri, 10 Jan 2003 10:19 pm, ts wrote:

Well, no good idea (eow? == true)


tim@bates.id.au

Aha! This works perfectly. Thankyou, matz - I knew there had to be someone who
knew more about it than me, and who else but you?

I could afterwards untaint the module and prevent any other robots from
modifying that class, no?

Tim Bates

···

On Sat, 11 Jan 2003 04:23 am, Yukihiro Matsumoto wrote:

There’s no restriction to create subclass in $SAFE level 4.
The point is constant assignment. Wrap with a tainted module for
example.


tim@bates.id.au

What does that mean? I'm not familiar with the 'eow?' method...

End Of Week :-)))

You say your code sample is 1.8.0 - I have 1.6.7 and I just get

I've a good reason to work with 1.8.0

marvin:~$ ruby b.rb
b.rb:7: void value expression
b.rb:7: void value expression
marvin:~$

try it with something like

   module R
      Tmp = class << self
               # ...
            end
   end

just to see the error message given at level 4

I don't quite understand how this code sample works anyway - what is the
difference between doing

I work at singleton level.

Guy Decoux

Hi,

···

In message “Re: Security problems” on 03/01/11, Tim Bates tim@bates.id.au writes:

I could afterwards untaint the module and prevent any other robots from
modifying that class, no?

Yes. Use “untaint” method.

						matz.

b.rb:12: Insecure: can’t modify string (SecurityError)

Line 12 is this line from your original snippet:
class MyRobot < Robot

Tim Bates

···

On Sat, 11 Jan 2003 12:31 am, ts wrote:

module R
Tmp = class << self
# …
end
end


tim@bates.id.au

b.rb:12: Insecure: can't modify string (SecurityError)

You have found : internally ruby use a method (rb_str_cat), when it will
register the new class, which give this error. This is modified in 1.8.0

Guy Decoux