diff options
| author | Bruce M Simpson <bms@FreeBSD.org> | 2026-08-02 13:09:57 +0000 |
|---|---|---|
| committer | Bruce M Simpson <bms@FreeBSD.org> | 2026-08-03 15:47:24 +0000 |
| commit | 459af94e43b0fe2ef91e14aa867c3b1aa1fb9690 (patch) | |
| tree | afac17b8764f680f01da290305f711b0ac10366c | |
| parent | c8d4287e30d6dc2ed3d4378133758adabc0030a3 (diff) | |
netinet6: Fix some issues with passing v4-mapped groups to IPv6 sockets.
1. EFAULT was happening because sooptcopyin() from inp_join_group() was
seeing the user-space thread descriptor in the faked-up sockopt. So, do
not attempt a user copyin(); defer to C99 initialization nulling sopt_td
for us to force a KVA memcpy().
2. It seems necessary to byte-swap ipv6mr_multiaddr.s6_addr32[3] on amd64
for similar reasons as to how the user-space initialization needed for
passing an IPv4-mapped group address also requires byte-swapping of the
0x0000FFFF field for s6_addr32[2]; it is a direct assignment to a integer
member of a struct, NOT a memcpy().
3. The assignment to imr_interface within in6_v6_mreq_to_v4() was obfuscated
by a cast back to its own type due to use of the IA_SIN() macro. Elided.
With this change, the feature gap seems to be closed; tested with a simple
link-scope IPv4 group under 224.0.0.0/24 with an mlx5(4) SR-IOV VF in bhyve.
PR: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=193246
Differential Revision: https://reviews.freebsd.org/D58590
| -rw-r--r-- | sys/netinet6/in6_mcast.c | 12 |
1 files changed, 5 insertions, 7 deletions
diff --git a/sys/netinet6/in6_mcast.c b/sys/netinet6/in6_mcast.c index bc7da2d14a04..036d58e5bd92 100644 --- a/sys/netinet6/in6_mcast.c +++ b/sys/netinet6/in6_mcast.c @@ -1924,7 +1924,7 @@ in6_v6_mreq_to_v4(struct ipv6_mreq *mreq, struct ip_mreq *mreq_v4) error = EADDRNOTAVAIL; goto out; } - mreq_v4->imr_interface.s_addr = IA_SIN(ia)->sin_addr.s_addr; + mreq_v4->imr_interface.s_addr = ia->ia_addr.sin_addr.s_addr; error = 0; out: @@ -1991,12 +1991,11 @@ in6p_join_group(struct inpcb *inp, struct sockopt *sopt) .sopt_name = IP_ADD_MEMBERSHIP, .sopt_val = &mreq_v4, .sopt_valsize = sizeof(mreq_v4), - .sopt_rights = sopt->sopt_rights, - .sopt_td = sopt->sopt_td + .sopt_rights = sopt->sopt_rights }; mreq_v4.imr_multiaddr.s_addr = - mreq.ipv6mr_multiaddr.s6_addr32[3]; + htonl(mreq.ipv6mr_multiaddr.s6_addr32[3]); if (mreq.ipv6mr_interface == 0) mreq_v4.imr_interface.s_addr = INADDR_ANY; else @@ -2333,12 +2332,11 @@ in6p_leave_group(struct inpcb *inp, struct sockopt *sopt) .sopt_name = IP_DROP_MEMBERSHIP, .sopt_val = &mreq_v4, .sopt_valsize = sizeof(mreq_v4), - .sopt_rights = sopt->sopt_rights, - .sopt_td = sopt->sopt_td + .sopt_rights = sopt->sopt_rights }; mreq_v4.imr_multiaddr.s_addr = - mreq.ipv6mr_multiaddr.s6_addr32[3]; + htonl(mreq.ipv6mr_multiaddr.s6_addr32[3]); if (mreq.ipv6mr_interface == 0) mreq_v4.imr_interface.s_addr = INADDR_ANY; else |
