Date: Sun, 12 Apr 2026 18:35:42 +0000 From: Gleb Smirnoff <glebius@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: git: edece33b38eb - main - inpcb: move local address assignment out of in_pcbdisconnect() Message-ID: <69dbe5fe.3a555.54922024@gitrepo.freebsd.org>
index | next in thread | raw e-mail
The branch main has been updated by glebius: URL: https://cgit.FreeBSD.org/src/commit/?id=edece33b38ebcba46bd4d81382ebdb5a634a0c6d commit edece33b38ebcba46bd4d81382ebdb5a634a0c6d Author: Gleb Smirnoff <glebius@FreeBSD.org> AuthorDate: 2026-04-12 18:34:57 +0000 Commit: Gleb Smirnoff <glebius@FreeBSD.org> CommitDate: 2026-04-12 18:34:57 +0000 inpcb: move local address assignment out of in_pcbdisconnect() The logic of clearing local address at the protocol level makes sense. It is feature of UDP, not of any protocol, that local address is cleared on disconnect. This code can be tracked down to pre-FreeBSD times. For example, for TCP we want a disconnected socket to return previously used local address with getsockname(2). The TCP has successfully evaded that by not calling in_pcbdisconnect() and calling in_pcbdetach() in the very old code and in_pcbdrop() later. After D55661 TCP again has this potential bug masked. Better make it right than rely on such unintentional evasions. The raw IP sockets don't use in_pcbdisconnect(), but they are going to in the near future. If in_pcbdisconnect() clears local address for them, that would be a larger bug than just getsockname(). A raw socket may be bound with bind(2) and then connect(2)ed, and then disconnected, e.g. connect(INADDR_ANY). And when we run raw IP socket through in_pcbdisconnect() we don't want to lose local address. This reverts D38362. This reverts commit 2589ec0f365777faacf36bd1eb24706538836b17. Reviewed by: rrs, markj Differential Revision: https://reviews.freebsd.org/D56170 --- sys/netinet/in_pcb.c | 1 - sys/netinet/udp_usrreq.c | 3 +++ sys/netinet6/in6_pcb.c | 1 - sys/netinet6/udp6_usrreq.c | 3 +++ 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index 29214fbd2cf6..7b294e0a92d5 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -1465,7 +1465,6 @@ in_pcbdisconnect(struct inpcb *inp) if ((inp->inp_socket->so_proto->pr_flags & PR_CONNREQUIRED) == 0) { /* See the comment in in_pcbinshash(). */ inp->inp_smr = smr_advance(inp->inp_pcbinfo->ipi_smr); - inp->inp_laddr.s_addr = INADDR_ANY; inp->inp_faddr.s_addr = INADDR_ANY; inp->inp_fport = 0; } diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index b973b299ca56..23b0ca684b09 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -1528,6 +1528,7 @@ udp_abort(struct socket *so) INP_WLOCK(inp); if (inp->inp_faddr.s_addr != INADDR_ANY) { in_pcbdisconnect(inp); + inp->inp_laddr.s_addr = INADDR_ANY; soisdisconnected(so); } INP_WUNLOCK(inp); @@ -1630,6 +1631,7 @@ udp_close(struct socket *so) INP_WLOCK(inp); if (inp->inp_faddr.s_addr != INADDR_ANY) { in_pcbdisconnect(inp); + inp->inp_laddr.s_addr = INADDR_ANY; soisdisconnected(so); } INP_WUNLOCK(inp); @@ -1697,6 +1699,7 @@ udp_disconnect(struct socket *so) return (ENOTCONN); } in_pcbdisconnect(inp); + inp->inp_laddr.s_addr = INADDR_ANY; SOCK_LOCK(so); so->so_state &= ~SS_ISCONNECTED; /* XXX */ SOCK_UNLOCK(so); diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c index 136f5c8a9828..ad596cf761d2 100644 --- a/sys/netinet6/in6_pcb.c +++ b/sys/netinet6/in6_pcb.c @@ -542,7 +542,6 @@ in6_pcbdisconnect(struct inpcb *inp) /* See the comment in in_pcbinshash(). */ inp->inp_smr = smr_advance(inp->inp_pcbinfo->ipi_smr); /* XXX-MJ torn writes are visible to SMR lookup */ - memset(&inp->in6p_laddr, 0, sizeof(inp->in6p_laddr)); memset(&inp->in6p_faddr, 0, sizeof(inp->in6p_faddr)); inp->inp_fport = 0; } diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c index 3f4c3111fa5b..ede791a7d175 100644 --- a/sys/netinet6/udp6_usrreq.c +++ b/sys/netinet6/udp6_usrreq.c @@ -996,6 +996,7 @@ udp6_abort(struct socket *so) if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { in6_pcbdisconnect(inp); + memset(&inp->in6p_laddr, 0, sizeof(inp->in6p_laddr)); soisdisconnected(so); } INP_WUNLOCK(inp); @@ -1105,6 +1106,7 @@ udp6_close(struct socket *so) #endif if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { in6_pcbdisconnect(inp); + memset(&inp->in6p_laddr, 0, sizeof(inp->in6p_laddr)); soisdisconnected(so); } INP_WUNLOCK(inp); @@ -1239,6 +1241,7 @@ udp6_disconnect(struct socket *so) } in6_pcbdisconnect(inp); + memset(&inp->in6p_laddr, 0, sizeof(inp->in6p_laddr)); SOCK_LOCK(so); so->so_state &= ~SS_ISCONNECTED; /* XXX */ SOCK_UNLOCK(so);home | help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?69dbe5fe.3a555.54922024>
