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
|
From fb685ebb9f8391ab2836715c9c347ee50a0c9f48 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: backport, https://anongit.mindrot.org/openssh.git/commit/?id=29ef8a04866ca14688d5b7fed7b8b9deab851f77
Last-Update: 2023-09-17
Patch-Name: CVE-2023-38408-2.patch
---
misc.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++
misc.h | 1 +
ssh-pkcs11.c | 4 +++
ssh-sk.c | 6 ++--
4 files changed, 88 insertions(+), 2 deletions(-)
diff --git a/misc.c b/misc.c
index c75a795c2..c6e9e71a3 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>
@@ -2463,3 +2467,78 @@ ssh_signal(int signum, sshsig_t handler)
}
return osa.sa_handler;
}
+
+/*
+ * 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("%s: nlist failed for %s", __func__, path);
+ goto out;
+ }
+ if (r != 0 || nl[0].n_value == 0 || nl[0].n_type == 0) {
+ error("%s: library %s does not contain symbol %s",
+ __func__, 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("%s: open %s: %s", __func__, path, strerror(errno));
+ return -1;
+ }
+ if (fstat(fd, &st) != 0) {
+ error("%s: fstat %s: %s", __func__, path, strerror(errno));
+ goto out;
+ }
+ if (!S_ISREG(st.st_mode)) {
+ error("%s: %s is not a regular file", __func__, path);
+ goto out;
+ }
+ if (st.st_size < 0 ||
+ (size_t)st.st_size < strlen(s) ||
+ st.st_size >= INT_MAX/2) {
+ error("%s: %s bad size %lld",
+ __func__, 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("%s: mmap %s: %s", __func__, path, strerror(errno));
+ goto out;
+ }
+ if (memmem(m, sz, s, strlen(s)) == NULL) {
+ error("%s: %s does not contain expected string %s",
+ __func__, 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 b34c798e7..eb30bb454 100644
--- a/misc.h
+++ b/misc.h
@@ -90,6 +90,7 @@ const char *atoi_err(const char *, int *);
int parse_absolute_time(const char *, uint64_t *);
void format_absolute_time(uint64_t, char *, size_t);
int path_absolute(const char *);
+int lib_contains_symbol(const char *, const char *);
void sock_set_v6only(int);
diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c
index d864051c4..df4d53626 100644
--- a/ssh-pkcs11.c
+++ b/ssh-pkcs11.c
@@ -1514,6 +1514,10 @@ pkcs11_register_provider(char *provider_id, char *pin,
__func__, 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 1455df635..76fee8af2 100644
--- a/ssh-sk.c
+++ b/ssh-sk.c
@@ -123,10 +123,12 @@ sshsk_open(const char *path)
#endif
return ret;
}
- 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",
|