public inbox for passt-dev@passt.top
 help / color / mirror / code / Atom feed
From: Stefano Brivio <sbrivio@redhat.com>
To: passt-dev@passt.top
Cc: David Gibson <david@gibson.dropbear.id.au>
Subject: [PATCH v2 2/4] dhcp: Make option parsing more robust, explicitly handle options 0 and 255
Date: Thu, 16 Jul 2026 09:22:20 +0200	[thread overview]
Message-ID: <20260716072222.1819811-3-sbrivio@redhat.com> (raw)
In-Reply-To: <20260716072222.1819811-1-sbrivio@redhat.com>

The initial option-scanning loop in dhcp(), so far, ignored options 0
(Pad Option, RFC 2132, Section 3.1) and 255 (End Option, RFC 2132,
Section 3.2).

As a result:

- if we ever encountered option 0 in the middle of option fields
  (never seen in practice), we would potentially terminate the loop
  too early, before scanning remaining options

- a malformed message with an option 255 followed by a length byte
  would (reliably) cause us to terminate as we would exceed the
  allocated size for the 'opts' array, which is detected as buffer
  overflow by the FORTIFY_SOURCE mechanism

The latter was reported as potential vulnerability by AISLE, but it's
not actually a vulnerability as we always terminate without carrying
on further handling, and in our security model the guest is able to
sabotage its own connectivity in any case (for example, a malformed
frame from the hypervisor would cause us to reset the connection, or
entirely flooding the flow table would cause inbound connectivity to
stop working, etc.).

The reported behaviour, however, is indeed a defect, as it affects
the functional robustness to a hypothetical issue in a DHCP client,
and that's something we definitely want to fix.

Make the option parsing loop more robust by:

- resizing 'opts' from 255 to 256 elements: there's no particular
  reason to try to save a tiny bit of memory (which shouldn't even
  be allocated in practice) instead of being defensive about it

- explicitly handle options 0 (skip one byte, continue) and 255 (stop
  processing options) in the option-scanning loop

- scanning the last two bytes of options as well and using
  iov_tail_size(data) directly as loop condition, instead of a rather
  inconsistent usage of opt_len

This bug was found and an initial version of the patch was written by
the AISLE AI security scanning tool (https://aisle.com/platform).

Reported-by: AISLE
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
---
v2:
  - Handle one-byte options before IOV_REMOVE_HEADER() for the length byte
  - Use iov_tail_size(data) as loop condition instead of mixing things up
    with opt_len

 dhcp.c | 22 +++++++++++++---------
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/dhcp.c b/dhcp.c
index 1ff8cba..c3c7422 100644
--- a/dhcp.c
+++ b/dhcp.c
@@ -49,7 +49,7 @@ struct opt {
 	uint8_t c[255];
 };
 
-static struct opt opts[255];
+static struct opt opts[256];
 
 #define DHCPDISCOVER	1
 #define DHCPOFFER	2
@@ -363,25 +363,29 @@ int dhcp(const struct ctx *c, struct iov_tail *data)
 	for (i = 0; i < ARRAY_SIZE(opts); i++)
 		opts[i].clen = -1;
 
-	opt_len = iov_tail_size(data);
-	while (opt_len >= 2) {
+	while ((opt_len = iov_tail_size(data))) {
 		uint8_t olen_storage, type_storage;
 		const uint8_t *olen;
 		uint8_t *type;
 
-		type = IOV_REMOVE_HEADER(data, type_storage);
-		olen = IOV_REMOVE_HEADER(data, olen_storage);
-		if (!type || !olen)
+		if (!(type = IOV_REMOVE_HEADER(data, type_storage)))
 			return -1;
 
-		opt_len = iov_tail_size(data);
-		if (opt_len < *olen)
+		if (*type == 255)
+			break;
+
+		if (*type == 0) /* Pad Option (RFC 2132, 3.1): one byte */
+			continue;
+
+		if (!(olen = IOV_REMOVE_HEADER(data, olen_storage)))
+			return -1;
+
+		if (opt_len - 2 < *olen)
 			return -1;
 
 		iov_to_buf(&data->iov[0], data->cnt, data->off, &opts[*type].c, *olen);
 		opts[*type].clen = *olen;
 		iov_drop_header(data, *olen);
-		opt_len -= *olen;
 	}
 
 	opts[80].slen = -1;
-- 
2.43.0


  parent reply	other threads:[~2026-07-16  7:22 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-16  7:22 [PATCH v2 0/4] Assorted fixes, address a static checker warning Stefano Brivio
2026-07-16  7:22 ` [PATCH v2 1/4] CONTRIBUTING.md: The tag is "Link:", regardless of how many we have Stefano Brivio
2026-07-16  7:22 ` Stefano Brivio [this message]
2026-07-16  7:30   ` [PATCH v2 2/4] dhcp: Make option parsing more robust, explicitly handle options 0 and 255 David Gibson
2026-07-16  7:22 ` [PATCH v2 3/4] passt.1, pesto.1: ::1 is an address, not a port Stefano Brivio
2026-07-16  7:22 ` [PATCH v2 4/4] ndp: Use high quality entropy in NDP timer even if not needed Stefano Brivio
2026-07-16  7:34   ` David Gibson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260716072222.1819811-3-sbrivio@redhat.com \
    --to=sbrivio@redhat.com \
    --cc=david@gibson.dropbear.id.au \
    --cc=passt-dev@passt.top \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://passt.top/passt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for IMAP folder(s).