[Git][debian-proftpd-team/proftpd][trixie] [skip-ci] Patches for CVE-2026-119147, CVE-2026-119146 & CVE-2026-119364
Hilmar Preuße (@hilmar)
gitlab at salsa.debian.org
Sun Nov 1 23:16:48 GMT 2026
Hilmar Preuße pushed to branch trixie at Debian ProFTPD Team / proftpd
Commits:
88d4757b by Hilmar Preuße at 2026-11-02T00:15:47+01:00
[skip-ci] Patches for CVE-2026-119147, CVE-2026-119146 & CVE-2026-119364
- - - - -
4 changed files:
- + debian/patches/1570fd3b7a70b447bd59b175ed7fb01fb3d8242b.diff
- + debian/patches/4bafd1e9861506e77b9ea3ed277b58e60eacfe4d.diff
- + debian/patches/ab5c8cd35f85b75e90019a32674a1f1062268bec.diff
- debian/patches/series
Changes:
=====================================
debian/patches/1570fd3b7a70b447bd59b175ed7fb01fb3d8242b.diff
=====================================
@@ -0,0 +1,76 @@
+From 1570fd3b7a70b447bd59b175ed7fb01fb3d8242b Mon Sep 17 00:00:00 2001
+From: TJ Saunders <tj at castaglia.org>
+Date: Wed, 21 Oct 2026 10:49:06 -0700
+Subject: [PATCH] When an authenticated user invokes the SFTP "copy-file"
+ extension and the destination does not exist, mod_sftp performs the copy
+ without checking some policies, allowing for file creation in directories
+ denied by `<Limit WRITE>`.
+
+Thanks to Abraxas Labs and MiniMax Security for reporting this issue.
+---
+ contrib/mod_sftp/fxp.c | 32 ++++++++++++++++++++++++--------
+ 1 file changed, 24 insertions(+), 8 deletions(-)
+
+--- proftpd.orig/contrib/mod_sftp/fxp.c
++++ proftpd/contrib/mod_sftp/fxp.c
+@@ -4681,29 +4681,22 @@
+ res = pr_fsio_stat(dst, &st);
+ if (res == 0) {
+ unsigned char *allow_overwrite = NULL;
+- int limit_allow;
+
+ allow_overwrite = get_param_ptr(get_dir_ctxt(fxp->pool, dst),
+ "AllowOverwrite", FALSE);
+
+ cmd2 = pr_cmd_alloc(fxp->pool, 3, "SITE_COPY", src, dst);
+ cmd2->arg = pstrdup(fxp->pool, args);
+- limit_allow = dir_check(fxp->pool, cmd2, "WRITE", dst, NULL);
+
+ if (!overwrite ||
+ (allow_overwrite == NULL ||
+- *allow_overwrite == FALSE) ||
+- !limit_allow) {
++ *allow_overwrite == FALSE)) {
+ xerrno = EACCES;
+
+ if (!overwrite) {
+ (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
+ "'%s' exists and client did not request COPY overwrites", dst);
+
+- } else if (!limit_allow) {
+- (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
+- "COPY to '%s' blocked by <Limit> configuration", dst);
+-
+ } else {
+ (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
+ "AllowOverwrite permission denied for '%s'", dst);
+@@ -4764,6 +4757,29 @@
+
+ fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
+ reason, NULL);
++
++ fxp_cmd_dispatch_err(cmd);
++
++ resp = fxp_packet_create(fxp->pool, fxp->channel_id);
++ resp->payload = ptr;
++ resp->payload_sz = (bufsz - buflen);
++
++ return fxp_packet_write(resp);
++ }
++
++ if (!dir_check(fxp->pool, cmd2, "WRITE", dst, NULL)) {
++ xerrno = EACCES;
++
++ (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
++ "COPY to '%s' blocked by <Limit> configuration", dst);
++
++ status_code = fxp_errno2status(xerrno, &reason);
++
++ pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
++ (unsigned long) status_code, reason);
++
++ fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
++ reason, NULL);
+
+ fxp_cmd_dispatch_err(cmd);
+
=====================================
debian/patches/4bafd1e9861506e77b9ea3ed277b58e60eacfe4d.diff
=====================================
@@ -0,0 +1,55 @@
+From 4bafd1e9861506e77b9ea3ed277b58e60eacfe4d Mon Sep 17 00:00:00 2001
+From: TJ Saunders <tj at castaglia.org>
+Date: Sun, 6 Sep 2026 14:51:15 -0700
+Subject: [PATCH] Guard against overly-long keys overflowing buffers when the
+ "utf8trans" builtin `RewriteMap` type is used.
+
+Thanks to Bruno Henc for reporting this issue.
+---
+ contrib/mod_rewrite.c | 21 ++++++++++++++++++---
+ 1 file changed, 18 insertions(+), 3 deletions(-)
+
+--- proftpd.orig/contrib/mod_rewrite.c
++++ proftpd/contrib/mod_rewrite.c
+@@ -1634,9 +1634,10 @@
+ */
+ static int rewrite_utf8_to_ucs4(unsigned long *ucs4_buf,
+ size_t utf8_len, unsigned char *utf8_buf) {
+- const unsigned char *utf8_endbuf = utf8_buf + utf8_len;
++ const unsigned char *utf8_endbuf;
+ int ucs_len = 0;
+
++ utf8_endbuf = utf8_buf + utf8_len;
+ while (utf8_buf != utf8_endbuf) {
+ pr_signals_handle();
+
+@@ -2003,13 +2004,27 @@
+ }
+
+ static char *rewrite_map_int_utf8trans(pool *map_pool, char *key) {
+- int ucs4strlen = 0;
+ static unsigned char utf8_val[PR_TUNABLE_BUFFER_SIZE] = {'\0'};
+ static unsigned long ucs4_longs[PR_TUNABLE_BUFFER_SIZE] = {0L};
++ int ucs4strlen = 0;
++ size_t key_len = 0;
+
+ /* If the key is NULL or empty, do nothing. */
++ if (key != NULL) {
++ key_len = strlen(key);
++ }
++
+ if (key == NULL ||
+- strlen(key) == 0) {
++ key_len == 0) {
++ return NULL;
++ }
++
++ /* If the key length exceeds our buffers, reject it. */
++ if (key_len >= sizeof(utf8_val)) {
++ rewrite_log("utf8trans: key '%.100s...' length (%lu bytes) exceeds "
++ "maximum allowed length (%lu bytes), rejecting", key,
++ (unsigned long) key_len, (unsigned long) sizeof(utf8_val));
++ errno = EPERM;
+ return NULL;
+ }
+
=====================================
debian/patches/ab5c8cd35f85b75e90019a32674a1f1062268bec.diff
=====================================
@@ -0,0 +1,115 @@
+From ab5c8cd35f85b75e90019a32674a1f1062268bec Mon Sep 17 00:00:00 2001
+From: TJ Saunders <tj at castaglia.org>
+Date: Sat, 17 Oct 2026 13:12:56 -0700
+Subject: [PATCH] Issue #2374: Resolve the destination path in order to handle
+ any potential symlinks, and use the resolved path for <Limit> checks.
+
+---
+ contrib/mod_copy.c | 51 +++++++++++++++++++++++++++++++++++-----------
+ 1 file changed, 39 insertions(+), 12 deletions(-)
+
+--- proftpd.orig/contrib/mod_copy.c
++++ proftpd/contrib/mod_copy.c
+@@ -610,7 +610,29 @@
+ return PR_ERROR(cmd);
+ }
+
+- to = dir_canonical_vpath(cmd->tmp_pool, decoded_path);
++ pr_fs_clear_cache2(decoded_path);
++ to = dir_realpath(cmd->tmp_pool, decoded_path);
++ if (to == NULL) {
++ /* Try using dir_best_path(), as xfer_pre_stor() does. */
++ to = dir_best_path(cmd->tmp_pool, decoded_path);
++ }
++
++ cmd_name = cmd->argv[0];
++ pr_cmd_set_name(cmd, "SITE_COPY");
++ if (!dir_check(cmd->tmp_pool, cmd, G_READ, from, NULL)) {
++ int xerrno = EPERM;
++
++ pr_cmd_set_name(cmd, cmd_name);
++ pr_log_debug(DEBUG8, "%s %s %s denied by <Limit> configuration",
++ (char *) cmd->argv[0], (char *) cmd->argv[1], from);
++ pr_response_add_err(R_550, "%s: %s", (char *) cmd->argv[2],
++ strerror(xerrno));
++
++ pr_cmd_set_errno(cmd, xerrno);
++ errno = xerrno;
++ return PR_ERROR(cmd);
++ }
++ pr_cmd_set_name(cmd, cmd_name);
+
+ cmd_name = cmd->argv[0];
+ pr_cmd_set_name(cmd, "SITE_COPY");
+@@ -618,8 +640,8 @@
+ int xerrno = EPERM;
+
+ pr_cmd_set_name(cmd, cmd_name);
+- pr_log_debug(DEBUG8, "%s denied by <Limit> configuration",
+- (char *) cmd->argv[0]);
++ pr_log_debug(DEBUG8, "%s %s %s denied by <Limit> configuration",
++ (char *) cmd->argv[0], (char *) cmd->argv[1], to);
+ pr_response_add_err(R_550, "%s: %s", (char *) cmd->argv[3],
+ strerror(xerrno));
+
+@@ -776,7 +798,7 @@
+
+ MODRET copy_cpto(cmd_rec *cmd) {
+ register unsigned int i;
+- const char *from, *to = "";
++ const char *from, *to = "", *resolved_to;
+ char *cmd_name;
+ unsigned char *authenticated = NULL;
+
+@@ -834,16 +856,21 @@
+ to = pstrcat(cmd->tmp_pool, to, *to ? " " : "", decoded_path, NULL);
+ }
+
+- to = dir_canonical_vpath(cmd->tmp_pool, to);
++ pr_fs_clear_cache2(to);
++ resolved_to = dir_realpath(cmd->tmp_pool, to);
++ if (resolved_to == NULL) {
++ /* Try using dir_best_path(), as xfer_pre_stor() does. */
++ resolved_to = dir_best_path(cmd->tmp_pool, to);
++ }
+
+ cmd_name = cmd->argv[0];
+ pr_cmd_set_name(cmd, "SITE_CPTO");
+- if (!dir_check(cmd->tmp_pool, cmd, G_WRITE, to, NULL)) {
++ if (!dir_check(cmd->tmp_pool, cmd, G_WRITE, resolved_to, NULL)) {
+ int xerrno = EPERM;
+
+ pr_cmd_set_name(cmd, cmd_name);
+- pr_log_debug(DEBUG8, "%s denied by <Limit> configuration",
+- (char *) cmd->argv[0]);
++ pr_log_debug(DEBUG8, "%s %s %s denied by <Limit> configuration",
++ (char *) cmd->argv[0], (char *) cmd->argv[1], to);
+ pr_response_add_err(R_550, "%s: %s", to, strerror(xerrno));
+
+ pr_cmd_set_errno(cmd, xerrno);
+@@ -852,12 +879,12 @@
+ }
+ pr_cmd_set_name(cmd, cmd_name);
+
+- if (copy_paths(cmd->tmp_pool, from, to) < 0) {
++ if (copy_paths(cmd->tmp_pool, from, resolved_to) < 0) {
+ int xerrno = errno;
+ const char *err_code = R_550;
+
+ pr_log_debug(DEBUG7, MOD_COPY_VERSION
+- ": error copying '%s' to '%s': %s", from, to, strerror(xerrno));
++ ": error copying '%s' to '%s': %s", from, resolved_to, strerror(xerrno));
+
+ /* Check errno for EDQOUT (or the most appropriate alternative).
+ * (I hate the fact that FTP has a special response code just for
+@@ -882,8 +909,8 @@
+ break;
+ }
+
+- pr_response_add_err(err_code, "%s: %s", (char *) cmd->argv[1],
+- strerror(xerrno));
++ pr_response_add_err(err_code, "%s %s: %s", (char *) cmd->argv[0],
++ (char *) cmd->argv[1], strerror(xerrno));
+
+ pr_cmd_set_errno(cmd, xerrno);
+ errno = xerrno;
=====================================
debian/patches/series
=====================================
@@ -35,3 +35,9 @@ mod_sftp-1.3.8d-issue2190.diff
508eb4d1b8c550b5f3059ad5b33d60c6b6c76bc7.diff
# Debian #1151962 #3 Issue #2093 (PR #2094)
c1607a2a219d56443809de326e673b4e38b3bc58.diff
+# CVE-2026-119147
+1570fd3b7a70b447bd59b175ed7fb01fb3d8242b.diff
+# CVE-2026-119146
+4bafd1e9861506e77b9ea3ed277b58e60eacfe4d.diff
+# CVE-2026-119364
+ab5c8cd35f85b75e90019a32674a1f1062268bec.diff
View it on GitLab: https://salsa.debian.org/debian-proftpd-team/proftpd/-/commit/88d4757b0299066e97e377b228536b851d0203e4
--
View it on GitLab: https://salsa.debian.org/debian-proftpd-team/proftpd/-/commit/88d4757b0299066e97e377b228536b851d0203e4
You're receiving this email because of your account on salsa.debian.org. Manage all notifications: https://salsa.debian.org/-/profile/notifications | Help: https://salsa.debian.org/help
More information about the Pkg-proftpd-maintainers
mailing list