Date: Thu, 7 Oct 2021 14:05:01 GMT From: Mark Johnston <markj@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org Subject: git: 160ed20e623d - stable/13 - socket: Avoid clearing SS_ISCONNECTING if soconnect() fails Message-ID: <202110071405.197E513m013858@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch stable/13 has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=160ed20e623d44756e3e50bd99fbc9aee73e1595 commit 160ed20e623d44756e3e50bd99fbc9aee73e1595 Author: Mark Johnston <markj@FreeBSD.org> AuthorDate: 2021-09-07 18:51:54 +0000 Commit: Mark Johnston <markj@FreeBSD.org> CommitDate: 2021-10-07 13:57:27 +0000 socket: Avoid clearing SS_ISCONNECTING if soconnect() fails This behaviour appears to date from the 4.4 BSD import. It has two problems: 1. The update to so_state is not protected by the socket lock, so concurrent updates to so_state may be lost. 2. Suppose two threads race to call connect(2) on a socket, and one succeeds while the other fails. Then the failing thread may incorrectly clear SS_ISCONNECTING, confusing the state machine. Simply remove the update. It does not appear to be necessary: pru_connect implementations which call soisconnecting() only do so after all failure modes have been handled. For instance, tcp_connect() and tcp6_connect() will never return an error after calling soisconnected(). However, we cannot correctly assert that SS_ISCONNECTED is not set after an error from soconnect() since the socket lock is not held across the pru_connect call, so a concurrent connect(2) may have set the flag. Sponsored by: The FreeBSD Foundation (cherry picked from commit a8aa6f1f784b91acb4ef9387a28c78311493eb66) --- sys/kern/uipc_syscalls.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c index 3208dc0491dd..44079bae1e9b 100644 --- a/sys/kern/uipc_syscalls.c +++ b/sys/kern/uipc_syscalls.c @@ -484,7 +484,7 @@ kern_connectat(struct thread *td, int dirfd, int fd, struct sockaddr *sa) { struct socket *so; struct file *fp; - int error, interrupted = 0; + int error; #ifdef CAPABILITY_MODE if (IN_CAPABILITY_MODE(td) && (dirfd == AT_FDCWD)) @@ -522,11 +522,8 @@ kern_connectat(struct thread *td, int dirfd, int fd, struct sockaddr *sa) while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { error = msleep(&so->so_timeo, &so->so_lock, PSOCK | PCATCH, "connec", 0); - if (error != 0) { - if (error == EINTR || error == ERESTART) - interrupted = 1; + if (error != 0) break; - } } if (error == 0) { error = so->so_error; @@ -534,8 +531,6 @@ kern_connectat(struct thread *td, int dirfd, int fd, struct sockaddr *sa) } SOCK_UNLOCK(so); bad: - if (!interrupted) - so->so_state &= ~SS_ISCONNECTING; if (error == ERESTART) error = EINTR; done1:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202110071405.197E513m013858>