Commit 406492d9 authored by Eric Dumazet's avatar Eric Dumazet Committed by Geliang Tang
Browse files

inet: lockless IP_PKTOPTIONS implementation

mainline inclusion
from mainline-v6.7-rc1
commit c4480eb5504c9771f935cbca58a3b874bdd36af8
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I9VYQ9
CVE: NA

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/?id=c4480eb5504c9771f935cbca58a3b874bdd36af8



--------------------------------

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: default avatarEric Dumazet <edumazet@google.com>
Reviewed-by: default avatarDavid Ahern <dsahern@kernel.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Reviewed-by: default avatarJackie Liu <liuyun01@kylinos.cn>
Signed-off-by: default avatarGeliang Tang <tanggeliang@kylinos.cn>
parent 38bd05d3
Loading
Loading
Loading
Loading
+37 −39
Original line number Diff line number Diff line
@@ -1642,6 +1642,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;
@@ -1687,45 +1724,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;