From ripley at stats.ox.ac.uk  Mon Mar 27 19:33:01 2006
From: ripley at stats.ox.ac.uk (Prof Brian Ripley)
Date: Mon, 27 Mar 2006 18:33:01 +0100 (BST)
Subject: [Rd] Operator masks in R, restrict set of applicable functions
In-Reply-To: <442819DD.1000300@cebitec.uni-bielefeld.de>
References: <4427A0C9.90303@cebitec.uni-bielefeld.de>
	<Pine.LNX.4.64.0603270933370.6974@gannet.stats.ox.ac.uk>
	<442819DD.1000300@cebitec.uni-bielefeld.de>
Message-ID: <Pine.LNX.4.64.0603271816380.17917@gannet.stats.ox.ac.uk>

On Mon, 27 Mar 2006, Michael Dondrup wrote:

> Thank you very much,
> Sorry for bothering again, but how about this:
>
>> assignInNamespace('system',function(...)stop('No system!'),'base')
>> system()
> Error in system() : No system!
>> base::system()
> Error in base::system() : No system!
>> detach(package:utils) # no way back?
>
> I guess there is a way to circumvent that, too?

Yes.  For base::system is just

> system
function (command, intern = FALSE, ignore.stderr = FALSE)
.Internal(system(if (ignore.stderr) paste(command, "2>/dev/null") else 
command,
     intern))
<environment: namespace:base>

so you can just call the .Internal.

If designing R from scratch it would be a good idea to separate out all 
the 'unsafe' (for a suitable definition) function and provide ways to lock 
their internal code.  Some of this would be fairly easy to do (e.g. 
disabling the internals of system), but I am not sure a partial solution 
would be much help.  And disabling dyn.load would be almost impossible in 
general use, as that would stop standard packages being loaded, and they 
are loaded after user code (e.g. .Rprofile) is run.

> Of course, if it works, it's tideous work to do this for all unsafe functions 
> (of course: file, url, unlink, dyn.load,...,  maybe I'm just too cautious )
> I would really  like to chroot the R-process, and agree it would be the best 
> option, but I'm using RSPerl, which loads R.so. Hence, I cannot restrict 
> R-code more than the web-server(at least I think so).

That is not clear to me.  I thought you mentioned CGI, not a server 
extension, so my understanding was that R was running in a separate 
process from the server.

> Though this would be 
> necessary, as the web-server accesses some files that unsafe code should 
> never even be able to read, including the cgi-scripts.
>
> Thank you again
> Michael
>
>
> Prof Brian Ripley wrote:
>> On Mon, 27 Mar 2006, Michael Dondrup wrote:
>> 
>> 
>>> Hi,
>>> is there a way to restrict the set of admissible functions for an eval()
>>> statement to a possibly 'safe' set, excluding all potentially dangerous
>>> functions like 'system', 'open', etc.(like, for instance, in the 'Safe'
>>> module for Perl)?
>> 
>> 
>> In short, no.  (BTW, what is unsafe about 'open'?  What are you trying to 
>> circumvent here?  E.g. unlink() might be on your list, as might file().)
>> 
>> The normal approach is to run R in an environment which restricts what the 
>> user can do: that should be sufficient to avoid unwanted file deletions, 
>> for example.
>> 
>> One could argue that a lot of these operations should be in a package other 
>> than base, but much of R is itself written in R and assumes them. (I did 
>> look into putting system() and file.*() in utils when the current 
>> organization of packages was made, but at least at the time they were too 
>> deeply embedded in other functionality.)
>> 
>> One idea would be to evaluate your expression in a strictly controlled 
>> environment of your own choosing, but there are ways for knowledgeable 
>> users to circumvent that (see below).
>> 
>> 
>>> The background for this question is, that this would be run in a
>>> CGI-environment. The user should be able to input some R-code (a
>>> function assignment), thereafter the code is parsed, evaluated and the
>>> type of function parameters checked by a call to 'formals'
>>> like in:
>>> 
>>>> expr <- parse(text='foo <- function(x = numeric()){mean(x)}')
>>>> eval(expr[1])
>>>> formals(foo)
>>> 
>>> $x
>>> numeric()
>>> 
>>> of course, this is highly dangerous, given this setting, as one could try
>>> 
>>>> expr <- parse(text='system("ls");
>>> 
>>> foo <- function(x = numeric()){mean(x)}') # or more evil things
>>> 
>>>> eval(expr)
>>> 
>>> I know I could do something like
>>> 
>>>> system <- function(...) stop ('This is not allowed!')
>>> 
>>> but it's rather likely to miss one of the 'bad' functions.
>> 
>> 
>> But a user can use base::system, and load packages which could contain 
>> arbitrarily dangerous code (even its own compiled-code version of system).
>> 
>> 
>>> Any ideas would be appreciated.
>>> 
>>> Regards
>>> Michael Dondrup
>>> 
>>> ______________________________________________
>>> R-devel at r-project.org mailing list
>>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>> 
>>> 
>> 
>> 
>
>
>

-- 
Brian D. Ripley,                  ripley at stats.ox.ac.uk
Professor of Applied Statistics,  http://www.stats.ox.ac.uk/~ripley/
University of Oxford,             Tel:  +44 1865 272861 (self)
1 South Parks Road,                     +44 1865 272866 (PA)
Oxford OX1 3TG, UK                Fax:  +44 1865 272595



[Rd] Operator masks in R, restrict set of applicable functions
Prof Brian Ripley