Untrusted environment: Difference between revisions

From Rosetta Code
Content added Content deleted
(+J)
m (describe arguments to !:)
Line 14: Line 14:
In fact, there is only one word which reach outside the execution environment (the functional scope of the program): '''<tt>!:</tt>''', the aptly named "foreign" operator. This one operator encapsulates all access to the outside world, and even the "behind the scenes world" of J's own memory space.
In fact, there is only one word which reach outside the execution environment (the functional scope of the program): '''<tt>!:</tt>''', the aptly named "foreign" operator. This one operator encapsulates all access to the outside world, and even the "behind the scenes world" of J's own memory space.


The operator takes two arguments and derives a function, which specifies which kind of foreign interface you want. For example, <tt>1'''!:'''1</tt> is the specific function to read a file, and <tt>1'''!:'''2</tt> is the function to write one (as in <tt>1'''!:'''1 'filename'</tt> and <tt>some_data 1'''!:'''2 'filename'</tt>, respectively). The foreign function <tt>15'''!:'''0</tt> allows the J programmer to call a shared library (dll, so, dylib, etc), <tt>2'''!:'''5</tt> reads environment variables (e.g. <tt>2'''!:'''5'PATH'</tt>), and <tt>2'''!:'''55</tt> will terminate the program (quit, die: the mnemonic is that <tt>255</tt> is the "last" value of a byte, and <tt>2'''!:'''55</tt> is the "last" thing you want to do in a J program).
The operator takes two arguments and derives a function, which specifies which kind of foreign interface you want. For example, <tt>1'''!:'''1</tt> is the specific function to read a file, and <tt>1'''!:'''2</tt> is the function to write one (as in <tt>1'''!:'''1 'filename'</tt> and <tt>some_data 1'''!:'''2 'filename'</tt>, respectively). The foreign function <tt>15'''!:'''0</tt> allows the J programmer to call a shared library (dll, so, dylib, etc), <tt>2'''!:'''5</tt> reads environment variables (e.g. <tt>2'''!:'''5'PATH'</tt>), and <tt>2'''!:'''55</tt> will terminate the program (quit, die: the mnemonic is that <tt>255</tt> is the "last" value of a byte, and <tt>2'''!:'''55</tt> is the "last" thing you want to do in a J program). There are many more, grouped into families (the first argument to <tt>'''!:'''</tt> specifies which family you want, e.g. <tt>''1'''''!:'''n</tt> is the ''file'' family, and <tt>1'''!:'''''1''</tt> is to ''read'' a file, specifically).


But the key thing is that this one operator, <tt>'''!:'''</tt> controls all the dangerous stuff, so if we want to prevent dangerous stuff, we only have to put guards in one place. And, in fact, we have "foreign controls": foreign functions which themselves control which foreign functions are allowed. In other words, there's only one "door" to J, and we can lock it.
But the key thing is that this one operator, <tt>'''!:'''</tt>, controls ''all'' the dangerous stuff, so if we want to prevent dangerous stuff, we only have to put guards in one place. And, in fact, we have "foreign controls": foreign functions which themselves control which foreign functions are allowed. In other words, there's only one "door" to J, and we can lock it.


From the J documentation:
From the J documentation:

Revision as of 01:53, 18 January 2013

Untrusted environment is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Sometimes it is useful to run code with inputs from untrusted users, untrusted code, etc. Explain the features your language uses in these circumstances and give sample code.

The intention is that the definition is to be interpreted broadly; different languages will solve this task in very different ways and with (generally) incomparable results.

J

J has some security mechanisms built in, and they are detailed below. But to understand their scope (and limitations), it's probably helpful to provide some context first.

J is a function-level language, expressed with composition of primitive words, like + for plus and ! for factorial and @ for function-composition and / for reduce, etc.

Because J is also (mostly) functional, almost all of these primitive words are also "native": that is, they stay within the bounds of the execution environment, and cannot reach outside of it to the host system. They cannot even effect J's own memory space, except through assigning variables.

In fact, there is only one word which reach outside the execution environment (the functional scope of the program): !:, the aptly named "foreign" operator. This one operator encapsulates all access to the outside world, and even the "behind the scenes world" of J's own memory space.

The operator takes two arguments and derives a function, which specifies which kind of foreign interface you want. For example, 1!:1 is the specific function to read a file, and 1!:2 is the function to write one (as in 1!:1 'filename' and some_data 1!:2 'filename', respectively). The foreign function 15!:0 allows the J programmer to call a shared library (dll, so, dylib, etc), 2!:5 reads environment variables (e.g. 2!:5'PATH'), and 2!:55 will terminate the program (quit, die: the mnemonic is that 255 is the "last" value of a byte, and 2!:55 is the "last" thing you want to do in a J program). There are many more, grouped into families (the first argument to !: specifies which family you want, e.g. 1!:n is the file family, and 1!:1 is to read a file, specifically).

But the key thing is that this one operator, !:, controls all the dangerous stuff, so if we want to prevent dangerous stuff, we only have to put guards in one place. And, in fact, we have "foreign controls": foreign functions which themselves control which foreign functions are allowed. In other words, there's only one "door" to J, and we can lock it.

From the J documentation:

9!:25 y Security Level: The security level is either 0 or 1. It is initially 0, and may be set to 1 (and can not be reset to 0). When the security level is 1, executing Window driver commands and certain foreigns (!:) that can alter the external state cause a “security violation” error to be signalled. The following foreigns are prohibited: dyads 0!:n , 1!:n except 1!:40 , 1!:41, and 1!:42 , 2!:n , and 16!:n .

There are further foreign controls on how much space, or time, a single execution is allowed to take:

9!:33 y Execution Time Limit: The execution time limit is a single non-negative (possibly non-integral) number of seconds. The limit is reduced for every line of immediate execution that exceeds a minimum granularity, and execution is interrupted with a “time limit error” if a non-zero limit is set and goes to 0.
9!:21 y Memory Limit: An upper bound on the size of any one memory allocation. The memory limit is initially 2^30 on 32-bit systems and 2^62 on 64-bit systems.

With all that said, the language has seen limited use in contexts where code injection is a concern, so these mechanisms are rarely exercised (and somewhat dated).

PARI/GP

GP has a default, secure, which disallows the system and extern commands. Once activated this default cannot be removed without input from the user (i.e., not a script).

<lang parigp>default(secure,1); system("del file.txt"); default(secure,0); \\ Ineffective without user input</lang>

Perl

Perl can be invoked in taint mode with the command line option -T. While in this mode input from the user, and all variables derived from it, cannot be used in certain contexts until 'sanitized' by being passed through a regular expression.

<lang perl>#!/usr/bin/perl -T my $f = $ARGV[0]; open FILE, ">$f" or die 'Cannot open file for writing'; print FILE "Modifying an arbitrary file\n"; close FILE;</lang>

Ruby

Ruby handles untrusted input with the global variable $SAFE. Settings higher than 0 invoke an increasing level of sandboxing and general paranoia. <lang ruby>require 'cgi' $SAFE = 4 cgi = CGI::new("html4") eval(cgi["arbitrary_input"].to_s)</lang>

UNIX Shell

Sometimes chroot jails are used to add a layer of security to <lang bash>mkdir ~/jail cd ~/jail; chroot ~/jail; setuid(9); # if 9 is the userid of a non-root user rm /etc/hosts # actually points to ~/jail/etc/hosts</lang>