Skip to content

boot: bootutil: bounds-check TLV length in tlv iterator#2733

Open
d3zd3z wants to merge 1 commit into
mcu-tools:mainfrom
d3zd3z:fix-tlv-overflow
Open

boot: bootutil: bounds-check TLV length in tlv iterator#2733
d3zd3z wants to merge 1 commit into
mcu-tools:mainfrom
d3zd3z:fix-tlv-overflow

Conversation

@d3zd3z
Copy link
Copy Markdown
Member

@d3zd3z d3zd3z commented May 14, 2026

Summary

Adds a bounds check to bootutil_tlv_iter_next() so that a TLV header and its payload are verified to lie fully within the TLV section before the iterator advances or hands an (off, len) pair to the caller.

tlv.it_len is a uint16_t read straight from flash and is attacker-controlled in a crafted image. Without this check, a bogus length advances it->tlv_off past it->tlv_end and yields an out-of-section (off, len) pair.

Severity / framing

This is a defense-in-depth / robustness fix, not a critical vulnerability:

  • Every current consumer in image_validate.c already validates len against a small fixed buffer before reading (hash, key, signature, security counter, UUID), so a bogus it_len does not currently cause a large out-of-bounds read or a buffer overflow.
  • An overshooting iterator previously just terminated the while (it->tlv_off < it->tlv_end) loop early; malformed TLVs cause validation to fail closed, not to be bypassed.

The value of the fix is that it makes the iterator self-contained and correct instead of relying on every current and future caller to sanity-check len, and it converts silent early-termination on a malformed image into an explicit error.

Behavioural change

Malformed TLV lengths now produce an explicit iteration error (-1) instead of silently truncating iteration. For valid images the check is a no-op.

The check

The three clauses short-circuit left-to-right so the uint32_t arithmetic can neither underflow nor wrap: clause 1 guards the subtraction in the later clauses, and clause 2 ensures sizeof(tlv) fits before clause 3 subtracts it.

Testing

Existing sim suite passes unchanged with sig-rsa, sig-ecdsa, and sig-ecdsa,swap-offset (25 tests each). The check is a no-op for any well-formed image, so no behavioural change is expected for valid images. No dedicated negative test is added: the prior behaviour was already fail-closed, so a crafted-image test would exercise a path whose observable outcome is unchanged.

`bootutil_tlv_iter_next()` reads a TLV header from flash and advances
`it->tlv_off` by `sizeof(tlv) + tlv.it_len` without checking that the
header and its payload actually lie within the TLV section.
`tlv.it_len` is a `uint16_t` taken straight from flash and is
attacker-controlled in a crafted image, so a bogus length could
advance the iterator past `it->tlv_end` and hand the caller an
`(off, len)` pair pointing outside the TLV section.

Every current consumer in `image_validate.c` already validates `len`
against a small fixed buffer before reading, so this is a
defense-in-depth / robustness fix rather than an exploitable
vulnerability. The check makes the iterator self-contained instead
of relying on every caller to sanity-check `len`, and converts silent
early termination on a malformed image into an explicit error.

Malformed TLV lengths now produce an explicit iteration error
instead of silently truncating iteration.

Assisted-By: Claude:opus-4.7
Signed-off-by: David Brown <david.brown@linaro.org>
Copilot AI review requested due to automatic review settings May 14, 2026 15:55
@d3zd3z d3zd3z requested a review from davidvincze as a code owner May 14, 2026 15:55
@d3zd3z d3zd3z requested review from de-nordic and nordicjm May 14, 2026 15:56
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds TLV iterator validation intended to reject malformed TLV entries whose payload would extend beyond the declared TLV section.

Changes:

  • Adds length/bounds validation in bootutil_tlv_iter_next().
  • Logs and returns an explicit iteration error for malformed TLV sizes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread boot/bootutil/src/tlv.c
Comment on lines +143 to +145
if (it->tlv_off > it->tlv_end ||
(uint32_t)sizeof(tlv) > it->tlv_end - it->tlv_off ||
tlv.it_len > it->tlv_end - it->tlv_off - (uint32_t)sizeof(tlv)) {
Comment thread boot/bootutil/src/tlv.c
Comment on lines +143 to +145
if (it->tlv_off > it->tlv_end ||
(uint32_t)sizeof(tlv) > it->tlv_end - it->tlv_off ||
tlv.it_len > it->tlv_end - it->tlv_off - (uint32_t)sizeof(tlv)) {
Comment thread boot/bootutil/src/tlv.c
Comment on lines +143 to +145
if (it->tlv_off > it->tlv_end ||
(uint32_t)sizeof(tlv) > it->tlv_end - it->tlv_off ||
tlv.it_len > it->tlv_end - it->tlv_off - (uint32_t)sizeof(tlv)) {
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants