ipv6: make IPV6_FREEBIND and IPV6_TRANSPARENT setsockopt lockless

IPV6_FREEBIND and IPV6_TRANSPARENT still take the socket lock despite
using inet_assign_bit() to update the flags shared with IP_FREEBIND
and IP_TRANSPARENT. IPv6 TCP and UDP sockets can already update these
flags without the lock through the corresponding SOL_IP options.

Move both options to the lockless setsockopt path.

Signed-off-by: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
Reviewed-by: Hangbin Liu <liuhangbin@kylinos.cn>
Link: https://patch.msgid.link/20260912134040.215664-1-xuanqiang.luo@linux.dev
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
Xuanqiang Luo 2026-09-12 21:40:40 +08:00 committed by Paolo Abeni
parent 859e40055c
commit 546f109fdb

View File

@ -398,6 +398,21 @@ int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
/* Handle options that can be set without locking the socket. */
switch (optname) {
case IPV6_FREEBIND:
if (optlen < sizeof(int))
return -EINVAL;
/* Shared with IP_FREEBIND. */
inet_assign_bit(FREEBIND, sk, valbool);
return 0;
case IPV6_TRANSPARENT:
if (valbool && !sockopt_ns_capable(net->user_ns, CAP_NET_RAW) &&
!sockopt_ns_capable(net->user_ns, CAP_NET_ADMIN))
return -EPERM;
if (optlen < sizeof(int))
return -EINVAL;
/* Shared with IP_TRANSPARENT. */
inet_assign_bit(TRANSPARENT, sk, valbool);
return 0;
case IPV6_UNICAST_HOPS:
if (optlen < sizeof(int))
return -EINVAL;
@ -666,27 +681,6 @@ int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
retv = 0;
break;
case IPV6_TRANSPARENT:
if (valbool && !sockopt_ns_capable(net->user_ns, CAP_NET_RAW) &&
!sockopt_ns_capable(net->user_ns, CAP_NET_ADMIN)) {
retv = -EPERM;
break;
}
if (optlen < sizeof(int))
goto e_inval;
/* we don't have a separate transparent bit for IPV6 we use the one in the IPv4 socket */
inet_assign_bit(TRANSPARENT, sk, valbool);
retv = 0;
break;
case IPV6_FREEBIND:
if (optlen < sizeof(int))
goto e_inval;
/* we also don't have a separate freebind bit for IPV6 */
inet_assign_bit(FREEBIND, sk, valbool);
retv = 0;
break;
case IPV6_RECVORIGDSTADDR:
if (optlen < sizeof(int))
goto e_inval;