Index | Thread | Search

From:
Tom Smyth <tom.smyth@wirelessconnect.eu>
Subject:
trunk_port_create() does not reject the trunk interface itself
To:
tech <tech@openbsd.org>
Date:
Wed, 4 Nov 2026 00:37:14 +0000

Download raw body.

Thread
  • Tom Smyth:

    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).