[openssh-commits] [openssh] 02/04: upstream: Stop doing access() before execve(). It is a TOCTOU, but

git+noreply at mindrot.org git+noreply at mindrot.org
Tue Mar 10 14:46:10 AEDT 2026


This is an automated email from the git hooks/post-receive script.

djm pushed a commit to branch master
in repository openssh.

commit b75bf339eae6115c544bdcefa0d67a6dcc971ec5
Author: deraadt at openbsd.org <deraadt at openbsd.org>
AuthorDate: Sat Mar 7 18:27:52 2026 +0000

    upstream: Stop doing access() before execve(). It is a TOCTOU, but
    
    also it forces use of unveil "rx" instead of "x". This is done by using a
    pipe() through the fork+execve attempt to expose execve failure and create
    the same error return as the access() used to do. ok djm dtucker
    
    OpenBSD-Commit-ID: f9ee96e20352f35dc6f39127e0cc6b804700200a
---
 ssh-sk-client.c | 42 +++++++++++++++++++++++++++++++-----------
 1 file changed, 31 insertions(+), 11 deletions(-)

diff --git a/ssh-sk-client.c b/ssh-sk-client.c
index df3dd0fc7..c8b0695b0 100644
--- a/ssh-sk-client.c
+++ b/ssh-sk-client.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-sk-client.c,v 1.14 2026/02/14 00:18:34 jsg Exp $ */
+/* $OpenBSD: ssh-sk-client.c,v 1.15 2026/03/07 18:27:52 deraadt Exp $ */
 /*
  * Copyright (c) 2019 Google LLC
  *
@@ -29,6 +29,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <fcntl.h>
 
 #include "log.h"
 #include "ssherr.h"
@@ -45,9 +46,10 @@ static int
 start_helper(int *fdp, pid_t *pidp, void (**osigchldp)(int))
 {
 	void (*osigchld)(int);
-	int oerrno, pair[2];
+	int oerrno, pair[2], execpipe[2];
+	ssize_t n;
 	pid_t pid;
-	char *helper, *verbosity = NULL;
+	char execbuf[100], *helper, *verbosity = NULL;
 
 	*fdp = -1;
 	*pidp = 0;
@@ -56,19 +58,20 @@ start_helper(int *fdp, pid_t *pidp, void (**osigchldp)(int))
 	helper = getenv("SSH_SK_HELPER");
 	if (helper == NULL || strlen(helper) == 0)
 		helper = _PATH_SSH_SK_HELPER;
-	if (access(helper, X_OK) != 0) {
-		oerrno = errno;
-		error_f("helper \"%s\" unusable: %s", helper, strerror(errno));
-		errno = oerrno;
-		return SSH_ERR_SYSTEM_ERROR;
-	}
 #ifdef DEBUG_SK
 	verbosity = "-vvv";
 #endif
 
+	/* Create a O_CLOEXEC pipe to capture the execve() failure */
+	if (pipe(execpipe) == -1) {
+		error("pipe:  %s", strerror(errno));
+		return SSH_ERR_SYSTEM_ERROR;
+	}
 	/* Start helper */
 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) {
 		error("socketpair: %s", strerror(errno));
+		close(execpipe[0]);
+		close(execpipe[1]);
 		return SSH_ERR_SYSTEM_ERROR;
 	}
 	osigchld = ssh_signal(SIGCHLD, SIG_DFL);
@@ -77,14 +80,20 @@ start_helper(int *fdp, pid_t *pidp, void (**osigchldp)(int))
 		error("fork: %s", strerror(errno));
 		close(pair[0]);
 		close(pair[1]);
+		close(execpipe[0]);
+		close(execpipe[1]);
 		ssh_signal(SIGCHLD, osigchld);
 		errno = oerrno;
 		return SSH_ERR_SYSTEM_ERROR;
 	}
 	if (pid == 0) {
+		close(execpipe[0]);
+		fcntl(execpipe[1], F_SETFD, FD_CLOEXEC);
 		if ((dup2(pair[1], STDIN_FILENO) == -1) ||
 		    (dup2(pair[1], STDOUT_FILENO) == -1)) {
-			error_f("dup2: %s", strerror(errno));
+			snprintf(execbuf, sizeof execbuf,
+			    "dup2: %s", strerror(errno));
+			write(execpipe[1], execbuf, strlen(execbuf)+1);
 			_exit(1);
 		}
 		close(pair[0]);
@@ -93,11 +102,22 @@ start_helper(int *fdp, pid_t *pidp, void (**osigchldp)(int))
 		debug_f("starting %s %s", helper,
 		    verbosity == NULL ? "" : verbosity);
 		execlp(helper, helper, verbosity, (char *)NULL);
-		error_f("execlp: %s", strerror(errno));
+		snprintf(execbuf, sizeof execbuf,
+		    "execlp: %s", strerror(errno));
+		write(execpipe[1], execbuf, strlen(execbuf)+1);
 		_exit(1);
 	}
 	close(pair[1]);
 
+	close(execpipe[1]);
+	n = read(execpipe[0], execbuf, sizeof execbuf);
+	close(execpipe[0]);
+	if (n > 0) {
+		execbuf[n] = '\0';
+		error("%s", execbuf);
+		return SSH_ERR_SYSTEM_ERROR;
+	}
+
 	/* success */
 	debug3_f("started pid=%ld", (long)pid);
 	*fdp = pair[0];

-- 
To stop receiving notification emails like this one, please contact
djm at mindrot.org.


More information about the openssh-commits mailing list