<feed xmlns='http://www.w3.org/2005/Atom'>
<title>passt/dhcp.c, branch 2026_07_16.090d739</title>
<subtitle>Plug A Simple Socket Transport</subtitle>
<link rel='alternate' type='text/html' href='https://passt.top/passt/'/>
<entry>
<title>dhcp: Make option parsing more robust, explicitly handle options 0 and 255</title>
<updated>2026-07-16T08:46:22+00:00</updated>
<author>
<name>Stefano Brivio</name>
<email>sbrivio@redhat.com</email>
</author>
<published>2026-07-15T22:56:23+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=7d0c07728813880d6049abb3dc33dcaf8154ff66'/>
<id>7d0c07728813880d6049abb3dc33dcaf8154ff66</id>
<content type='text'>
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 &lt;sbrivio@redhat.com&gt;
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
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 &lt;sbrivio@redhat.com&gt;
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>treewide: Don't rely on terminator records in ip[46].dns arrays</title>
<updated>2026-01-10T18:27:45+00:00</updated>
<author>
<name>David Gibson</name>
<email>david@gibson.dropbear.id.au</email>
</author>
<published>2026-01-07T01:46:04+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=accc33148e0aab5597b7f409f8e97f8985c1828a'/>
<id>accc33148e0aab5597b7f409f8e97f8985c1828a</id>
<content type='text'>
In our arrays of DNS resolvers to pass to the guest we use a blank entry
to indicate the end of the list.  We rely on this when scanning the array,
not having separate bounds checking.  clang-tidy 21.1.7 has fancier
checking for array overruns in loops, but it's not able to reason that
there's always a terminating entry, so complains.

Indeed, it's correct to do so in this case.  Although we allow space in the
arrays for the terminator (size MAXNS + 1), add_dns[46]() check only for
    idx &gt;= ARRAY_SIZE()
before adding an entry.  This allows it to consume the last slot with a
"real" entry, meaning the places where we scan really could overrun.

Fix the bug, and make it easier to reason about (for both clang-tidy and
people) by using ARRAY_SIZE() base bounds checking.  Treat the terminator
explicitly as an early exit case using 'break'.

Signed-off-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Reviewed-by: Laurent Vivier &lt;lvivier@redhat.com&gt;
[sbrivio: Fix up comments to @dns in structs ip4_ctx and ip6_ctx]
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
In our arrays of DNS resolvers to pass to the guest we use a blank entry
to indicate the end of the list.  We rely on this when scanning the array,
not having separate bounds checking.  clang-tidy 21.1.7 has fancier
checking for array overruns in loops, but it's not able to reason that
there's always a terminating entry, so complains.

Indeed, it's correct to do so in this case.  Although we allow space in the
arrays for the terminator (size MAXNS + 1), add_dns[46]() check only for
    idx &gt;= ARRAY_SIZE()
before adding an entry.  This allows it to consume the last slot with a
"real" entry, meaning the places where we scan really could overrun.

Fix the bug, and make it easier to reason about (for both clang-tidy and
people) by using ARRAY_SIZE() base bounds checking.  Treat the terminator
explicitly as an early exit case using 'break'.

Signed-off-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Reviewed-by: Laurent Vivier &lt;lvivier@redhat.com&gt;
[sbrivio: Fix up comments to @dns in structs ip4_ctx and ip6_ctx]
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>dhcp: Fix coding style violations in dhcp() function</title>
<updated>2025-09-18T15:11:36+00:00</updated>
<author>
<name>Laurent Vivier</name>
<email>lvivier@redhat.com</email>
</author>
<published>2025-09-17T06:41:42+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=6f23cb9fdb59a8369780c19a06c0739e1c2c8c09'/>
<id>6f23cb9fdb59a8369780c19a06c0739e1c2c8c09</id>
<content type='text'>
The dhcp() function wasn't following the inverted Christmas tree
variable declaration ordering convention.

Signed-off-by: Laurent Vivier &lt;lvivier@redhat.com&gt;
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The dhcp() function wasn't following the inverted Christmas tree
variable declaration ordering convention.

Signed-off-by: Laurent Vivier &lt;lvivier@redhat.com&gt;
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>dhcp: use iov_tail rather than pool</title>
<updated>2025-09-03T18:43:39+00:00</updated>
<author>
<name>Laurent Vivier</name>
<email>lvivier@redhat.com</email>
</author>
<published>2025-09-02T07:52:46+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=3a261fdeb62a14823b8ff42c3dea8439de30befe'/>
<id>3a261fdeb62a14823b8ff42c3dea8439de30befe</id>
<content type='text'>
This patch refactors the dhcp() function to accept `struct iov_tail *data`
directly as its packet input, replacing the previous `const struct pool *p`
parameter. Consequently, dhcp() no longer fetches packet data internally
using packet_data().

This change simplifies callers, such as tap4_handler(), which now pass
the iov_tail representing the L2 frame directly to dhcp(). This removes
the need for intermediate packet pool handling for DHCP processing.

Signed-off-by: Laurent Vivier &lt;lvivier@redhat.com&gt;
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
This patch refactors the dhcp() function to accept `struct iov_tail *data`
directly as its packet input, replacing the previous `const struct pool *p`
parameter. Consequently, dhcp() no longer fetches packet data internally
using packet_data().

This change simplifies callers, such as tap4_handler(), which now pass
the iov_tail representing the L2 frame directly to dhcp(). This removes
the need for intermediate packet pool handling for DHCP processing.

Signed-off-by: Laurent Vivier &lt;lvivier@redhat.com&gt;
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>packet: rename packet_data() to packet_get()</title>
<updated>2025-09-03T18:43:35+00:00</updated>
<author>
<name>Laurent Vivier</name>
<email>lvivier@redhat.com</email>
</author>
<published>2025-09-02T07:52:44+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=7e2535163a846077617c880721b511fd83f0f8b8'/>
<id>7e2535163a846077617c880721b511fd83f0f8b8</id>
<content type='text'>
As we have removed packet_get(), we can rename packet_data() to packet_get()
as the name is clearer.

Signed-off-by: Laurent Vivier &lt;lvivier@redhat.com&gt;
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
As we have removed packet_get(), we can rename packet_data() to packet_get()
as the name is clearer.

Signed-off-by: Laurent Vivier &lt;lvivier@redhat.com&gt;
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>dhcp: Convert to iov_tail</title>
<updated>2025-09-03T18:43:28+00:00</updated>
<author>
<name>Laurent Vivier</name>
<email>lvivier@redhat.com</email>
</author>
<published>2025-09-02T07:52:40+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=84a4d3e9dcd733f0c59881ca94ec761c1b64671e'/>
<id>84a4d3e9dcd733f0c59881ca94ec761c1b64671e</id>
<content type='text'>
Use packet_data() and extract headers using IOV_REMOVE_HEADER()
and IOV_PEEK_HEADER() rather than packet_get().

Signed-off-by: Laurent Vivier &lt;lvivier@redhat.com&gt;
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Use packet_data() and extract headers using IOV_REMOVE_HEADER()
and IOV_PEEK_HEADER() rather than packet_get().

Signed-off-by: Laurent Vivier &lt;lvivier@redhat.com&gt;
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>dhcp: Add option code byte in calculation for OPT_MAX boundary check</title>
<updated>2025-02-19T22:33:19+00:00</updated>
<author>
<name>Stefano Brivio</name>
<email>sbrivio@redhat.com</email>
</author>
<published>2025-02-18T08:42:28+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=16553c82806e0a55508baf553cb79e902638c10f'/>
<id>16553c82806e0a55508baf553cb79e902638c10f</id>
<content type='text'>
Otherwise we'll limit messages to 577 bytes, instead of 576 bytes as
intended:

  $ fqdn="thirtytwocharactersforeachlabel.thirtytwocharactersforeachlabel.thirtytwocharactersforeachlabel.thirtytwocharactersforeachlabel.thirtytwocharactersforeachlabel.thirtytwocharactersforeachlabel.thirtytwocharactersforeachlabel.then_make_it_251_with_this"
  $ hostname="__eighteen_bytes__"
  $ ./pasta --fqdn ${fqdn} -H ${hostname} -p dhcp.pcap -- /sbin/dhclient -4
  Saving packet capture to dhcp.pcap
  $ tshark -r dhcp.pcap -V -Y 'dhcp.option.value == 5' | grep "Total Length"
      Total Length: 577

This was hidden by the issue fixed by commit bcc4908c2b4a ("dhcp
Remove option 255 length byte") until now.

Fixes: 31e8109a86ee ("dhcp, dhcpv6: Add hostname and client fqdn ops")
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Reviewed-by: Enrique Llorente &lt;ellorent@redhat.com&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Otherwise we'll limit messages to 577 bytes, instead of 576 bytes as
intended:

  $ fqdn="thirtytwocharactersforeachlabel.thirtytwocharactersforeachlabel.thirtytwocharactersforeachlabel.thirtytwocharactersforeachlabel.thirtytwocharactersforeachlabel.thirtytwocharactersforeachlabel.thirtytwocharactersforeachlabel.then_make_it_251_with_this"
  $ hostname="__eighteen_bytes__"
  $ ./pasta --fqdn ${fqdn} -H ${hostname} -p dhcp.pcap -- /sbin/dhclient -4
  Saving packet capture to dhcp.pcap
  $ tshark -r dhcp.pcap -V -Y 'dhcp.option.value == 5' | grep "Total Length"
      Total Length: 577

This was hidden by the issue fixed by commit bcc4908c2b4a ("dhcp
Remove option 255 length byte") until now.

Fixes: 31e8109a86ee ("dhcp, dhcpv6: Add hostname and client fqdn ops")
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Reviewed-by: Enrique Llorente &lt;ellorent@redhat.com&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>conf: Use 0 instead of -1 as "unassigned" mtu value</title>
<updated>2025-02-19T05:35:41+00:00</updated>
<author>
<name>David Gibson</name>
<email>david@gibson.dropbear.id.au</email>
</author>
<published>2025-02-19T03:14:28+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=1cc5d4c9fe0a84d3d39fc07358996989ca1b5875'/>
<id>1cc5d4c9fe0a84d3d39fc07358996989ca1b5875</id>
<content type='text'>
On the command line -m 0 means "don't assign an MTU" (letting the guest use
its default.  However, internally we use (c-&gt;mtu == -1) to represent that
state.  We use (c-&gt;mtu == 0) to represent "the user didn't specify on the
command line, so use the default" - but this is only used during conf(),
never afterwards.

This is unnecessarily confusing.  We can instead just initialise c-&gt;mtu to
its default (65520) before parsing options and use 0 on both the command
line and internally to represent the "don't assign" special case.  This
ensures that c-&gt;mtu is always 0..65535, so we can store it in a uint16_t
which is more natural.

Signed-off-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
On the command line -m 0 means "don't assign an MTU" (letting the guest use
its default.  However, internally we use (c-&gt;mtu == -1) to represent that
state.  We use (c-&gt;mtu == 0) to represent "the user didn't specify on the
command line, so use the default" - but this is only used during conf(),
never afterwards.

This is unnecessarily confusing.  We can instead just initialise c-&gt;mtu to
its default (65520) before parsing options and use 0 on both the command
line and internally to represent the "don't assign" special case.  This
ensures that c-&gt;mtu is always 0..65535, so we can store it in a uint16_t
which is more natural.

Signed-off-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>dhcp: Remove option 255 length byte</title>
<updated>2025-02-18T07:42:35+00:00</updated>
<author>
<name>Enrique Llorente</name>
<email>ellorent@redhat.com</email>
</author>
<published>2025-02-17T09:28:14+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=bcc4908c2b4a20c581f2b03fed40da97b804106f'/>
<id>bcc4908c2b4a20c581f2b03fed40da97b804106f</id>
<content type='text'>
The option 255 (end of options) do not need the length byte, this change
remove that allowing to have one extra byte at other dynamic options.

Signed-off-by: Enrique Llorente &lt;ellorent@redhat.com&gt;
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The option 255 (end of options) do not need the length byte, this change
remove that allowing to have one extra byte at other dynamic options.

Signed-off-by: Enrique Llorente &lt;ellorent@redhat.com&gt;
Reviewed-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>dhcp, dhcpv6: Add hostname and client fqdn ops</title>
<updated>2025-02-10T17:30:24+00:00</updated>
<author>
<name>Enrique Llorente</name>
<email>ellorent@redhat.com</email>
</author>
<published>2025-02-07T11:36:55+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=31e8109a86eeebb473ffba8124a3f399cf0aeccf'/>
<id>31e8109a86eeebb473ffba8124a3f399cf0aeccf</id>
<content type='text'>
Both DHCPv4 and DHCPv6 has the capability to pass the hostname to
clients, the DHCPv4 uses option 12 (hostname) while the DHCPv6 uses option 39
(client fqdn), for some virt deployments like kubevirt is expected to
have the VirtualMachine name as the guest hostname.

This change add the following arguments:
 - -H --hostname NAME to configure the hostname DHCPv4 option(12)
 - --fqdn NAME to configure client fqdn option for both DHCPv4(81) and
   DHCPv6(39)

Signed-off-by: Enrique Llorente &lt;ellorent@redhat.com&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Both DHCPv4 and DHCPv6 has the capability to pass the hostname to
clients, the DHCPv4 uses option 12 (hostname) while the DHCPv6 uses option 39
(client fqdn), for some virt deployments like kubevirt is expected to
have the VirtualMachine name as the guest hostname.

This change add the following arguments:
 - -H --hostname NAME to configure the hostname DHCPv4 option(12)
 - --fqdn NAME to configure client fqdn option for both DHCPv4(81) and
   DHCPv6(39)

Signed-off-by: Enrique Llorente &lt;ellorent@redhat.com&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</pre>
</div>
</content>
</entry>
</feed>
