Skip to contentSkip to conversation

sctp: fix a memory leak

PATCH In review Xin Long 2 participants 4 messages Nov 4, 2019

Subsystems (3)
lore
Share & tools
lore

Xin Long

author maintainer
#0 lore raw

cover sctp: fix a memory leak

These 2 patches are missed in linux-4.14.y, it will cause crash when commit 63dfb7938b13 ("sctp: change sctp_prot .no_autobind with true") is backported only.

Conflicts:
- Context difference in Patch 1/2 due to the lack of

    Commit c981f254cc82.

Xin Long (2):
sctp: fix the issue that flags are ignored when using kernel_connect
sctp: not bind the socket in sctp_connect

 include/net/sctp/sctp.h |  2 ++
 net/sctp/ipv6.c         |  2 +-
 net/sctp/protocol.c     |  2 +-
 net/sctp/socket.c       | 55 ++++++++++++++++++++++++++-----------------------
 4 files changed, 33 insertions(+), 28 deletions(-)
Signature · 1 line
2.1.0
author maintainer
#1 lore raw

PATCH 1/2 sctp: fix the issue that flags are ignored when using kernel_connect

[ Upstream commit 644fbdeacf1d3edd366e44b8ba214de9d1dd66a9 ]

Now sctp uses inet_dgram_connect as its proto_ops .connect, and the flags param can't be passed into its proto .connect where this flags is really needed.

sctp works around it by getting flags from socket file in __sctp_connect. It works for connecting from userspace, as inherently the user sock has socket file and it passes f_flags as the flags param into the proto_ops .connect.

However, the sock created by sock_create_kern doesn't have a socket file, and it passes the flags (like O_NONBLOCK) by using the flags param in kernel_connect, which calls proto_ops .connect later.

So to fix it, this patch defines a new proto_ops .connect for sctp, sctp_inet_connect, which calls __sctp_connect() directly with this flags param. After this, the sctp's proto .connect can be removed.

Note that sctp_inet_connect doesn't need to do some checks that are not needed for sctp, which makes thing better than with inet_dgram_connect.

---
 include/net/sctp/sctp.h |  2 ++
 net/sctp/ipv6.c         |  2 +-
 net/sctp/protocol.c     |  2 +-
 net/sctp/socket.c       | 56 +++++++++++++++++++++++++++++++++----------------
 4 files changed, 42 insertions(+), 20 deletions(-)
include/net/sctp/sctp.h +2 -0
index 749a428..c713bd6 100644
@@ -103,6 +103,8 @@ void sctp_addr_wq_mgmt(struct net *, struct sctp_sockaddr_entry *, int);
 /*
  * sctp/socket.c
  */
+int sctp_inet_connect(struct socket *sock, struct sockaddr *uaddr,
+		      int addr_len, int flags);
 int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb);
 int sctp_inet_listen(struct socket *sock, int backlog);
 void sctp_write_space(struct sock *sk);
net/sctp/ipv6.c +1 -1
index 7eb06fa..53a66ee 100644
@@ -974,7 +974,7 @@ static const struct proto_ops inet6_seqpacket_ops = {
 	.owner		   = THIS_MODULE,
 	.release	   = inet6_release,
 	.bind		   = inet6_bind,
-	.connect	   = inet_dgram_connect,
+	.connect	   = sctp_inet_connect,
 	.socketpair	   = sock_no_socketpair,
 	.accept		   = inet_accept,
 	.getname	   = sctp_getname,
net/sctp/protocol.c +1 -1
index 6af871b..01f88e9 100644
@@ -1019,7 +1019,7 @@ static const struct proto_ops inet_seqpacket_ops = {
 	.owner		   = THIS_MODULE,
 	.release	   = inet_release,	/* Needs to be wrapped... */
 	.bind		   = inet_bind,
-	.connect	   = inet_dgram_connect,
+	.connect	   = sctp_inet_connect,
 	.socketpair	   = sock_no_socketpair,
 	.accept		   = inet_accept,
 	.getname	   = inet_getname,	/* Semantics are different.  */
net/sctp/socket.c +38 -18

126 lines not on this page · raw message

Signature · 1 line
2.1.0
author maintainer
#2 lore raw

PATCH 2/2 sctp: not bind the socket in sctp_connect

[ Upstream commit 9b6c08878e23adb7cc84bdca94d8a944b03f099e ]

Now when sctp_connect() is called with a wrong sa_family, it binds to a port but doesn't set bp->port, then sctp_get_af_specific will return NULL and sctp_connect() returns -EINVAL.

Then if sctp_bind() is called to bind to another port, the last port it has bound will leak due to bp->port is NULL by then.

sctp_connect() doesn't need to bind ports, as later __sctp_connect will do it if bp->port is NULL. So remove it from sctp_connect(). While at it, remove the unnecessary sockaddr.sa_family len check as it's already done in sctp_inet_connect.

Fixes 644fbdeacf1d ("sctp: fix the issue that flags are ignored when using kernel_connect")
Reported-by [email protected]
---
 net/sctp/socket.c | 21 ++-------------------
 1 file changed, 2 insertions(+), 19 deletions(-)
net/sctp/socket.c +2 -19
index c9c23ca..4045d20 100644
@@ -4168,34 +4168,17 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,
 static int sctp_connect(struct sock *sk, struct sockaddr *addr,
 			int addr_len, int flags)
 {
-	struct inet_sock *inet = inet_sk(sk);
 	struct sctp_af *af;
-	int err = 0;
+	int err = -EINVAL;
 
 	lock_sock(sk);
-
 	pr_debug("%s: sk:%p, sockaddr:%p, addr_len:%d\n", __func__, sk,
 		 addr, addr_len);
 
-	/* We may need to bind the socket. */
-	if (!inet->inet_num) {
-		if (sk->sk_prot->get_port(sk, 0)) {
-			release_sock(sk);
-			return -EAGAIN;
-		}
-		inet->inet_sport = htons(inet->inet_num);
-	}
-
 	/* Validate addr_len before calling common connect/connectx routine. */
 	af = sctp_get_af_specific(addr->sa_family);
-	if (!af || addr_len < af->sockaddr_len) {
-		err = -EINVAL;
-	} else {
-		/* Pass correct addr len to common routine (so it knows there
-		 * is only one address being passed.
-		 */
+	if (af && addr_len >= af->sockaddr_len)
 		err = __sctp_connect(sk, addr, af->sockaddr_len, flags, NULL);
-	}
 
 	release_sock(sk);
 	return err;
Signature · 1 line
2.1.0
maintainer
#3 lore raw
In reply to Xin Long
Quoted 11 lines · Xin Long

These 2 patches are missed in linux-4.14.y, it will cause crash when commit 63dfb7938b13 ("sctp: change sctp_prot .no_autobind with true") is backported only.

Conflicts:
- Context difference in Patch 1/2 due to the lack of

    Commit c981f254cc82.

Xin Long (2):
sctp: fix the issue that flags are ignored when using kernel_connect
sctp: not bind the socket in sctp_connect

Thanks for these, now queued up.

greg k-h