git: 8209af15a699 - stable/14 - udp: fix sending of IPv4-mapped addresses

From: Michael Tuexen <tuexen_at_FreeBSD.org>
Date: Fri, 13 Oct 2023 20:16:42 UTC
The branch stable/14 has been updated by tuexen:

URL: https://cgit.FreeBSD.org/src/commit/?id=8209af15a6994d52276be05380e0c0b7ae117cea

commit 8209af15a6994d52276be05380e0c0b7ae117cea
Author:     Michael Tuexen <tuexen@FreeBSD.org>
AuthorDate: 2023-10-07 13:56:00 +0000
Commit:     Michael Tuexen <tuexen@FreeBSD.org>
CommitDate: 2023-10-13 20:13:44 +0000

    udp: fix sending of IPv4-mapped addresses
    
    The inp_vflags field must be adjusted during the call of
    in_pcbbind_setup(). This is consistent with the other places in the
    code, but not elegant at all.
    
    PR:                     274009
    Reported by:            syzbot+81ccc423a2737ed031ac@syzkaller.appspotmail.com
    Reported by:            syzbot+c8e3dac881bba85bc029@syzkaller.appspotmail.com
    Reviewed by:            markj, rrs, rscheff
    Sponsored by:           Netflix, Inc.
    Differential Revision:  https://reviews.freebsd.org/D42031
    
    (cherry picked from commit abca3ae7734f664ee9c5edc7a9d3a17e29180bdb)
---
 sys/netinet/udp_usrreq.c | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c
index 70d738bf2108..cbda7f536262 100644
--- a/sys/netinet/udp_usrreq.c
+++ b/sys/netinet/udp_usrreq.c
@@ -1050,7 +1050,7 @@ udp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
 	int cscov_partial = 0;
 	int ipflags = 0;
 	u_short fport, lport;
-	u_char tos;
+	u_char tos, vflagsav;
 	uint8_t pr;
 	uint16_t cscov = 0;
 	uint32_t flowid = 0;
@@ -1092,7 +1092,8 @@ udp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
 	 * pcb hash.
 	 */
 	if (sin == NULL ||
-	    (inp->inp_laddr.s_addr == INADDR_ANY && inp->inp_lport == 0))
+	    (inp->inp_laddr.s_addr == INADDR_ANY && inp->inp_lport == 0) ||
+	    (flags & PRUS_IPV6) != 0)
 		INP_WLOCK(inp);
 	else
 		INP_RLOCK(inp);
@@ -1203,10 +1204,17 @@ udp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
 			error = EINVAL;
 			goto release;
 		}
+		if ((flags & PRUS_IPV6) != 0) {
+			vflagsav = inp->inp_vflag;
+			inp->inp_vflag |= INP_IPV4;
+			inp->inp_vflag &= ~INP_IPV6;
+		}
 		INP_HASH_WLOCK(pcbinfo);
 		error = in_pcbbind_setup(inp, &src, &laddr.s_addr, &lport,
 		    td->td_ucred);
 		INP_HASH_WUNLOCK(pcbinfo);
+		if ((flags & PRUS_IPV6) != 0)
+			inp->inp_vflag = vflagsav;
 		if (error)
 			goto release;
 	}
@@ -1249,9 +1257,16 @@ udp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
 		    inp->inp_lport == 0 ||
 		    sin->sin_addr.s_addr == INADDR_ANY ||
 		    sin->sin_addr.s_addr == INADDR_BROADCAST) {
+			if ((flags & PRUS_IPV6) != 0) {
+				vflagsav = inp->inp_vflag;
+				inp->inp_vflag |= INP_IPV4;
+				inp->inp_vflag &= ~INP_IPV6;
+			}
 			INP_HASH_WLOCK(pcbinfo);
 			error = in_pcbconnect_setup(inp, sin, &laddr.s_addr,
 			    &lport, &faddr.s_addr, &fport, td->td_ucred);
+			if ((flags & PRUS_IPV6) != 0)
+				inp->inp_vflag = vflagsav;
 			if (error) {
 				INP_HASH_WUNLOCK(pcbinfo);
 				goto release;