CVE-2023-38408 (published 2023-07-20T03:15Z)

The PKCS#11 feature in ssh-agent in OpenSSH before 9.3p2 has an insufficiently trustworthy search path, leading to remote code execution if an agent is forwarded to an attacker-controlled system. (Code in /usr/lib is not necessarily safe for loading into ssh-agent.) NOTE: this issue exists because of an incomplete fix for CVE-2016-10009.

CVSS v3 base score: 9.8, CRITICAL (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-428
cwe_name: Unquoted Search Path or Element
description: The product uses a search path that contains an unquoted element, in which the element contains whitespace or other separators. This can cause the product to access resources in a parent path.
extended_description: If a malicious individual has access to the file system, it is possible to elevate privileges by inserting such a file as "C:\Program.exe" to be run by a privileged program making use of WinExec.
         

Fix information:
repo_url: https://github.com/openbsd/src
commit_details: repo_url: https://github.com/openbsd/src
author: djm
author_date: 2023-07-19 13:56:33+00:00
msg: Disallow remote addition of FIDO/PKCS11 provider libraries to
ssh-agent by default.

The old behaviour of allowing remote clients from loading providers
can be restored using `ssh-agent -O allow-remote-pkcs11`.

Detection of local/remote clients requires a ssh(1) that supports
the `session-bind@openssh.com` extension. Forwarding access to a
ssh-agent socket using non-OpenSSH tools may circumvent this control.

ok markus@
repository: repo_url: https://github.com/openbsd/src
repo_name: openbsd/src
description: Read-only git conversion of OpenBSD's official CVS src repository. Pull requests not accepted - send diffs to the tech@ mailing list.
repo_language: C
owner: openbsd
file_changes: filename: ssh-agent.1
change_type: ModificationType.MODIFY
diff: @@ -1,4 +1,4 @@
-.\" $OpenBSD: ssh-agent.1,v 1.75 2022/10/07 06:00:58 jmc Exp $
+.\" $OpenBSD: ssh-agent.1,v 1.76 2023/07/19 13:56:33 djm Exp $
 .\"
 .\" Author: Tatu Ylonen <ylo@cs.hut.fi>
 .\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -34,7 +34,7 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd $Mdocdate: October 7 2022 $
+.Dd $Mdocdate: July 19 2023 $
 .Dt SSH-AGENT 1
 .Os
 .Sh NAME
@@ -107,9 +107,27 @@ environment variable).
 .It Fl O Ar option
 Specify an option when starting
 .Nm .
-Currently only one option is supported:
+Currently two options are supported:
+.Cm allow-remote-pkcs11
+and
 .Cm no-restrict-websafe .
-This instructs
+.Pp
+The
+.Cm allow-remote-pkcs11
+option allows clients of a forwarded
+.Nm
+to load PKCS#11 or FIDO provider libraries.
+By default only local clients may perform this operation.
+Note that signalling that a
+.Nm
+client remote is performed by
+.Xr ssh 1 ,
+and use of other tools to forward access to the agent socket may circumvent
+this restriction.
+.Pp
+The
+.Cm no-restrict-websafe ,
+instructs
 .Nm
 to permit signatures using FIDO keys that might be web authentication
 requests.

programming_language: Shell
filename: ssh-agent.c
change_type: ModificationType.MODIFY
diff: @@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-agent.c,v 1.299 2023/07/10 04:51:26 djm Exp $ */
+/* $OpenBSD: ssh-agent.c,v 1.300 2023/07/19 13:56:33 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -156,6 +156,12 @@ char socket_dir[PATH_MAX];
 /* Pattern-list of allowed PKCS#11/Security key paths */
 static char *allowed_providers;
 
+/*
+ * Allows PKCS11 providers or SK keys that use non-internal providers to
+ * be added over a remote connection (identified by session-bind@openssh.com).
+ */
+static int remote_add_provider;
+
 /* locking */
 #define LOCK_SIZE	32
 #define LOCK_SALT_SIZE	16
@@ -1215,6 +1221,12 @@ process_add_identity(SocketEntry *e)
 		if (strcasecmp(sk_provider, "internal") == 0) {
 			debug_f("internal provider");
 		} else {
+			if (e->nsession_ids != 0 && !remote_add_provider) {
+				verbose("failed add of SK provider \"%.100s\": "
+				    "remote addition of providers is disabled",
+				    sk_provider);
+				goto out;
+			}
 			if (realpath(sk_provider, canonical_provider) == NULL) {
 				verbose("failed provider \"%.100s\": "
 				    "realpath: %s", sk_provider,
@@ -1378,6 +1390,11 @@ process_add_smartcard_key(SocketEntry *e)
 		error_f("failed to parse constraints");
 		goto send;
 	}
+	if (e->nsession_ids != 0 && !remote_add_provider) {
+		verbose("failed PKCS#11 add of \"%.100s\": remote addition of "
+		    "providers is disabled", provider);
+		goto send;
+	}
 	if (realpath(provider, canonical_provider) == NULL) {
 		verbose("failed PKCS#11 add of \"%.100s\": realpath: %s",
 		    provider, strerror(errno));
@@ -2032,7 +2049,9 @@ main(int ac, char **av)
 			break;
 		case 'O':
 			if (strcmp(optarg, "no-restrict-websafe") == 0)
-				restrict_websafe  = 0;
+				restrict_websafe = 0;
+			else if (strcmp(optarg, "allow-remote-pkcs11") == 0)
+				remote_add_provider = 1;
 			else
 				fatal("Unknown -O option");
 			break;

programming_language: C
repo_url: https://github.com/openbsd/src
commit_details: repo_url: https://github.com/openbsd/src
author: djm
author_date: 2023-07-19 14:02:27+00:00
msg: Ensure FIDO/PKCS11 libraries contain expected symbols

This checks via nlist(3) that candidate provider libraries contain one
of the symbols that we will require prior to dlopen(), which can cause
a number of side effects, including execution of constructors.

Feedback deraadt; ok markus
repository: repo_url: https://github.com/openbsd/src
repo_name: openbsd/src
description: Read-only git conversion of OpenBSD's official CVS src repository. Pull requests not accepted - send diffs to the tech@ mailing list.
repo_language: C
owner: openbsd
file_changes: filename: misc.c
change_type: ModificationType.MODIFY
diff: @@ -1,4 +1,4 @@
-/* $OpenBSD: misc.c,v 1.183 2023/07/14 07:44:21 dtucker Exp $ */
+/* $OpenBSD: misc.c,v 1.184 2023/07/19 14:02:27 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  * Copyright (c) 2005-2020 Damien Miller.  All rights reserved.
@@ -40,6 +40,7 @@
 #include <pwd.h>
 #include <libgen.h>
 #include <limits.h>
+#include <nlist.h>
 #include <poll.h>
 #include <signal.h>
 #include <stdarg.h>
@@ -2814,3 +2815,31 @@ ptimeout_isset(struct timespec *pt)
 {
 	return pt->tv_sec != -1;
 }
+
+/*
+ * Returns zero if the library at 'path' contains symbol 's', nonzero
+ * otherwise.
+ */
+int
+lib_contains_symbol(const char *path, const char *s)
+{
+	struct nlist nl[2];
+	int ret = -1, r;
+
+	memset(nl, 0, sizeof(nl));
+	nl[0].n_name = xstrdup(s);
+	nl[1].n_name = NULL;
+	if ((r = nlist(path, nl)) == -1) {
+		error_f("nlist failed for %s", path);
+		goto out;
+	}
+	if (r != 0 || nl[0].n_value == 0 || nl[0].n_type == 0) {
+		error_f("library %s does not contain symbol %s", path, s);
+		goto out;
+	}
+	/* success */
+	ret = 0;
+ out:
+	free(nl[0].n_name);
+	return ret;
+}

programming_language: C
filename: misc.h
change_type: ModificationType.MODIFY
diff: @@ -1,4 +1,4 @@
-/* $OpenBSD: misc.h,v 1.102 2023/03/03 02:37:58 dtucker Exp $ */
+/* $OpenBSD: misc.h,v 1.103 2023/07/19 14:02:27 djm Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -96,6 +96,7 @@ int	 parse_absolute_time(const char *, uint64_t *);
 void	 format_absolute_time(uint64_t, char *, size_t);
 int	 path_absolute(const char *);
 int	 stdfd_devnull(int, int, int);
+int	 lib_contains_symbol(const char *, const char *);
 
 struct passwd *pwcopy(struct passwd *);
 const char *ssh_gai_strerror(int);

programming_language: C
filename: ssh-pkcs11.c
change_type: ModificationType.MODIFY
diff: @@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-pkcs11.c,v 1.57 2023/07/19 13:55:53 djm Exp $ */
+/* $OpenBSD: ssh-pkcs11.c,v 1.58 2023/07/19 14:02:27 djm Exp $ */
 /*
  * Copyright (c) 2010 Markus Friedl.  All rights reserved.
  * Copyright (c) 2014 Pedro Martelletto. All rights reserved.
@@ -1507,6 +1507,10 @@ pkcs11_register_provider(char *provider_id, char *pin,
 		debug_f("provider already registered: %s", provider_id);
 		goto fail;
 	}
+	if (lib_contains_symbol(provider_id, "C_GetFunctionList") != 0) {
+		error("provider %s is not a PKCS11 library", provider_id);
+		goto fail;
+	}
 	/* open shared pkcs11-library */
 	if ((handle = dlopen(provider_id, RTLD_NOW)) == NULL) {
 		error("dlopen %s failed: %s", provider_id, dlerror());

programming_language: C
filename: ssh-sk.c
change_type: ModificationType.MODIFY
diff: @@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-sk.c,v 1.39 2022/07/20 03:29:14 djm Exp $ */
+/* $OpenBSD: ssh-sk.c,v 1.40 2023/07/19 14:02:27 djm Exp $ */
 /*
  * Copyright (c) 2019 Google LLC
  *
@@ -113,15 +113,18 @@ sshsk_open(const char *path)
 		ret->sk_load_resident_keys = ssh_sk_load_resident_keys;
 		return ret;
 	}
+	if (lib_contains_symbol(path, "sk_api_version") != 0) {
+		error("provider %s is not an OpenSSH FIDO library", path);
+		goto fail;
+	}
 	if ((ret->dlhandle = dlopen(path, RTLD_NOW)) == NULL) {
 		error("Provider \"%s\" dlopen failed: %s", path, dlerror());
 		goto fail;
 	}
 	if ((ret->sk_api_version = dlsym(ret->dlhandle,
 	    "sk_api_version")) == NULL) {
-		error("Provider \"%s\" dlsym(sk_api_version) failed: %s",
+		fatal("Provider \"%s\" dlsym(sk_api_version) failed: %s",
 		    path, dlerror());
-		goto fail;
 	}
 	version = ret->sk_api_version();
 	debug_f("provider %s implements version 0x%08lx", ret->path,

programming_language: C
repo_url: https://github.com/openbsd/src
commit_details: repo_url: https://github.com/openbsd/src
author: djm
author_date: 2023-07-19 13:55:53+00:00
msg: terminate process if requested to load a PKCS#11 provider that
isn't a PKCS#11 provider; from / ok markus@
repository: repo_url: https://github.com/openbsd/src
repo_name: openbsd/src
description: Read-only git conversion of OpenBSD's official CVS src repository. Pull requests not accepted - send diffs to the tech@ mailing list.
repo_language: C
owner: openbsd
file_changes: filename: ssh-pkcs11.c
change_type: ModificationType.MODIFY
diff: @@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-pkcs11.c,v 1.56 2023/03/08 05:33:53 tb Exp $ */
+/* $OpenBSD: ssh-pkcs11.c,v 1.57 2023/07/19 13:55:53 djm Exp $ */
 /*
  * Copyright (c) 2010 Markus Friedl.  All rights reserved.
  * Copyright (c) 2014 Pedro Martelletto. All rights reserved.
@@ -1512,10 +1512,8 @@ pkcs11_register_provider(char *provider_id, char *pin,
 		error("dlopen %s failed: %s", provider_id, dlerror());
 		goto fail;
 	}
-	if ((getfunctionlist = dlsym(handle, "C_GetFunctionList")) == NULL) {
-		error("dlsym(C_GetFunctionList) failed: %s", dlerror());
-		goto fail;
-	}
+	if ((getfunctionlist = dlsym(handle, "C_GetFunctionList")) == NULL)
+		fatal("dlsym(C_GetFunctionList) failed: %s", dlerror());
 	p = xcalloc(1, sizeof(*p));
 	p->name = xstrdup(provider_id);
 	p->handle = handle;

programming_language: C