summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--meta-networking/recipes-daemons/proftpd/files/CVE-2023-51713.patch278
-rw-r--r--meta-networking/recipes-daemons/proftpd/proftpd_1.3.7c.bb1
2 files changed, 279 insertions, 0 deletions
diff --git a/meta-networking/recipes-daemons/proftpd/files/CVE-2023-51713.patch b/meta-networking/recipes-daemons/proftpd/files/CVE-2023-51713.patch
new file mode 100644
index 0000000000..377d8a74ec
--- /dev/null
+++ b/meta-networking/recipes-daemons/proftpd/files/CVE-2023-51713.patch
@@ -0,0 +1,278 @@
1From 97bbe68363ccf2de0c07f67170ec64a8b4d62592 Mon Sep 17 00:00:00 2001
2From: TJ Saunders <tj@castaglia.org>
3Date: Sun, 6 Aug 2023 13:16:26 -0700
4Subject: [PATCH] Issue #1683: Avoid an edge case when handling unexpectedly
5 formatted input text from client, caused by quote/backslash semantics, by
6 skipping those semantics.
7
8Upstream-Status: Backport [https://github.com/proftpd/proftpd/commit/97bbe68363ccf2de0c07f67170ec64a8b4d62592]
9CVE: CVE-2023-51713
10Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
11Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
12---
13 include/str.h | 3 ++-
14 src/main.c | 34 +++++++++++++++++++++++++++++----
15 src/str.c | 22 +++++++++++++---------
16 tests/api/str.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-
17 4 files changed, 94 insertions(+), 15 deletions(-)
18
19diff --git a/include/str.h b/include/str.h
20index f08398017..1261ae2c2 100644
21--- a/include/str.h
22+++ b/include/str.h
23@@ -1,6 +1,6 @@
24 /*
25 * ProFTPD - FTP server daemon
26- * Copyright (c) 2008-2020 The ProFTPD Project team
27+ * Copyright (c) 2008-2023 The ProFTPD Project team
28 *
29 * This program is free software; you can redistribute it and/or modify
30 * it under the terms of the GNU General Public License as published by
31@@ -131,6 +131,7 @@ const char *pr_gid2str(pool *, gid_t);
32 #define PR_STR_FL_PRESERVE_COMMENTS 0x0001
33 #define PR_STR_FL_PRESERVE_WHITESPACE 0x0002
34 #define PR_STR_FL_IGNORE_CASE 0x0004
35+#define PR_STR_FL_IGNORE_QUOTES 0x0008
36
37 char *pr_str_get_token(char **, char *);
38 char *pr_str_get_token2(char **, char *, size_t *);
39diff --git a/src/main.c b/src/main.c
40index ee9c1eecb..e6b70731d 100644
41--- a/src/main.c
42+++ b/src/main.c
43@@ -811,8 +811,24 @@ static cmd_rec *make_ftp_cmd(pool *p, char *buf, size_t buflen, int flags) {
44 return NULL;
45 }
46
47+ /* By default, pr_str_get_word will handle quotes and backslashes for
48+ * escaping characters. This can produce words which are shorter, use
49+ * fewer bytes than the corresponding input buffer.
50+ *
51+ * In this particular situation, we use the length of this initial word
52+ * for determining the length of the remaining buffer bytes, assumed to
53+ * contain the FTP command arguments. If this initial word is thus
54+ * unexpectedly "shorter", due to nonconformant FTP text, it can lead
55+ * the subsequent buffer scan, looking for CRNUL sequencees, to access
56+ * unexpected memory addresses (Issue #1683).
57+ *
58+ * Thus for this particular situation, we tell the function to ignore/skip
59+ * such quote/backslash semantics, and treat them as any other character
60+ * using the IGNORE_QUOTES flag.
61+ */
62+
63 ptr = buf;
64- wrd = pr_str_get_word(&ptr, str_flags);
65+ wrd = pr_str_get_word(&ptr, str_flags|PR_STR_FL_IGNORE_QUOTES);
66 if (wrd == NULL) {
67 /* Nothing there...bail out. */
68 pr_trace_msg("ctrl", 5, "command '%s' is empty, ignoring", buf);
69@@ -820,6 +836,11 @@ static cmd_rec *make_ftp_cmd(pool *p, char *buf, size_t buflen, int flags) {
70 return NULL;
71 }
72
73+ /* Note that this first word is the FTP command. This is why we make
74+ * use of the ptr buffer, which advances through the input buffer as
75+ * we read words from the buffer.
76+ */
77+
78 subpool = make_sub_pool(p);
79 pr_pool_tag(subpool, "make_ftp_cmd pool");
80 cmd = pcalloc(subpool, sizeof(cmd_rec));
81@@ -846,6 +867,7 @@ static cmd_rec *make_ftp_cmd(pool *p, char *buf, size_t buflen, int flags) {
82 arg_len = buflen - strlen(wrd);
83 arg = pcalloc(cmd->pool, arg_len + 1);
84
85+ /* Remember that ptr here is advanced past the first word. */
86 for (i = 0, j = 0; i < arg_len; i++) {
87 pr_signals_handle();
88 if (i > 1 &&
89@@ -854,14 +876,13 @@ static cmd_rec *make_ftp_cmd(pool *p, char *buf, size_t buflen, int flags) {
90
91 /* Strip out the NUL by simply not copying it into the new buffer. */
92 have_crnul = TRUE;
93+
94 } else {
95 arg[j++] = ptr[i];
96 }
97 }
98
99- cmd->arg = arg;
100-
101- if (have_crnul) {
102+ if (have_crnul == TRUE) {
103 char *dup_arg;
104
105 /* Now make a copy of the stripped argument; this is what we need to
106@@ -871,6 +892,11 @@ static cmd_rec *make_ftp_cmd(pool *p, char *buf, size_t buflen, int flags) {
107 ptr = dup_arg;
108 }
109
110+ cmd->arg = arg;
111+
112+ /* Now we can read the remamining words, as command arguments, from the
113+ * input buffer.
114+ */
115 while ((wrd = pr_str_get_word(&ptr, str_flags)) != NULL) {
116 pr_signals_handle();
117 *((char **) push_array(tarr)) = pstrdup(cmd->pool, wrd);
118diff --git a/src/str.c b/src/str.c
119index bcca4ae4d..a2ff74daf 100644
120--- a/src/str.c
121+++ b/src/str.c
122@@ -1,6 +1,6 @@
123 /*
124 * ProFTPD - FTP server daemon
125- * Copyright (c) 2008-2017 The ProFTPD Project team
126+ * Copyright (c) 2008-2023 The ProFTPD Project team
127 *
128 * This program is free software; you can redistribute it and/or modify
129 * it under the terms of the GNU General Public License as published by
130@@ -1209,7 +1209,7 @@ int pr_str_get_nbytes(const char *str, const char *units, off_t *nbytes) {
131
132 char *pr_str_get_word(char **cp, int flags) {
133 char *res, *dst;
134- char quote_mode = 0;
135+ int quote_mode = FALSE;
136
137 if (cp == NULL ||
138 !*cp ||
139@@ -1238,24 +1238,28 @@ char *pr_str_get_word(char **cp, int flags) {
140 }
141 }
142
143- if (**cp == '\"') {
144- quote_mode++;
145- (*cp)++;
146+ if (!(flags & PR_STR_FL_IGNORE_QUOTES)) {
147+ if (**cp == '\"') {
148+ quote_mode = TRUE;
149+ (*cp)++;
150+ }
151 }
152
153 while (**cp && (quote_mode ? (**cp != '\"') : !PR_ISSPACE(**cp))) {
154 pr_signals_handle();
155
156- if (**cp == '\\' && quote_mode) {
157-
158+ if (**cp == '\\' &&
159+ quote_mode == TRUE) {
160 /* Escaped char */
161 if (*((*cp)+1)) {
162- *dst = *(++(*cp));
163+ *dst++ = *(++(*cp));
164+ (*cp)++;
165+ continue;
166 }
167 }
168
169 *dst++ = **cp;
170- ++(*cp);
171+ (*cp)++;
172 }
173
174 if (**cp) {
175diff --git a/tests/api/str.c b/tests/api/str.c
176index 050f5c563..bc64f0fb0 100644
177--- a/tests/api/str.c
178+++ b/tests/api/str.c
179@@ -1,6 +1,6 @@
180 /*
181 * ProFTPD - FTP server testsuite
182- * Copyright (c) 2008-2017 The ProFTPD Project team
183+ * Copyright (c) 2008-2023 The ProFTPD Project team
184 *
185 * This program is free software; you can redistribute it and/or modify
186 * it under the terms of the GNU General Public License as published by
187@@ -695,19 +695,23 @@ END_TEST
188 START_TEST (get_word_test) {
189 char *ok, *res, *str;
190
191+ mark_point();
192 res = pr_str_get_word(NULL, 0);
193 fail_unless(res == NULL, "Failed to handle null arguments");
194 fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
195
196+ mark_point();
197 str = NULL;
198 res = pr_str_get_word(&str, 0);
199 fail_unless(res == NULL, "Failed to handle null str argument");
200 fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
201
202+ mark_point();
203 str = pstrdup(p, " ");
204 res = pr_str_get_word(&str, 0);
205 fail_unless(res == NULL, "Failed to handle whitespace argument");
206
207+ mark_point();
208 str = pstrdup(p, " foo");
209 res = pr_str_get_word(&str, PR_STR_FL_PRESERVE_WHITESPACE);
210 fail_unless(res != NULL, "Failed to handle whitespace argument: %s",
211@@ -723,6 +727,7 @@ START_TEST (get_word_test) {
212 ok = "foo";
213 fail_unless(strcmp(res, ok) == 0, "Expected '%s', got '%s'", ok, res);
214
215+ mark_point();
216 str = pstrdup(p, " # foo");
217 res = pr_str_get_word(&str, 0);
218 fail_unless(res == NULL, "Failed to handle commented argument");
219@@ -742,6 +747,8 @@ START_TEST (get_word_test) {
220 fail_unless(strcmp(res, ok) == 0, "Expected '%s', got '%s'", ok, res);
221
222 /* Test multiple embedded quotes. */
223+
224+ mark_point();
225 str = pstrdup(p, "foo \"bar baz\" qux \"quz norf\"");
226 res = pr_str_get_word(&str, 0);
227 fail_unless(res != NULL, "Failed to handle quoted argument: %s",
228@@ -770,6 +777,47 @@ START_TEST (get_word_test) {
229
230 ok = "quz norf";
231 fail_unless(strcmp(res, ok) == 0, "Expected '%s', got '%s'", ok, res);
232+
233+
234+ /* Test embedded quotes with backslashes (Issue #1683). */
235+ mark_point();
236+
237+ str = pstrdup(p, "\"\\\\SYST\"");
238+ res = pr_str_get_word(&str, 0);
239+ fail_unless(res != NULL, "Failed to handle quoted argument: %s",
240+ strerror(errno));
241+
242+ ok = "\\SYST";
243+ fail_unless(strcmp(res, ok) == 0, "Expected '%s', got '%s'", ok, res);
244+
245+ mark_point();
246+ str = pstrdup(p, "\"\"\\\\SYST");
247+ res = pr_str_get_word(&str, 0);
248+ fail_unless(res != NULL, "Failed to handle quoted argument: %s",
249+ strerror(errno));
250+
251+ /* Note that pr_str_get_word() is intended to be called multiple times
252+ * on an advancing buffer, effectively tokenizing the buffer. This is
253+ * why the function does NOT decrement its quote mode.
254+ */
255+ ok = "";
256+ fail_unless(strcmp(res, ok) == 0, "Expected '%s', got '%s'", ok, res);
257+
258+ /* Now do the same tests with the IGNORE_QUOTES flag */
259+ mark_point();
260+
261+ str = ok = pstrdup(p, "\"\\\\SYST\"");
262+ res = pr_str_get_word(&str, PR_STR_FL_IGNORE_QUOTES);
263+ fail_unless(res != NULL, "Failed to handle quoted argument: %s",
264+ strerror(errno));
265+ fail_unless(strcmp(res, ok) == 0, "Expected '%s', got '%s'", ok, res);
266+
267+ mark_point();
268+ str = ok = pstrdup(p, "\"\"\\\\SYST");
269+ res = pr_str_get_word(&str, PR_STR_FL_IGNORE_QUOTES);
270+ fail_unless(res != NULL, "Failed to handle quoted argument: %s",
271+ strerror(errno));
272+ fail_unless(strcmp(res, ok) == 0, "Expected '%s', got '%s'", ok, res);
273 }
274 END_TEST
275
276--
2772.25.1
278
diff --git a/meta-networking/recipes-daemons/proftpd/proftpd_1.3.7c.bb b/meta-networking/recipes-daemons/proftpd/proftpd_1.3.7c.bb
index b45cb6aaec..ec38fb54e1 100644
--- a/meta-networking/recipes-daemons/proftpd/proftpd_1.3.7c.bb
+++ b/meta-networking/recipes-daemons/proftpd/proftpd_1.3.7c.bb
@@ -15,6 +15,7 @@ SRC_URI = "git://github.com/proftpd/proftpd.git;branch=${BRANCH};protocol=https
15 file://contrib.patch \ 15 file://contrib.patch \
16 file://build_fixup.patch \ 16 file://build_fixup.patch \
17 file://proftpd.service \ 17 file://proftpd.service \
18 file://CVE-2023-51713.patch \
18 file://CVE-2024-57392.patch \ 19 file://CVE-2024-57392.patch \
19 " 20 "
20 21