Package: release.debian.org
Severity: normal
Tags: trixie
X-Debbugs-Cc: [email protected]
Control: affects -1 + src:proftpd-dfsg
User: [email protected]
Usertags: pu

(Please provide enough information to help the release team
to judge the request efficiently. E.g. by filling in the
sections below.)

[ Reason ]
There were a few security leaks recently discovered in the proftp
code. This update addresses these leaks (see below in [Changes]).

[ Impact ]
If the update is not approved, the existing proftp installations
will further suffer from the security leaks in question.

[ Tests ]
The proftp package has an automated test suite, which runs successful
even after applying the pataches.

[ Risks ]
See tests.

[ Checklist ]
  [X] *all* changes are documented in the d/changelog
  [X] I reviewed all changes and I approve them
  [X] attach debdiff against the package in stable
  [X] the issue is verified as fixed in unstable

[ Changes ]
The update contains the 4 patches to address CVE-2026-44331 /
CVE-2026-53994 / CVE-2026-63091 / CVE-2026-63090

[ Other info ]
N/A.
diff -Nru proftpd-dfsg-1.3.8.c+dfsg/debian/changelog proftpd-dfsg-1.3.8.c+dfsg/debian/changelog
--- proftpd-dfsg-1.3.8.c+dfsg/debian/changelog	2026-05-01 12:48:15.000000000 +0200
+++ proftpd-dfsg-1.3.8.c+dfsg/debian/changelog	2026-07-22 22:58:45.000000000 +0200
@@ -1,3 +1,12 @@
+proftpd-dfsg (1.3.8.c+dfsg-4+deb13u3) trixie; urgency=medium
+
+  * Add patch for CVE-2026-44331 (Closes: #1135840).
+  * Add patch for CVE-2026-53994.
+  * Add patch for CVE-2026-63091.
+  * Add patch for CVE-2026-63090.
+
+ -- Hilmar Preuße <[email protected]>  Wed, 22 Jul 2026 22:58:45 +0200
+
 proftpd-dfsg (1.3.8.c+dfsg-4+deb13u2) trixie; urgency=medium
 
   * Add patch for CVE-2026-42167 (Closes: #1135119).
diff -Nru proftpd-dfsg-1.3.8.c+dfsg/debian/gitlab-ci.yml proftpd-dfsg-1.3.8.c+dfsg/debian/gitlab-ci.yml
--- proftpd-dfsg-1.3.8.c+dfsg/debian/gitlab-ci.yml	2026-05-01 12:47:52.000000000 +0200
+++ proftpd-dfsg-1.3.8.c+dfsg/debian/gitlab-ci.yml	2026-07-22 22:58:45.000000000 +0200
@@ -7,9 +7,11 @@
 variables:
   SALSA_CI_DISABLE_APTLY: 0
   SALSA_CI_DISABLE_AUTOPKGTEST: 1
+  SALSA_CI_DISABLE_DEBREBUILD: 1
   SALSA_CI_DISABLE_BLHC: 1
   SALSA_CI_DISABLE_LINTIAN: 0
   SALSA_CI_DISABLE_PIUPARTS: 0
   SALSA_CI_DISABLE_REPROTEST: 1
   SALSA_CI_DISABLE_BUILD_PACKAGE_ALL: 0
-  SALSA_CI_DISABLE_BUILD_PACKAGE_ANY: 0
\ No newline at end of file
+  SALSA_CI_DISABLE_BUILD_PACKAGE_ANY: 0
+  SALSA_CI_DISABLE_USCAN: 1
diff -Nru proftpd-dfsg-1.3.8.c+dfsg/debian/patches/07797aba88dca902da7eaf1dfe262c8896943de7.diff proftpd-dfsg-1.3.8.c+dfsg/debian/patches/07797aba88dca902da7eaf1dfe262c8896943de7.diff
--- proftpd-dfsg-1.3.8.c+dfsg/debian/patches/07797aba88dca902da7eaf1dfe262c8896943de7.diff	1970-01-01 01:00:00.000000000 +0100
+++ proftpd-dfsg-1.3.8.c+dfsg/debian/patches/07797aba88dca902da7eaf1dfe262c8896943de7.diff	2026-05-23 10:50:34.000000000 +0200
@@ -0,0 +1,103 @@
+From 07797aba88dca902da7eaf1dfe262c8896943de7 Mon Sep 17 00:00:00 2001
+From: TJ Saunders <[email protected]>
+Date: Tue, 5 May 2026 09:56:33 -0700
+Subject: [PATCH] Issue #2057: Properly escape the "name" provided when doing
+ SQL lookups for allowed/denied client IP addresses or DNS names.
+
+---
+ contrib/mod_wrap2_sql.c | 49 +++++++++++++++++++++++++++++++++++++----
+ 1 file changed, 45 insertions(+), 4 deletions(-)
+
+diff --git a/contrib/mod_wrap2_sql.c b/contrib/mod_wrap2_sql.c
+index eaf6ea7dc5..d4fd56e699 100644
+--- a/contrib/mod_wrap2_sql.c
++++ b/contrib/mod_wrap2_sql.c
+@@ -1,7 +1,7 @@
+ /*
+  * ProFTPD: mod_wrap2_sql -- a mod_wrap2 sub-module for supplying IP-based
+  *                           access control data via SQL tables
+- * Copyright (c) 2002-2016 TJ Saunders
++ * Copyright (c) 2002-2026 TJ Saunders
+  *
+  * 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
+@@ -25,7 +25,7 @@
+ #include "mod_wrap2.h"
+ #include "mod_sql.h"
+ 
+-#define MOD_WRAP2_SQL_VERSION		"mod_wrap2_sql/1.0"
++#define MOD_WRAP2_SQL_VERSION		"mod_wrap2_sql/1.1"
+ 
+ #define WRAP2_SQL_NSLOTS		2
+ #define WRAP2_SQL_CLIENT_QUERY_IDX	0
+@@ -62,6 +62,41 @@ static int sqltab_close_cb(wrap2_table_t *sqltab) {
+   return 0;
+ }
+ 
++static char *sqltab_get_escaped_text(pool *p, wrap2_table_t *sqltab,
++    const char *text) {
++  pool *tmp_pool = NULL;
++  cmdtable *sql_cmdtab = NULL;
++  cmd_rec *sql_cmd = NULL;
++  modret_t *sql_res = NULL;
++
++  /* Find the cmdtable for the sql_escapestr command, as the provided
++   * name needs to be properly escaped for SQL syntax; see Issue #2057.
++   */
++  sql_cmdtab = pr_stash_get_symbol2(PR_SYM_HOOK, "sql_escapestr", NULL, NULL,
++    NULL);
++  if (sql_cmdtab == NULL) {
++    wrap2_log("error: unable to find SQL hook symbol 'sql_escapestr': "
++      "perhaps your proftpd.conf needs 'LoadModule mod_sql.c'?");
++    return NULL;
++  }
++
++  sql_cmd = sql_cmd_create(tmp_pool, 1, text);
++  sql_res = pr_module_call(sql_cmdtab->m, sql_cmdtab->handler, sql_cmd);
++  if (sql_res == NULL) {
++    wrap2_log("sql_escapestr '%s' returned no data; "
++      "see the mod_sql.c SQLLogFile for more details", text);
++    return NULL;
++  }
++
++  if (MODRET_ISERROR(sql_res)) {
++    wrap2_log("error processing sql_escapestr '%s': "
++      "check the mod_sql.c SQLLogFile for more details", text);
++    return NULL;
++  }
++
++  return sql_res->data;
++}
++
+ static array_header *sqltab_fetch_clients_cb(wrap2_table_t *sqltab,
+     const char *name) {
+   register unsigned int i;
+@@ -70,12 +105,18 @@ static array_header *sqltab_fetch_clients_cb(wrap2_table_t *sqltab,
+   cmd_rec *sql_cmd = NULL;
+   modret_t *sql_res = NULL;
+   array_header *sql_data = NULL;
+-  char *query = NULL, **vals = NULL;
++  char *escaped_name = NULL, *query = NULL, **vals = NULL;
+   array_header *clients_list = NULL;
+ 
+   /* Allocate a temporary pool for the duration of this read. */
+   tmp_pool = make_sub_pool(sqltab->tab_pool);
+ 
++  escaped_name = sqltab_get_escaped_text(tmp_pool, sqltab, name);
++  if (escaped_name == NULL) {
++    destroy_pool(tmp_pool);
++    return NULL;
++  }
++
+   query = ((char **) sqltab->tab_data)[WRAP2_SQL_CLIENT_QUERY_IDX];
+ 
+   /* Find the cmdtable for the sql_lookup command. */
+@@ -89,7 +130,7 @@ static array_header *sqltab_fetch_clients_cb(wrap2_table_t *sqltab,
+   }
+ 
+   /* Prepare the SELECT query. */
+-  sql_cmd = sql_cmd_create(tmp_pool, 3, "sql_lookup", query, name);
++  sql_cmd = sql_cmd_create(tmp_pool, 3, "sql_lookup", query, escaped_name);
+ 
+   /* Call the handler. */
+   sql_res = pr_module_call(sql_cmdtab->m, sql_cmdtab->handler, sql_cmd);
diff -Nru proftpd-dfsg-1.3.8.c+dfsg/debian/patches/baf4b7929758c72cdb6cf16325fa25f435d23db6.diff proftpd-dfsg-1.3.8.c+dfsg/debian/patches/baf4b7929758c72cdb6cf16325fa25f435d23db6.diff
--- proftpd-dfsg-1.3.8.c+dfsg/debian/patches/baf4b7929758c72cdb6cf16325fa25f435d23db6.diff	1970-01-01 01:00:00.000000000 +0100
+++ proftpd-dfsg-1.3.8.c+dfsg/debian/patches/baf4b7929758c72cdb6cf16325fa25f435d23db6.diff	2026-07-22 22:58:45.000000000 +0200
@@ -0,0 +1,49 @@
+From baf4b7929758c72cdb6cf16325fa25f435d23db6 Mon Sep 17 00:00:00 2001
+From: TJ Saunders <[email protected]>
+Date: Wed, 1 Jul 2026 09:14:38 -0700
+Subject: [PATCH] Exercise caution when reading the client-provided file size
+ for SCP uploads, as it could possibly overflow our size type.
+
+Thanks to Fabian Wahle of Hap Security for reporting this issue.
+---
+ contrib/mod_sftp/scp.c | 23 +++++++++++++++++------
+ 1 file changed, 17 insertions(+), 6 deletions(-)
+
+diff --git a/contrib/mod_sftp/scp.c b/contrib/mod_sftp/scp.c
+index 8c105587f..b1f3e89ae 100644
+--- a/contrib/mod_sftp/scp.c
++++ b/contrib/mod_sftp/scp.c
+@@ -603,16 +603,27 @@ static int recv_perms(pool *p, uint32_t channel_id, char *mode_str,
+ 
+ static int recv_filesz(pool *p, uint32_t channel_id, char *size_str,
+     off_t *filesz) {
+-  register unsigned int i;
++  char *endp = NULL;
++  unsigned long long sz;
++  *filesz = 0;
+ 
+-  /* The file size field could be of arbitrary length. */
+-  for (i = 0, *filesz = 0; PR_ISDIGIT(size_str[i]); i++) {
+-    pr_signals_handle();
++#if defined(HAVE_STROULL)
++  sz = strtoull(size_str, &endp, 10);
++#else
++  sz = strtoul(size_str, &endp, 10);
++#endif /* HAVE_STROULL */
+ 
+-    *filesz = (*filesz * 10) + (size_str[i] - '0');
++  *filesz = (off_t) sz;
++
++  /* Watch for cases where the sent file size might overflow our size type. */
++  if (*filesz < 0) {
++    pr_trace_msg(trace_channel, 2, "file size out of range");
++    write_confirm(p, channel_id, 1, "file size out of range");
++    return -1;
+   }
+ 
+-  if (size_str[i] != ' ') {
++  if (endp == NULL ||
++      *endp != ' ') {
+     pr_trace_msg(trace_channel, 2, "file size not followed by space delimiter");
+     write_confirm(p, channel_id, 1, "file size not delimited");
+     return -1;
diff -Nru proftpd-dfsg-1.3.8.c+dfsg/debian/patches/mod_sftp-1.3.8d-issue2115.diff proftpd-dfsg-1.3.8.c+dfsg/debian/patches/mod_sftp-1.3.8d-issue2115.diff
--- proftpd-dfsg-1.3.8.c+dfsg/debian/patches/mod_sftp-1.3.8d-issue2115.diff	1970-01-01 01:00:00.000000000 +0100
+++ proftpd-dfsg-1.3.8.c+dfsg/debian/patches/mod_sftp-1.3.8d-issue2115.diff	2026-07-22 22:58:45.000000000 +0200
@@ -0,0 +1,44 @@
+diff --git a/contrib/mod_sftp/fxp.c b/contrib/mod_sftp/fxp.c
+index d61e71046..8e867649c 100644
+--- a/contrib/mod_sftp/fxp.c
++++ b/contrib/mod_sftp/fxp.c
+@@ -3381,6 +3381,23 @@ static struct fxp_packet *fxp_packet_read(uint32_t channel_id,
+       "(%lu bytes remaining in buffer)", (unsigned long) fxp->packet_len,
+       (unsigned long) buflen);
+ 
++    /* We require 5 bytes of SFTP request data at a minimum: 1 byte for the
++     * request type, and 4 bytes for the payload length (Issue #2115).
++     */
++    if (fxp->packet_len < 5) {
++      (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
++        "illegal SFTP request length (%lu bytes, require at least 5 bytes), "
++        "rejecting", (unsigned long) fxp->packet_len);
++      SFTP_DISCONNECT_CONN(SFTP_SSH2_DISCONNECT_BY_APPLICATION, NULL);
++    }
++
++    if (fxp->packet_len > FXP_MAX_PACKET_LEN) {
++      (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
++        "received excessive SFTP packet (len %lu > max %lu bytes), rejecting",
++        (unsigned long) fxp->packet_len, (unsigned long) FXP_MAX_PACKET_LEN);
++      SFTP_DISCONNECT_CONN(SFTP_SSH2_DISCONNECT_BY_APPLICATION, NULL);
++    }
++
+     if (buflen == 0) {
+       fxp_packet_set_packet(fxp);
+       fxp_packet_clear_cache();
+@@ -13674,15 +13691,6 @@ int sftp_fxp_handle_packet(pool *p, void *ssh2, uint32_t channel_id,
+         (unsigned long) channel_id);
+     }
+ 
+-    if (fxp->packet_len > FXP_MAX_PACKET_LEN) {
+-      (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
+-        "received excessive SFTP packet (len %lu > max %lu bytes), rejecting",
+-        (unsigned long) fxp->packet_len, (unsigned long) FXP_MAX_PACKET_LEN);
+-      destroy_pool(fxp->pool);
+-      errno = EPERM;
+-      return -1;
+-    }
+-
+     fxp_session = fxp_get_session(channel_id);
+     if (fxp_session == NULL) {
+       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
diff -Nru proftpd-dfsg-1.3.8.c+dfsg/debian/patches/mod_sftp-1.3.8d-issue2190.diff proftpd-dfsg-1.3.8.c+dfsg/debian/patches/mod_sftp-1.3.8d-issue2190.diff
--- proftpd-dfsg-1.3.8.c+dfsg/debian/patches/mod_sftp-1.3.8d-issue2190.diff	1970-01-01 01:00:00.000000000 +0100
+++ proftpd-dfsg-1.3.8.c+dfsg/debian/patches/mod_sftp-1.3.8d-issue2190.diff	2026-07-22 22:58:45.000000000 +0200
@@ -0,0 +1,81 @@
+diff --git a/contrib/mod_sftp/fxp.c b/contrib/mod_sftp/fxp.c
+index d61e71046..a7631eaa4 100644
+--- a/contrib/mod_sftp/fxp.c
++++ b/contrib/mod_sftp/fxp.c
+@@ -264,11 +264,11 @@ struct fxp_buffer {
+ #define	FXP_PACKET_HAVE_PAYLOAD_SIZE	0x0008
+ #define	FXP_PACKET_HAVE_PAYLOAD		0x0010
+ 
+-/* After 32K of allocation from the scratch SFTP payload pool, destroy the
++/* After 64K of allocation from the scratch SFTP payload pool, destroy the
+  * pool and create a new one.  This will prevent unbounded allocation
+  * from the pool.
+  */
+-#define FXP_PACKET_DATA_ALLOC_MAX_SZ		(1024 * 32)
++#define FXP_PACKET_DATA_ALLOC_MAX_SZ		(1024 * 64)
+ static size_t fxp_packet_data_allocsz = 0;
+ 
+ #define FXP_PACKET_DATA_DEFAULT_SZ		(1024 * 16)
+@@ -3288,37 +3288,45 @@ static void fxp_packet_add_cache(unsigned char *data, uint32_t datalen) {
+ 
+     } else {
+       /* We need a larger buffer.  Round up to the nearest 1K size. */
++      pool *tmp_pool;
++      char *cached_data;
++      uint32_t cached_datalen;
+       size_t sz;
+ 
+-      sz = sftp_crypto_get_size(curr_buflen + datalen + 1, 1024);
++      if (curr_buflen + datalen > FXP_MAX_PACKET_LEN) {
++        (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
++          "received excessive SFTP data (len %lu > max %lu bytes), rejecting",
++          (unsigned long) curr_buflen + datalen,
++          (unsigned long) FXP_MAX_PACKET_LEN);
++        SFTP_DISCONNECT_CONN(SFTP_SSH2_DISCONNECT_BY_APPLICATION, NULL);
++      }
+ 
+-      if (fxp_packet_data_allocsz > FXP_PACKET_DATA_ALLOC_MAX_SZ) {
+-        pool *tmp_pool;
+-        char *tmp_data;
+-        uint32_t tmp_datalen;
++      /* Get the existing cached data before allocating a larger buffer. */
++      tmp_pool = make_sub_pool(fxp_pool);
++
++      cached_datalen = curr_buflen;
++      cached_data = palloc(tmp_pool, cached_datalen);
++      memcpy(cached_data, curr_buf, cached_datalen);
+ 
++      if (fxp_packet_data_allocsz > FXP_PACKET_DATA_ALLOC_MAX_SZ) {
+         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
+           "renewing SFTP packet data pool");
+ 
+-        tmp_pool = make_sub_pool(fxp_pool);
+-        tmp_datalen = curr_buflen;
+-        tmp_data = palloc(tmp_pool, tmp_datalen);                
+-        memcpy(tmp_data, curr_buf, tmp_datalen);
+-        
+         destroy_pool(curr_buf_pool);
+ 
+         curr_buf_pool = make_sub_pool(fxp_pool);
+         pr_pool_tag(curr_buf_pool, "SFTP packet buffer pool");
++      }
+ 
+-        curr_bufsz = sz;
+-        curr_buf = palloc(curr_buf_pool, curr_bufsz);
+-        fxp_packet_data_allocsz += sz;
++      sz = sftp_crypto_get_size(curr_buflen + datalen + 1, 1024);
++      curr_bufsz = sz;
++      curr_buf = palloc(curr_buf_pool, curr_bufsz);
++      fxp_packet_data_allocsz += sz;
+ 
+-        memcpy(curr_buf, tmp_data, tmp_datalen);
+-        curr_buflen = tmp_datalen;
++      memcpy(curr_buf, cached_data, cached_datalen);
++      curr_buflen = cached_datalen;
+ 
+-        destroy_pool(tmp_pool);
+-      }
++      destroy_pool(tmp_pool);
+     }
+ 
+     /* Append the SSH2 data to the current unconsumed buffer.
diff -Nru proftpd-dfsg-1.3.8.c+dfsg/debian/patches/series proftpd-dfsg-1.3.8.c+dfsg/debian/patches/series
--- proftpd-dfsg-1.3.8.c+dfsg/debian/patches/series	2026-05-01 12:47:52.000000000 +0200
+++ proftpd-dfsg-1.3.8.c+dfsg/debian/patches/series	2026-07-22 22:58:45.000000000 +0200
@@ -21,3 +21,11 @@
 14c006b62c09d1efe302c57b2d183a489bcb22dc.diff
 9b2b4a3e32d251798bf8fa841b124ab15ba58f11.diff
 2052_pghmcfc.diff
+# issue 2057, CVE-2026-44331
+07797aba88dca902da7eaf1dfe262c8896943de7.diff
+# issue 2115, CVE-2026-53994
+mod_sftp-1.3.8d-issue2115.diff
+# issue 2201, CVE-2026-63091
+baf4b7929758c72cdb6cf16325fa25f435d23db6.diff
+# issue 2190, CVE-2026-63090
+mod_sftp-1.3.8d-issue2190.diff

Attachment: signature.asc
Description: PGP signature

Reply via email to