diff mbox series

[meta-networking,scarthgap] proftpd: Fix CVE-2023-51713

Message ID 20250606062020.6004-1-vanusuri@mvista.com
State New
Headers show
Series [meta-networking,scarthgap] proftpd: Fix CVE-2023-51713 | expand

Commit Message

Vijay Anusuri June 6, 2025, 6:20 a.m. UTC
From: Vijay Anusuri <vanusuri@mvista.com>

Upstream-Status: Backport from https://github.com/proftpd/proftpd/commit/97bbe68363ccf2de0c07f67170ec64a8b4d62592

Link: https://git.openembedded.org/meta-openembedded/commit/?h=kirkstone&id=730e44900a0a86265bad93a16b5a5ff344a07266

Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
---
 .../proftpd/files/CVE-2023-51713.patch        | 278 ++++++++++++++++++
 .../recipes-daemons/proftpd/proftpd_1.3.7c.bb |   1 +
 2 files changed, 279 insertions(+)
 create mode 100644 meta-networking/recipes-daemons/proftpd/files/CVE-2023-51713.patch

Comments

Vijay Anusuri July 15, 2025, 2:17 a.m. UTC | #1
Hi Team,

Any update regarding the patch for CVE-2023-51713 ?


Thanks,
Vijay


On Fri, Jun 6, 2025 at 11:50 AM <vanusuri@mvista.com> wrote:

> From: Vijay Anusuri <vanusuri@mvista.com>
>
> Upstream-Status: Backport from
> https://github.com/proftpd/proftpd/commit/97bbe68363ccf2de0c07f67170ec64a8b4d62592
>
> Link:
> https://git.openembedded.org/meta-openembedded/commit/?h=kirkstone&id=730e44900a0a86265bad93a16b5a5ff344a07266
>
> Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
> ---
>  .../proftpd/files/CVE-2023-51713.patch        | 278 ++++++++++++++++++
>  .../recipes-daemons/proftpd/proftpd_1.3.7c.bb |   1 +
>  2 files changed, 279 insertions(+)
>  create mode 100644
> meta-networking/recipes-daemons/proftpd/files/CVE-2023-51713.patch
>
> 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 @@
> +From 97bbe68363ccf2de0c07f67170ec64a8b4d62592 Mon Sep 17 00:00:00 2001
> +From: TJ Saunders <tj@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.
> +
> +Upstream-Status: Backport [
> https://github.com/proftpd/proftpd/commit/97bbe68363ccf2de0c07f67170ec64a8b4d62592
> ]
> +CVE: CVE-2023-51713
> +Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
> +Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
> +---
> + include/str.h   |  3 ++-
> + src/main.c      | 34 +++++++++++++++++++++++++++++----
> + src/str.c       | 22 +++++++++++++---------
> + tests/api/str.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-
> + 4 files changed, 94 insertions(+), 15 deletions(-)
> +
> +diff --git a/include/str.h b/include/str.h
> +index f08398017..1261ae2c2 100644
> +--- a/include/str.h
> ++++ b/include/str.h
> +@@ -1,6 +1,6 @@
> + /*
> +  * ProFTPD - FTP server daemon
> +- * Copyright (c) 2008-2020 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
> +@@ -131,6 +131,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 ee9c1eecb..e6b70731d 100644
> +--- a/src/main.c
> ++++ b/src/main.c
> +@@ -811,8 +811,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);
> +@@ -820,6 +836,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));
> +@@ -846,6 +867,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 &&
> +@@ -854,14 +876,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
> +@@ -871,6 +892,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 bcca4ae4d..a2ff74daf 100644
> +--- a/src/str.c
> ++++ b/src/str.c
> +@@ -1,6 +1,6 @@
> + /*
> +  * ProFTPD - FTP server daemon
> +- * Copyright (c) 2008-2017 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
> +@@ -1209,7 +1209,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 ||
> +@@ -1238,24 +1238,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 050f5c563..bc64f0fb0 100644
> +--- a/tests/api/str.c
> ++++ b/tests/api/str.c
> +@@ -1,6 +1,6 @@
> + /*
> +  * ProFTPD - FTP server testsuite
> +- * Copyright (c) 2008-2017 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
> +@@ -695,19 +695,23 @@ END_TEST
> + START_TEST (get_word_test) {
> +   char *ok, *res, *str;
> +
> ++  mark_point();
> +   res = pr_str_get_word(NULL, 0);
> +   fail_unless(res == NULL, "Failed to handle null arguments");
> +   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
> +
> ++  mark_point();
> +   str = NULL;
> +   res = pr_str_get_word(&str, 0);
> +   fail_unless(res == NULL, "Failed to handle null str argument");
> +   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
> +
> ++  mark_point();
> +   str = pstrdup(p, "  ");
> +   res = pr_str_get_word(&str, 0);
> +   fail_unless(res == NULL, "Failed to handle whitespace argument");
> +
> ++  mark_point();
> +   str = pstrdup(p, " foo");
> +   res = pr_str_get_word(&str, PR_STR_FL_PRESERVE_WHITESPACE);
> +   fail_unless(res != NULL, "Failed to handle whitespace argument: %s",
> +@@ -723,6 +727,7 @@ START_TEST (get_word_test) {
> +   ok = "foo";
> +   fail_unless(strcmp(res, ok) == 0, "Expected '%s', got '%s'", ok, res);
> +
> ++  mark_point();
> +   str = pstrdup(p, "  # foo");
> +   res = pr_str_get_word(&str, 0);
> +   fail_unless(res == NULL, "Failed to handle commented argument");
> +@@ -742,6 +747,8 @@ START_TEST (get_word_test) {
> +   fail_unless(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);
> +   fail_unless(res != NULL, "Failed to handle quoted argument: %s",
> +@@ -770,6 +777,47 @@ START_TEST (get_word_test) {
> +
> +   ok = "quz norf";
> +   fail_unless(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);
> ++  fail_unless(res != NULL, "Failed to handle quoted argument: %s",
> ++    strerror(errno));
> ++
> ++  ok = "\\SYST";
> ++  fail_unless(strcmp(res, ok) == 0, "Expected '%s', got '%s'", ok, res);
> ++
> ++  mark_point();
> ++  str = pstrdup(p, "\"\"\\\\SYST");
> ++  res = pr_str_get_word(&str, 0);
> ++  fail_unless(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 = "";
> ++  fail_unless(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);
> ++  fail_unless(res != NULL, "Failed to handle quoted argument: %s",
> ++    strerror(errno));
> ++  fail_unless(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);
> ++  fail_unless(res != NULL, "Failed to handle quoted argument: %s",
> ++    strerror(errno));
> ++  fail_unless(strcmp(res, ok) == 0, "Expected '%s', got '%s'", ok, res);
> + }
> + END_TEST
> +
> +--
> +2.25.1
> +
> 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
> <http://github.com/proftpd/proftpd.git;branch=$%7BBRANCH%7D;protocol=https>
>             file://contrib.patch  \
>             file://build_fixup.patch \
>             file://proftpd.service \
> +           file://CVE-2023-51713.patch \
>             file://CVE-2024-57392.patch \
>             "
>
> --
> 2.25.1
>
>
diff mbox series

Patch

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 @@ 
+From 97bbe68363ccf2de0c07f67170ec64a8b4d62592 Mon Sep 17 00:00:00 2001
+From: TJ Saunders <tj@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.
+
+Upstream-Status: Backport [https://github.com/proftpd/proftpd/commit/97bbe68363ccf2de0c07f67170ec64a8b4d62592]
+CVE: CVE-2023-51713
+Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
+Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
+---
+ include/str.h   |  3 ++-
+ src/main.c      | 34 +++++++++++++++++++++++++++++----
+ src/str.c       | 22 +++++++++++++---------
+ tests/api/str.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-
+ 4 files changed, 94 insertions(+), 15 deletions(-)
+
+diff --git a/include/str.h b/include/str.h
+index f08398017..1261ae2c2 100644
+--- a/include/str.h
++++ b/include/str.h
+@@ -1,6 +1,6 @@
+ /*
+  * ProFTPD - FTP server daemon
+- * Copyright (c) 2008-2020 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
+@@ -131,6 +131,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 ee9c1eecb..e6b70731d 100644
+--- a/src/main.c
++++ b/src/main.c
+@@ -811,8 +811,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);
+@@ -820,6 +836,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));
+@@ -846,6 +867,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 &&
+@@ -854,14 +876,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
+@@ -871,6 +892,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 bcca4ae4d..a2ff74daf 100644
+--- a/src/str.c
++++ b/src/str.c
+@@ -1,6 +1,6 @@
+ /*
+  * ProFTPD - FTP server daemon
+- * Copyright (c) 2008-2017 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
+@@ -1209,7 +1209,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 ||
+@@ -1238,24 +1238,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 050f5c563..bc64f0fb0 100644
+--- a/tests/api/str.c
++++ b/tests/api/str.c
+@@ -1,6 +1,6 @@
+ /*
+  * ProFTPD - FTP server testsuite
+- * Copyright (c) 2008-2017 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
+@@ -695,19 +695,23 @@ END_TEST
+ START_TEST (get_word_test) {
+   char *ok, *res, *str;
+ 
++  mark_point();
+   res = pr_str_get_word(NULL, 0);
+   fail_unless(res == NULL, "Failed to handle null arguments");
+   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
+ 
++  mark_point();
+   str = NULL;
+   res = pr_str_get_word(&str, 0);
+   fail_unless(res == NULL, "Failed to handle null str argument");
+   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
+ 
++  mark_point();
+   str = pstrdup(p, "  ");
+   res = pr_str_get_word(&str, 0);
+   fail_unless(res == NULL, "Failed to handle whitespace argument");
+ 
++  mark_point();
+   str = pstrdup(p, " foo");
+   res = pr_str_get_word(&str, PR_STR_FL_PRESERVE_WHITESPACE);
+   fail_unless(res != NULL, "Failed to handle whitespace argument: %s",
+@@ -723,6 +727,7 @@ START_TEST (get_word_test) {
+   ok = "foo";
+   fail_unless(strcmp(res, ok) == 0, "Expected '%s', got '%s'", ok, res);
+ 
++  mark_point();
+   str = pstrdup(p, "  # foo");
+   res = pr_str_get_word(&str, 0);
+   fail_unless(res == NULL, "Failed to handle commented argument");
+@@ -742,6 +747,8 @@ START_TEST (get_word_test) {
+   fail_unless(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);
+   fail_unless(res != NULL, "Failed to handle quoted argument: %s",
+@@ -770,6 +777,47 @@ START_TEST (get_word_test) {
+ 
+   ok = "quz norf";
+   fail_unless(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);
++  fail_unless(res != NULL, "Failed to handle quoted argument: %s",
++    strerror(errno));
++
++  ok = "\\SYST";
++  fail_unless(strcmp(res, ok) == 0, "Expected '%s', got '%s'", ok, res);
++
++  mark_point();
++  str = pstrdup(p, "\"\"\\\\SYST");
++  res = pr_str_get_word(&str, 0);
++  fail_unless(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 = "";
++  fail_unless(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);
++  fail_unless(res != NULL, "Failed to handle quoted argument: %s",
++    strerror(errno));
++  fail_unless(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);
++  fail_unless(res != NULL, "Failed to handle quoted argument: %s",
++    strerror(errno));
++  fail_unless(strcmp(res, ok) == 0, "Expected '%s', got '%s'", ok, res);
+ }
+ END_TEST
+ 
+-- 
+2.25.1
+
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
            file://contrib.patch  \
            file://build_fixup.patch \
            file://proftpd.service \
+           file://CVE-2023-51713.patch \
            file://CVE-2024-57392.patch \
            "