enforce at a process level, rather than
word level.
Singularity also provides flexible
hardware-based process isolation as
a secondary mechanism. A Singularity hardware-protection domain is an
address space holding one or more
SIPs. Domains can run in either user
or kernel mode (ring 3 and ring 0 on
an x86 processor). At runtime, the sys-tem-configuration manifest specifies
which SIPs reside in which domains.
Domains allow untrusted code to be
isolated behind conventional hardware-protection mechanisms while
more trusted code resides in the same
address space, benefiting from faster
communications and failure isolation
(see Figure 3).
Domains also enable Singularity developers to run a series of experiments
comparing the execution overheads of
software and hardware isolation. 1 The
basic cost of software isolation is the
runtime checks for null pointers and
array accesses ( 4.7% of CPU cycles). By
contrast, hardware isolation similar to
conventional operating systems (
separate address spaces and protection domains) incurred a cost of up to 38% of
CPU cycles (see Figure 4).
Table 3. Basic cost (in cPu cycles) of common operations between isolated processes on
an amD athlon 64 3000+ system.
Process create
and start
minimum
kernel aPi call
Thread
context switch
message
request/reply
Singularity
353,000
freeBSD 5. 3 Linux 2. 6. 11 (Red hat fc4) Windows XP (SP2)
1,030,000 719,000 5,380,000
91
878
437
627
346
911
906
753
803
13,300
5,800
6,340
figure 3. hybrid hardware-software isolation using SiPs and domains.
Unsigned
App2
sIP
Protection domain
ring 3
ring 0
App1
Signed
extension
Unsigned
extension
Unsigned
Driver
Signed
Driver
Kernel
modular System architecture
Unlike many systems, Singularity assumes that software contains bugs
and consequently is likely to fail occasionally. Singularity’s architecture
aims to contain the consequence of a
failure within a fault-isolation boundary, thereby allowing the system to detect the failure and recover by restarting the failed component. Although
less intellectually appealing than flawless operation, most complex artifacts
share this paradigm and most programmers are comfortable with it; for
example, a car does not stop running
when a headlight burns out or a tire
goes flat.
Tight coupling between compo-
nents in monolithic software systems
routinely means the failure of one
component can bring down an appli-
cation and, in the worst case, the sys-
tem itself. The epitome of this prob-
lem is the common plug-in software
architecture that allows extensions to
be dynamically loaded into a host’s ad-
dress space. Plug-ins (such as device
drivers, browser extensions, and spell
checkers) share their host process’s
address space and have unconstrained
access to its code and data structures.
An extension’s failure typically causes
the host to fail as well. Considerable
evidence shows that extensions are
less reliable than host code; for ex-
ample, Orgovan and Tricker reported11
that approximately 85% of the Win-
dows XP kernel crashes they studied is
caused by device drivers, and Chou et
al. reported that the Linux drivers they
studied have up to seven times the bug
density of other kernel code. 5