| /** @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. |
| |
| */ |