Skip to content

bfdd: --dplaneaddr unixc: client mode always fails with EINVAL (connect addrlen exceeds sizeof(sockaddr_un)) #22608

Description

@w453y

Description

bfdd's distributed-BFD client mode over a unix socket (--dplaneaddr unixc:<path>) never establishes a connection. Every connect attempt fails with EINVAL and retries every 3 seconds. The TCP transports (ipv4c:/ipv6c:) work fine.

Root cause: bfd_dplane_client_init() in bfdd/dplane.c discards the caller's salen and stores the size of the address union instead:

if (salen <= sizeof(bdc->addr)) {
        memcpy(&bdc->addr, sa, salen);
        bdc->addrlen = sizeof(bdc->addr);   /* should be salen */

bdc->addr is a union of sockaddr / sockaddr_in / sockaddr_in6 / sockaddr_un. sizeof(struct sockaddr_un) is 110, but the union is padded to 112 by sockaddr_in6 alignment. bfd_dplane_client_connect() then calls connect() with addrlen=112, and the kernel's AF_UNIX address validation (unix_validate_addr() in net/unix/af_unix.c) rejects any addrlen greater than sizeof(struct sockaddr_un) with -EINVAL. Inet sockets tolerate oversized addrlen, which is why only the unix transport is affected.

git log -S addrlen -- bfdd/dplane.c shows this logic is unchanged since client mode was introduced (6655b43, "bfdd: support connecting to BFD data plane"), and the code is identical on current master — so unixc: appears to have never worked on Linux.

The fix is one line (verified locally, see Additional context):

memcpy(&bdc->addr, sa, salen);
bdc->addrlen = salen;

with the truncation branch keeping sizeof(bdc->addr) as today. Happy to send a PR.

Version

w453y@bfd-dut:~/xdp-bfd$ sudo vtysh -c "show version"                   FRRouting 10.5.1 (bfd-dut) on Linux(7.0.0-27-generic).                  Copyright 1996-2005 Kunihiro Ishiguro, et al.                           configured with:
    '--build=x86_64-linux-gnu' '--prefix=/usr' '--includedir=${prefix}/include' '--mandir=${prefix}/share/man' '--infodir=${prefix}/share/info' '--sysconfdir=/etc' '--localstatedir=/var' '--disable-option-checking' '--disable-silent-rules' '--libdir=${prefix}/lib/x86_64-linux-gnu' '--runstatedir=/run' '--disable-maintainer-mode' '--sbindir=/usr/lib/frr' '--with-vtysh-pager=/usr/bin/pager' '--libdir=/usr/lib/x86_64-linux-gnu/frr' '--with-moduledir=/usr/lib/x86_64-linux-gnu/frr/modules' '--disable-dependency-tracking' '--enable-rpki' '--enable-scripting' '--enable-pim6d' '--with-libpam' '--enable-doc' '--enable-doc-html' '--enable-snmp' '--enable-fpm' '--disable-protobuf' '--disable-zeromq' '--enable-ospfapi' '--enable-bgp-vnc' '--enable-multipath=256' '--enable-user=frr' '--enable-group=frr' '--enable-vty-group=frrvty' '--enable-configfile-mask=0640' '--enable-logfile-mask=0640' 'build_alias=x86_64-linux-gnu' 'LIBS= -latomic' 'PYTHON=python3'
w453y@bfd-dut:~/xdp-bfd$

Distro package: Ubuntu 26.04, frr 10.5.1-1ubuntu4.1 (Ubuntu's configure flags). Kernel 7.0.0-27-generic, x86_64.

Not yet tested against a build of current master, but the relevant code in bfdd/dplane.c is byte-identical on master (checked at commit 4c4f48295a), so the behavior is expected to be identical.

How to reproduce

Single host, no BFD peers needed — the failure is the local dataplane socket connection itself.

  1. Start any unix-socket listener:

    socat UNIX-LISTEN:/tmp/frr-repro.sock,fork,mode=777 -
    
  2. Start bfdd in dataplane client mode, e.g. in /etc/frr/daemons:

    bfdd_options="  --daemon -A 127.0.0.1 --dplaneaddr unixc:/tmp/frr-repro.sock"
    

    then: systemctl restart frr

  3. Observe: journalctl -u frr | grep dplane, and/or strace -f -e trace=connect -p $(pidof bfdd)

Expected behavior

bfdd connects to the unix-socket dataplane listener, the same way it successfully connects with the TCP transport (ipv4c:).

Actual behavior

The connection never establishes; bfdd retries every 3 seconds:

bfdd[13438]: [K880F-QRW5M] bfd_dplane_client_connect: data plane connection failed: Invalid argument

strace shows the oversized address length being passed to connect(2):

connect(16, {sa_family=AF_UNIX, sun_path="/tmp/frr-repro.sock"}, 112) = -1 EINVAL (Invalid argument)

Size check compiled on the same system (x86_64, glibc):

sizeof(sockaddr_un)  = 110
sizeof(sockaddr_in6) = 28
sizeof(union addr)   = 112

Additional context

Fix verified locally: rebuilt bfdd from the 10.5.1 source with only the one-line change (bdc->addrlen = salen; in the non-truncating branch of bfd_dplane_client_init) and it successfully connects to the same unix-socket listener that stock bfdd fails against with EINVAL.

Found while building an external BFD dataplane against the bfddp protocol (https://github.com/w453y/xdp-bfd). The ipv4c: transport works end-to-end with unmodified bfdd, so this is purely the unix client path.

Checklist

  • I have searched the open issues for this bug.
  • I have not included sensitive information in this report.

Metadata

Metadata

Assignees

No one assigned

    Labels

    triageNeeds further investigation

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions