mirror of
https://github.com/ipxe/ipxe
synced 2026-10-07 15:05:42 +03:00
149 lines
6.8 KiB
Plaintext
149 lines
6.8 KiB
Plaintext
/** @page threat_model Threat model
|
|
|
|
@section overview Overview
|
|
|
|
iPXE is a network-capable bootloader, generally operating at ring 0
|
|
(or equivalent) with all memory protections disabled. All data
|
|
originating from the network should be considered to be untrusted and
|
|
potentially malicious.
|
|
|
|
Under UEFI, iPXE operates before ExitBootServices() is called. An
|
|
exploit against iPXE can therefore potentially produce a Secure Boot
|
|
compromise, requiring all existing binaries to be revoked (by
|
|
incrementing the SBAT generation in include/ipxe/sbat.h for the
|
|
official binaries that are signed via the iPXE shim).
|
|
|
|
@subsection threats Threats
|
|
|
|
The primary threat category is traffic originating from a network
|
|
peer. All code on the receive datapath must carefully validate
|
|
received lengths and contents during parsing.
|
|
|
|
iPXE includes its own cryptographic stack (covering TLS, CMS, X.509,
|
|
etc). This stack is used for iPXE's own security (HTTPS connections
|
|
and code-signing verification) but is entirely unrelated to UEFI
|
|
Secure Boot since iPXE defers all Secure Boot decisions to the
|
|
platform's own LoadImage() and StartImage() calls. A compromise
|
|
within iPXE's cryptographic stack would be a compromise of iPXE's
|
|
security, but would not be a Secure Boot exploit (unless it also
|
|
allowed for e.g. arbitrary code execution or an out-of-bounds write).
|
|
|
|
@subsection secboot UEFI Secure Boot
|
|
|
|
Files may be annotated with FILE_SECBOOT() declarations to indicate
|
|
whether or not they are permitted to be included in a UEFI Secure Boot
|
|
build. The absence of a marker is taken to prohibit inclusion.
|
|
|
|
Exclusion from a UEFI Secure Boot build does not indicate that a file
|
|
is outside the scope of the threat model, but does generally indicate
|
|
that it is a lower priority.
|
|
|
|
There are some files that are explicitly marked as FORBIDDEN, for
|
|
various reasons:
|
|
|
|
- Some files are intrinsically insecure by design. For example, the
|
|
GDB debugging stub allows a remote device to read and write
|
|
arbitrary host memory locations.
|
|
|
|
- Some files are excluded by policy. For example, the direct kernel
|
|
loading capability in image/lkrn.c is marked as FORBIDDEN to
|
|
ensure that iPXE's policy of delegating Secure Boot decisions to
|
|
the platform firmware's LoadImage() and StartImage() is respected.
|
|
|
|
- Some obsolete cryptographic algorithms such as MD4 and MD5 are
|
|
excluded to prevent their accidental inclusion via configuration
|
|
changes.
|
|
|
|
- Some third-party code such as the 802.11 stack has previously been
|
|
reviewed and found to contain multiple security holes (mostly
|
|
failing to check return values for memory allocation or other
|
|
failures), and is excluded by agreement with Microsoft. Files in
|
|
this category need not be reviewed for security issues: they are
|
|
already known to contain holes and a full rewrite is required
|
|
before it becomes worthwhile to raise individual issues.
|
|
|
|
@subsection exclusions Exclusions
|
|
|
|
Malicious locally attached hardware is explicitly outside the scope of
|
|
iPXE's threat model. DMA-capable hardware is assumed to have write
|
|
access to all of host memory (i.e. an IOMMU is not assumed to be
|
|
present). Device drivers are therefore not required to exhaustively
|
|
defend against incorrect or inconsistent values written by DMA-capable
|
|
hardware, since it is assumed that any such hardware could already
|
|
crash the system (or overwrite iPXE's code) without any further
|
|
assistance.
|
|
|
|
DMA-incapable hardware (such as USB devices) are on the edge of the
|
|
threat model. It is assumed that an attacker with physical access to
|
|
attach new hardware also has the ability to take full control of the
|
|
system anyway (e.g. by disabling UEFI Secure Boot). That said, USB
|
|
device drivers should generally guard against misbehaving USB or other
|
|
DMA-incapable hardware, since that hardware would not otherwise be
|
|
able to crash the system.
|
|
|
|
Under UEFI, other boot services code running on the same system is
|
|
similarly on the edge of the threat model. If UEFI Secure Boot is
|
|
enabled, then any other code running on the same system must itself be
|
|
part of a signed binary (or be part of the platform firmware), and so
|
|
is by definition already at least as privileged as iPXE itself. That
|
|
said, iPXE components that interact via UEFI protocols should be
|
|
written defensively, since experience shows that UEFI firmware code
|
|
quality is generally quite poor, especially in closed-source vendor
|
|
firmware that does not simply use the upstream EDK2 components.
|
|
|
|
Infiniband local networks are generally regarded as being within the
|
|
trust boundary, not least because iPXE includes support for remote DMA
|
|
access. (For this reason, Infiniband device drivers are excluded from
|
|
a Secure Boot build.)
|
|
|
|
iPXE generally transfers control to whatever payload it boots at the
|
|
same privilege level held by iPXE itself (i.e. ring 0 or equivalent).
|
|
There are therefore some classes of defect that are simply not
|
|
interesting. For example, a malformed NBI image could potentially be
|
|
able to exploit a bug in arch/x86/image/nbi.c, but this would be
|
|
utterly pointless since the exploit cannot do anything that a
|
|
well-formed NBI image could not do simply by allowing itself to be
|
|
executed.
|
|
|
|
@subsection notes Notes
|
|
|
|
There are several recurring patterns and helper functions used in iPXE
|
|
that any security reviewer should be familiar with:
|
|
|
|
- Dynamic memory allocation via malloc() (or any other allocator
|
|
such as realloc(), umalloc(), dma_alloc(), etc) is expected to be
|
|
safe against malicious parameters (such as excessive allocation
|
|
sizes), and all callers are expected to handle allocation failures
|
|
gracefully. The comments in core/malloc.c provide some of the
|
|
@ref malloc "internal details".
|
|
|
|
- Assertions via assert() are non-terminating and are no-ops in
|
|
production builds. See the documentation for @ref assert for more
|
|
details.
|
|
|
|
- Errors are generally expected to be caught (unless explicitly
|
|
ignored) and propagated to the caller. Error handling code should
|
|
use the @ref composable_errors "composable structured goto"
|
|
pattern where relevant.
|
|
|
|
- I/O buffers are used extensively to hold transmitted and received
|
|
packet data. The documentation for struct @ref io_buffer
|
|
describes the semantics and caveats for manipulating these
|
|
buffers safely.
|
|
|
|
- @ref xferbuf "Data transfer buffers" are often used to provide a
|
|
bounds-checking abstraction around long-term host storage. The
|
|
comments in core/xferbuf.c describe the semantics.
|
|
|
|
- ASN.1 parsing is handled by an extremely paranoid set of @ref
|
|
asn1parse "helper functions" that should be safe to use on any
|
|
untrusted input.
|
|
|
|
- The non-standard ssnprintf() variation of the standard snprintf()
|
|
C library function is often used to assemble content from a
|
|
sequence of formatted strings, in a way that is designed to be
|
|
safe against buffer size underflow. See the documentation for
|
|
@ref ssnprintf for more details.
|
|
|
|
*/
|