From nobody Wed Jul 22 11:50:11 2026 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4h4sy04Tjtz6m2Pf for ; Wed, 22 Jul 2026 11:50:16 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR1" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4h4sy03TjQz3PkL for ; Wed, 22 Jul 2026 11:50:16 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1784721016; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=W9+bx4drnviRj9xh9zLKUIDc+PUwhph73lvvmj4GQhA=; b=MsR/MKHGV7I+ys7XL32/VD/5rwANUfd5U7p9UPqchYq+ZblFcWSKscBT6tLA1nZbxxFhCB PcPusp33di6WRR6JDKOewpM2IOHrpqcEH6q4EB+uKSo91A7ndg2MvR2Co2uBEdKECcrM05 VSfP9aYyj+ip7Q2MsZoo61aE7wAO39DZY33K1CIjquAWuHjWd8gFKmXAj2/eiPcDi1Kixj xauVhaOCDh/0ISrOESkqaoZApR+TFFkmZEMXnUgmhDYSQkmJFfwqdUvRsmWJ3SsE3cVO33 rq8sE/NkEmo/RZ1iuee0EvQvr2fw88yMUddzSSL9UDdNZJcL2xtCe45/PztDzA== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1784721016; a=rsa-sha256; cv=none; b=uw1bC+b8phLayqj7jLt2y6j04sVazDkKyiBlH/J/su/a9KLZRDR8HtzoGG66mrBmMt+swF CYqfIKo0nw0JzBJL2Ax15IPw11qm02AeBd7e+oryXE+fZ0v39UvSluOPQxquWx9bvewFj3 bgmybsoyc+xd8z1TFtPf+n9HosqOV3DCB03mpLzzpG9yJR2YLSQZ9ae/AVVq1n3pYT+moD 7nXLCDfF9XqAcndt6H68sf6WxyNFMCbqjwE/JvSQ39nNmmarcWpp9YKgme7rQ2s1tDNUsV CU7nCMAynJLVzHWuT5l0j63JfUcQnpd/eA4RV1oTJOOr1IWbcQAM2sLY8qPJXg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1784721016; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=W9+bx4drnviRj9xh9zLKUIDc+PUwhph73lvvmj4GQhA=; b=PrgfXJ80tS1TbaLxl0wl6ilCwK5TfTvth06Lk05kLmbV1nYopclUbVY/ceHX+nUXmsxXBu wnyhPAMk5npAcRiXfUA05rsGIdLulLRlMl873vbY9l4sgn9r+5GV0kzXMJrQXtPFKcpMaM qLZUucrnDjsNFh0oIoH8ZAiTCbyQBBPR9EIruHuzf9G6tAS9k3VQbGcwi+uZI7Vabld/5H 4/xIPsqv82wC/B0npFuTmtp0uK5+BDbH/L7qsRFbGaFr/v5IpOKEluIBM9EOkAGyN61r21 CbYLP/pbq1e2bs6Goen2UrTzH3KI0yjvkIziIr7gRe+7KHYMfj7HSJKW6FP2Kw== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4h4sy02Xb7z2fp for ; Wed, 22 Jul 2026 11:50:16 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 3dcce by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Wed, 22 Jul 2026 11:50:11 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Bojan Novk=?utf-8?Q?ovi=C4=87?= Subject: git: 948ad32ae1e0 - main - bind(2): Lookup local address in current FIB if '*.bind_all_fibs' is active List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: bnovkov X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 948ad32ae1e0811f45e1d38f26636fefed5051f0 Auto-Submitted: auto-generated Date: Wed, 22 Jul 2026 11:50:11 +0000 Message-Id: <6a60ae73.3dcce.1e92e06d@gitrepo.freebsd.org> The branch main has been updated by bnovkov: URL: https://cgit.FreeBSD.org/src/commit/?id=948ad32ae1e0811f45e1d38f26636fefed5051f0 commit 948ad32ae1e0811f45e1d38f26636fefed5051f0 Author: Bojan Novković AuthorDate: 2026-07-15 13:47:01 +0000 Commit: Bojan Novković CommitDate: 2026-07-22 11:48:02 +0000 bind(2): Lookup local address in current FIB if '*.bind_all_fibs' is active When a protocol-specific 'bind_all_fibs' tunable is set to 0, a listening socket will only receive traffic originating from the FIB it was bound to. However, there are no checks to determine whether an address exists in the target FIB when binding the socket, which can lead to a situation where a socket and the address it was bound to belong to different FIBs. Prevent this footgun by looking up the requested address in the current FIB if 'bind_all_fibs' is active and returning an error if the address does not exist. Sponsored by: Stormshield Sponsored by: Klara, Inc. Differential Revision: https://reviews.freebsd.org/D58281 Reviewed by: glebius, pouria, markj MFC after: 2 weeks --- sys/netinet/in_pcb.c | 2 +- sys/netinet/raw_ip.c | 7 ++- sys/netinet6/in6_pcb.c | 2 +- sys/netinet6/raw_ip6.c | 7 ++- tests/sys/netinet/Makefile | 1 + tests/sys/netinet/fib_bind.py | 100 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 113 insertions(+), 6 deletions(-) diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index 8be91dc3eca2..365db895acda 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -925,7 +925,7 @@ in_pcbbind_avail(struct inpcb *inp, const struct in_addr laddr, * to any endpoint address, local or not. */ if ((inp->inp_flags & INP_BINDANY) == 0 && - ifa_ifwithaddr_check((const struct sockaddr *)&sin) == 0) + ifa_ifwithaddr_fib_check((const struct sockaddr *)&sin, fib) == 0) return (EADDRNOTAVAIL); } diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c index 67e798ccad54..45d974ff60f0 100644 --- a/sys/netinet/raw_ip.c +++ b/sys/netinet/raw_ip.c @@ -860,7 +860,7 @@ rip_bind(struct socket *so, struct sockaddr *nam, struct thread *td) { struct sockaddr_in *addr = (struct sockaddr_in *)nam; struct inpcb *inp; - int error; + int fib, error; if (nam->sa_family != AF_INET) return (EAFNOSUPPORT); @@ -874,11 +874,14 @@ rip_bind(struct socket *so, struct sockaddr *nam, struct thread *td) inp = sotoinpcb(so); KASSERT(inp != NULL, ("rip_bind: inp == NULL")); + fib = V_rip_bind_all_fibs == 0 ? inp->inp_inc.inc_fibnum : + RT_ALL_FIBS; + if (CK_STAILQ_EMPTY(&V_ifnet) || (addr->sin_family != AF_INET && addr->sin_family != AF_IMPLINK) || (addr->sin_addr.s_addr && (inp->inp_flags & INP_BINDANY) == 0 && - ifa_ifwithaddr_check((struct sockaddr *)addr) == 0)) + ifa_ifwithaddr_fib_check((struct sockaddr *)addr, fib) == 0)) return (EADDRNOTAVAIL); INP_WLOCK(inp); diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c index fc4cd3c9b1ad..3af4c0a14468 100644 --- a/sys/netinet6/in6_pcb.c +++ b/sys/netinet6/in6_pcb.c @@ -208,7 +208,7 @@ in6_pcbbind_avail(struct inpcb *inp, const struct sockaddr_in6 *sin6, int fib, sin6.sin6_addr = *laddr; NET_EPOCH_ENTER(et); - if ((ifa = ifa_ifwithaddr((const struct sockaddr *)&sin6)) == + if ((ifa = ifa_ifwithaddr_fib((const struct sockaddr *)&sin6, fib)) == NULL && (inp->inp_flags & INP_BINDANY) == 0) { NET_EPOCH_EXIT(et); return (EADDRNOTAVAIL); diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c index a92035831c6c..8c503f70af0f 100644 --- a/sys/netinet6/raw_ip6.c +++ b/sys/netinet6/raw_ip6.c @@ -743,7 +743,7 @@ rip6_bind(struct socket *so, struct sockaddr *nam, struct thread *td) struct inpcb *inp; struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam; struct ifaddr *ifa = NULL; - int error = 0; + int fib, error = 0; inp = sotoinpcb(so); KASSERT(inp != NULL, ("rip6_bind: inp == NULL")); @@ -759,9 +759,12 @@ rip6_bind(struct socket *so, struct sockaddr *nam, struct thread *td) if ((error = sa6_embedscope(addr, V_ip6_use_defzone)) != 0) return (error); + fib = V_rip_bind_all_fibs == 0 ? inp->inp_inc.inc_fibnum : + RT_ALL_FIBS; + NET_EPOCH_ENTER(et); if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) && - (ifa = ifa_ifwithaddr((struct sockaddr *)addr)) == NULL) { + (ifa = ifa_ifwithaddr_fib((struct sockaddr *)addr, fib)) == NULL) { NET_EPOCH_EXIT(et); return (EADDRNOTAVAIL); } diff --git a/tests/sys/netinet/Makefile b/tests/sys/netinet/Makefile index d5bfdad0a812..0812dc12a242 100644 --- a/tests/sys/netinet/Makefile +++ b/tests/sys/netinet/Makefile @@ -30,6 +30,7 @@ ATF_TESTS_SH= arp \ redirect ATF_TESTS_PYTEST+= carp.py \ + fib_bind.py \ igmp.py \ ip_mroute.py \ tcp_hpts_test.py diff --git a/tests/sys/netinet/fib_bind.py b/tests/sys/netinet/fib_bind.py new file mode 100644 index 000000000000..6768fcee5009 --- /dev/null +++ b/tests/sys/netinet/fib_bind.py @@ -0,0 +1,100 @@ +# +# Copyright (c) 2026 Stormshield +# +# SPDX-License-Identifier: BSD-2-Clause +# + +import pytest +import errno +import os +import socket +import struct +import sys +import logging + +from atf_python.sys.net.vnet import VnetTestTemplate +from atf_python.sys.net.tools import ToolsHelper + +def _common(tunable, addr, domain, type, proto): + """ + Test what happens when we try to bind a socket to an + address that is not present in the current FIB. + """ + sysctl_output = ToolsHelper.get_output(f"sysctl {tunable}") + tunable_val = int(sysctl_output.split(":")[1]) + if tunable_val != 0: + pytest.skip(f"{tunable} must be set to 0") + + port = 12345 if type != socket.SOCK_RAW else 0 + s = socket.socket(domain, type, proto) + s.setsockopt(socket.SOL_SOCKET, socket.SO_SETFIB, 0) + + failed = False + try: + s.bind((addr, port)) + except OSError as e: + assert e.errno == errno.EADDRNOTAVAIL + failed = True + assert failed + + s.setsockopt(socket.SOL_SOCKET, socket.SO_SETFIB, 1) + + failed = False + try: + s.bind((addr, port)) + except OSError: + failed = True + assert not failed + s.close() + +class TestFibBind(VnetTestTemplate): + REQUIRED_MODULES = [] + TOPOLOGY = { + "vnet1": { "ifaces": [ "if1", "if2" ] }, + "if1": { + "prefixes4": [("192.168.1.1/24", "192.168.1.2/24")], + "fib": (0, 0), + }, + "if2": { + "prefixes4": [("192.168.2.1/24", "192.168.2.2/24")], + "fib": (1, 0), + }, + } + + def setup_method(self, method): + super().setup_method(method) + + def test_TCP(self): + _common("net.inet.tcp.bind_all_fibs", "192.168.2.1", socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP) + + def test_UDP(self): + _common("net.inet.udp.bind_all_fibs", "192.168.2.1", socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) + + def test_RAW(self): + _common("net.inet.raw.bind_all_fibs", "192.168.2.1", socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_IP) + +class TestFibBind6(VnetTestTemplate): + REQUIRED_MODULES = [] + TOPOLOGY = { + "vnet1": { "ifaces": [ "if1", "if2" ] }, + "if1": { + "prefixes6": [("2001:db8:0:1::1/64", "2001:db8:0:1::2/64")], + "fib": (0, 0), + }, + "if2": { + "prefixes6": [("2001:db8:0:2::1/64", "2001:db8:0:2::2/64")], + "fib": (1, 0), + }, + } + + def setup_method(self, method): + super().setup_method(method) + + def test_TCP(self): + _common("net.inet.tcp.bind_all_fibs", "2001:db8:0:2::1", socket.AF_INET6, socket.SOCK_STREAM, socket.IPPROTO_TCP) + + def test_UDP(self): + _common("net.inet.udp.bind_all_fibs", "2001:db8:0:2::1", socket.AF_INET6, socket.SOCK_DGRAM, socket.IPPROTO_UDP) + + def test_RAW(self): + _common("net.inet.raw.bind_all_fibs", "2001:db8:0:2::1", socket.AF_INET6, socket.SOCK_RAW, socket.IPPROTO_IPV6)