summaryrefslogtreecommitdiffstats
path: root/debian/patches/CVE-2023-38408-3.patch
blob: 60892228607f9eec700d5d0e837723fdf5c75562 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
From 29c7785a3673101b3af8f6f712795fa128e52ddd Mon Sep 17 00:00:00 2001
From: "djm@openbsd.org" <djm@openbsd.org>
Date: Wed, 19 Jul 2023 14:02:27 +0000
Subject: upstream: 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

OpenBSD-Commit-ID: 1508a5fbd74e329e69a55b56c453c292029aefbe

Origin: upstream, https://anongit.mindrot.org/openssh.git/commit/?id=29ef8a04866ca14688d5b7fed7b8b9deab851f77
Last-Update: 2023-09-17

Patch-Name: CVE-2023-38408-3.patch
---
 misc.c       | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 misc.h       |  1 +
 ssh-pkcs11.c |  4 +++
 ssh-sk.c     |  8 +++---
 4 files changed, 86 insertions(+), 3 deletions(-)

diff --git a/misc.c b/misc.c
index 2268d8875..36e72f5b5 100644
--- a/misc.c
+++ b/misc.c
@@ -22,6 +22,7 @@
 
 #include <sys/types.h>
 #include <sys/ioctl.h>
+#include <sys/mman.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/time.h>
@@ -35,6 +36,9 @@
 #ifdef HAVE_POLL_H
 #include <poll.h>
 #endif
+#ifdef HAVE_NLIST_H
+#include <nlist.h>
+#endif
 #include <signal.h>
 #include <stdarg.h>
 #include <stdio.h>
@@ -2962,3 +2966,75 @@ 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)
+{
+#ifdef HAVE_NLIST_H
+	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;
+#else /* HAVE_NLIST_H */
+	int fd, ret = -1;
+	struct stat st;
+	void *m = NULL;
+	size_t sz = 0;
+
+	memset(&st, 0, sizeof(st));
+	if ((fd = open(path, O_RDONLY)) < 0) {
+		error_f("open %s: %s", path, strerror(errno));
+		return -1;
+	}
+	if (fstat(fd, &st) != 0) {
+		error_f("fstat %s: %s", path, strerror(errno));
+		goto out;
+	}
+	if (!S_ISREG(st.st_mode)) {
+		error_f("%s is not a regular file", path);
+		goto out;
+	}
+	if (st.st_size < 0 ||
+	    (size_t)st.st_size < strlen(s) ||
+	    st.st_size >= INT_MAX/2) {
+		error_f("%s bad size %lld", path, (long long)st.st_size);
+		goto out;
+	}
+	sz = (size_t)st.st_size;
+	if ((m = mmap(NULL, sz, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED ||
+	    m == NULL) {
+		error_f("mmap %s: %s", path, strerror(errno));
+		goto out;
+	}
+	if (memmem(m, sz, s, strlen(s)) == NULL) {
+		error_f("%s does not contain expected string %s", path, s);
+		goto out;
+	}
+	/* success */
+	ret = 0;
+ out:
+	if (m != NULL && m != MAP_FAILED)
+		munmap(m, sz);
+	close(fd);
+	return ret;
+#endif /* HAVE_NLIST_H */
+}
diff --git a/misc.h b/misc.h
index 31b6557c6..1a49e7cec 100644
--- a/misc.h
+++ b/misc.h
@@ -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 *);
 
 void	 sock_set_v6only(int);
 
diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c
index 9e48c134e..0aef37934 100644
--- a/ssh-pkcs11.c
+++ b/ssh-pkcs11.c
@@ -1532,6 +1532,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());
diff --git a/ssh-sk.c b/ssh-sk.c
index fbeb39320..d1c18803f 100644
--- a/ssh-sk.c
+++ b/ssh-sk.c
@@ -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
  *
@@ -133,10 +133,12 @@ sshsk_open(const char *path)
 		goto fail;
 #endif
 	}
-	if ((ret->dlhandle = dlopen(path, RTLD_NOW)) == NULL) {
-		error("Provider \"%s\" dlopen failed: %s", path, dlerror());
+	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)
+		fatal("Provider \"%s\" dlopen failed: %s", path, dlerror());
 	if ((ret->sk_api_version = dlsym(ret->dlhandle,
 	    "sk_api_version")) == NULL) {
 		error("Provider \"%s\" dlsym(sk_api_version) failed: %s",