Hi all,
I am working on an embedded Ruby application that may support
user-written Ruby plugins in the future, and I am trying to get a rough
idea as to what is and isn’t possible, as it will affect the design I go
with. Basically, if you’ve worked on such a thing before, please share
your experiences.
The ideal in my case is that the app will load in user-written Ruby code
as a plugin, and the plugin author can interact with the rest of the
code via a predefined and restricted set of objects and methods, but
cannot mess with things outside of its environment, and especially not
start exploring outside that environment in any way. I want to be able
to completely lock the user out of using certain objects or classes.
Having not done anything like this in Ruby before, I’m trying to get a
feel as to what might be possible and practical.
For example, many of the criteria in a $SAFE level of 4 seem appropriate
to me- although what I’m really after is a way to lock things up, call
some user code, and then revert back to a normal $SAFE level. It looks
like the only way this could really be done though is to launch the
plugin in its own (Ruby) thread and handle any synchronisation issues
arising from it myself. Is this right?
Being able to set up my own access control by intercepting every method
call made by the plugin would also be useful. I could then, for example,
have a set of testing criteria that I could use on each method call to
determine if it should be allowed (for example, class whitelists). I
wonder if I could set up a series of proxy objects for objects that I’d
like to wrap, but I wouldn’t want a plugin author to use those proxy
classes to get at the original objects, and mess with them directly. The
interface could be as thin as two objects- an application object that
you send messages to, and a plugin base object that the plugin uses to
receive messages from the application. In this case I’d like the user to
be able to create their own classes, manipulate strings and arrays (for
example), but not interact with any of the remaining Ruby code at all,
and certainly not examine it in any way.
As some app users might run plugins other app users have written, being
able to limit the damage they can cause is also important. I’m not
fussed if certain operations could cause a denial of service (eg. just
run “while true; end”), as the environment would be such that the
affected user could just kill the process and disable the plugin- it’s
not a web server. I would be fussed though if the plugin was able to
read and write files to the system directly, or cause lasting damage
outside of the application itself.
As you can tell, my thoughts on the subject are still somewhat
disorganised. I’m trying to determine roughly which parts of this
infrastructure would be easy, difficult, or impossible to implement. I
would greatly benefit from the thoughts and experiences of people who
have been down this road before. If you can find the time, please share
your experiences, and let me know what worked, and what did not.
Thanks in advance, apologies for the long, rambling question.
Garth