restricted execution

Shawn Pearce spearce@REDACTED
Tue Jun 10 04:47:27 CEST 2003


I'd go a different, but close approach:

spawn a process, and in spawn_opt give it an optional security
module:  {security_manager, mysecmgr}.

The module mysecmgr implements a 'security_manager' behavior, such as:

-module(mysecmgr).
-behavior(security_manager).
-export_all.

send_message(To, Message) ->
	case sets:exists(get(mysecmgr_sendlist), To) of
		true -> To ! Message;
		false -> exit(security_error)
	end.

put(mysecmgr_safemod, _) ->
	exit(security_error);
put(mysecmgr_sendlist, _) ->
	exit(security_error);
put(Key, Value) ->
	erlang:put(Key, Value).

remote_call(erlang, Function, Args) -> apply(erlang, Function, Args);
remote_call(lists, Function, Args) -> apply(lists, Function, Args);
remote_call(sets, Function, Args) -> apply(sets, Function, Args);
remote_call(dict, Function, Args) -> apply(dict, Function, Args);
remote_call(_, _, _) -> exit(security_error).


The VM would have to pass these 3 critical calls (!/send_message, put
and remote module call) through the security manager module, rather
than doing it directly.  But the security manager would have to have
access to do the calls itself, without recursing into itself.


Sort of weird I guess, and most likely impossible to implement without
creating duplicate versions of every module ('safe' and 'unsafe') and
making sure the security manager's apply/3 in remote_call/3 doesn't
jump to the unsafe version  of any module (as that might then be able
to subvert the security manager).


My other idea was to do this at compile time.  Create a parse transform
in erlc that cannot be bypassed, which would convert these 3 cases
to calls to the security manager module, which is obtained from the
process dictionary.  Also define a module_info/1 flag which indicates if
if the module is safe or not.

The security manager module would be complied without the +safe parse
transform option.


When you spawn, only spawn into a safe module.  If the safe module will
call an unsafe module (or send a message, or attempt to modify the
process dictionary), it goes through the security manager set in the
process dictionary, which is an 'unsafe' module and can call the other
unsafe modules, or rewrite the module name to call the 'safe' form.


This of course leaves open the attack that a user may give you a .beam
file which claims it is safe, but isn't.  Here is where a bytecode
verifier is needed to ensure remote calls are only done to the security
manager, and the same with remote sends.

Yeck, now we are getting up to the point of Java.


I've been thinking about this a lot lately, as I have been contemplating
building a system in Erlang where I'd want safe and unsafe processes,
some running user code, others' not, and the user code should not have
unlimited access to gen_tcp, file, etc.

Since users would be required to supply source code, and have the
node compile it, I can ensure it was built with the +safe parse
transform, and ensure they go through my security module.  Which would
be effective, but slower.


I don't know enough about the gen_tcp/gen_udp/ssl/file/code/etc. modules
to know if just limiting remote sends is enough.  Certainly a 'safe'
process must also not be able to open ports, etc so some erlang module
functions must also be offlimits to these processes.  However, I see
little point to restrict their use of sets, dict, lists, string.  But
ets/dets does make sense to restrict access to as well.


erlang@REDACTED wrote:
> This is my week for stupid questions ... on the plus side I'm finding 
> erlang so compelling that I might actually gain some proficiency by dint of
> outright practice.
> 
> This evening's topic for debate before the symposium:
> 
> In my researches online (so many that by now my head spins) I see lots of
> references to safe, or safer, erlang, and various models of restricted
> execution.
> 
> Well, that's nice.  If I really, really wanted to run something relatively
> customised, I could always implement a virtual machine (not a possibility 
> I have completely eliminated, but one I'd prefer to avoid).  I'd rather not,
> and this is pretty much my bottom line, have to deal with non-standard
> forms of the language.
> 
> What I do want to be able to do:  run a user-provided process with some
> assurance that the only external data access it has is precisely that which
> I can provide it.
> 
> I realise that quite likely the basic form of Erlang doesn't make provision
> for this, but looking at the facilities for cookies and so on, it strikes
> me that something ought to be possible.
> 
> Is there a particularly common or usual answer to this?  I've worked in 
> telecom situations, and I know that quite a lot of kit works with shared
> secrets, which is pretty much what the cookies implement.  Anyone have
> any suggestions?
> 
> My ideal situation: spawn a process, give it in its arguments a few 
> processes it can communicate with, and leave it with no other sources of
> information, nor external contact facilities.
> 
> 

-- 
Shawn.

  Art is the tree of life.  Science is the tree of death.



More information about the erlang-questions mailing list