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

  * CVE-2025-9648: Infinite loop in mg_handle_form_request
    (Closes: #1118285)
  * CVE-2025-55763: Buffer overflow in the URI parser
    (Closes: #1112507)
diffstat for civetweb-1.16+dfsg civetweb-1.16+dfsg

 changelog                                                        |   10 
 patches/0001-Make-parsing-of-URL-encoded-forms-more-robust.patch |  246 
++++++++++
 patches/CVE-2025-55763.patch                                     |   86 +++
 patches/series                                                   |    2 
 4 files changed, 344 insertions(+)

diff -Nru civetweb-1.16+dfsg/debian/changelog 
civetweb-1.16+dfsg/debian/changelog
--- civetweb-1.16+dfsg/debian/changelog 2024-07-20 00:23:09.000000000 +0300
+++ civetweb-1.16+dfsg/debian/changelog 2026-03-07 11:54:47.000000000 +0200
@@ -1,3 +1,13 @@
+civetweb (1.16+dfsg-2+deb13u1) trixie; urgency=medium
+
+  * Non-maintainer upload.
+  * CVE-2025-9648: Infinite loop in mg_handle_form_request
+    (Closes: #1118285)
+  * CVE-2025-55763: Buffer overflow in the URI parser
+    (Closes: #1112507)
+
+ -- Adrian Bunk <[email protected]>  Sat, 07 Mar 2026 11:54:47 +0200
+
 civetweb (1.16+dfsg-2) unstable; urgency=medium
 
   * Unfuzz patches.
diff -Nru 
civetweb-1.16+dfsg/debian/patches/0001-Make-parsing-of-URL-encoded-forms-more-robust.patch
 
civetweb-1.16+dfsg/debian/patches/0001-Make-parsing-of-URL-encoded-forms-more-robust.patch
--- 
civetweb-1.16+dfsg/debian/patches/0001-Make-parsing-of-URL-encoded-forms-more-robust.patch
  1970-01-01 02:00:00.000000000 +0200
+++ 
civetweb-1.16+dfsg/debian/patches/0001-Make-parsing-of-URL-encoded-forms-more-robust.patch
  2026-03-06 22:51:24.000000000 +0200
@@ -0,0 +1,246 @@
+From e947ee9bae82ab5035ccc48430d820bc3968ac77 Mon Sep 17 00:00:00 2001
+From: bel2125 <[email protected]>
+Date: Tue, 2 Sep 2025 14:08:41 +0200
+Subject: Make parsing of URL encoded forms more robust
+
+Reject requests that obviously violate the URL encoding.
+Fixes #1348
+---
+ src/civetweb.c      |  5 +++++
+ src/handle_form.inl | 46 +++++++++++++++++++++++++++++++++++++--------
+ 2 files changed, 43 insertions(+), 8 deletions(-)
+
+diff --git a/src/civetweb.c b/src/civetweb.c
+index 3e93d570..1f13f3f4 100644
+--- a/src/civetweb.c
++++ b/src/civetweb.c
+@@ -7052,6 +7052,7 @@ mg_url_decode(const char *src,
+               int is_form_url_encoded)
+ {
+       int i, j, a, b;
++
+ #define HEXTOI(x) (isdigit(x) ? (x - '0') : (x - 'W'))
+ 
+       for (i = j = 0; (i < src_len) && (j < (dst_len - 1)); i++, j++) {
+@@ -7064,11 +7065,15 @@ mg_url_decode(const char *src,
+                       i += 2;
+               } else if (is_form_url_encoded && (src[i] == '+')) {
+                       dst[j] = ' ';
++              } else if ((unsigned char)src[i] <= ' ') {
++                      return -1; /* invalid character */
+               } else {
+                       dst[j] = src[i];
+               }
+       }
+ 
++#undef HEXTOI
++
+       dst[j] = '\0'; /* Null-terminate the destination */
+ 
+       return (i >= src_len) ? j : -1;
+diff --git a/src/handle_form.inl b/src/handle_form.inl
+index be477a05..0ebaf560 100644
+--- a/src/handle_form.inl
++++ b/src/handle_form.inl
+@@ -1,4 +1,4 @@
+-/* Copyright (c) 2016-2021 the Civetweb developers
++/* Copyright (c) 2016-2025 the Civetweb developers
+  *
+  * Permission is hereby granted, free of charge, to any person obtaining a 
copy
+  * of this software and associated documentation files (the "Software"), to 
deal
+@@ -39,7 +39,7 @@ url_encoded_field_found(const struct mg_connection *conn,
+           mg_url_decode(key, (int)key_len, key_dec, (int)sizeof(key_dec), 1);
+ 
+       if (((size_t)key_dec_len >= (size_t)sizeof(key_dec)) || (key_dec_len < 
0)) {
+-              return MG_FORM_FIELD_STORAGE_SKIP;
++              return MG_FORM_FIELD_STORAGE_ABORT;
+       }
+ 
+       if (filename) {
+@@ -53,7 +53,7 @@ url_encoded_field_found(const struct mg_connection *conn,
+                   || (filename_dec_len < 0)) {
+                       /* Log error message and skip this field. */
+                       mg_cry_internal(conn, "%s: Cannot decode filename", 
__func__);
+-                      return MG_FORM_FIELD_STORAGE_SKIP;
++                      return MG_FORM_FIELD_STORAGE_ABORT;
+               }
+               remove_dot_segments(filename_dec);
+ 
+@@ -95,6 +95,7 @@ url_encoded_field_get(
+     struct mg_form_data_handler *fdh)
+ {
+       char key_dec[1024];
++      int key_dec_len;
+ 
+       char *value_dec = (char *)mg_malloc_ctx(*value_len + 1, conn->phys_ctx);
+       int value_dec_len, ret;
+@@ -108,7 +109,8 @@ url_encoded_field_get(
+               return MG_FORM_FIELD_STORAGE_ABORT;
+       }
+ 
+-      mg_url_decode(key, (int)key_len, key_dec, (int)sizeof(key_dec), 1);
++      key_dec_len = mg_url_decode(
++          key, (int)key_len, key_dec, (int)sizeof(key_dec), 1);
+ 
+       if (*value_len >= 2 && value[*value_len - 2] == '%')
+               *value_len -= 2;
+@@ -117,6 +119,11 @@ url_encoded_field_get(
+       value_dec_len = mg_url_decode(
+           value, (int)*value_len, value_dec, ((int)*value_len) + 1, 1);
+ 
++      if ((key_dec_len < 0) || (value_dec_len < 0)) {
++              mg_free(value_dec);
++              return MG_FORM_FIELD_STORAGE_ABORT;
++      }
++
+       ret = fdh->field_get(key_dec,
+                            value_dec,
+                            (size_t)value_dec_len,
+@@ -136,9 +143,13 @@ unencoded_field_get(const struct mg_connection *conn,
+                     struct mg_form_data_handler *fdh)
+ {
+       char key_dec[1024];
++      int key_dec_len;
+       (void)conn;
+ 
+-      mg_url_decode(key, (int)key_len, key_dec, (int)sizeof(key_dec), 1);
++      key_dec_len = mg_url_decode(key, (int)key_len, key_dec, 
(int)sizeof(key_dec), 1);
++      if (key_dec_len < 0) {
++              return MG_FORM_FIELD_STORAGE_ABORT;
++      }
+ 
+       return fdh->field_get(key_dec, value, value_len, fdh->user_data);
+ }
+@@ -188,6 +199,7 @@ mg_handle_form_request(struct mg_connection *conn,
+       int buf_fill = 0;
+       int r;
+       int field_count = 0;
++      int abort_read = 0;
+       struct mg_file fstore = STRUCT_FILE_INITIALIZER;
+       int64_t file_size = 0; /* init here, to a avoid a false positive
+                                "uninitialized variable used" warning */
+@@ -278,6 +290,7 @@ mg_handle_form_request(struct mg_connection *conn,
+                                   conn, data, (size_t)keylen, val, (size_t 
*)&vallen, fdh);
+                               if (r == MG_FORM_FIELD_HANDLE_ABORT) {
+                                       /* Stop request handling */
++                                      abort_read = 1;
+                                       break;
+                               }
+                               if (r == MG_FORM_FIELD_HANDLE_NEXT) {
+@@ -320,6 +333,7 @@ mg_handle_form_request(struct mg_connection *conn,
+                                                       r = field_stored(conn, 
path, file_size, fdh);
+                                                       if (r == 
MG_FORM_FIELD_HANDLE_ABORT) {
+                                                               /* Stop request 
handling */
++                                                              abort_read = 1;
+                                                               break;
+                                                       }
+ 
+@@ -358,6 +372,7 @@ mg_handle_form_request(struct mg_connection *conn,
+                       if ((field_storage & MG_FORM_FIELD_STORAGE_ABORT)
+                           == MG_FORM_FIELD_STORAGE_ABORT) {
+                               /* Stop parsing the request */
++                              abort_read = 1;
+                               break;
+                       }
+ 
+@@ -386,7 +401,7 @@ mg_handle_form_request(struct mg_connection *conn,
+                * Here we use "POST", and read the data from the request body.
+                * The data read on the fly, so it is not required to buffer the
+                * entire request in memory before processing it. */
+-              for (;;) {
++              while (!abort_read) {
+                       const char *val;
+                       const char *next;
+                       ptrdiff_t keylen, vallen;
+@@ -440,6 +455,7 @@ mg_handle_form_request(struct mg_connection *conn,
+                       if ((field_storage & MG_FORM_FIELD_STORAGE_ABORT)
+                           == MG_FORM_FIELD_STORAGE_ABORT) {
+                               /* Stop parsing the request */
++                              abort_read = 1;
+                               break;
+                       }
+ 
+@@ -468,6 +484,15 @@ mg_handle_form_request(struct mg_connection *conn,
+                               } else {
+                                       vallen = (ptrdiff_t)strlen(val);
+                                       end_of_key_value_pair_found = 
all_data_read;
++                                      if ((buf + buf_fill) > (val + vallen)) {
++                                              /* Avoid DoS attacks by having 
a zero byte in the middle of
++                                               * a request that is supposed 
to be URL encoded. Since this
++                                               * request is certainly 
invalid, according to the protocol
++                                               * specification, stop 
processing it. Fixes #1348 */
++                                              abort_read = 1;
++                                              break;
++                                      }
++
+                               }
+ 
+                               if (field_storage == MG_FORM_FIELD_STORAGE_GET) 
{
+@@ -489,6 +514,7 @@ mg_handle_form_request(struct mg_connection *conn,
+                                       get_block++;
+                                       if (r == MG_FORM_FIELD_HANDLE_ABORT) {
+                                               /* Stop request handling */
++                                              abort_read = 1;
+                                               break;
+                                       }
+                                       if (r == MG_FORM_FIELD_HANDLE_NEXT) {
+@@ -557,7 +583,6 @@ mg_handle_form_request(struct mg_connection *conn,
+                                               val = buf;
+                                       }
+                               }
+-
+                       } while (!end_of_key_value_pair_found);
+ 
+ #if !defined(NO_FILESYSTEMS)
+@@ -568,6 +593,7 @@ mg_handle_form_request(struct mg_connection *conn,
+                                       r = field_stored(conn, path, file_size, 
fdh);
+                                       if (r == MG_FORM_FIELD_HANDLE_ABORT) {
+                                               /* Stop request handling */
++                                              abort_read = 1;
+                                               break;
+                                       }
+                               } else {
+@@ -581,7 +607,7 @@ mg_handle_form_request(struct mg_connection *conn,
+                       }
+ #endif /* NO_FILESYSTEMS */
+ 
+-                      if (all_data_read && (buf_fill == 0)) {
++                      if ((all_data_read && (buf_fill == 0)) || abort_read) {
+                               /* nothing more to process */
+                               break;
+                       }
+@@ -937,6 +963,7 @@ mg_handle_form_request(struct mg_connection *conn,
+                                       get_block++;
+                                       if (r == MG_FORM_FIELD_HANDLE_ABORT) {
+                                               /* Stop request handling */
++                                              abort_read = 1;
+                                               break;
+                                       }
+                                       if (r == MG_FORM_FIELD_HANDLE_NEXT) {
+@@ -1011,6 +1038,7 @@ mg_handle_form_request(struct mg_connection *conn,
+                                                       fdh);
+                               if (r == MG_FORM_FIELD_HANDLE_ABORT) {
+                                       /* Stop request handling */
++                                      abort_read = 1;
+                                       break;
+                               }
+                               if (r == MG_FORM_FIELD_HANDLE_NEXT) {
+@@ -1039,6 +1067,7 @@ mg_handle_form_request(struct mg_connection *conn,
+                                                       r = field_stored(conn, 
path, file_size, fdh);
+                                                       if (r == 
MG_FORM_FIELD_HANDLE_ABORT) {
+                                                               /* Stop request 
handling */
++                                                              abort_read = 1;
+                                                               break;
+                                                       }
+                                               } else {
+@@ -1057,6 +1086,7 @@ mg_handle_form_request(struct mg_connection *conn,
+                       if ((field_storage & MG_FORM_FIELD_STORAGE_ABORT)
+                           == MG_FORM_FIELD_STORAGE_ABORT) {
+                               /* Stop parsing the request */
++                              abort_read = 1;
+                               break;
+                       }
+ 
+-- 
+2.47.3
+
diff -Nru civetweb-1.16+dfsg/debian/patches/CVE-2025-55763.patch 
civetweb-1.16+dfsg/debian/patches/CVE-2025-55763.patch
--- civetweb-1.16+dfsg/debian/patches/CVE-2025-55763.patch      1970-01-01 
02:00:00.000000000 +0200
+++ civetweb-1.16+dfsg/debian/patches/CVE-2025-55763.patch      2026-03-06 
22:51:37.000000000 +0200
@@ -0,0 +1,86 @@
+From 76e222bcb77ba8452e5da4e82ae6cecd499c25e0 Mon Sep 17 00:00:00 2001
+From: krispybyte <[email protected]>
+Date: Sat, 21 Jun 2025 23:33:50 +0300
+Subject: [PATCH 1/2] Fix heap overflow in directory URI slash redirection
+
+---
+ src/civetweb.c | 23 ++++++++++++++++++-----
+ 1 file changed, 18 insertions(+), 5 deletions(-)
+
+Origin: 
https://github.com/civetweb/civetweb/commit/c584455624d9a9f6ec72839f61dd3cdb9d8435ba.patch
+Bug: https://github.com/civetweb/civetweb/pull/1347
+
+diff --git a/src/civetweb.c b/src/civetweb.c
+index bbc9aa8be..e969c939f 100644
+--- a/src/civetweb.c
++++ b/src/civetweb.c
+@@ -15579,7 +15579,6 @@ handle_request(struct mg_connection *conn)
+       /* 12. Directory uris should end with a slash */
+       if (file.stat.is_directory && ((uri_len = (int)strlen(ri->local_uri)) > 
0)
+           && (ri->local_uri[uri_len - 1] != '/')) {
+-
+               /* Path + server root */
+               size_t buflen = UTF8_PATH_MAX * 2 + 2;
+               char *new_path;
+@@ -15592,12 +15591,26 @@ handle_request(struct mg_connection *conn)
+                       mg_send_http_error(conn, 500, "out or memory");
+               } else {
+                       mg_get_request_link(conn, new_path, buflen - 1);
+-                      strcat(new_path, "/");
++
++                      size_t len = strlen(new_path);
++                      if (len + 1 < buflen) {
++                              new_path[len] = '/';
++                              new_path[len + 1] = '\0';
++                              len += 1;
++                      }
++
+                       if (ri->query_string) {
+-                              /* Append ? and query string */
+-                              strcat(new_path, "?");
+-                              strcat(new_path, ri->query_string);
++                              if (len + 1 < buflen) {
++                                      new_path[len] = '?';
++                                      new_path[len + 1] = '\0';
++                                      len += 1;
++                              }
++
++                              /* Append with size of space left for query 
string + null terminator */
++                              size_t max_append = buflen - len - 1;
++                              strncat(new_path, ri->query_string, max_append);
+                       }
++
+                       mg_send_http_redirect(conn, new_path, 301);
+                       mg_free(new_path);
+               }
+
+From d5321963b1d0bc953101de91f8588bf83db73bf5 Mon Sep 17 00:00:00 2001
+From: krispybyte <[email protected]>
+Date: Sun, 22 Jun 2025 00:23:06 +0300
+Subject: [PATCH 2/2] Fit code style
+
+---
+ src/civetweb.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/civetweb.c b/src/civetweb.c
+index e969c939f..6af91f874 100644
+--- a/src/civetweb.c
++++ b/src/civetweb.c
+@@ -15596,14 +15596,14 @@ handle_request(struct mg_connection *conn)
+                       if (len + 1 < buflen) {
+                               new_path[len] = '/';
+                               new_path[len + 1] = '\0';
+-                              len += 1;
++                              len++;
+                       }
+ 
+                       if (ri->query_string) {
+                               if (len + 1 < buflen) {
+                                       new_path[len] = '?';
+                                       new_path[len + 1] = '\0';
+-                                      len += 1;
++                                      len++;
+                               }
+ 
+                               /* Append with size of space left for query 
string + null terminator */
diff -Nru civetweb-1.16+dfsg/debian/patches/series 
civetweb-1.16+dfsg/debian/patches/series
--- civetweb-1.16+dfsg/debian/patches/series    2024-07-20 00:23:09.000000000 
+0300
+++ civetweb-1.16+dfsg/debian/patches/series    2026-03-07 11:54:47.000000000 
+0200
@@ -1,2 +1,4 @@
 soversion
 webdav-uploads
+CVE-2025-55763.patch
+0001-Make-parsing-of-URL-encoded-forms-more-robust.patch

Reply via email to