CSE 227: Lecture 8
The topics covered in this lecture are
These are methods for safe kernel extensions and have applications to
other contexts where untrusted code must be run, usually for
In-kernel packet filter to eliminate frequent kernel-user context
switches to deliver packets most of which will be filtered and
discarded. Main idea: the use of a ``little language'' designed for
packet filtering. Features op-codes for matching IP packet header
elements, forward only branches, and of course the ability to
either discard the packet or to forward it up to user-level code for
more complex matching or processing.
Spin operating system permitted kernel extensions since the kernel and
all extensions were written in Modula 3. (Very low level parts of the
kernel was in assembler.) The key observations are that the
type-safety of Modula 3 is enforced by the compiler, and the
correspondance between the generated object code and the source is
guaranteed by the compiler by a digital signature. Further, the
confidentiality of the signature generation key embedded in the
compiler binary is ensured by (standard) operating system access controls.
Drawbacks include having to choose between a master key for all
compiler distributions, or not having the ability to distribute kernel
extension modules in binary form.
In SFI binary code is instrumented to add checks before potentially
dangerous operations. Original work done on the MIPS; no public
working implementation for IA32 have been demonstrated AFAIK. Key
optimizations include putting data into a separate, power-of-2 sized
region with two 4*32K additional (register offset) memory chunks
before and after the power-of-2 region, so protection against stray
memory writes can be implemented using a mask and an OR instruction to
set the high-order bits of a pointer.
Control transfers are constrained to jump inside of a similar separate
region of text; the control transfer targets must be the beginning of
identified basic blocks so that neither the store protection
instructions nor the jump protection instructions may be bypassed.
Note that the original prototype required the use of a modified
version of gcc which kept a register free for use by the mask/OR
operations, and the only place where a jump instruction used a
register is for a switch statement.
In PCC, a proof-generating compiler emits a proof of security
(relative to a given security policy) along with the machine code. In
the original prototype, the length of the proof could be exponential
on the size of the program, though there's been extensive work
recently on reducing the size of the proof. The code, along with the
proof, is sent to the code consumer (e.g., kernel), which uses a proof
verifier -- a type checker -- to verify that the code and the proof
satisfies the consumer's security policy prior to allowing control to
be transferred to the code.
PCC code can be extremely efficient. A drawback is that the proof of
correctness/security is relative to a given security policy, so in a
system where there may be many security policies or where the security
policy is not known ahead of time, the proof-generating compiler will
not know what to do. An important advanntage is that the typechecker
is small, so the additional complexity to the TCB is small.
search CSE |
bsy's home page |
pgp certserver |
firstname.lastname@example.org, last updated Thu Feb 6 22:50:28 PST 2003. Copyright 2003 Bennet Yee.