* [PATCH net 0/5] net/smc: fixes 2019-04-11
@ 2019-04-11 9:17 Ursula Braun
2019-04-11 9:17 ` [PATCH net 1/5] net/smc: wait for pending work before clcsock release_sock Ursula Braun
` (5 more replies)
0 siblings, 6 replies; 7+ messages in thread
From: Ursula Braun @ 2019-04-11 9:17 UTC (permalink / raw)
To: davem
Cc: netdev, linux-s390, schwidefsky, heiko.carstens, raspl, kgraul,
ubraun
From: Ursula Braun <ursula.braun@de.ibm.com>
Dave,
here are some fixes in different areas of the smc code for the net
tree.
Thanks, Ursula
Kangjie Lu (1):
net/smc: fix a NULL pointer dereference
Karsten Graul (2):
net/smc: wait for pending work before clcsock release_sock
net/smc: fix return code from FLUSH command
Ursula Braun (2):
net/smc: propagate file from SMC to TCP socket
net/smc: move unhash before release of clcsock
include/net/sock.h | 6 ------
net/smc/af_smc.c | 58 +++++++++++++++++++++++++++++++++++------------------
net/smc/smc_close.c | 25 +++++++++++++++++++----
net/smc/smc_close.h | 1 +
net/smc/smc_ism.c | 5 +++++
net/smc/smc_pnet.c | 3 ++-
6 files changed, 68 insertions(+), 30 deletions(-)
--
2.16.4
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH net 1/5] net/smc: wait for pending work before clcsock release_sock
2019-04-11 9:17 [PATCH net 0/5] net/smc: fixes 2019-04-11 Ursula Braun
@ 2019-04-11 9:17 ` Ursula Braun
2019-04-11 9:17 ` [PATCH net 2/5] net/smc: fix a NULL pointer dereference Ursula Braun
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Ursula Braun @ 2019-04-11 9:17 UTC (permalink / raw)
To: davem
Cc: netdev, linux-s390, schwidefsky, heiko.carstens, raspl, kgraul,
ubraun
From: Karsten Graul <kgraul@linux.ibm.com>
When the clcsock is already released using sock_release() and a pending
smc_listen_work accesses the clcsock than that will fail. Solve this
by canceling and waiting for the work to complete first. Because the
work holds the sock_lock it must make sure that the lock is not hold
before the new helper smc_clcsock_release() is invoked. And before the
smc_listen_work starts working check if the parent listen socket is
still valid, otherwise stop the work early.
Signed-off-by: Karsten Graul <kgraul@linux.ibm.com>
Signed-off-by: Ursula Braun <ubraun@linux.ibm.com>
---
net/smc/af_smc.c | 14 ++++++++------
net/smc/smc_close.c | 25 +++++++++++++++++++++----
net/smc/smc_close.h | 1 +
3 files changed, 30 insertions(+), 10 deletions(-)
diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
index 77ef53596d18..9bdaed2f2e35 100644
--- a/net/smc/af_smc.c
+++ b/net/smc/af_smc.c
@@ -167,10 +167,9 @@ static int smc_release(struct socket *sock)
if (sk->sk_state == SMC_CLOSED) {
if (smc->clcsock) {
- mutex_lock(&smc->clcsock_release_lock);
- sock_release(smc->clcsock);
- smc->clcsock = NULL;
- mutex_unlock(&smc->clcsock_release_lock);
+ release_sock(sk);
+ smc_clcsock_release(smc);
+ lock_sock(sk);
}
if (!smc->use_fallback)
smc_conn_free(&smc->conn);
@@ -1037,13 +1036,13 @@ static void smc_listen_out(struct smc_sock *new_smc)
struct smc_sock *lsmc = new_smc->listen_smc;
struct sock *newsmcsk = &new_smc->sk;
- lock_sock_nested(&lsmc->sk, SINGLE_DEPTH_NESTING);
if (lsmc->sk.sk_state == SMC_LISTEN) {
+ lock_sock_nested(&lsmc->sk, SINGLE_DEPTH_NESTING);
smc_accept_enqueue(&lsmc->sk, newsmcsk);
+ release_sock(&lsmc->sk);
} else { /* no longer listening */
smc_close_non_accepted(newsmcsk);
}
- release_sock(&lsmc->sk);
/* Wake up accept */
lsmc->sk.sk_data_ready(&lsmc->sk);
@@ -1237,6 +1236,9 @@ static void smc_listen_work(struct work_struct *work)
int rc = 0;
u8 ibport;
+ if (new_smc->listen_smc->sk.sk_state != SMC_LISTEN)
+ return smc_listen_out_err(new_smc);
+
if (new_smc->use_fallback) {
smc_listen_out_connected(new_smc);
return;
diff --git a/net/smc/smc_close.c b/net/smc/smc_close.c
index 2ad37e998509..fc06720b53c1 100644
--- a/net/smc/smc_close.c
+++ b/net/smc/smc_close.c
@@ -21,6 +21,22 @@
#define SMC_CLOSE_WAIT_LISTEN_CLCSOCK_TIME (5 * HZ)
+/* release the clcsock that is assigned to the smc_sock */
+void smc_clcsock_release(struct smc_sock *smc)
+{
+ struct socket *tcp;
+
+ if (smc->listen_smc && current_work() != &smc->smc_listen_work)
+ cancel_work_sync(&smc->smc_listen_work);
+ mutex_lock(&smc->clcsock_release_lock);
+ if (smc->clcsock) {
+ tcp = smc->clcsock;
+ smc->clcsock = NULL;
+ sock_release(tcp);
+ }
+ mutex_unlock(&smc->clcsock_release_lock);
+}
+
static void smc_close_cleanup_listen(struct sock *parent)
{
struct sock *sk;
@@ -321,6 +337,7 @@ static void smc_close_passive_work(struct work_struct *work)
close_work);
struct smc_sock *smc = container_of(conn, struct smc_sock, conn);
struct smc_cdc_conn_state_flags *rxflags;
+ bool release_clcsock = false;
struct sock *sk = &smc->sk;
int old_state;
@@ -400,13 +417,13 @@ static void smc_close_passive_work(struct work_struct *work)
if ((sk->sk_state == SMC_CLOSED) &&
(sock_flag(sk, SOCK_DEAD) || !sk->sk_socket)) {
smc_conn_free(conn);
- if (smc->clcsock) {
- sock_release(smc->clcsock);
- smc->clcsock = NULL;
- }
+ if (smc->clcsock)
+ release_clcsock = true;
}
}
release_sock(sk);
+ if (release_clcsock)
+ smc_clcsock_release(smc);
sock_put(sk); /* sock_hold done by schedulers of close_work */
}
diff --git a/net/smc/smc_close.h b/net/smc/smc_close.h
index 19eb6a211c23..e0e3b5df25d2 100644
--- a/net/smc/smc_close.h
+++ b/net/smc/smc_close.h
@@ -23,5 +23,6 @@ void smc_close_wake_tx_prepared(struct smc_sock *smc);
int smc_close_active(struct smc_sock *smc);
int smc_close_shutdown_write(struct smc_sock *smc);
void smc_close_init(struct smc_sock *smc);
+void smc_clcsock_release(struct smc_sock *smc);
#endif /* SMC_CLOSE_H */
--
2.16.4
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH net 2/5] net/smc: fix a NULL pointer dereference
2019-04-11 9:17 [PATCH net 0/5] net/smc: fixes 2019-04-11 Ursula Braun
2019-04-11 9:17 ` [PATCH net 1/5] net/smc: wait for pending work before clcsock release_sock Ursula Braun
@ 2019-04-11 9:17 ` Ursula Braun
2019-04-11 9:17 ` [PATCH net 3/5] net/smc: propagate file from SMC to TCP socket Ursula Braun
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Ursula Braun @ 2019-04-11 9:17 UTC (permalink / raw)
To: davem
Cc: netdev, linux-s390, schwidefsky, heiko.carstens, raspl, kgraul,
ubraun
From: Kangjie Lu <kjlu@umn.edu>
In case alloc_ordered_workqueue fails, the fix returns NULL
to avoid NULL pointer dereference.
Signed-off-by: Kangjie Lu <kjlu@umn.edu>
Signed-off-by: Ursula Braun <ubraun@linux.ibm.com>
---
net/smc/smc_ism.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/net/smc/smc_ism.c b/net/smc/smc_ism.c
index 2fff79db1a59..e89e918b88e0 100644
--- a/net/smc/smc_ism.c
+++ b/net/smc/smc_ism.c
@@ -289,6 +289,11 @@ struct smcd_dev *smcd_alloc_dev(struct device *parent, const char *name,
INIT_LIST_HEAD(&smcd->vlan);
smcd->event_wq = alloc_ordered_workqueue("ism_evt_wq-%s)",
WQ_MEM_RECLAIM, name);
+ if (!smcd->event_wq) {
+ kfree(smcd->conn);
+ kfree(smcd);
+ return NULL;
+ }
return smcd;
}
EXPORT_SYMBOL_GPL(smcd_alloc_dev);
--
2.16.4
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH net 3/5] net/smc: propagate file from SMC to TCP socket
2019-04-11 9:17 [PATCH net 0/5] net/smc: fixes 2019-04-11 Ursula Braun
2019-04-11 9:17 ` [PATCH net 1/5] net/smc: wait for pending work before clcsock release_sock Ursula Braun
2019-04-11 9:17 ` [PATCH net 2/5] net/smc: fix a NULL pointer dereference Ursula Braun
@ 2019-04-11 9:17 ` Ursula Braun
2019-04-11 9:17 ` [PATCH net 4/5] net/smc: fix return code from FLUSH command Ursula Braun
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Ursula Braun @ 2019-04-11 9:17 UTC (permalink / raw)
To: davem
Cc: netdev, linux-s390, schwidefsky, heiko.carstens, raspl, kgraul,
ubraun
fcntl(fd, F_SETOWN, getpid()) selects the recipient of SIGURG signals
that are delivered when out-of-band data arrives on socket fd.
If an SMC socket program makes use of such an fcntl() call, it fails
in case of fallback to TCP-mode. In case of fallback the traffic is
processed with the internal TCP socket. Propagating field "file" from the
SMC socket to the internal TCP socket fixes the issue.
Reviewed-by: Karsten Graul <kgraul@linux.ibm.com>
Signed-off-by: Ursula Braun <ubraun@linux.ibm.com>
---
include/net/sock.h | 6 ------
net/smc/af_smc.c | 38 ++++++++++++++++++++++++++++----------
2 files changed, 28 insertions(+), 16 deletions(-)
diff --git a/include/net/sock.h b/include/net/sock.h
index 8de5ee258b93..341f8bafa0cf 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -2084,12 +2084,6 @@ static inline bool skwq_has_sleeper(struct socket_wq *wq)
* @p: poll_table
*
* See the comments in the wq_has_sleeper function.
- *
- * Do not derive sock from filp->private_data here. An SMC socket establishes
- * an internal TCP socket that is used in the fallback case. All socket
- * operations on the SMC socket are then forwarded to the TCP socket. In case of
- * poll, the filp->private_data pointer references the SMC socket because the
- * TCP socket has no file assigned.
*/
static inline void sock_poll_wait(struct file *filp, struct socket *sock,
poll_table *p)
diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
index 9bdaed2f2e35..d2a0d15f809c 100644
--- a/net/smc/af_smc.c
+++ b/net/smc/af_smc.c
@@ -445,10 +445,19 @@ static void smc_link_save_peer_info(struct smc_link *link,
link->peer_mtu = clc->qp_mtu;
}
+static void smc_switch_to_fallback(struct smc_sock *smc)
+{
+ smc->use_fallback = true;
+ if (smc->sk.sk_socket && smc->sk.sk_socket->file) {
+ smc->clcsock->file = smc->sk.sk_socket->file;
+ smc->clcsock->file->private_data = smc->clcsock;
+ }
+}
+
/* fall back during connect */
static int smc_connect_fallback(struct smc_sock *smc, int reason_code)
{
- smc->use_fallback = true;
+ smc_switch_to_fallback(smc);
smc->fallback_rsn = reason_code;
smc_copy_sock_settings_to_clc(smc);
if (smc->sk.sk_state == SMC_INIT)
@@ -774,10 +783,14 @@ static void smc_connect_work(struct work_struct *work)
smc->sk.sk_err = -rc;
out:
- if (smc->sk.sk_err)
- smc->sk.sk_state_change(&smc->sk);
- else
- smc->sk.sk_write_space(&smc->sk);
+ if (!sock_flag(&smc->sk, SOCK_DEAD)) {
+ if (smc->sk.sk_err) {
+ smc->sk.sk_state_change(&smc->sk);
+ } else { /* allow polling before and after fallback decision */
+ smc->clcsock->sk->sk_write_space(smc->clcsock->sk);
+ smc->sk.sk_write_space(&smc->sk);
+ }
+ }
kfree(smc->connect_info);
smc->connect_info = NULL;
release_sock(&smc->sk);
@@ -934,8 +947,13 @@ struct sock *smc_accept_dequeue(struct sock *parent,
sock_put(new_sk); /* final */
continue;
}
- if (new_sock)
+ if (new_sock) {
sock_graft(new_sk, new_sock);
+ if (isk->use_fallback) {
+ smc_sk(new_sk)->clcsock->file = new_sock->file;
+ isk->clcsock->file->private_data = isk->clcsock;
+ }
+ }
return new_sk;
}
return NULL;
@@ -1086,7 +1104,7 @@ static void smc_listen_decline(struct smc_sock *new_smc, int reason_code,
return;
}
smc_conn_free(&new_smc->conn);
- new_smc->use_fallback = true;
+ smc_switch_to_fallback(new_smc);
new_smc->fallback_rsn = reason_code;
if (reason_code && reason_code != SMC_CLC_DECL_PEERDECL) {
if (smc_clc_send_decline(new_smc, reason_code) < 0) {
@@ -1246,7 +1264,7 @@ static void smc_listen_work(struct work_struct *work)
/* check if peer is smc capable */
if (!tcp_sk(newclcsock->sk)->syn_smc) {
- new_smc->use_fallback = true;
+ smc_switch_to_fallback(new_smc);
new_smc->fallback_rsn = SMC_CLC_DECL_PEERNOSMC;
smc_listen_out_connected(new_smc);
return;
@@ -1503,7 +1521,7 @@ static int smc_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
if (msg->msg_flags & MSG_FASTOPEN) {
if (sk->sk_state == SMC_INIT) {
- smc->use_fallback = true;
+ smc_switch_to_fallback(smc);
smc->fallback_rsn = SMC_CLC_DECL_OPTUNSUPP;
} else {
rc = -EINVAL;
@@ -1705,7 +1723,7 @@ static int smc_setsockopt(struct socket *sock, int level, int optname,
case TCP_FASTOPEN_NO_COOKIE:
/* option not supported by SMC */
if (sk->sk_state == SMC_INIT) {
- smc->use_fallback = true;
+ smc_switch_to_fallback(smc);
smc->fallback_rsn = SMC_CLC_DECL_OPTUNSUPP;
} else {
if (!smc->use_fallback)
--
2.16.4
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH net 4/5] net/smc: fix return code from FLUSH command
2019-04-11 9:17 [PATCH net 0/5] net/smc: fixes 2019-04-11 Ursula Braun
` (2 preceding siblings ...)
2019-04-11 9:17 ` [PATCH net 3/5] net/smc: propagate file from SMC to TCP socket Ursula Braun
@ 2019-04-11 9:17 ` Ursula Braun
2019-04-11 9:17 ` [PATCH net 5/5] net/smc: move unhash before release of clcsock Ursula Braun
2019-04-11 18:04 ` [PATCH net 0/5] net/smc: fixes 2019-04-11 David Miller
5 siblings, 0 replies; 7+ messages in thread
From: Ursula Braun @ 2019-04-11 9:17 UTC (permalink / raw)
To: davem
Cc: netdev, linux-s390, schwidefsky, heiko.carstens, raspl, kgraul,
ubraun
From: Karsten Graul <kgraul@linux.ibm.com>
The FLUSH command is used to empty the pnet table. No return code is
expected from the command. Commit a9d8b0b1e3d6 added namespace support
for the pnet table and changed the FLUSH command processing to call
smc_pnet_remove_by_pnetid() to remove the pnet entries. This function
returns -ENOENT when no entry was deleted, which is now the return code
of the FLUSH command. As a result the FLUSH command will return an error
when the pnet table is already empty.
Restore the expected behavior and let FLUSH always return 0.
Fixes: a9d8b0b1e3d6 ("net/smc: add pnet table namespace support")
Signed-off-by: Karsten Graul <kgraul@linux.ibm.com>
Signed-off-by: Ursula Braun <ubraun@linux.ibm.com>
---
net/smc/smc_pnet.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/smc/smc_pnet.c b/net/smc/smc_pnet.c
index 8d2f6296279c..0285c7f9e79b 100644
--- a/net/smc/smc_pnet.c
+++ b/net/smc/smc_pnet.c
@@ -603,7 +603,8 @@ static int smc_pnet_flush(struct sk_buff *skb, struct genl_info *info)
{
struct net *net = genl_info_net(info);
- return smc_pnet_remove_by_pnetid(net, NULL);
+ smc_pnet_remove_by_pnetid(net, NULL);
+ return 0;
}
/* SMC_PNETID generic netlink operation definition */
--
2.16.4
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH net 5/5] net/smc: move unhash before release of clcsock
2019-04-11 9:17 [PATCH net 0/5] net/smc: fixes 2019-04-11 Ursula Braun
` (3 preceding siblings ...)
2019-04-11 9:17 ` [PATCH net 4/5] net/smc: fix return code from FLUSH command Ursula Braun
@ 2019-04-11 9:17 ` Ursula Braun
2019-04-11 18:04 ` [PATCH net 0/5] net/smc: fixes 2019-04-11 David Miller
5 siblings, 0 replies; 7+ messages in thread
From: Ursula Braun @ 2019-04-11 9:17 UTC (permalink / raw)
To: davem
Cc: netdev, linux-s390, schwidefsky, heiko.carstens, raspl, kgraul,
ubraun
Commit <26d92e951fe0>
("net/smc: move unhash as early as possible in smc_release()")
fixes one occurrence in the smc code, but the same pattern exists
in other places. This patch covers the remaining occurrences and
makes sure, the unhash operation is done before the smc->clcsock is
released. This avoids a potential use-after-free in smc_diag_dump().
Reviewed-by: Karsten Graul <kgraul@linux.ibm.com>
Signed-off-by: Ursula Braun <ubraun@linux.ibm.com>
---
net/smc/af_smc.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
index d2a0d15f809c..6f869ef49b32 100644
--- a/net/smc/af_smc.c
+++ b/net/smc/af_smc.c
@@ -884,11 +884,11 @@ static int smc_clcsock_accept(struct smc_sock *lsmc, struct smc_sock **new_smc)
if (rc < 0)
lsk->sk_err = -rc;
if (rc < 0 || lsk->sk_state == SMC_CLOSED) {
+ new_sk->sk_prot->unhash(new_sk);
if (new_clcsock)
sock_release(new_clcsock);
new_sk->sk_state = SMC_CLOSED;
sock_set_flag(new_sk, SOCK_DEAD);
- new_sk->sk_prot->unhash(new_sk);
sock_put(new_sk); /* final */
*new_smc = NULL;
goto out;
@@ -939,11 +939,11 @@ struct sock *smc_accept_dequeue(struct sock *parent,
smc_accept_unlink(new_sk);
if (new_sk->sk_state == SMC_CLOSED) {
+ new_sk->sk_prot->unhash(new_sk);
if (isk->clcsock) {
sock_release(isk->clcsock);
isk->clcsock = NULL;
}
- new_sk->sk_prot->unhash(new_sk);
sock_put(new_sk); /* final */
continue;
}
@@ -973,6 +973,7 @@ void smc_close_non_accepted(struct sock *sk)
sock_set_flag(sk, SOCK_DEAD);
sk->sk_shutdown |= SHUTDOWN_MASK;
}
+ sk->sk_prot->unhash(sk);
if (smc->clcsock) {
struct socket *tcp;
@@ -988,7 +989,6 @@ void smc_close_non_accepted(struct sock *sk)
smc_conn_free(&smc->conn);
}
release_sock(sk);
- sk->sk_prot->unhash(sk);
sock_put(sk); /* final sock_put */
}
--
2.16.4
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH net 0/5] net/smc: fixes 2019-04-11
2019-04-11 9:17 [PATCH net 0/5] net/smc: fixes 2019-04-11 Ursula Braun
` (4 preceding siblings ...)
2019-04-11 9:17 ` [PATCH net 5/5] net/smc: move unhash before release of clcsock Ursula Braun
@ 2019-04-11 18:04 ` David Miller
5 siblings, 0 replies; 7+ messages in thread
From: David Miller @ 2019-04-11 18:04 UTC (permalink / raw)
To: ubraun; +Cc: netdev, linux-s390, schwidefsky, heiko.carstens, raspl, kgraul
From: Ursula Braun <ubraun@linux.ibm.com>
Date: Thu, 11 Apr 2019 11:17:29 +0200
> here are some fixes in different areas of the smc code for the net
> tree.
Series applied, thank you.
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2019-04-11 18:04 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-04-11 9:17 [PATCH net 0/5] net/smc: fixes 2019-04-11 Ursula Braun
2019-04-11 9:17 ` [PATCH net 1/5] net/smc: wait for pending work before clcsock release_sock Ursula Braun
2019-04-11 9:17 ` [PATCH net 2/5] net/smc: fix a NULL pointer dereference Ursula Braun
2019-04-11 9:17 ` [PATCH net 3/5] net/smc: propagate file from SMC to TCP socket Ursula Braun
2019-04-11 9:17 ` [PATCH net 4/5] net/smc: fix return code from FLUSH command Ursula Braun
2019-04-11 9:17 ` [PATCH net 5/5] net/smc: move unhash before release of clcsock Ursula Braun
2019-04-11 18:04 ` [PATCH net 0/5] net/smc: fixes 2019-04-11 David Miller
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).