Linux kernel -stable discussions
 help / color / mirror / Atom feed
* [PATCH linux-4.14.y 0/2] sctp: fix a memory leak
@ 2019-11-04  5:16 Xin Long
  2019-11-04  5:16 ` [PATCH linux-4.14.y 1/2] sctp: fix the issue that flags are ignored when using kernel_connect Xin Long
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Xin Long @ 2019-11-04  5:16 UTC (permalink / raw)
  To: stable, linux-sctp; +Cc: Marcelo Ricardo Leitner, Neil Horman, sashal, gregkh

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(-)

-- 
2.1.0


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH linux-4.14.y 1/2] sctp: fix the issue that flags are ignored when using kernel_connect
  2019-11-04  5:16 [PATCH linux-4.14.y 0/2] sctp: fix a memory leak Xin Long
@ 2019-11-04  5:16 ` Xin Long
  2019-11-04  5:16 ` [PATCH linux-4.14.y 2/2] sctp: not bind the socket in sctp_connect Xin Long
  2019-11-04 10:57 ` [PATCH linux-4.14.y 0/2] sctp: fix a memory leak Greg KH
  2 siblings, 0 replies; 4+ messages in thread
From: Xin Long @ 2019-11-04  5:16 UTC (permalink / raw)
  To: stable, linux-sctp; +Cc: Marcelo Ricardo Leitner, Neil Horman, sashal, gregkh

[ 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.

Suggested-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Signed-off-by: Xin Long <lucien.xin@gmail.com>
Acked-by: Neil Horman <nhorman@tuxdriver.com>
Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Reviewed-by: Michal Kubecek <mkubecek@suse.cz>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 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(-)

diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
index 749a428..c713bd6 100644
--- a/include/net/sctp/sctp.h
+++ b/include/net/sctp/sctp.h
@@ -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);
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index 7eb06fa..53a66ee 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -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,
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 6af871b..01f88e9 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -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.  */
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index a18e9be..c9c23ca 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -1076,7 +1076,7 @@ static int sctp_setsockopt_bindx(struct sock *sk,
  */
 static int __sctp_connect(struct sock *sk,
 			  struct sockaddr *kaddrs,
-			  int addrs_size,
+			  int addrs_size, int flags,
 			  sctp_assoc_t *assoc_id)
 {
 	struct net *net = sock_net(sk);
@@ -1094,7 +1094,6 @@ static int __sctp_connect(struct sock *sk,
 	union sctp_addr *sa_addr = NULL;
 	void *addr_buf;
 	unsigned short port;
-	unsigned int f_flags = 0;
 
 	sp = sctp_sk(sk);
 	ep = sp->ep;
@@ -1244,13 +1243,7 @@ static int __sctp_connect(struct sock *sk,
 	sp->pf->to_sk_daddr(sa_addr, sk);
 	sk->sk_err = 0;
 
-	/* in-kernel sockets don't generally have a file allocated to them
-	 * if all they do is call sock_create_kern().
-	 */
-	if (sk->sk_socket->file)
-		f_flags = sk->sk_socket->file->f_flags;
-
-	timeo = sock_sndtimeo(sk, f_flags & O_NONBLOCK);
+	timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
 
 	if (assoc_id)
 		*assoc_id = asoc->assoc_id;
@@ -1345,7 +1338,7 @@ static int __sctp_setsockopt_connectx(struct sock *sk,
 {
 	struct sockaddr *kaddrs;
 	gfp_t gfp = GFP_KERNEL;
-	int err = 0;
+	int err = 0, flags = 0;
 
 	pr_debug("%s: sk:%p addrs:%p addrs_size:%d\n",
 		 __func__, sk, addrs, addrs_size);
@@ -1365,11 +1358,18 @@ static int __sctp_setsockopt_connectx(struct sock *sk,
 		return -ENOMEM;
 
 	if (__copy_from_user(kaddrs, addrs, addrs_size)) {
-		err = -EFAULT;
-	} else {
-		err = __sctp_connect(sk, kaddrs, addrs_size, assoc_id);
+		kfree(kaddrs);
+		return -EFAULT;
 	}
 
+	/* in-kernel sockets don't generally have a file allocated to them
+	 * if all they do is call sock_create_kern().
+	 */
+	if (sk->sk_socket->file)
+		flags = sk->sk_socket->file->f_flags;
+
+	err = __sctp_connect(sk, kaddrs, addrs_size, flags, assoc_id);
+
 	kfree(kaddrs);
 
 	return err;
@@ -4166,16 +4166,26 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,
  * len: the size of the address.
  */
 static int sctp_connect(struct sock *sk, struct sockaddr *addr,
-			int addr_len)
+			int addr_len, int flags)
 {
-	int err = 0;
+	struct inet_sock *inet = inet_sk(sk);
 	struct sctp_af *af;
+	int err = 0;
 
 	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) {
@@ -4184,13 +4194,25 @@ static int sctp_connect(struct sock *sk, struct sockaddr *addr,
 		/* Pass correct addr len to common routine (so it knows there
 		 * is only one address being passed.
 		 */
-		err = __sctp_connect(sk, addr, af->sockaddr_len, NULL);
+		err = __sctp_connect(sk, addr, af->sockaddr_len, flags, NULL);
 	}
 
 	release_sock(sk);
 	return err;
 }
 
+int sctp_inet_connect(struct socket *sock, struct sockaddr *uaddr,
+		      int addr_len, int flags)
+{
+	if (addr_len < sizeof(uaddr->sa_family))
+		return -EINVAL;
+
+	if (uaddr->sa_family == AF_UNSPEC)
+		return -EOPNOTSUPP;
+
+	return sctp_connect(sock->sk, uaddr, addr_len, flags);
+}
+
 /* FIXME: Write comments. */
 static int sctp_disconnect(struct sock *sk, int flags)
 {
@@ -8298,7 +8320,6 @@ struct proto sctp_prot = {
 	.name        =	"SCTP",
 	.owner       =	THIS_MODULE,
 	.close       =	sctp_close,
-	.connect     =	sctp_connect,
 	.disconnect  =	sctp_disconnect,
 	.accept      =	sctp_accept,
 	.ioctl       =	sctp_ioctl,
@@ -8337,7 +8358,6 @@ struct proto sctpv6_prot = {
 	.name		= "SCTPv6",
 	.owner		= THIS_MODULE,
 	.close		= sctp_close,
-	.connect	= sctp_connect,
 	.disconnect	= sctp_disconnect,
 	.accept		= sctp_accept,
 	.ioctl		= sctp_ioctl,
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH linux-4.14.y 2/2] sctp: not bind the socket in sctp_connect
  2019-11-04  5:16 [PATCH linux-4.14.y 0/2] sctp: fix a memory leak Xin Long
  2019-11-04  5:16 ` [PATCH linux-4.14.y 1/2] sctp: fix the issue that flags are ignored when using kernel_connect Xin Long
@ 2019-11-04  5:16 ` Xin Long
  2019-11-04 10:57 ` [PATCH linux-4.14.y 0/2] sctp: fix a memory leak Greg KH
  2 siblings, 0 replies; 4+ messages in thread
From: Xin Long @ 2019-11-04  5:16 UTC (permalink / raw)
  To: stable, linux-sctp; +Cc: Marcelo Ricardo Leitner, Neil Horman, sashal, gregkh

[ 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: syzbot+079bf326b38072f849d9@syzkaller.appspotmail.com
Signed-off-by: Xin Long <lucien.xin@gmail.com>
Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 net/sctp/socket.c | 21 ++-------------------
 1 file changed, 2 insertions(+), 19 deletions(-)

diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index c9c23ca..4045d20 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -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;
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH linux-4.14.y 0/2] sctp: fix a memory leak
  2019-11-04  5:16 [PATCH linux-4.14.y 0/2] sctp: fix a memory leak Xin Long
  2019-11-04  5:16 ` [PATCH linux-4.14.y 1/2] sctp: fix the issue that flags are ignored when using kernel_connect Xin Long
  2019-11-04  5:16 ` [PATCH linux-4.14.y 2/2] sctp: not bind the socket in sctp_connect Xin Long
@ 2019-11-04 10:57 ` Greg KH
  2 siblings, 0 replies; 4+ messages in thread
From: Greg KH @ 2019-11-04 10:57 UTC (permalink / raw)
  To: Xin Long; +Cc: stable, linux-sctp, Marcelo Ricardo Leitner, Neil Horman, sashal

On Mon, Nov 04, 2019 at 01:16:24PM +0800, Xin Long wrote:
> 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

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2019-11-04 10:57 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-11-04  5:16 [PATCH linux-4.14.y 0/2] sctp: fix a memory leak Xin Long
2019-11-04  5:16 ` [PATCH linux-4.14.y 1/2] sctp: fix the issue that flags are ignored when using kernel_connect Xin Long
2019-11-04  5:16 ` [PATCH linux-4.14.y 2/2] sctp: not bind the socket in sctp_connect Xin Long
2019-11-04 10:57 ` [PATCH linux-4.14.y 0/2] sctp: fix a memory leak Greg KH

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox