summaryrefslogtreecommitdiffstats
path: root/meta-networking
diff options
context:
space:
mode:
authorVijay Anusuri <vanusuri@mvista.com>2025-12-10 23:08:37 +0530
committerAnuj Mittal <anuj.mittal@oss.qualcomm.com>2025-12-11 08:02:03 +0530
commitb4812b18eec77e9f0286bd6b81a5c3032ac0d3be (patch)
tree6321ea21b3178b95319b88506a262854e573983b /meta-networking
parent5775e1a6435debe337e156fa74e5af8e45368ca0 (diff)
downloadmeta-openembedded-b4812b18eec77e9f0286bd6b81a5c3032ac0d3be.tar.gz
proftpd: Fix CVE-2023-48795
Upstream-Status: Backport from https://github.com/proftpd/proftpd/commit/bcec15efe6c53dac40420731013f1cd2fd54123b Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> Signed-off-by: Gyorgy Sarvari <skandigraun@gmail.com> (cherry picked from commit 6c8ae54fc345fb6249f1cc92ed769d451ddc12b5) Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com> Signed-off-by: Anuj Mittal <anuj.mittal@oss.qualcomm.com>
Diffstat (limited to 'meta-networking')
-rw-r--r--meta-networking/recipes-daemons/proftpd/files/CVE-2023-48795.patch785
-rw-r--r--meta-networking/recipes-daemons/proftpd/proftpd_1.3.7f.bb1
2 files changed, 786 insertions, 0 deletions
diff --git a/meta-networking/recipes-daemons/proftpd/files/CVE-2023-48795.patch b/meta-networking/recipes-daemons/proftpd/files/CVE-2023-48795.patch
new file mode 100644
index 0000000000..0f54430deb
--- /dev/null
+++ b/meta-networking/recipes-daemons/proftpd/files/CVE-2023-48795.patch
@@ -0,0 +1,785 @@
1From 05afec052cea4de87a8467f9c5583ffe226ce06e Mon Sep 17 00:00:00 2001
2From: TJ Saunders <tj@castaglia.org>
3Date: Tue, 19 Dec 2023 18:55:58 -0800
4Subject: [PATCH] Issue #1760: Implement the "strict KEX" mitigations for the
5 Terrapin SSH protocol attack (CVE-2023-48795).
6
7Upstream-Status: Backport [https://github.com/proftpd/proftpd/commit/bcec15efe6c53dac40420731013f1cd2fd54123b]
8CVE: CVE-2023-48795
9Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
10Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
11---
12 contrib/mod_sftp/kex.c | 126 +++++++---
13 contrib/mod_sftp/mod_sftp.c | 8 +-
14 contrib/mod_sftp/mod_sftp.h.in | 35 +--
15 contrib/mod_sftp/packet.c | 12 +
16 contrib/mod_sftp/packet.h | 9 +-
17 contrib/mod_sftp/tap.c | 26 ++-
18 contrib/mod_sftp/tap.h | 5 +-
19 doc/contrib/mod_sftp.html | 15 +-
20 tests/t/lib/ProFTPD/Tests/Modules/mod_sftp.pm | 217 ++++++++++++++++++
21 9 files changed, 398 insertions(+), 55 deletions(-)
22
23diff --git a/contrib/mod_sftp/kex.c b/contrib/mod_sftp/kex.c
24index 6a19c88bb..3d9068139 100644
25--- a/contrib/mod_sftp/kex.c
26+++ b/contrib/mod_sftp/kex.c
27@@ -149,6 +149,13 @@ static struct sftp_kex *kex_first_kex = NULL;
28 static struct sftp_kex *kex_rekey_kex = NULL;
29 static int kex_sent_kexinit = FALSE;
30
31+/* Using strict kex? Note that we maintain this value here, rather than
32+ * in the sftp_kex struct, so that any "use strict KEX" flag set via the
33+ * first KEXINIT is used through any subsequent KEXINITs.
34+ */
35+static int use_strict_kex = FALSE;
36+static int kex_done_first_kex = FALSE;
37+
38 /* Diffie-Hellman group moduli */
39
40 static const char *dh_group1_str =
41@@ -1578,6 +1585,16 @@ static const char *get_kexinit_exchange_list(pool *p) {
42 res = pstrcat(p, res, *res ? "," : "", pstrdup(p, "ext-info-s"), NULL);
43 }
44
45+ if (!(sftp_opts & SFTP_OPT_NO_STRICT_KEX)) {
46+ /* Indicate support for OpenSSH's custom "strict KEX" mode extension,
47+ * but only if we have not done/completed our first KEX.
48+ */
49+ if (kex_done_first_kex == FALSE) {
50+ res = pstrcat(p, res, *res ? "," : "",
51+ pstrdup(p, "kex-strict-s-v00@openssh.com"), NULL);
52+ }
53+ }
54+
55 return res;
56 }
57
58@@ -2159,6 +2176,21 @@ static int get_session_names(struct sftp_kex *kex, int *correct_guess) {
59 pr_trace_msg(trace_channel, 20, "client %s EXT_INFO support",
60 kex->use_ext_info ? "signaled" : "did not signal" );
61
62+ if (!(sftp_opts & SFTP_OPT_NO_STRICT_KEX)) {
63+ /* Did the client indicate "strict kex" support (Issue 1760)?
64+ *
65+ * Note that we only check for this if it is our first KEXINIT.
66+ * The "strict kex" extension is ignored in any subsequent KEXINITs, as
67+ * for rekeys.
68+ */
69+ if (kex_done_first_kex == FALSE) {
70+ use_strict_kex = sftp_misc_namelist_contains(kex->pool,
71+ client_list, "kex-strict-c-v00@openssh.com");
72+ pr_trace_msg(trace_channel, 20, "client %s strict KEX support",
73+ use_strict_kex ? "signaled" : "did not signal" );
74+ }
75+ }
76+
77 } else {
78 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
79 "no shared key exchange algorithm found (client sent '%s', server sent "
80@@ -4391,7 +4423,6 @@ static int handle_kex_ecdh(struct ssh2_packet *pkt, struct sftp_kex *kex) {
81 destroy_pool(pkt->pool);
82 return 0;
83 }
84-
85 #endif /* PR_USE_OPENSSL_ECC */
86
87 static struct ssh2_packet *read_kex_packet(pool *p, struct sftp_kex *kex,
88@@ -4442,6 +4473,10 @@ static struct ssh2_packet *read_kex_packet(pool *p, struct sftp_kex *kex,
89 /* Per RFC 4253, Section 11, DEBUG, DISCONNECT, IGNORE, and UNIMPLEMENTED
90 * messages can occur at any time, even during KEX. We have to be prepared
91 * for this, and Do The Right Thing(tm).
92+ *
93+ * However, due to the Terrapin attack, if we are using a "strict KEX"
94+ * mode, then only DISCONNECT messages can occur during KEX; DEBUG,
95+ * IGNORE, and UNIMPLEMENTED messages will lead to disconnecting.
96 */
97
98 mesg_type = sftp_ssh2_packet_get_mesg_type(pkt);
99@@ -4469,36 +4504,44 @@ static struct ssh2_packet *read_kex_packet(pool *p, struct sftp_kex *kex,
100 break;
101 }
102
103- switch (mesg_type) {
104- case SFTP_SSH2_MSG_DEBUG:
105- sftp_ssh2_packet_handle_debug(pkt);
106- pr_response_set_pool(NULL);
107- pkt = NULL;
108- break;
109-
110+ switch (msg_type) {
111+ /* DISCONNECT messages are always allowed. */
112 case SFTP_SSH2_MSG_DISCONNECT:
113 sftp_ssh2_packet_handle_disconnect(pkt);
114 pr_response_set_pool(NULL);
115 pkt = NULL;
116 break;
117
118+ case SFTP_SSH2_MSG_DEBUG:
119+ if (use_strict_kex == FALSE) {
120+ sftp_ssh2_packet_handle_debug(pkt);
121+ pr_response_set_pool(NULL);
122+ pkt = NULL;
123+ break;
124+ }
125+
126 case SFTP_SSH2_MSG_IGNORE:
127- sftp_ssh2_packet_handle_ignore(pkt);
128- pr_response_set_pool(NULL);
129- pkt = NULL;
130- break;
131+ if (use_strict_kex == FALSE) {
132+ sftp_ssh2_packet_handle_ignore(pkt);
133+ pr_response_set_pool(NULL);
134+ pkt = NULL;
135+ break;
136+ }
137
138 case SFTP_SSH2_MSG_UNIMPLEMENTED:
139- sftp_ssh2_packet_handle_unimplemented(pkt);
140- pr_response_set_pool(NULL);
141- pkt = NULL;
142- break;
143+ if (use_strict_kex == FALSE) {
144+ sftp_ssh2_packet_handle_unimplemented(pkt);
145+ pr_response_set_pool(NULL);
146+ pkt = NULL;
147+ break;
148+ }
149
150 default:
151 /* For any other message type, it's considered a protocol error. */
152 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
153- "received %s (%d) unexpectedly, disconnecting",
154- sftp_ssh2_packet_get_mesg_type_desc(mesg_type), mesg_type);
155+ "received %s (%d) unexpectedly%s, disconnecting",
156+ sftp_ssh2_packet_get_msg_type_desc(msg_type), msg_type,
157+ use_strict_kex ? " during strict KEX" : "");
158 pr_response_set_pool(NULL);
159 destroy_kex(kex);
160 destroy_pool(pkt->pool);
161@@ -4519,7 +4562,7 @@ int sftp_kex_handle(struct ssh2_packet *pkt) {
162 * initial connect (kex_first_kex not null), or because we
163 * are in a server-initiated rekeying (kex_rekey_kex not null).
164 */
165- if (kex_first_kex) {
166+ if (kex_first_kex != NULL) {
167 kex = kex_first_kex;
168
169 /* We need to assign the client/server versions, which this struct
170@@ -4528,7 +4571,7 @@ int sftp_kex_handle(struct ssh2_packet *pkt) {
171 kex->client_version = kex_client_version;
172 kex->server_version = kex_server_version;
173
174- } else if (kex_rekey_kex) {
175+ } else if (kex_rekey_kex != NULL) {
176 kex = kex_rekey_kex;
177
178 } else {
179@@ -4564,6 +4607,24 @@ int sftp_kex_handle(struct ssh2_packet *pkt) {
180 return -1;
181 }
182
183+ if (use_strict_kex == TRUE &&
184+ kex_done_first_kex == FALSE) {
185+ uint32_t client_seqno;
186+
187+ client_seqno = sftp_ssh2_packet_get_client_seqno();
188+ if (client_seqno != 1) {
189+ /* Receiving any messages other than a KEXINIT as the first client
190+ * message indicates the possibility of the Terrapin attack being
191+ * conducted (Issue 1760). Thus we disconnect the client in such
192+ * cases.
193+ */
194+ (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
195+ "'strict KEX' violation, as KEXINIT was not the first message; disconnecting");
196+ destroy_kex(kex);
197+ SFTP_DISCONNECT_CONN(SFTP_SSH2_DISCONNECT_BY_APPLICATION, NULL);
198+ }
199+ }
200+
201 /* Once we have received the client KEXINIT message, we can compare what we
202 * want to send against what we already received from the client.
203 *
204@@ -4622,7 +4683,7 @@ int sftp_kex_handle(struct ssh2_packet *pkt) {
205
206 destroy_pool(pkt->pool);
207
208- if (!kex_sent_kexinit) {
209+ if (kex_sent_kexinit == FALSE) {
210 pkt = sftp_ssh2_packet_create(kex_pool);
211 res = write_kexinit(pkt, kex);
212 if (res < 0) {
213@@ -4645,7 +4706,7 @@ int sftp_kex_handle(struct ssh2_packet *pkt) {
214 }
215 }
216
217- if (!kex_sent_kexinit) {
218+ if (kex_sent_kexinit == FALSE) {
219 pkt = sftp_ssh2_packet_create(kex_pool);
220 res = write_kexinit(pkt, kex);
221 if (res < 0) {
222@@ -4770,7 +4831,7 @@ int sftp_kex_handle(struct ssh2_packet *pkt) {
223 NULL, 1, SFTP_SSH2_MSG_NEWKEYS);
224
225 /* If we didn't send our NEWKEYS message earlier, do it now. */
226- if (!sent_newkeys) {
227+ if (sent_newkeys == FALSE) {
228 struct ssh2_packet *pkt2;
229
230 pr_trace_msg(trace_channel, 9, "sending NEWKEYS message to client");
231@@ -4794,6 +4855,11 @@ int sftp_kex_handle(struct ssh2_packet *pkt) {
232 destroy_pool(pkt2->pool);
233 }
234
235+ if (use_strict_kex == TRUE) {
236+ sftp_ssh2_packet_reset_client_seqno();
237+ sftp_ssh2_packet_reset_server_seqno();
238+ }
239+
240 /* Last but certainly not least, set up the keys for encryption and
241 * authentication, based on H and K.
242 */
243@@ -4813,6 +4879,9 @@ int sftp_kex_handle(struct ssh2_packet *pkt) {
244 destroy_pool(pkt->pool);
245 cmd = NULL;
246
247+ /* We've now completed our KEX, possibly our first. */
248+ kex_done_first_kex = TRUE;
249+
250 /* If extension negotiation has not been disabled, AND if we have not
251 * received a service request, AND if the client sent "ext-info-c", THEN
252 * send our EXT_INFO. We do not want send this during rekeys.
253@@ -4849,6 +4918,12 @@ int sftp_kex_handle(struct ssh2_packet *pkt) {
254 cmd = NULL;
255 }
256
257+ /* Only start the TAP timer after we have completed our first KEX.
258+ * Otherwise, we risk sending "illegal" packets prior to, or during,
259+ * a "strict KEX" session (Issue 1760).
260+ */
261+ sftp_tap_start_policy();
262+
263 /* Reset this flag for the next time through. */
264 kex_sent_kexinit = FALSE;
265
266@@ -4878,7 +4953,7 @@ int sftp_kex_free(void) {
267 destroy_kex(rekey_kex);
268 }
269
270- if (kex_pool) {
271+ if (kex_pool != NULL) {
272 destroy_pool(kex_pool);
273 kex_pool = NULL;
274 }
275@@ -5050,7 +5125,7 @@ int sftp_kex_send_first_kexinit(void) {
276 struct ssh2_packet *pkt;
277 int res;
278
279- if (!kex_pool) {
280+ if (kex_pool == NULL) {
281 kex_pool = make_sub_pool(sftp_pool);
282 pr_pool_tag(kex_pool, "Kex Pool");
283 }
284@@ -5085,4 +5160,3 @@ int sftp_kex_send_first_kexinit(void) {
285 destroy_pool(pkt->pool);
286 return 0;
287 }
288-
289diff --git a/contrib/mod_sftp/mod_sftp.c b/contrib/mod_sftp/mod_sftp.c
290index a88162c0d..1f94e4d9d 100644
291--- a/contrib/mod_sftp/mod_sftp.c
292+++ b/contrib/mod_sftp/mod_sftp.c
293@@ -1,6 +1,6 @@
294 /*
295 * ProFTPD - mod_sftp
296- * Copyright (c) 2008-2022 TJ Saunders
297+ * Copyright (c) 2008-2023 TJ Saunders
298 *
299 * This program is free software; you can redistribute it and/or modify
300 * it under the terms of the GNU General Public License as published by
301@@ -1415,8 +1415,9 @@ MODRET set_sftpoptions(cmd_rec *cmd) {
302 config_rec *c;
303 unsigned long opts = 0UL;
304
305- if (cmd->argc-1 == 0)
306+ if (cmd->argc-1 == 0) {
307 CONF_ERROR(cmd, "wrong number of parameters");
308+ }
309
310 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
311
312@@ -1480,6 +1481,9 @@ MODRET set_sftpoptions(cmd_rec *cmd) {
313 } else if (strcmp(cmd->argv[i], "NoExtensionNegotiation") == 0) {
314 opts |= SFTP_OPT_NO_EXT_INFO;
315
316+ } else if (strcmp(cmd->argv[i], "NoStrictKex") == 0) {
317+ opts |= SFTP_OPT_NO_STRICT_KEX;
318+
319 } else {
320 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, ": unknown SFTPOption '",
321 cmd->argv[i], "'", NULL));
322diff --git a/contrib/mod_sftp/mod_sftp.h.in b/contrib/mod_sftp/mod_sftp.h.in
323index 9af590e8e..bde722f23 100644
324--- a/contrib/mod_sftp/mod_sftp.h.in
325+++ b/contrib/mod_sftp/mod_sftp.h.in
326@@ -126,23 +126,24 @@
327 #define SFTP_SESS_STATE_HAVE_EXT_INFO 0x00010
328
329 /* mod_sftp option flags */
330-#define SFTP_OPT_IGNORE_SFTP_UPLOAD_PERMS 0x00001
331-#define SFTP_OPT_IGNORE_SCP_UPLOAD_PERMS 0x00002
332-#define SFTP_OPT_PESSIMISTIC_KEXINIT 0x00004
333-#define SFTP_OPT_OLD_PROTO_COMPAT 0x00008
334-#define SFTP_OPT_MATCH_KEY_SUBJECT 0x00010
335-#define SFTP_OPT_IGNORE_SFTP_SET_PERMS 0x00020
336-#define SFTP_OPT_IGNORE_SFTP_SET_TIMES 0x00040
337-#define SFTP_OPT_IGNORE_SFTP_SET_OWNERS 0x00080
338-#define SFTP_OPT_IGNORE_SCP_UPLOAD_TIMES 0x00100
339-#define SFTP_OPT_ALLOW_INSECURE_LOGIN 0x00200
340-#define SFTP_OPT_INSECURE_HOSTKEY_PERMS 0x00400
341-#define SFTP_OPT_ALLOW_WEAK_DH 0x00800
342-#define SFTP_OPT_IGNORE_FIFOS 0x01000
343-#define SFTP_OPT_IGNORE_SFTP_UPLOAD_XATTRS 0x02000
344-#define SFTP_OPT_IGNORE_SFTP_SET_XATTRS 0x04000
345-#define SFTP_OPT_INCLUDE_SFTP_TIMES 0x08000
346-#define SFTP_OPT_NO_EXT_INFO 0x10000
347+#define SFTP_OPT_IGNORE_SFTP_UPLOAD_PERMS 0x000001
348+#define SFTP_OPT_IGNORE_SCP_UPLOAD_PERMS 0x000002
349+#define SFTP_OPT_PESSIMISTIC_KEXINIT 0x000004
350+#define SFTP_OPT_OLD_PROTO_COMPAT 0x000008
351+#define SFTP_OPT_MATCH_KEY_SUBJECT 0x000010
352+#define SFTP_OPT_IGNORE_SFTP_SET_PERMS 0x000020
353+#define SFTP_OPT_IGNORE_SFTP_SET_TIMES 0x000040
354+#define SFTP_OPT_IGNORE_SFTP_SET_OWNERS 0x000080
355+#define SFTP_OPT_IGNORE_SCP_UPLOAD_TIMES 0x000100
356+#define SFTP_OPT_ALLOW_INSECURE_LOGIN 0x000200
357+#define SFTP_OPT_INSECURE_HOSTKEY_PERMS 0x000400
358+#define SFTP_OPT_ALLOW_WEAK_DH 0x000800
359+#define SFTP_OPT_IGNORE_FIFOS 0x001000
360+#define SFTP_OPT_IGNORE_SFTP_UPLOAD_XATTRS 0x002000
361+#define SFTP_OPT_IGNORE_SFTP_SET_XATTRS 0x004000
362+#define SFTP_OPT_INCLUDE_SFTP_TIMES 0x008000
363+#define SFTP_OPT_NO_EXT_INFO 0x010000
364+#define SFTP_OPT_NO_STRICT_KEX 0x040000
365
366 /* mod_sftp service flags */
367 #define SFTP_SERVICE_FL_SFTP 0x0001
368diff --git a/contrib/mod_sftp/packet.c b/contrib/mod_sftp/packet.c
369index b0067ea80..d8c97e92b 100644
370--- a/contrib/mod_sftp/packet.c
371+++ b/contrib/mod_sftp/packet.c
372@@ -1742,6 +1742,18 @@ int sftp_ssh2_packet_rekey_set_size(off_t size) {
373 return 0;
374 }
375
376+uint32_t sftp_ssh2_packet_get_client_seqno(void) {
377+ return packet_client_seqno;
378+}
379+
380+void sftp_ssh2_packet_reset_client_seqno(void) {
381+ packet_client_seqno = 0;
382+}
383+
384+void sftp_ssh2_packet_reset_server_seqno(void) {
385+ packet_server_seqno = 0;
386+}
387+
388 int sftp_ssh2_packet_send_version(void) {
389 if (!sent_version_id) {
390 int res;
391diff --git a/contrib/mod_sftp/packet.h b/contrib/mod_sftp/packet.h
392index a424e9b25..fe538cbd7 100644
393--- a/contrib/mod_sftp/packet.h
394+++ b/contrib/mod_sftp/packet.h
395@@ -1,6 +1,6 @@
396 /*
397 * ProFTPD - mod_sftp packet IO
398- * Copyright (c) 2008-2020 TJ Saunders
399+ * Copyright (c) 2008-2023 TJ Saunders
400 *
401 * This program is free software; you can redistribute it and/or modify
402 * it under the terms of the GNU General Public License as published by
403@@ -107,6 +107,13 @@ int sftp_ssh2_packet_rekey_reset(void);
404 int sftp_ssh2_packet_rekey_set_seqno(uint32_t);
405 int sftp_ssh2_packet_rekey_set_size(off_t);
406
407+/* These are used for implementing the "strict KEX" mitigations of the Terrapin
408+ * attack (Issue 1760).
409+ */
410+uint32_t sftp_ssh2_packet_get_client_seqno(void);
411+void sftp_ssh2_packet_reset_client_seqno(void);
412+void sftp_ssh2_packet_reset_server_seqno(void);
413+
414 int sftp_ssh2_packet_send_version(void);
415 int sftp_ssh2_packet_set_poll_timeout(int);
416 int sftp_ssh2_packet_set_version(const char *);
417diff --git a/contrib/mod_sftp/tap.c b/contrib/mod_sftp/tap.c
418index 95f388e43..7eaf959e2 100644
419--- a/contrib/mod_sftp/tap.c
420+++ b/contrib/mod_sftp/tap.c
421@@ -1,6 +1,6 @@
422 /*
423 * ProFTPD - mod_sftp traffic analysis protection
424- * Copyright (c) 2008-2016 TJ Saunders
425+ * Copyright (c) 2008-2023 TJ Saunders
426 *
427 * This program is free software; you can redistribute it and/or modify
428 * it under the terms of the GNU General Public License as published by
429@@ -149,7 +149,6 @@ static void set_policy_chance(struct sftp_tap_policy *policy) {
430 }
431
432 static void set_policy_timer(struct sftp_tap_policy *policy) {
433-
434 /* Start a timer which checks the last times we received and sent packets.
435 * From there, we may want to inject a TAP message, depending on the
436 * policy.
437@@ -177,6 +176,16 @@ int sftp_tap_send_packet(void) {
438 int rnd;
439 unsigned int chance;
440
441+ /* Due to chances of violating client-side "strict KEX" Terrapin
442+ * mitigations, we will not send packets if we are in the middle of a KEX.
443+ */
444+ if (!(sftp_sess_state & SFTP_SESS_STATE_HAVE_KEX) ||
445+ (sftp_sess_state & SFTP_SESS_STATE_REKEYING)) {
446+ pr_trace_msg(trace_channel, 11,
447+ "unwilling to send TAP packet during KEX");
448+ return 0;
449+ }
450+
451 if (!sftp_interop_supports_feature(SFTP_SSH2_FEAT_IGNORE_MSG)) {
452 pr_trace_msg(trace_channel, 3,
453 "unable to send TAP packet: IGNORE not supported by client");
454@@ -205,7 +214,7 @@ int sftp_tap_send_packet(void) {
455 struct ssh2_packet *pkt;
456 unsigned int max_datalen = 8192;
457
458- if (curr_policy.max_datalen) {
459+ if (curr_policy.max_datalen > 0) {
460 max_datalen = curr_policy.max_datalen;
461 }
462
463@@ -246,15 +255,15 @@ int sftp_tap_send_packet(void) {
464 int sftp_tap_set_policy(const char *policy) {
465 register unsigned int i;
466
467- if (tap_pool) {
468+ if (tap_pool != NULL) {
469
470 /* Special case: IFF the existing policy is 'none' AND the given
471 * policy is 'rogaway', just return. The 'none' policy must have been
472 * explicitly configured, and it should override the automatic use of
473 * the 'rogaway' policy.
474 */
475- if (strncmp(curr_policy.policy, "none", 5) == 0 &&
476- strncasecmp(policy, "rogaway", 8) == 0) {
477+ if (strcasecmp(curr_policy.policy, "none") == 0 &&
478+ strcasecmp(policy, "rogaway") == 0) {
479 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
480 "'none' traffic policy explicitly configured, ignoring '%s' policy",
481 policy);
482@@ -278,7 +287,6 @@ int sftp_tap_set_policy(const char *policy) {
483 if (strcasecmp(tap_policies[i].policy, policy) == 0) {
484 copy_policy(&curr_policy, &(tap_policies[i]));
485 set_policy_chance(&curr_policy);
486- set_policy_timer(&curr_policy);
487 return 0;
488 }
489 }
490@@ -286,3 +294,7 @@ int sftp_tap_set_policy(const char *policy) {
491 errno = ENOENT;
492 return -1;
493 }
494+
495+void sftp_tap_start_policy(void) {
496+ set_policy_timer(&curr_policy);
497+}
498diff --git a/contrib/mod_sftp/tap.h b/contrib/mod_sftp/tap.h
499index 4a4c065d2..312223595 100644
500--- a/contrib/mod_sftp/tap.h
501+++ b/contrib/mod_sftp/tap.h
502@@ -1,6 +1,6 @@
503 /*
504 * ProFTPD - mod_sftp traffic analysis protection
505- * Copyright (c) 2008-2016 TJ Saunders
506+ * Copyright (c) 2008-2013 TJ Saunders
507 *
508 * This program is free software; you can redistribute it and/or modify
509 * it under the terms of the GNU General Public License as published by
510@@ -63,4 +63,7 @@ int sftp_tap_send_packet(void);
511 */
512 int sftp_tap_set_policy(const char *);
513
514+/* Sets the configured TAP policy in motion. */
515+void sftp_tap_start_policy(void);
516+
517 #endif /* MOD_SFTP_TAP_H */
518diff --git a/doc/contrib/mod_sftp.html b/doc/contrib/mod_sftp.html
519index 60c3436fa..cfc639d05 100644
520--- a/doc/contrib/mod_sftp.html
521+++ b/doc/contrib/mod_sftp.html
522@@ -1186,6 +1186,19 @@ The currently implemented options are:
523 <code>proftpd-1.3.7rc4</code>.
524 </li>
525
526+ <p>
527+ <li><code>NoStrictKex</code><br>
528+ <p>
529+ By default, <code>mod_sftp</code> will honor/support the OpenSSH
530+ "strict KEX" mode extension, "kex-strict-c-v00@openssh.com" and
531+ "kex-strict-s-v00@openssh.com". Use this option to disable support for
532+ these custom OpenSSH extensions.
533+
534+ <p>
535+ <b>Note</b> that this option first appeared in
536+ <code>proftpd-1.3.9rc1</code>.
537+ </li>
538+
539 <p>
540 <li><code>OldProtocolCompat</code><br>
541 <p>
542@@ -2642,7 +2655,7 @@ deal with this issue, then, you can hopefully upgrade to ProFTPD 1.3.6 or later,
543 <p>
544 <hr>
545 <font size=2><b><i>
546-&copy; Copyright 2008-2021 TJ Saunders<br>
547+&copy; Copyright 2008-2023 TJ Saunders<br>
548 All Rights Reserved<br>
549 </i></b></font>
550 <hr>
551diff --git a/tests/t/lib/ProFTPD/Tests/Modules/mod_sftp.pm b/tests/t/lib/ProFTPD/Tests/Modules/mod_sftp.pm
552index b4bdf516b..8c2be5465 100644
553--- a/tests/t/lib/ProFTPD/Tests/Modules/mod_sftp.pm
554+++ b/tests/t/lib/ProFTPD/Tests/Modules/mod_sftp.pm
555@@ -87,6 +87,11 @@ my $TESTS = {
556 test_class => [qw(forking ssh2)],
557 },
558
559+ ssh2_ext_kex_strict_terrapin_issue1760 => {
560+ order => ++$order,
561+ test_class => [qw(bug forking ssh2)],
562+ },
563+
564 ssh2_hostkey_rsa => {
565 order => ++$order,
566 test_class => [qw(forking ssh2)],
567@@ -3885,6 +3890,218 @@ EOC
568 unlink($log_file);
569 }
570
571+sub ssh2_ext_kex_strict_terrapin_issue1760 {
572+ my $self = shift;
573+ my $tmpdir = $self->{tmpdir};
574+ my $setup = test_setup($tmpdir, 'sftp');
575+
576+ my $rsa_host_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/ssh_host_rsa_key');
577+ my $dsa_host_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/ssh_host_dsa_key');
578+
579+ my $rsa_priv_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/test_rsa_key');
580+ my $rsa_pub_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/test_rsa_key.pub');
581+ my $rsa_rfc4716_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/authorized_rsa_keys');
582+
583+ my $authorized_keys = File::Spec->rel2abs("$tmpdir/.authorized_keys");
584+ unless (copy($rsa_rfc4716_key, $authorized_keys)) {
585+ die("Can't copy $rsa_rfc4716_key to $authorized_keys: $!");
586+ }
587+
588+ my $ssh_config = File::Spec->rel2abs("$tmpdir/ssh.conf");
589+ if (open(my $fh, "> $ssh_config")) {
590+ print $fh <<EOC;
591+HostKeyAlgorithms rsa-sha2-256
592+IdentityAgent none
593+PubkeyAcceptedKeyTypes rsa-sha2-256
594+EOC
595+ unless (close($fh)) {
596+ die("Can't write $ssh_config: $!");
597+ }
598+
599+ } else {
600+ die("Can't open $ssh_config: $!");
601+ }
602+
603+ my $batch_file = File::Spec->rel2abs("$tmpdir/sftp-batch.conf");
604+ if (open(my $fh, "> $batch_file")) {
605+ print $fh "ls -l\n";
606+
607+ unless (close($fh)) {
608+ die("Can't write $batch_file: $!");
609+ }
610+
611+ } else {
612+ die("Can't open $batch_file: $!");
613+ }
614+
615+ my $config = {
616+ PidFile => $setup->{pid_file},
617+ ScoreboardFile => $setup->{scoreboard_file},
618+ SystemLog => $setup->{log_file},
619+ TraceLog => $setup->{log_file},
620+ Trace => 'ssh2:30 sftp:20 scp:20',
621+
622+ AuthUserFile => $setup->{auth_user_file},
623+ AuthGroupFile => $setup->{auth_group_file},
624+ AuthOrder => 'mod_auth_file.c',
625+
626+ IfModules => {
627+ 'mod_delay.c' => {
628+ DelayEngine => 'off',
629+ },
630+
631+ 'mod_sftp.c' => [
632+ "SFTPEngine on",
633+ "SFTPLog $setup->{log_file}",
634+
635+ "SFTPHostKey $rsa_host_key",
636+ "SFTPHostKey $dsa_host_key",
637+
638+ "SFTPAuthorizedUserKeys file:~/.authorized_keys",
639+ ],
640+ },
641+ };
642+
643+ my ($port, $config_user, $config_group) = config_write($setup->{config_file},
644+ $config);
645+
646+ # Open pipes, for use between the parent and child processes. Specifically,
647+ # the child will indicate when it's done with its test by writing a message
648+ # to the parent.
649+ my ($rfh, $wfh);
650+ unless (pipe($rfh, $wfh)) {
651+ die("Can't open pipe: $!");
652+ }
653+
654+ require Net::SSH2;
655+
656+ my $ex;
657+
658+ # Fork child
659+ $self->handle_sigchld();
660+ defined(my $pid = fork()) or die("Can't fork: $!");
661+ if ($pid) {
662+ eval {
663+ # We use OpenSSH-9.6p1 to test our "strict KEX" Terrapin mitigations.
664+ my $sftp = '/Users/tj/local/openssh-9.6p1/bin/sftp';
665+
666+ my @cmd = (
667+ $sftp,
668+ '-F',
669+ $ssh_config,
670+ '-oBatchMode=yes',
671+ '-oCheckHostIP=no',
672+ '-oCompression=yes',
673+ "-oPort=$port",
674+ "-oIdentityFile=$rsa_priv_key",
675+ '-oPubkeyAuthentication=yes',
676+ '-oStrictHostKeyChecking=no',
677+ '-oUserKnownHostsFile=/dev/null',
678+ '-vvv',
679+ '-b',
680+ $batch_file,
681+ "$setup->{user}\@127.0.0.1",
682+ );
683+
684+ my $sftp_rh = IO::Handle->new();
685+ my $sftp_wh = IO::Handle->new();
686+ my $sftp_eh = IO::Handle->new();
687+
688+ $sftp_wh->autoflush(1);
689+
690+ sleep(1);
691+
692+ local $SIG{CHLD} = 'DEFAULT';
693+
694+ # Make sure that the perms on the priv key are what OpenSSH wants
695+ unless (chmod(0400, $rsa_priv_key)) {
696+ die("Can't set perms on $rsa_priv_key to 0400: $!");
697+ }
698+
699+ if ($ENV{TEST_VERBOSE}) {
700+ print STDERR "Executing: ", join(' ', @cmd), "\n";
701+ }
702+
703+ my $sftp_pid = open3($sftp_wh, $sftp_rh, $sftp_eh, @cmd);
704+ waitpid($sftp_pid, 0);
705+ my $exit_status = $?;
706+
707+ # Restore the perms on the priv key
708+ unless (chmod(0644, $rsa_priv_key)) {
709+ die("Can't set perms on $rsa_priv_key to 0644: $!");
710+ }
711+
712+ my ($res, $errstr);
713+ if ($exit_status >> 8 == 0) {
714+ $errstr = join('', <$sftp_eh>);
715+ $res = 0;
716+
717+ } else {
718+ $errstr = join('', <$sftp_eh>);
719+ if ($ENV{TEST_VERBOSE}) {
720+ print STDERR "Stderr: $errstr\n";
721+ }
722+
723+ $res = 1;
724+ }
725+
726+ unless ($res == 0) {
727+ die("Can't list files on server: $errstr");
728+ }
729+ };
730+ if ($@) {
731+ $ex = $@;
732+ }
733+
734+ $wfh->print("done\n");
735+ $wfh->flush();
736+
737+ } else {
738+ eval { server_wait($setup->{config_file}, $rfh) };
739+ if ($@) {
740+ warn($@);
741+ exit 1;
742+ }
743+
744+ exit 0;
745+ }
746+
747+ # Stop server
748+ server_stop($setup->{pid_file});
749+ $self->assert_child_ok($pid);
750+
751+ eval {
752+ if (open(my $fh, "< $setup->{log_file}")) {
753+ my $ok = 0;
754+
755+ while (my $line = <$fh>) {
756+ chomp($line);
757+
758+ if ($ENV{TEST_VERBOSE}) {
759+ print STDERR "# $line\n";
760+ }
761+
762+ if ($line =~ /client signaled strict KEX support/) {
763+ $ok = 1;
764+ last;
765+ }
766+ }
767+
768+ close($fh);
769+
770+ $self->assert($ok, test_msg("Did not see expected 'strict KEX' TraceLog message"));
771+
772+ } else {
773+ die("Can't read $setup->{log_file}: $!");
774+ }
775+ };
776+ if ($@) {
777+ $ex = $@;
778+ }
779+
780+ test_cleanup($setup->{log_file}, $ex);
781+}
782+
783 sub ssh2_hostkey_rsa {
784 my $self = shift;
785 my $tmpdir = $self->{tmpdir};
diff --git a/meta-networking/recipes-daemons/proftpd/proftpd_1.3.7f.bb b/meta-networking/recipes-daemons/proftpd/proftpd_1.3.7f.bb
index 312fe24387..9bfe9aed03 100644
--- a/meta-networking/recipes-daemons/proftpd/proftpd_1.3.7f.bb
+++ b/meta-networking/recipes-daemons/proftpd/proftpd_1.3.7f.bb
@@ -17,6 +17,7 @@ SRC_URI = "git://github.com/proftpd/proftpd.git;branch=${BRANCH};protocol=https
17 file://proftpd.service \ 17 file://proftpd.service \
18 file://CVE-2023-51713.patch \ 18 file://CVE-2023-51713.patch \
19 file://CVE-2024-57392.patch \ 19 file://CVE-2024-57392.patch \
20 file://CVE-2023-48795.patch \
20 " 21 "
21 22
22S = "${WORKDIR}/git" 23S = "${WORKDIR}/git"