Download raw body.
trunk_port_create() does not reject the trunk interface itself
>Synopsis: trunk_port_create() does not reject the trunk interface itself
as a port, unlike aggr_add_port(). "ifconfig trunkN trunkport
trunkN" succeeds and leaves the trunk in a corrupt self-enslaved
state (promiscuous, lladdr zeroed, listed as its own port).
>Category: kernel
>Severity: non-critical
>Priority: low
>Class: sw-bug
>Release: OpenBSD 8.0-current (snapshot, GENERIC.MP #125, 2026-11-02)
>Environment:
System : OpenBSD 8.0
Details : OpenBSD 8.0-current (GENERIC.MP) #125: Mon Nov 2
04:56:12 CST 2026
deraadt@amd64.openbsd.org:/usr/src/sys/arch/amd64/compile/GENERIC.MP
Architecture: OpenBSD.amd64
Machine : amd64 (QEMU/KVM guest, 2 vcpu)
>Description:
A freshly created trunk(4) is an IFT_ETHER interface (ether_ifattach()).
trunk_port_create() (sys/net/if_trunk.c) screens a candidate port with:
- tr_count >= TRUNK_MAX_PORTS (ENOSPC)
- trunk_port_get(NULL, ifp) (already a port of this trunk: EBUSY)
- if_type != IFT_ETHER (EPROTONOSUPPORT)
- ac_trport already set (already a trunk/aggr port: EBUSY)
- ether_brport_isset(ifp) (already a bridge/veb/tpmr port: EBUSY)
- stacking depth
but it never checks that the candidate is the trunk's *own* ifnet. The
trunk itself is IFT_ETHER, is not yet one of its own ports, and has no
ac_trport/brport set, so it passes every gate. Consequently:
ifconfig trunk100 trunkport trunk100
succeeds (rc 0). The trunk is put into promiscuous mode, its link-layer
address is zeroed, and it is recorded as its own member port
("trunkdev trunk100", flagged master,stack).
aggr(4) guards against exactly this in aggr_add_port():
if (ifp0->if_index == ifp->if_index) {
error = EINVAL;
...
trunk(4) has no equivalent self-check.
No crash was observed: bringing the self-enslaved trunk up, assigning an
address, removing the port with -trunkport, and destroying it all
completed without panic, hang or splassert on the test machine. The
defect is state corruption / robustness, not memory unsafety -- but the
configuration is nonsensical and should be refused, matching aggr(4).
The operation is available to root via ioctl(SIOCSTRUNKPORT); no special
hardware is involved.
>How-To-Repeat:
As root:
ifconfig trunk100 create
ifconfig trunk100 trunkport trunk100 # should fail, but succeeds
ifconfig trunk100 # shows trunk100 as its own
# port, PROMISC, lladdr 00:...:00
>Fix:
Reject the trunk's own ifnet in trunk_port_create(), mirroring
aggr_add_port(). trunk_port_create() already has the trunk softc "tr"
in hand; its ifnet is &tr->tr_ac.ac_if.
Index: sys/net/if_trunk.c
===================================================================
--- sys/net/if_trunk.c
+++ sys/net/if_trunk.c
@@ -283,6 +283,10 @@ trunk_port_create(struct trunk_softc *tr
if (tr->tr_count >= TRUNK_MAX_PORTS)
return (ENOSPC);
+ /* Reject the trunk being added to itself */
+ if (ifp == &tr->tr_ac.ac_if)
+ return (EINVAL);
+
/* Check if port has already been associated to a trunk */
if (trunk_port_get(NULL, ifp) != NULL)
return (EBUSY);
>Verification:
Built GENERIC.MP from -current with the diff applied and booted it
(OpenBSD 8.0-current GENERIC.MP #1, 2026-11-04) on an isolated amd64
KVM guest. On the stock #125 kernel the trunkport-self step succeeds;
on the patched kernel:
# ifconfig trunk100 trunkport trunk100
ifconfig: trunk100 trunk100: SIOCSTRUNKPORT: Invalid argument
# ifconfig trunk100
trunk100: flags=8802<BROADCAST,SIMPLEX,MULTICAST> mtu 1500
trunk: trunkproto roundrobin
groups: trunk
i.e. the self-enslave is refused with EINVAL and the trunk is left in a
clean state (not promiscuous, no self-port).
trunk_port_create() does not reject the trunk interface itself