From: Matthew Flatt <mflatt@cs.utah.edu>
To: plt-scheme@fast.cs.utah.edu
Date: Mon, 25 Mar 2002 09:26:42 -0700 (MST)
Subject: 200alpha15 (security guards)

The exp-tagged code in CVS for MzScheme and MrEd is now version
200alpha15.

The main change in this version is the addition of "security guards" to
check filesystem and network access.

Security Guards
---------------

In principle, programmers could always sand-box a program through a
namespace that constains a retricted set of primitives. But
constructing a useful and restricted namespace is tedious, at best.

To make sand-boxing easier, we’ve added an access check around each
access of the filesystem or network in MzScheme’s primitives. The
access check calls a function provided by the current security guard
--- as determined by the new `current-security-guard’ parameter ---
giving the guard a pathname/hostname, plus an indication of the kind of
access that is needed (read, write, etc.). If the function does not
raise an exception, access is granted.

For example, evaluating the following expression should cut off all
filesystem and network access:

 (current-security-guard
     (make-security-guard (current-security-guard)
         ;; filesystem check:
         (lambda (who path mode) (raise ’no-filesystem!))
         ;; network check:
         (lambda (who host port-number) (raise ’no-network!))))

A new security guard can be created only as a child of an existing
security guard, and access checks always consult the parent as well as
the child, so a program can’t arbitrarily increase its access by
creating a new security guard.

See the latest documentation for details.

Security and Extensions
-----------------------

Extension implementors must insert access check into their code using
the following new functions:

 void scheme_security_check_file(const char *who, char *filename, int guards);
 void scheme_security_check_network(const char *who, char *host, int port);

Of course, most sand-boxing security guards will simply disallow the
loading of extensions.

Why Security Guards Definitely Don’t Work, Yet
----------------------------------------------

A gaping security hole remains in MzScheme: bytecodes (usually from .zo
files) are not fully validated, so ill-formed bytecodes can in
principle do arbitrarily bad things. It’s not enough to simply cut off
filesystem access; an expression such as

 (parameterize ([read-accept-compiled #t])
    (read (open-input-string "#~...")))

can do anything with a cleverly chosen "...", I think.

Also, MrEd is still missing some access checks.

These bugs will be fixed soon.

Will Security Guards Ever Work?
-------------------------------

I think so, but I’m interested in feedback (either about the interface
or the implementation) from anyone who knows something about security.

There are *so many* things that can go wrong. For example, in my
initial specification, the string and list passed to a security-guard
procedure were mutable, so a child security guard could mutate the
arguments before the parent security guard saw them. I caught that one,
but I wonder how many other things I’ve missed.

(Knowing just a little about security, and knowing a fair bit about the
PLT Scheme infrastructure, my guess is that the problem is no more
difficult than the problem of preventing seg faults --- but, almost by
definition, also no easier.)

Matthew