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.
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::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
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
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%
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: