[openssh-commits] [openssh] 03/03: upstream: avoid race between multiple processes attempting to
git+noreply at mindrot.org
git+noreply at mindrot.org
Tue Sep 22 14:21:54 AEST 2026
This is an automated email from the git hooks/post-receive script.
dtucker pushed a commit to branch master
in repository openssh.
commit 2a72e9755bdd63c3a4b6a25437a63e8b5eef23a4
Author: djm at openbsd.org <djm at openbsd.org>
AuthorDate: Tue Sep 22 03:22:00 2026 +0000
upstream: avoid race between multiple processes attempting to
establish multiplexing control socket by moving socket creation earlier in
ssh(1)'s life. Patch from Jens Rosenboom via bz3971
ok naddy dtucker
OpenBSD-Commit-ID: 8361fb1cd20668216e06c9ba7b4ce72b2ba56fb7
---
clientloop.h | 3 ++-
mux.c | 73 ++++++++++++++++++++++++++++++------------------------------
ssh.c | 8 +++++--
3 files changed, 45 insertions(+), 39 deletions(-)
diff --git a/clientloop.h b/clientloop.h
index ed3c54fa7..7509de26b 100644
--- a/clientloop.h
+++ b/clientloop.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: clientloop.h,v 1.41 2026/03/03 09:57:25 dtucker Exp $ */
+/* $OpenBSD: clientloop.h,v 1.42 2026/09/22 03:22:00 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo at cs.hut.fi>
@@ -78,6 +78,7 @@ void client_expect_confirm(struct ssh *, int, const char *,
#define SSHMUX_COMMAND_CONNINFO 9 /* Show connection information */
#define SSHMUX_COMMAND_CHANINFO 10 /* Show channels information */
+int muxserver(const char *);
void muxserver_listen(struct ssh *);
int muxclient(const char *);
void mux_exit_message(struct ssh *, Channel *, int);
diff --git a/mux.c b/mux.c
index e4c2a85ba..005e8375b 100644
--- a/mux.c
+++ b/mux.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mux.c,v 1.114 2026/09/16 07:47:29 jsg Exp $ */
+/* $OpenBSD: mux.c,v 1.115 2026/09/22 03:22:00 djm Exp $ */
/*
* Copyright (c) 2002-2008 Damien Miller <djm at openbsd.org>
*
@@ -1315,21 +1315,20 @@ mux_tty_alloc_failed(struct ssh *ssh, Channel *c)
sshbuf_free(m);
}
-/* Prepare a mux master to listen on a Unix domain socket. */
-void
-muxserver_listen(struct ssh *ssh)
+/*
+ * Create a listening Unix domain socket for mux master or find out that
+ * one exists already.
+ */
+int
+muxserver(const char *path)
{
mode_t old_umask;
- char *orig_control_path = options.control_path;
+ char *tmp_path;
char rbuf[16+1];
u_int i, r;
int oerrno;
- if (options.control_path == NULL ||
- options.control_master == SSHCTL_MASTER_NO)
- return;
-
- debug("setting up multiplex master socket");
+ debug("trying to setup multiplex master socket at %s", path);
/*
* Use a temporary path before listen so we can pseudo-atomically
@@ -1344,51 +1343,53 @@ muxserver_listen(struct ssh *ssh)
'0' + r - 26 - 26;
}
rbuf[sizeof(rbuf) - 1] = '\0';
- options.control_path = NULL;
- xasprintf(&options.control_path, "%s.%s", orig_control_path, rbuf);
- debug3_f("temporary control path %s", options.control_path);
+ xasprintf(&tmp_path, "%s.%s", path, rbuf);
+ debug3_f("temporary control path %s", tmp_path);
old_umask = umask(0177);
- muxserver_sock = unix_listener(options.control_path, 64, 0);
+ muxserver_sock = unix_listener(tmp_path, 64, 0);
oerrno = errno;
umask(old_umask);
if (muxserver_sock < 0) {
if (oerrno == EINVAL || oerrno == EADDRINUSE) {
- error("ControlSocket %s already exists, "
- "disabling multiplexing", options.control_path);
- disable_mux_master:
- if (muxserver_sock != -1) {
- close(muxserver_sock);
- muxserver_sock = -1;
- }
- free(orig_control_path);
- free(options.control_path);
- options.control_path = NULL;
- options.control_master = SSHCTL_MASTER_NO;
- return;
+ error("Temporary ControlSocket %s already exists", tmp_path);
+ free(tmp_path);
+ return -1;
} else {
/* unix_listener() logs the error */
cleanup_exit(255);
}
}
+ set_nonblock(muxserver_sock);
/* Now atomically "move" the mux socket into position */
- if (link(options.control_path, orig_control_path) != 0) {
+ if (link(tmp_path, path) != 0) {
if (errno != EEXIST) {
fatal_f("link mux listener %s => %s: %s",
- options.control_path, orig_control_path,
+ tmp_path, path,
strerror(errno));
}
- error("ControlSocket %s already exists, disabling multiplexing",
- orig_control_path);
- unlink(options.control_path);
- goto disable_mux_master;
+ debug("ControlSocket %s already exists", path);
+ close(muxserver_sock);
+ muxserver_sock = -1;
}
- unlink(options.control_path);
- free(options.control_path);
- options.control_path = orig_control_path;
+ unlink(tmp_path);
+ free(tmp_path);
+ return muxserver_sock;
+}
- set_nonblock(muxserver_sock);
+/* Prepare a mux master to listen on the previously created Unix domain socket. */
+void
+muxserver_listen(struct ssh *ssh)
+{
+ if (options.control_path == NULL ||
+ options.control_master == SSHCTL_MASTER_NO)
+ return;
+
+ debug("setting up multiplex master socket");
+ if (muxserver_sock < 0) {
+ muxserver_sock = muxserver(options.control_path);
+ }
mux_listener_channel = channel_new(ssh, "mux listener",
SSH_CHANNEL_MUX_LISTENER, muxserver_sock, muxserver_sock, -1,
diff --git a/ssh.c b/ssh.c
index 081f0ba4a..0640abe49 100644
--- a/ssh.c
+++ b/ssh.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh.c,v 1.640 2026/09/16 07:47:29 jsg Exp $ */
+/* $OpenBSD: ssh.c,v 1.641 2026/09/22 03:22:00 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo at cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo at cs.hut.fi>, Espoo, Finland
@@ -1634,7 +1634,11 @@ main(int ac, char **av)
fatal("No ControlPath specified for \"-O\" command");
if (options.control_path != NULL) {
int sock;
- if ((sock = muxclient(options.control_path)) >= 0) {
+
+ if (muxclient_command == 0 &&
+ (sock = muxserver(options.control_path)) >= 0) {
+ debug("We will be multiplex master, not client.");
+ } else if ((sock = muxclient(options.control_path)) >= 0) {
if (ssh_packet_set_connection(ssh, sock, sock) == NULL)
fatal("ssh_packet_set_connection failed");
ssh_packet_set_mux(ssh);
--
To stop receiving notification emails like this one, please contact
djm at mindrot.org.
More information about the openssh-commits
mailing list