The second line of defence is the Safe module of the Perl language.
The Safe module allows one to "sandbox" Perl code. That is, one can run Perl code while disallowing certain operations (such as file access).
A Safe module sandbox is called a "Safe compartment". Each Safe compartment has an "opcode mask" which specifies which operations are, and are not, allowed. On my system, "man Safe" gives you the Safe documentation, and "man Opcode" documents the names of the operations that you can permit or deny in a Safe compartment.
Safe also allows you to "share" arbitrary procedures and data with your Safe compartment. That means that I can, say, disallow all file access operations to my Safe compartment, but then allow it to call a certain specified subroutine from outside the compartment that is not hindered by the restrictions. This is how SPW works.
In SPW, opcodes are disallowed by default, with an enumerated list of allowed opcodes. The allowed opcodes in SPW (as of version 0.2) are the following, divided into categories (the categories are from the Opcode documentation) (the ones that start with a colon are actually a set of opcodes; see man Opcode
for details:
:base_opcodes = :base_core :base_mem :base_loop :base_io :base_orig :base_math
:filesys_open_opcodes = close
:ownprocess_opcodes = time
:still_to_be_decided_opcodes = sleep sort caller
DISallowed SPW Opcodes include, among others,
::filesys_read
, which includes stat
and all filetest opcodes
::sys_db
:the rest of :filesys_open
, including open
:all of :filesys_write
:all of :subprocess
, including backtick
and system
:the rest of :ownprocess
, including exec
:all of :others
, including SystemV? Interprocess Communications
:the rest of :still_to_be_decided
, including socket, ioctl,
and entereval
So, if an attacker wants to execute a system program, access the network, or write to the filesystem, they'll probably have to break through the Safe compartment controls somehow.
Of course, a wiki needs to do some of these things (particularly manipulate the filesystem). The solution is to "share" a bunch of routines with the wiki which allow safety-checked I/O. These routines are in UsemodUnsafe.pm
. UsemodUnsafe.pm
itself is NOT able to be changed by SPW (and therefore, cannot be changed by users of the wiki).
So far, UsemodUnsafe? allows pretty much arbitrary file operations within the /spw directory -- the routines check their arguments to try to eliminate any special characters, and to make sure that the target file paths all start with "/spw/" (and they can't contain more than one consecutive ".", so you can't just say "/spw/../".)
UsemodUnsafe? also provides a GetRemoteHost? subroutine and a sanitized call to the diff
program.
When SPW is started, the script which is actually run is /var/www/spw.pl
. This script is NOT able to be modified by SPW. This script sets up a Safe compartment. Within the restricted compartment, the script executes the script /spw/spw_main.pl
. spw_main.pl
is the part which SPW itself can modify.
The webserver is setup so that spw_main (or anything else in the the /spw directory) cannot be run directly; so in theory there is no way for an attacker to execute their code unless it is from within a Safe compartment.