Skip to content

Commit

Permalink
inet: lockless IP_PKTOPTIONS implementation
Browse files Browse the repository at this point in the history
Current implementation is already lockless, because the socket
lock is released before reading socket fields.

Add missing READ_ONCE() annotations.

Note that corresponding WRITE_ONCE() are needed, the order
of the patches do not really matter.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Eric Dumazet authored and David S. Miller committed Oct 1, 2023
1 parent 959d5c1 commit c4480eb
Showing 1 changed file with 37 additions and 39 deletions.
76 changes: 37 additions & 39 deletions net/ipv4/ip_sockglue.c
Original file line number Diff line number Diff line change
Expand Up @@ -1633,6 +1633,43 @@ int do_ip_getsockopt(struct sock *sk, int level, int optname,
return -ENOTCONN;
goto copyval;
}
case IP_PKTOPTIONS:
{
struct msghdr msg;

if (sk->sk_type != SOCK_STREAM)
return -ENOPROTOOPT;

if (optval.is_kernel) {
msg.msg_control_is_user = false;
msg.msg_control = optval.kernel;
} else {
msg.msg_control_is_user = true;
msg.msg_control_user = optval.user;
}
msg.msg_controllen = len;
msg.msg_flags = in_compat_syscall() ? MSG_CMSG_COMPAT : 0;

if (inet_test_bit(PKTINFO, sk)) {
struct in_pktinfo info;

info.ipi_addr.s_addr = READ_ONCE(inet->inet_rcv_saddr);
info.ipi_spec_dst.s_addr = READ_ONCE(inet->inet_rcv_saddr);
info.ipi_ifindex = READ_ONCE(inet->mc_index);
put_cmsg(&msg, SOL_IP, IP_PKTINFO, sizeof(info), &info);
}
if (inet_test_bit(TTL, sk)) {
int hlim = READ_ONCE(inet->mc_ttl);

put_cmsg(&msg, SOL_IP, IP_TTL, sizeof(hlim), &hlim);
}
if (inet_test_bit(TOS, sk)) {
int tos = READ_ONCE(inet->rcv_tos);
put_cmsg(&msg, SOL_IP, IP_TOS, sizeof(tos), &tos);
}
len -= msg.msg_controllen;
return copy_to_sockptr(optlen, &len, sizeof(int));
}
case IP_UNICAST_IF:
val = (__force int)htonl((__u32) READ_ONCE(inet->uc_index));
goto copyval;
Expand Down Expand Up @@ -1678,45 +1715,6 @@ int do_ip_getsockopt(struct sock *sk, int level, int optname,
else
err = ip_get_mcast_msfilter(sk, optval, optlen, len);
goto out;
case IP_PKTOPTIONS:
{
struct msghdr msg;

sockopt_release_sock(sk);

if (sk->sk_type != SOCK_STREAM)
return -ENOPROTOOPT;

if (optval.is_kernel) {
msg.msg_control_is_user = false;
msg.msg_control = optval.kernel;
} else {
msg.msg_control_is_user = true;
msg.msg_control_user = optval.user;
}
msg.msg_controllen = len;
msg.msg_flags = in_compat_syscall() ? MSG_CMSG_COMPAT : 0;

if (inet_test_bit(PKTINFO, sk)) {
struct in_pktinfo info;

info.ipi_addr.s_addr = inet->inet_rcv_saddr;
info.ipi_spec_dst.s_addr = inet->inet_rcv_saddr;
info.ipi_ifindex = inet->mc_index;
put_cmsg(&msg, SOL_IP, IP_PKTINFO, sizeof(info), &info);
}
if (inet_test_bit(TTL, sk)) {
int hlim = READ_ONCE(inet->mc_ttl);

put_cmsg(&msg, SOL_IP, IP_TTL, sizeof(hlim), &hlim);
}
if (inet_test_bit(TOS, sk)) {
int tos = inet->rcv_tos;
put_cmsg(&msg, SOL_IP, IP_TOS, sizeof(tos), &tos);
}
len -= msg.msg_controllen;
return copy_to_sockptr(optlen, &len, sizeof(int));
}
case IP_LOCAL_PORT_RANGE:
val = inet->local_port_range.hi << 16 | inet->local_port_range.lo;
break;
Expand Down

0 comments on commit c4480eb

Please sign in to comment.