From: Tom Smyth Subject: trunk_port_create() does not reject the trunk interface itself To: tech Date: Wed, 4 Nov 2026 00:37:14 +0000 >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 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).