diff options
author | Shubham Kulkarni <skulkarni@mvista.com> | 2023-09-06 13:28:50 +0530 |
---|---|---|
committer | Steve Sakoman <steve@sakoman.com> | 2023-09-15 03:47:11 -1000 |
commit | 0485ee7a6b889f7161732435bb1136bd86954f44 (patch) | |
tree | e81c430345c3559ae9cf1b99729898bd3e34b3b0 /meta/recipes-connectivity/openssh/openssh/CVE-2023-38408-11.patch | |
parent | 90175073f614c8430e1ed694501df4e5474d57aa (diff) | |
download | poky-0485ee7a6b889f7161732435bb1136bd86954f44.tar.gz |
openssh: Securiry fix for CVE-2023-38408
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.
References:
https://nvd.nist.gov/vuln/detail/CVE-2023-38408
Upstream patches:
https://github.com/openssh/openssh-portable/commit/dee22129, https://github.com/openssh/openssh-portable/commit/099cdf59,
https://github.com/openssh/openssh-portable/commit/29ef8a04, https://github.com/openssh/openssh-portable/commit/892506b1,
https://github.com/openssh/openssh-portable/commit/0c111eb8, https://github.com/openssh/openssh-portable/commit/52a03e9f,
https://github.com/openssh/openssh-portable/commit/1fe16fd6, https://github.com/openssh/openssh-portable/commit/e0e8bee8,
https://github.com/openssh/openssh-portable/commit/8afaa7d7, https://github.com/openssh/openssh-portable/commit/1a4b9275,
https://github.com/openssh/openssh-portable/commit/4c1e3ce8, https://github.com/openssh/openssh-portable/commit/1f2731f5.
(From OE-Core rev: 9242b8218858d2bebb3235929fea7e7235cd40f3)
Signed-off-by: Shubham Kulkarni <skulkarni@mvista.com>
Signed-off-by: Steve Sakoman <steve@sakoman.com>
Diffstat (limited to 'meta/recipes-connectivity/openssh/openssh/CVE-2023-38408-11.patch')
-rw-r--r-- | meta/recipes-connectivity/openssh/openssh/CVE-2023-38408-11.patch | 307 |
1 files changed, 307 insertions, 0 deletions
diff --git a/meta/recipes-connectivity/openssh/openssh/CVE-2023-38408-11.patch b/meta/recipes-connectivity/openssh/openssh/CVE-2023-38408-11.patch new file mode 100644 index 0000000000..c300393ebf --- /dev/null +++ b/meta/recipes-connectivity/openssh/openssh/CVE-2023-38408-11.patch | |||
@@ -0,0 +1,307 @@ | |||
1 | From 2b3b369c8cf71f9ef5942a5e074e6f86e7ca1e0c Mon Sep 17 00:00:00 2001 | ||
2 | From: "djm@openbsd.org" <djm@openbsd.org> | ||
3 | Date: Sun, 19 Dec 2021 22:09:23 +0000 | ||
4 | Subject: [PATCH 11/12] upstream: ssh-agent side of binding | ||
5 | |||
6 | record session ID/hostkey/forwarding status for each active socket. | ||
7 | |||
8 | Attempt to parse data-to-be-signed at signature request time and extract | ||
9 | session ID from the blob if it is a pubkey userauth request. | ||
10 | |||
11 | ok markus@ | ||
12 | |||
13 | OpenBSD-Commit-ID: a80fd41e292b18b67508362129e9fed549abd318 | ||
14 | |||
15 | Upstream-Status: Backport [https://github.com/openssh/openssh-portable/commit/4c1e3ce85e183a9d0c955c88589fed18e4d6a058] | ||
16 | CVE: CVE-2023-38408 | ||
17 | Signed-off-by: Shubham Kulkarni <skulkarni@mvista.com> | ||
18 | --- | ||
19 | authfd.h | 3 + | ||
20 | ssh-agent.c | 175 +++++++++++++++++++++++++++++++++++++++++++++++++--- | ||
21 | 2 files changed, 170 insertions(+), 8 deletions(-) | ||
22 | |||
23 | diff --git a/authfd.h b/authfd.h | ||
24 | index c3bf625..9cc9807 100644 | ||
25 | --- a/authfd.h | ||
26 | +++ b/authfd.h | ||
27 | @@ -76,6 +76,9 @@ int ssh_agent_sign(int sock, const struct sshkey *key, | ||
28 | #define SSH2_AGENTC_ADD_ID_CONSTRAINED 25 | ||
29 | #define SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED 26 | ||
30 | |||
31 | +/* generic extension mechanism */ | ||
32 | +#define SSH_AGENTC_EXTENSION 27 | ||
33 | + | ||
34 | #define SSH_AGENT_CONSTRAIN_LIFETIME 1 | ||
35 | #define SSH_AGENT_CONSTRAIN_CONFIRM 2 | ||
36 | #define SSH_AGENT_CONSTRAIN_MAXSIGN 3 | ||
37 | diff --git a/ssh-agent.c b/ssh-agent.c | ||
38 | index 7f1e14b..01c7f2b 100644 | ||
39 | --- a/ssh-agent.c | ||
40 | +++ b/ssh-agent.c | ||
41 | @@ -1,4 +1,4 @@ | ||
42 | -/* $OpenBSD: ssh-agent.c,v 1.275 2021/01/29 06:29:46 djm Exp $ */ | ||
43 | +/* $OpenBSD: ssh-agent.c,v 1.280 2021/12/19 22:09:23 djm Exp $ */ | ||
44 | /* | ||
45 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | ||
46 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | ||
47 | @@ -98,9 +98,15 @@ | ||
48 | #endif | ||
49 | |||
50 | /* Maximum accepted message length */ | ||
51 | -#define AGENT_MAX_LEN (256*1024) | ||
52 | +#define AGENT_MAX_LEN (256*1024) | ||
53 | /* Maximum bytes to read from client socket */ | ||
54 | -#define AGENT_RBUF_LEN (4096) | ||
55 | +#define AGENT_RBUF_LEN (4096) | ||
56 | +/* Maximum number of recorded session IDs/hostkeys per connection */ | ||
57 | +#define AGENT_MAX_SESSION_IDS 16 | ||
58 | +/* Maximum size of session ID */ | ||
59 | +#define AGENT_MAX_SID_LEN 128 | ||
60 | + | ||
61 | +/* XXX store hostkey_sid in a refcounted tree */ | ||
62 | |||
63 | typedef enum { | ||
64 | AUTH_UNUSED = 0, | ||
65 | @@ -108,12 +114,20 @@ typedef enum { | ||
66 | AUTH_CONNECTION = 2, | ||
67 | } sock_type; | ||
68 | |||
69 | +struct hostkey_sid { | ||
70 | + struct sshkey *key; | ||
71 | + struct sshbuf *sid; | ||
72 | + int forwarded; | ||
73 | +}; | ||
74 | + | ||
75 | typedef struct socket_entry { | ||
76 | int fd; | ||
77 | sock_type type; | ||
78 | struct sshbuf *input; | ||
79 | struct sshbuf *output; | ||
80 | struct sshbuf *request; | ||
81 | + size_t nsession_ids; | ||
82 | + struct hostkey_sid *session_ids; | ||
83 | } SocketEntry; | ||
84 | |||
85 | u_int sockets_alloc = 0; | ||
86 | @@ -174,10 +188,17 @@ static int restrict_websafe = 1; | ||
87 | static void | ||
88 | close_socket(SocketEntry *e) | ||
89 | { | ||
90 | + size_t i; | ||
91 | + | ||
92 | close(e->fd); | ||
93 | sshbuf_free(e->input); | ||
94 | sshbuf_free(e->output); | ||
95 | sshbuf_free(e->request); | ||
96 | + for (i = 0; i < e->nsession_ids; i++) { | ||
97 | + sshkey_free(e->session_ids[i].key); | ||
98 | + sshbuf_free(e->session_ids[i].sid); | ||
99 | + } | ||
100 | + free(e->session_ids); | ||
101 | memset(e, '\0', sizeof(*e)); | ||
102 | e->fd = -1; | ||
103 | e->type = AUTH_UNUSED; | ||
104 | @@ -423,6 +444,18 @@ check_websafe_message_contents(struct sshkey *key, struct sshbuf *data) | ||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | +static int | ||
109 | +buf_equal(const struct sshbuf *a, const struct sshbuf *b) | ||
110 | +{ | ||
111 | + if (sshbuf_ptr(a) == NULL || sshbuf_ptr(b) == NULL) | ||
112 | + return SSH_ERR_INVALID_ARGUMENT; | ||
113 | + if (sshbuf_len(a) != sshbuf_len(b)) | ||
114 | + return SSH_ERR_INVALID_FORMAT; | ||
115 | + if (timingsafe_bcmp(sshbuf_ptr(a), sshbuf_ptr(b), sshbuf_len(a)) != 0) | ||
116 | + return SSH_ERR_INVALID_FORMAT; | ||
117 | + return 0; | ||
118 | +} | ||
119 | + | ||
120 | /* ssh2 only */ | ||
121 | static void | ||
122 | process_sign_request2(SocketEntry *e) | ||
123 | @@ -431,8 +464,8 @@ process_sign_request2(SocketEntry *e) | ||
124 | size_t i, slen = 0; | ||
125 | u_int compat = 0, flags; | ||
126 | int r, ok = -1; | ||
127 | - char *fp = NULL; | ||
128 | - struct sshbuf *msg = NULL, *data = NULL; | ||
129 | + char *fp = NULL, *user = NULL, *sig_dest = NULL; | ||
130 | + struct sshbuf *msg = NULL, *data = NULL, *sid = NULL; | ||
131 | struct sshkey *key = NULL; | ||
132 | struct identity *id; | ||
133 | struct notifier_ctx *notifier = NULL; | ||
134 | @@ -452,7 +485,33 @@ process_sign_request2(SocketEntry *e) | ||
135 | verbose("%s: %s key not found", __func__, sshkey_type(key)); | ||
136 | goto send; | ||
137 | } | ||
138 | - if (id->confirm && confirm_key(id, NULL) != 0) { | ||
139 | + /* | ||
140 | + * If session IDs were recorded for this socket, then use them to | ||
141 | + * annotate the confirmation messages with the host keys. | ||
142 | + */ | ||
143 | + if (e->nsession_ids > 0 && | ||
144 | + parse_userauth_request(data, key, &user, &sid) == 0) { | ||
145 | + /* | ||
146 | + * session ID from userauth request should match the final | ||
147 | + * ID in the list recorded in the socket, unless the ssh | ||
148 | + * client at that point lacks the binding extension (or if | ||
149 | + * an attacker is trying to steal use of the agent). | ||
150 | + */ | ||
151 | + i = e->nsession_ids - 1; | ||
152 | + if (buf_equal(sid, e->session_ids[i].sid) == 0) { | ||
153 | + if ((fp = sshkey_fingerprint(e->session_ids[i].key, | ||
154 | + SSH_FP_HASH_DEFAULT, SSH_FP_DEFAULT)) == NULL) | ||
155 | + fatal("%s: fingerprint failed", __func__); | ||
156 | + debug3("%s: destination %s %s (slot %zu)", __func__, | ||
157 | + sshkey_type(e->session_ids[i].key), fp, i); | ||
158 | + xasprintf(&sig_dest, "public key request for " | ||
159 | + "target user \"%s\" to %s %s", user, | ||
160 | + sshkey_type(e->session_ids[i].key), fp); | ||
161 | + free(fp); | ||
162 | + fp = NULL; | ||
163 | + } | ||
164 | + }// | ||
165 | + if (id->confirm && confirm_key(id, sig_dest) != 0) { | ||
166 | verbose("%s: user refused key", __func__); | ||
167 | goto send; | ||
168 | } | ||
169 | @@ -467,8 +526,10 @@ process_sign_request2(SocketEntry *e) | ||
170 | SSH_FP_DEFAULT)) == NULL) | ||
171 | fatal("%s: fingerprint failed", __func__); | ||
172 | notifier = notify_start(0, | ||
173 | - "Confirm user presence for key %s %s", | ||
174 | - sshkey_type(id->key), fp); | ||
175 | + "Confirm user presence for key %s %s%s%s", | ||
176 | + sshkey_type(id->key), fp, | ||
177 | + sig_dest == NULL ? "" : "\n", | ||
178 | + sig_dest == NULL ? "" : sig_dest); | ||
179 | } | ||
180 | } | ||
181 | if ((r = sshkey_sign(id->key, &signature, &slen, | ||
182 | @@ -492,11 +553,14 @@ process_sign_request2(SocketEntry *e) | ||
183 | if ((r = sshbuf_put_stringb(e->output, msg)) != 0) | ||
184 | fatal("%s: buffer error: %s", __func__, ssh_err(r)); | ||
185 | |||
186 | + sshbuf_free(sid); | ||
187 | sshbuf_free(data); | ||
188 | sshbuf_free(msg); | ||
189 | sshkey_free(key); | ||
190 | free(fp); | ||
191 | free(signature); | ||
192 | + free(sig_dest); | ||
193 | + free(user); | ||
194 | } | ||
195 | |||
196 | /* shared */ | ||
197 | @@ -925,6 +989,98 @@ send: | ||
198 | } | ||
199 | #endif /* ENABLE_PKCS11 */ | ||
200 | |||
201 | +static int | ||
202 | +process_ext_session_bind(SocketEntry *e) | ||
203 | +{ | ||
204 | + int r, sid_match, key_match; | ||
205 | + struct sshkey *key = NULL; | ||
206 | + struct sshbuf *sid = NULL, *sig = NULL; | ||
207 | + char *fp = NULL; | ||
208 | + u_char fwd; | ||
209 | + size_t i; | ||
210 | + | ||
211 | + debug2("%s: entering", __func__); | ||
212 | + if ((r = sshkey_froms(e->request, &key)) != 0 || | ||
213 | + (r = sshbuf_froms(e->request, &sid)) != 0 || | ||
214 | + (r = sshbuf_froms(e->request, &sig)) != 0 || | ||
215 | + (r = sshbuf_get_u8(e->request, &fwd)) != 0) { | ||
216 | + error("%s: parse: %s", __func__, ssh_err(r)); | ||
217 | + goto out; | ||
218 | + } | ||
219 | + if ((fp = sshkey_fingerprint(key, SSH_FP_HASH_DEFAULT, | ||
220 | + SSH_FP_DEFAULT)) == NULL) | ||
221 | + fatal("%s: fingerprint failed", __func__); | ||
222 | + /* check signature with hostkey on session ID */ | ||
223 | + if ((r = sshkey_verify(key, sshbuf_ptr(sig), sshbuf_len(sig), | ||
224 | + sshbuf_ptr(sid), sshbuf_len(sid), NULL, 0, NULL)) != 0) { | ||
225 | + error("%s: sshkey_verify for %s %s: %s", __func__, sshkey_type(key), fp, ssh_err(r)); | ||
226 | + goto out; | ||
227 | + } | ||
228 | + /* check whether sid/key already recorded */ | ||
229 | + for (i = 0; i < e->nsession_ids; i++) { | ||
230 | + sid_match = buf_equal(sid, e->session_ids[i].sid) == 0; | ||
231 | + key_match = sshkey_equal(key, e->session_ids[i].key); | ||
232 | + if (sid_match && key_match) { | ||
233 | + debug("%s: session ID already recorded for %s %s", __func__, | ||
234 | + sshkey_type(key), fp); | ||
235 | + r = 0; | ||
236 | + goto out; | ||
237 | + } else if (sid_match) { | ||
238 | + error("%s: session ID recorded against different key " | ||
239 | + "for %s %s", __func__, sshkey_type(key), fp); | ||
240 | + r = -1; | ||
241 | + goto out; | ||
242 | + } | ||
243 | + /* | ||
244 | + * new sid with previously-seen key can happen, e.g. multiple | ||
245 | + * connections to the same host. | ||
246 | + */ | ||
247 | + } | ||
248 | + /* record new key/sid */ | ||
249 | + if (e->nsession_ids >= AGENT_MAX_SESSION_IDS) { | ||
250 | + error("%s: too many session IDs recorded", __func__); | ||
251 | + goto out; | ||
252 | + } | ||
253 | + e->session_ids = xrecallocarray(e->session_ids, e->nsession_ids, | ||
254 | + e->nsession_ids + 1, sizeof(*e->session_ids)); | ||
255 | + i = e->nsession_ids++; | ||
256 | + debug("%s: recorded %s %s (slot %zu of %d)", __func__, sshkey_type(key), fp, i, | ||
257 | + AGENT_MAX_SESSION_IDS); | ||
258 | + e->session_ids[i].key = key; | ||
259 | + e->session_ids[i].forwarded = fwd != 0; | ||
260 | + key = NULL; /* transferred */ | ||
261 | + /* can't transfer sid; it's refcounted and scoped to request's life */ | ||
262 | + if ((e->session_ids[i].sid = sshbuf_new()) == NULL) | ||
263 | + fatal("%s: sshbuf_new", __func__); | ||
264 | + if ((r = sshbuf_putb(e->session_ids[i].sid, sid)) != 0) | ||
265 | + fatal("%s: sshbuf_putb session ID: %s", __func__, ssh_err(r)); | ||
266 | + /* success */ | ||
267 | + r = 0; | ||
268 | + out: | ||
269 | + sshkey_free(key); | ||
270 | + sshbuf_free(sid); | ||
271 | + sshbuf_free(sig); | ||
272 | + return r == 0 ? 1 : 0; | ||
273 | +} | ||
274 | + | ||
275 | +static void | ||
276 | +process_extension(SocketEntry *e) | ||
277 | +{ | ||
278 | + int r, success = 0; | ||
279 | + char *name; | ||
280 | + | ||
281 | + debug2("%s: entering", __func__); | ||
282 | + if ((r = sshbuf_get_cstring(e->request, &name, NULL)) != 0) { | ||
283 | + error("%s: parse: %s", __func__, ssh_err(r)); | ||
284 | + goto send; | ||
285 | + } | ||
286 | + if (strcmp(name, "session-bind@openssh.com") == 0) | ||
287 | + success = process_ext_session_bind(e); | ||
288 | + else | ||
289 | + debug("%s: unsupported extension \"%s\"", __func__, name); | ||
290 | +send: | ||
291 | + send_status(e, success); | ||
292 | +} | ||
293 | /* | ||
294 | * dispatch incoming message. | ||
295 | * returns 1 on success, 0 for incomplete messages or -1 on error. | ||
296 | @@ -1019,6 +1175,9 @@ process_message(u_int socknum) | ||
297 | process_remove_smartcard_key(e); | ||
298 | break; | ||
299 | #endif /* ENABLE_PKCS11 */ | ||
300 | + case SSH_AGENTC_EXTENSION: | ||
301 | + process_extension(e); | ||
302 | + break; | ||
303 | default: | ||
304 | /* Unknown message. Respond with failure. */ | ||
305 | error("Unknown message %d", type); | ||
306 | -- | ||
307 | 2.41.0 | ||