[settings] Fix limited out-of-bounds read in fetch_numeric_setting()
The code in fetch_numeric_setting() reads the setting value into a
local fixed-size buffer but then passes the full setting length to
numeric_setting_value(). If the setting length exceeds the size of
the fixed-size buffer, then numeric_setting_value() will continue to
read bytes from the stack.
The number of bytes read is constrained: numeric_setting_value() will
exit with -ERANGE as soon as the value being constructed exceeds the
range of an unsigned long. The existence of a return address on the
stack thus provides an upper bound on how far numeric_setting_value()
can read before terminating with an error.
Creating a setting with a length of more than an unsigned long is
trivial, for example:
set thing:hexraw 00000000000000000000000000000000
However, the out-of-bounds read can be reached only via calls to the
fetch_[u]int[z]_setting() family of internal helper functions.
Reading the setting in a script via e.g. ${thing:uint32} goes via a
different code path that does not use a fixed-length buffer.
The fetch_[u]int[z]_setting() functions are called from only a few
places. Most uses are for boolean flags or bit masks. A few are
genuinely used as numeric values: the settings mechanism itself reads
and uses the "priority" setting, the network core reads the "mtu"
setting, and the SAN boot mechanism reads the drive number and retry
count.
An extremely determined attacker could potentially obtain up to eight
bytes of information from the stack (in a 64-bit build) by, for
example, creating two sibling settings blocks where one has an
overlength "priority" setting value, and then repeatedly manipulating
the priority in the other settings block and testing to see which
block ends up with the higher priority. The information that could be
obtained in this way is limited to the temporary values stored on the
stack by fetch_numeric_setting() itself, along with its own return
address. None of this information is security-sensitive, and so any
information leakage is a mere curiosity.
Fix by allocating a temporary copy within fetch_numeric_setting()
instead of using a fixed-size buffer. This has the downside of
introducing an otherwise unnecessary memory allocation (which could
potentially itself fail), but guarantees consistency with other
numeric interpretations of setting values. (The alternative approach
of rejecting overlength setting values would introduce a potential
inconsistency between the value returned by fetch_numeric_setting()
and the value obtained by formatting a setting using a numeric setting
type, or by numerating the setting.)
Signed-off-by: Michael Brown <mcb30@ipxe.org>
iPXE is the leading open source network boot firmware. It provides a full PXE implementation enhanced with additional features such as:
boot from a web server via HTTP or HTTPS,
boot from an iSCSI, FCoE, or AoE SAN,
control the boot process with a script,
You can use iPXE to replace the existing PXE ROM on your network card, or you can chainload into iPXE to obtain the features of iPXE without the hassle of reflashing.
iPXE is free, open-source software licensed under the GNU GPL (with some portions under GPL-compatible licences).
You can download the rolling release binaries (built from the latest commit), or use the most recent stable release.
For full documentation, visit the iPXE website.