[Git][debian-proftpd-team/proftpd][bookworm] Add patch for CVE-2023-51713.
Hilmar Preuße (@hilmar-guest)
gitlab at salsa.debian.org
Mon Jan 1 20:54:13 GMT 2024
Hilmar Preuße pushed to branch bookworm at Debian ProFTPD Team / proftpd
Commits:
7b0bf090 by Hilmar Preusse at 2024-01-01T20:53:24+00:00
Add patch for CVE-2023-51713.
- - - - -
3 changed files:
- debian/changelog
- + debian/patches/97bbe68363ccf2de0c07f67170ec64a8b4d62592.diff
- debian/patches/series
Changes:
=====================================
debian/changelog
=====================================
@@ -1,6 +1,9 @@
proftpd-dfsg (1.3.8+dfsg-4+deb12u3) UNRELEASED; urgency=medium
- * Add patch for Terrapine attack (CVE-2023-48795).
+ * Add patch for Terrapin attack (CVE-2023-48795).
+ * make_ftp_cmd in main.c in ProFTPD before 1.3.8a has a one-byte
+ out-of-bounds read, and daemon crash, because of mishandling of
+ quote/backslash semantics. (CVE-2023-51713).
-- Hilmar Preusse <hille42 at web.de> Fri, 22 Dec 2023 21:58:38 +0000
=====================================
debian/patches/97bbe68363ccf2de0c07f67170ec64a8b4d62592.diff
=====================================
@@ -0,0 +1,270 @@
+From 97bbe68363ccf2de0c07f67170ec64a8b4d62592 Mon Sep 17 00:00:00 2001
+From: TJ Saunders <tj at castaglia.org>
+Date: Sun, 6 Aug 2023 13:16:26 -0700
+Subject: [PATCH] Issue #1683: Avoid an edge case when handling unexpectedly
+ formatted input text from client, caused by quote/backslash semantics, by
+ skipping those semantics.
+
+---
+ include/str.h | 3 ++-
+ src/main.c | 34 ++++++++++++++++++++++++++++++----
+ src/str.c | 22 +++++++++++++---------
+ tests/api/str.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++-
+ 4 files changed, 93 insertions(+), 15 deletions(-)
+
+diff --git a/include/str.h b/include/str.h
+index 1e1add779a..57c5d8a6b6 100644
+--- a/include/str.h
++++ b/include/str.h
+@@ -1,6 +1,6 @@
+ /*
+ * ProFTPD - FTP server daemon
+- * Copyright (c) 2008-2021 The ProFTPD Project team
++ * Copyright (c) 2008-2023 The ProFTPD Project team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+@@ -137,6 +137,7 @@ const char *pr_gid2str(pool *, gid_t);
+ #define PR_STR_FL_PRESERVE_COMMENTS 0x0001
+ #define PR_STR_FL_PRESERVE_WHITESPACE 0x0002
+ #define PR_STR_FL_IGNORE_CASE 0x0004
++#define PR_STR_FL_IGNORE_QUOTES 0x0008
+
+ char *pr_str_get_token(char **, char *);
+ char *pr_str_get_token2(char **, char *, size_t *);
+diff --git a/src/main.c b/src/main.c
+index ae802b0cc5..e2b1f47c6a 100644
+--- a/src/main.c
++++ b/src/main.c
+@@ -821,8 +821,24 @@ static cmd_rec *make_ftp_cmd(pool *p, char *buf, size_t buflen, int flags) {
+ return NULL;
+ }
+
++ /* By default, pr_str_get_word will handle quotes and backslashes for
++ * escaping characters. This can produce words which are shorter, use
++ * fewer bytes than the corresponding input buffer.
++ *
++ * In this particular situation, we use the length of this initial word
++ * for determining the length of the remaining buffer bytes, assumed to
++ * contain the FTP command arguments. If this initial word is thus
++ * unexpectedly "shorter", due to nonconformant FTP text, it can lead
++ * the subsequent buffer scan, looking for CRNUL sequencees, to access
++ * unexpected memory addresses (Issue #1683).
++ *
++ * Thus for this particular situation, we tell the function to ignore/skip
++ * such quote/backslash semantics, and treat them as any other character
++ * using the IGNORE_QUOTES flag.
++ */
++
+ ptr = buf;
+- wrd = pr_str_get_word(&ptr, str_flags);
++ wrd = pr_str_get_word(&ptr, str_flags|PR_STR_FL_IGNORE_QUOTES);
+ if (wrd == NULL) {
+ /* Nothing there...bail out. */
+ pr_trace_msg("ctrl", 5, "command '%s' is empty, ignoring", buf);
+@@ -830,6 +846,11 @@ static cmd_rec *make_ftp_cmd(pool *p, char *buf, size_t buflen, int flags) {
+ return NULL;
+ }
+
++ /* Note that this first word is the FTP command. This is why we make
++ * use of the ptr buffer, which advances through the input buffer as
++ * we read words from the buffer.
++ */
++
+ subpool = make_sub_pool(p);
+ pr_pool_tag(subpool, "make_ftp_cmd pool");
+ cmd = pcalloc(subpool, sizeof(cmd_rec));
+@@ -856,6 +877,7 @@ static cmd_rec *make_ftp_cmd(pool *p, char *buf, size_t buflen, int flags) {
+ arg_len = buflen - strlen(wrd);
+ arg = pcalloc(cmd->pool, arg_len + 1);
+
++ /* Remember that ptr here is advanced past the first word. */
+ for (i = 0, j = 0; i < arg_len; i++) {
+ pr_signals_handle();
+ if (i > 1 &&
+@@ -864,14 +886,13 @@ static cmd_rec *make_ftp_cmd(pool *p, char *buf, size_t buflen, int flags) {
+
+ /* Strip out the NUL by simply not copying it into the new buffer. */
+ have_crnul = TRUE;
++
+ } else {
+ arg[j++] = ptr[i];
+ }
+ }
+
+- cmd->arg = arg;
+-
+- if (have_crnul) {
++ if (have_crnul == TRUE) {
+ char *dup_arg;
+
+ /* Now make a copy of the stripped argument; this is what we need to
+@@ -881,6 +902,11 @@ static cmd_rec *make_ftp_cmd(pool *p, char *buf, size_t buflen, int flags) {
+ ptr = dup_arg;
+ }
+
++ cmd->arg = arg;
++
++ /* Now we can read the remamining words, as command arguments, from the
++ * input buffer.
++ */
+ while ((wrd = pr_str_get_word(&ptr, str_flags)) != NULL) {
+ pr_signals_handle();
+ *((char **) push_array(tarr)) = pstrdup(cmd->pool, wrd);
+diff --git a/src/str.c b/src/str.c
+index 357610c87a..58f40f7030 100644
+--- a/src/str.c
++++ b/src/str.c
+@@ -1,6 +1,6 @@
+ /*
+ * ProFTPD - FTP server daemon
+- * Copyright (c) 2008-2022 The ProFTPD Project team
++ * Copyright (c) 2008-2023 The ProFTPD Project team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+@@ -1241,7 +1241,7 @@ int pr_str_get_nbytes(const char *str, const char *units, off_t *nbytes) {
+
+ char *pr_str_get_word(char **cp, int flags) {
+ char *res, *dst;
+- char quote_mode = 0;
++ int quote_mode = FALSE;
+
+ if (cp == NULL ||
+ !*cp ||
+@@ -1270,24 +1270,28 @@ char *pr_str_get_word(char **cp, int flags) {
+ }
+ }
+
+- if (**cp == '\"') {
+- quote_mode++;
+- (*cp)++;
++ if (!(flags & PR_STR_FL_IGNORE_QUOTES)) {
++ if (**cp == '\"') {
++ quote_mode = TRUE;
++ (*cp)++;
++ }
+ }
+
+ while (**cp && (quote_mode ? (**cp != '\"') : !PR_ISSPACE(**cp))) {
+ pr_signals_handle();
+
+- if (**cp == '\\' && quote_mode) {
+-
++ if (**cp == '\\' &&
++ quote_mode == TRUE) {
+ /* Escaped char */
+ if (*((*cp)+1)) {
+- *dst = *(++(*cp));
++ *dst++ = *(++(*cp));
++ (*cp)++;
++ continue;
+ }
+ }
+
+ *dst++ = **cp;
+- ++(*cp);
++ (*cp)++;
+ }
+
+ if (**cp) {
+diff --git a/tests/api/str.c b/tests/api/str.c
+index 73e991d9d8..e432fe761f 100644
+--- a/tests/api/str.c
++++ b/tests/api/str.c
+@@ -1,6 +1,6 @@
+ /*
+ * ProFTPD - FTP server testsuite
+- * Copyright (c) 2008-2021 The ProFTPD Project team
++ * Copyright (c) 2008-2023 The ProFTPD Project team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+@@ -700,19 +700,23 @@ END_TEST
+ START_TEST (get_word_test) {
+ char *ok, *res, *str;
+
++ mark_point();
+ res = pr_str_get_word(NULL, 0);
+ ck_assert_msg(res == NULL, "Failed to handle null arguments");
+ ck_assert_msg(errno == EINVAL, "Failed to set errno to EINVAL");
+
++ mark_point();
+ str = NULL;
+ res = pr_str_get_word(&str, 0);
+ ck_assert_msg(res == NULL, "Failed to handle null str argument");
+ ck_assert_msg(errno == EINVAL, "Failed to set errno to EINVAL");
+
++ mark_point();
+ str = pstrdup(p, " ");
+ res = pr_str_get_word(&str, 0);
+ ck_assert_msg(res == NULL, "Failed to handle whitespace argument");
+
++ mark_point();
+ str = pstrdup(p, " foo");
+ res = pr_str_get_word(&str, PR_STR_FL_PRESERVE_WHITESPACE);
+ ck_assert_msg(res != NULL, "Failed to handle whitespace argument: %s",
+@@ -728,6 +732,7 @@ START_TEST (get_word_test) {
+ ok = "foo";
+ ck_assert_msg(strcmp(res, ok) == 0, "Expected '%s', got '%s'", ok, res);
+
++ mark_point();
+ str = pstrdup(p, " # foo");
+ res = pr_str_get_word(&str, 0);
+ ck_assert_msg(res == NULL, "Failed to handle commented argument");
+@@ -747,6 +752,8 @@ START_TEST (get_word_test) {
+ ck_assert_msg(strcmp(res, ok) == 0, "Expected '%s', got '%s'", ok, res);
+
+ /* Test multiple embedded quotes. */
++
++ mark_point();
+ str = pstrdup(p, "foo \"bar baz\" qux \"quz norf\"");
+ res = pr_str_get_word(&str, 0);
+ ck_assert_msg(res != NULL, "Failed to handle quoted argument: %s",
+@@ -775,6 +782,46 @@ START_TEST (get_word_test) {
+
+ ok = "quz norf";
+ ck_assert_msg(strcmp(res, ok) == 0, "Expected '%s', got '%s'", ok, res);
++
++ /* Test embedded quotes with backslashes (Issue #1683). */
++ mark_point();
++
++ str = pstrdup(p, "\"\\\\SYST\"");
++ res = pr_str_get_word(&str, 0);
++ ck_assert_msg(res != NULL, "Failed to handle quoted argument: %s",
++ strerror(errno));
++
++ ok = "\\SYST";
++ ck_assert_msg(strcmp(res, ok) == 0, "Expected '%s', got '%s'", ok, res);
++
++ mark_point();
++ str = pstrdup(p, "\"\"\\\\SYST");
++ res = pr_str_get_word(&str, 0);
++ ck_assert_msg(res != NULL, "Failed to handle quoted argument: %s",
++ strerror(errno));
++
++ /* Note that pr_str_get_word() is intended to be called multiple times
++ * on an advancing buffer, effectively tokenizing the buffer. This is
++ * why the function does NOT decrement its quote mode.
++ */
++ ok = "";
++ ck_assert_msg(strcmp(res, ok) == 0, "Expected '%s', got '%s'", ok, res);
++
++ /* Now do the same tests with the IGNORE_QUOTES flag */
++ mark_point();
++
++ str = ok = pstrdup(p, "\"\\\\SYST\"");
++ res = pr_str_get_word(&str, PR_STR_FL_IGNORE_QUOTES);
++ ck_assert_msg(res != NULL, "Failed to handle quoted argument: %s",
++ strerror(errno));
++ ck_assert_msg(strcmp(res, ok) == 0, "Expected '%s', got '%s'", ok, res);
++
++ mark_point();
++ str = ok = pstrdup(p, "\"\"\\\\SYST");
++ res = pr_str_get_word(&str, PR_STR_FL_IGNORE_QUOTES);
++ ck_assert_msg(res != NULL, "Failed to handle quoted argument: %s",
++ strerror(errno));
++ ck_assert_msg(strcmp(res, ok) == 0, "Expected '%s', got '%s'", ok, res);
+ }
+ END_TEST
+
=====================================
debian/patches/series
=====================================
@@ -19,3 +19,4 @@ upstream_bug_1597.diff
03_disable_all_non_api_tests.diff
upstream_1707.diff
bcec15efe6c53dac40420731013f1cd2fd54123b.diff
+97bbe68363ccf2de0c07f67170ec64a8b4d62592.diff
View it on GitLab: https://salsa.debian.org/debian-proftpd-team/proftpd/-/commit/7b0bf090bb923f85d76d097849359aa2f186ff1a
--
View it on GitLab: https://salsa.debian.org/debian-proftpd-team/proftpd/-/commit/7b0bf090bb923f85d76d097849359aa2f186ff1a
You're receiving this email because of your account on salsa.debian.org.
More information about the Pkg-proftpd-maintainers
mailing list