Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net/smc: reduce sock_put() for fallback sockets

smc_release() calls a sock_put() for smc fallback sockets to cover
the passive closing sock_hold() in __smc_connect() and
smc_tcp_listen_work(). This does not make sense for sockets in state
SMC_LISTEN and SMC_INIT.
An SMC socket stays in state SMC_INIT if connect fails. The sock_put
in smc_connect_abort() does not cover all failures. Move it into
smc_connect_decline_fallback().

Fixes: ee9dfbef02d18 ("net/smc: handle sockopts forcing fallback")
Reported-by: syzbot+3a0748c8f2f210c0ef9b@syzkaller.appspotmail.com
Reported-by: syzbot+9e60d2428a42049a592a@syzkaller.appspotmail.com
Signed-off-by: Ursula Braun <ubraun@linux.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Ursula Braun and committed by
David S. Miller
e1bbdd57 000244d3

+12 -5
+10 -5
net/smc/af_smc.c
··· 147 147 smc->clcsock = NULL; 148 148 } 149 149 if (smc->use_fallback) { 150 - sock_put(sk); /* passive closing */ 150 + if (sk->sk_state != SMC_LISTEN && sk->sk_state != SMC_INIT) 151 + sock_put(sk); /* passive closing */ 151 152 sk->sk_state = SMC_CLOSED; 152 153 sk->sk_state_change(sk); 153 154 } ··· 418 417 { 419 418 int rc; 420 419 421 - if (reason_code < 0) /* error, fallback is not possible */ 420 + if (reason_code < 0) { /* error, fallback is not possible */ 421 + if (smc->sk.sk_state == SMC_INIT) 422 + sock_put(&smc->sk); /* passive closing */ 422 423 return reason_code; 424 + } 423 425 if (reason_code != SMC_CLC_DECL_REPLY) { 424 426 rc = smc_clc_send_decline(smc, reason_code); 425 - if (rc < 0) 427 + if (rc < 0) { 428 + if (smc->sk.sk_state == SMC_INIT) 429 + sock_put(&smc->sk); /* passive closing */ 426 430 return rc; 431 + } 427 432 } 428 433 return smc_connect_fallback(smc); 429 434 } ··· 442 435 smc_lgr_forget(smc->conn.lgr); 443 436 mutex_unlock(&smc_create_lgr_pending); 444 437 smc_conn_free(&smc->conn); 445 - if (reason_code < 0 && smc->sk.sk_state == SMC_INIT) 446 - sock_put(&smc->sk); /* passive closing */ 447 438 return reason_code; 448 439 } 449 440
+2
net/smc/smc_close.c
··· 107 107 } 108 108 switch (sk->sk_state) { 109 109 case SMC_INIT: 110 + sk->sk_state = SMC_PEERABORTWAIT; 111 + break; 110 112 case SMC_ACTIVE: 111 113 sk->sk_state = SMC_PEERABORTWAIT; 112 114 release_sock(sk);