clcsock can be released while kernel_accept() references it in TCP
listen worker. Also, clcsock needs to wake up before released if TCP
fallback is used and the clcsock is blocked by accept. Add a lock to
safely release clcsock and call kernel_sock_shutdown() to wake up
clcsock from accept in smc_release().
Reported-by: syzbot+0bf2e01269f1274b4b03@syzkaller.appspotmail.com
Reported-by: syzbot+e3132895630f957306bc@syzkaller.appspotmail.com
Signed-off-by: Myungho Jung <redacted>
---
net/smc/af_smc.c | 14 ++++++++++++--
net/smc/smc.h | 2 ++
2 files changed, 14 insertions(+), 2 deletions(-)
@@ -147,8 +147,14 @@ static int smc_release(struct socket *sock)sk->sk_shutdown|=SHUTDOWN_MASK;}if(smc->clcsock){+if(smc->use_fallback&&sk->sk_state==SMC_LISTEN){+/* wake up clcsock accept */+rc=kernel_sock_shutdown(smc->clcsock,SHUT_RDWR);+}+mutex_lock(&smc->clcsock_release_lock);sock_release(smc->clcsock);smc->clcsock=NULL;+mutex_unlock(&smc->clcsock_release_lock);}if(smc->use_fallback){if(sk->sk_state!=SMC_LISTEN&&sk->sk_state!=SMC_INIT)
clcsock can be released while kernel_accept() references it in TCP
listen worker. Also, clcsock needs to wake up before released if TCP
fallback is used and the clcsock is blocked by accept. Add a lock to
safely release clcsock and call kernel_sock_shutdown() to wake up
clcsock from accept in smc_release().
Thanks for your effort to solve this problem. I have some minor
improvement proposals:
@@ -147,8 +147,14 @@ static int smc_release(struct socket *sock)sk->sk_shutdown|=SHUTDOWN_MASK;}if(smc->clcsock){+if(smc->use_fallback&&sk->sk_state==SMC_LISTEN){+/* wake up clcsock accept */+rc=kernel_sock_shutdown(smc->clcsock,SHUT_RDWR);+}
This part is not needed, since an SMC socket in state SMC_LISTEN is never
a use_fallback socket.
quoted hunk
+ mutex_lock(&smc->clcsock_release_lock);
sock_release(smc->clcsock);
smc->clcsock = NULL;
+ mutex_unlock(&smc->clcsock_release_lock);
}
if (smc->use_fallback) {
if (sk->sk_state != SMC_LISTEN && sk->sk_state != SMC_INIT)
On Mon, Dec 17, 2018 at 03:58:58PM +0100, Ursula Braun wrote:
Hi Ursula,
Thank you for your suggestion. I have a question on your comment.
On 12/17/2018 06:21 AM, Myungho Jung wrote:
quoted
clcsock can be released while kernel_accept() references it in TCP
listen worker. Also, clcsock needs to wake up before released if TCP
fallback is used and the clcsock is blocked by accept. Add a lock to
safely release clcsock and call kernel_sock_shutdown() to wake up
clcsock from accept in smc_release().
Thanks for your effort to solve this problem. I have some minor
improvement proposals:
@@ -147,8 +147,14 @@ static int smc_release(struct socket *sock)sk->sk_shutdown|=SHUTDOWN_MASK;}if(smc->clcsock){+if(smc->use_fallback&&sk->sk_state==SMC_LISTEN){+/* wake up clcsock accept */+rc=kernel_sock_shutdown(smc->clcsock,SHUT_RDWR);+}
This part is not needed, since an SMC socket in state SMC_LISTEN is never
a use_fallback socket.
In smc_sendmsg(), set use_fallback to true if SMC socket is SMC_INIT
state and the message has MSG_FASTOPEN flag. After this, smc_listen()
would trigger smc_tcp_listen_work(). Is this not an expected scenario?
Then, what is the reason for not skipping smc_sendmsg() in SMC_INIT
state?
quoted
+ mutex_lock(&smc->clcsock_release_lock);
sock_release(smc->clcsock);
smc->clcsock = NULL;
+ mutex_unlock(&smc->clcsock_release_lock);
}
if (smc->use_fallback) {
if (sk->sk_state != SMC_LISTEN && sk->sk_state != SMC_INIT)
On Mon, Dec 17, 2018 at 03:58:58PM +0100, Ursula Braun wrote:
quoted
Hi Ursula,
Thank you for your suggestion. I have a question on your comment.
quoted
On 12/17/2018 06:21 AM, Myungho Jung wrote:
quoted
clcsock can be released while kernel_accept() references it in TCP
listen worker. Also, clcsock needs to wake up before released if TCP
fallback is used and the clcsock is blocked by accept. Add a lock to
safely release clcsock and call kernel_sock_shutdown() to wake up
clcsock from accept in smc_release().
Thanks for your effort to solve this problem. I have some minor
improvement proposals:
@@ -147,8 +147,14 @@ static int smc_release(struct socket *sock)sk->sk_shutdown|=SHUTDOWN_MASK;}if(smc->clcsock){+if(smc->use_fallback&&sk->sk_state==SMC_LISTEN){+/* wake up clcsock accept */+rc=kernel_sock_shutdown(smc->clcsock,SHUT_RDWR);+}
This part is not needed, since an SMC socket in state SMC_LISTEN is never
a use_fallback socket.
In smc_sendmsg(), set use_fallback to true if SMC socket is SMC_INIT
state and the message has MSG_FASTOPEN flag. After this, smc_listen()
would trigger smc_tcp_listen_work(). Is this not an expected scenario?
Then, what is the reason for not skipping smc_sendmsg() in SMC_INIT
state?
You are right, I have not had the FASTOPEN case in mind, sorry. If we want
to allow fallback in case of FASTOPEN, we need the kernel_sock_shutdown() here
for proper cleanup. Nice!
quoted
quoted
+ mutex_lock(&smc->clcsock_release_lock);
sock_release(smc->clcsock);
smc->clcsock = NULL;
+ mutex_unlock(&smc->clcsock_release_lock);
}
if (smc->use_fallback) {
if (sk->sk_state != SMC_LISTEN && sk->sk_state != SMC_INIT)