Hi Gary,

On 19/12/11 10:31, Gary Wright wrote:
> I'm not sure that I would want to rely on any language enforced constraints for executing 'hostile' code within the same address space as my main application.  I think a better solution is to run the foreign code (that sounds nicer) in an external process or even on a completely separate system and then use some sort of communication scheme to interact with the foreign code. If the communication scheme is well defined it also means that the plugin doesn't have to even be in Ruby.
>
> If you want to run it on the same system but in a different process you can arrange for the process to be 'locked down' in a sandbox or other restricted environment.  The specifics on how to do this are going to be very dependent on your production environment but perhaps someone will pipe up with some specific suggestions



> if you tell us about your environment.

I'll give it a shot. :)

I am developing a cross-platform app, Linux and Windows initially. Using 
Ruby code for plugins is extremely desirable as much of the app itself 
is already written in Ruby, and I don't want the users to even have to 
consider the platform. Most users would only be using a single platform 
anyway, and many plugin authors would be new to Ruby.

 From the perspective of a potential plugin, I would be providing the 
entire interface- every call that they could need to interact with the 
app would be provided. As mentioned, it could be as simple as message 
passing between a couple of objects. In fact, I don't want the plugin to 
be able to communicate outside the app, except through the API provided 
by the app. This includes networking, filesystem access, and the like. I 
would most likely supply a "require" replacement as well, and RubyGems 
or existing libraries wouldn't be directly usable. I would like plugin 
authors to be able to use things such as strings, arrays, create an 
manage their own custom classes, so forth. I could potentially whitelist 
allowed things if I could hook into things at various points.

Plugin authors would *generally* not be deliberately malicious, because 
they won't be entirely anonymous (as per if it was a online web app, for 
example), but it could happen, so I'd like to minimise the interactions 
with the external environment as much as possible. Some authors will be 
genuinely curious and be looking to explore the rest of the Ruby code 
that is running. I specifically want to limit this. A determined 
attacker will of course eventually succeed, but I want to make it difficult.

The app users would be the ones running the plugins. Most wouldn't be 
able to write a line of Ruby to save their lives, let alone understand 
plugins as anything more than a magic file they download. Thus, if they 
enabled a plugin that executed 99999999**999999999, it might lock the 
app up, but they'll just kill it, restart it, and not use the dodgy 
plugin next time. If the plugin was capable of blasting files away from 
their filesystem, then there is a problem. Thus maliciousness that 
causes an app crash is only a minor problem, maliciousness that deletes 
files is a big problem.

As most of the interaction would be in the form of method calls (ie. 
plugin calls app, expects a return value, app call plugin, expects a 
return value), a separate process for the app would be cumbersome. A 
separate thread would be slightly annoying, and in the same thread would 
be fine. However, I realise that the closer the plugin gets to the app 
in this way, the harder it will be to sandbox. My gut feeling is that 
the solution would probably be provided at the (Ruby) thread level.

The current state of the code is that the app is still in development, 
but many of the basics are in there. No plugin infrastructure exists 
yet, as I'm just starting to explore the possibilities (hence the reason 
for my post- I'm trying to figure out the best place to begin). The app 
itself is a C++ and embedded Ruby mix, and I've worked with both for the 
last decade or so. Patching the version of Ruby I am using myself is a 
possibility if it helps, as I'm fine building Ruby and potentially 
making very small changes. I am using the 1.9 series.

I'm happy answer any questions on specifics if it helps.

Garth