lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date:   Wed, 28 Nov 2018 17:56:26 -0800
From:   Christoph Paasch <cpaasch@...le.com>
To:     netdev@...r.kernel.org
Cc:     Ian Swett <ianswett@...gle.com>,
        Leif Hedstrom <lhedstrom@...le.com>,
        Jana Iyengar <jri.ietf@...il.com>,
        Eric Dumazet <edumazet@...gle.com>
Subject: [PATCH] udp: Allow to defer reception until connect() happened

There are use-cases where a host wants to use a UDP socket with a
specific 4-tuple. The way to do this is to bind() and then connect() the
socket. However, after the bind(), the socket starts receiving data even
if it does not match the intended 4-tuple. That is because after the
bind() UDP-socket will match in the lookup for all incoming UDP-traffic
that has the specific IP/port.

This patch prevents any incoming traffic until the connect() system-call
is called whenever the app sets the UDP socket-option
UDP_WAIT_FOR_CONNECT.

Signed-off-by: Christoph Paasch <cpaasch@...le.com>
---

Notes:
    Changes compared to the original RFC-submission:
    
    * Make it a UDP-specific socket-option
    * Rename it to 'wait-for-connect'
    
    Wrt to the discussion on the original RFC submission
    (cfr., https://marc.info/?l=linux-netdev&m=154102843910587&w=2):
    
    We believe that this patch is still useful to enable applications to use
    different models of implementing a UDP-server. For some frameworks it is much
    easier to have a socket per-connection and thus let the de-multiplexing happen
    in the kernel instead of the app.

 include/linux/udp.h      |  5 ++++-
 include/net/udp.h        |  1 +
 include/uapi/linux/udp.h |  1 +
 net/ipv4/udp.c           | 26 +++++++++++++++++++++++++-
 net/ipv4/udplite.c       |  2 +-
 net/ipv6/udp.c           | 15 ++++++++++++++-
 net/ipv6/udp_impl.h      |  1 +
 net/ipv6/udplite.c       |  2 +-
 8 files changed, 48 insertions(+), 5 deletions(-)

diff --git a/include/linux/udp.h b/include/linux/udp.h
index 2725c83395bf..9a715d25ce36 100644
--- a/include/linux/udp.h
+++ b/include/linux/udp.h
@@ -55,7 +55,10 @@ struct udp_sock {
 					   * different encapsulation layer set
 					   * this
 					   */
-			 gro_enabled:1;	/* Can accept GRO packets */
+			 gro_enabled:1,	/* Can accept GRO packets */
+			 wait_for_connect:1;/* Wait until app calls connect()
+					     * before accepting incoming data
+					     */
 	/*
 	 * Following member retains the information to create a UDP header
 	 * when the socket is uncorked.
diff --git a/include/net/udp.h b/include/net/udp.h
index fd6d948755c8..b7467a4129b3 100644
--- a/include/net/udp.h
+++ b/include/net/udp.h
@@ -285,6 +285,7 @@ int udp_get_port(struct sock *sk, unsigned short snum,
 				  const struct sock *));
 int udp_err(struct sk_buff *, u32);
 int udp_abort(struct sock *sk, int err);
+int udp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len);
 int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len);
 int udp_push_pending_frames(struct sock *sk);
 void udp_flush_pending_frames(struct sock *sk);
diff --git a/include/uapi/linux/udp.h b/include/uapi/linux/udp.h
index 30baccb6c9c4..b61f8e8dd80b 100644
--- a/include/uapi/linux/udp.h
+++ b/include/uapi/linux/udp.h
@@ -34,6 +34,7 @@ struct udphdr {
 #define UDP_NO_CHECK6_RX 102	/* Disable accpeting checksum for UDP6 */
 #define UDP_SEGMENT	103	/* Set GSO segmentation size */
 #define UDP_GRO		104	/* This socket can receive UDP GRO packets */
+#define UDP_WAIT_FOR_CONNECT	105	/* Don't accept incoming data until the app calls connect() */
 
 /* UDP encapsulation types */
 #define UDP_ENCAP_ESPINUDP_NON_IKE	1 /* draft-ietf-ipsec-nat-t-ike-00/01 */
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index aff2a8e99e01..c5adafcfd52f 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -407,6 +407,9 @@ static int compute_score(struct sock *sk, struct net *net,
 		return -1;
 	score += 4;
 
+	if (udp_sk(sk)->wait_for_connect)
+		return -1;
+
 	if (sk->sk_incoming_cpu == raw_smp_processor_id())
 		score++;
 	return score;
@@ -2601,6 +2604,10 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
 		release_sock(sk);
 		break;
 
+	case UDP_WAIT_FOR_CONNECT:
+		up->wait_for_connect = valbool;
+		break;
+
 	/*
 	 * 	UDP-Lite's partial checksum coverage (RFC 3828).
 	 */
@@ -2695,6 +2702,10 @@ int udp_lib_getsockopt(struct sock *sk, int level, int optname,
 		val = up->gso_size;
 		break;
 
+	case UDP_WAIT_FOR_CONNECT:
+		val = up->wait_for_connect;
+		break;
+
 	/* The following two cannot be changed on UDP sockets, the return is
 	 * always 0 (which corresponds to the full checksum coverage of UDP). */
 	case UDPLITE_SEND_CSCOV:
@@ -2779,12 +2790,25 @@ int udp_abort(struct sock *sk, int err)
 }
 EXPORT_SYMBOL_GPL(udp_abort);
 
+int udp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+{
+	int ret;
+
+	ret = ip4_datagram_connect(sk, uaddr, addr_len);
+
+	if (!ret)
+		udp_sk(sk)->wait_for_connect = 0;
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(udp_v4_connect);
+
 struct proto udp_prot = {
 	.name			= "UDP",
 	.owner			= THIS_MODULE,
 	.close			= udp_lib_close,
 	.pre_connect		= udp_pre_connect,
-	.connect		= ip4_datagram_connect,
+	.connect		= udp_v4_connect,
 	.disconnect		= udp_disconnect,
 	.ioctl			= udp_ioctl,
 	.init			= udp_init_sock,
diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c
index 39c7f17d916f..22c74822ff30 100644
--- a/net/ipv4/udplite.c
+++ b/net/ipv4/udplite.c
@@ -41,7 +41,7 @@ struct proto 	udplite_prot = {
 	.name		   = "UDP-Lite",
 	.owner		   = THIS_MODULE,
 	.close		   = udp_lib_close,
-	.connect	   = ip4_datagram_connect,
+	.connect	   = udp_v4_connect,
 	.disconnect	   = udp_disconnect,
 	.ioctl		   = udp_ioctl,
 	.init		   = udplite_sk_init,
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 09cba4cfe31f..c3a9101380de 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -1681,6 +1681,19 @@ void udp6_proc_exit(struct net *net)
 }
 #endif /* CONFIG_PROC_FS */
 
+int udp_v6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+{
+	int ret;
+
+	ret = ip6_datagram_connect(sk, uaddr, addr_len);
+
+	if (!ret)
+		udp_sk(sk)->wait_for_connect = 0;
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(udp_v6_connect);
+
 /* ------------------------------------------------------------------------ */
 
 struct proto udpv6_prot = {
@@ -1688,7 +1701,7 @@ struct proto udpv6_prot = {
 	.owner			= THIS_MODULE,
 	.close			= udp_lib_close,
 	.pre_connect		= udpv6_pre_connect,
-	.connect		= ip6_datagram_connect,
+	.connect		= udp_v6_connect,
 	.disconnect		= udp_disconnect,
 	.ioctl			= udp_ioctl,
 	.init			= udp_init_sock,
diff --git a/net/ipv6/udp_impl.h b/net/ipv6/udp_impl.h
index 5730e6503cb4..14e847b63db9 100644
--- a/net/ipv6/udp_impl.h
+++ b/net/ipv6/udp_impl.h
@@ -14,6 +14,7 @@ int __udp6_lib_err(struct sk_buff *, struct inet6_skb_parm *, u8, u8, int,
 
 int udp_v6_get_port(struct sock *sk, unsigned short snum);
 
+int udp_v6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len);
 int udpv6_getsockopt(struct sock *sk, int level, int optname,
 		     char __user *optval, int __user *optlen);
 int udpv6_setsockopt(struct sock *sk, int level, int optname,
diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c
index a125aebc29e5..035e1b2f2529 100644
--- a/net/ipv6/udplite.c
+++ b/net/ipv6/udplite.c
@@ -38,7 +38,7 @@ struct proto udplitev6_prot = {
 	.name		   = "UDPLITEv6",
 	.owner		   = THIS_MODULE,
 	.close		   = udp_lib_close,
-	.connect	   = ip6_datagram_connect,
+	.connect	   = udp_v6_connect,
 	.disconnect	   = udp_disconnect,
 	.ioctl		   = udp_ioctl,
 	.init		   = udplite_sk_init,
-- 
2.16.2

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ