From: Ankur Tyagi <[email protected]>

Details https://nvd.nist.gov/vuln/detail/CVE-2025-9648

Signed-off-by: Ankur Tyagi <[email protected]>
Signed-off-by: Anuj Mittal <[email protected]>
(cherry picked from commit eb338ebb606f22363be5b4114e25a10b494b4f55)

Rebased patch on Kirkstone's civetweb.

Signed-off-by: Gyorgy Sarvari <[email protected]>
---
 .../civetweb/civetweb/CVE-2025-9648.patch     | 234 ++++++++++++++++++
 .../civetweb/civetweb_git.bb                  |   1 +
 2 files changed, 235 insertions(+)
 create mode 100644 
meta-networking/recipes-connectivity/civetweb/civetweb/CVE-2025-9648.patch

diff --git 
a/meta-networking/recipes-connectivity/civetweb/civetweb/CVE-2025-9648.patch 
b/meta-networking/recipes-connectivity/civetweb/civetweb/CVE-2025-9648.patch
new file mode 100644
index 0000000000..e8ee00541e
--- /dev/null
+++ b/meta-networking/recipes-connectivity/civetweb/civetweb/CVE-2025-9648.patch
@@ -0,0 +1,234 @@
+From 6f10111d24f9f7bdb637bba77c27700ecff56244 Mon Sep 17 00:00:00 2001
+From: bel2125 <[email protected]>
+Date: Tue, 2 Sep 2025 14:08:41 +0200
+Subject: [PATCH] Make parsing of URL encoded forms more robust
+
+Reject requests that obviously violate the URL encoding.
+Fixes #1348
+
+CVE: CVE-2025-9648
+Upstream-Status: Backport 
[https://github.com/civetweb/civetweb/commit/782e18903515f43bafbf2e668994e82bdfa51133]
+(cherry picked from commit 782e18903515f43bafbf2e668994e82bdfa51133)
+Signed-off-by: Ankur Tyagi <[email protected]>
+---
+ src/civetweb.c      |  7 ++++++-
+ src/handle_form.inl | 46 +++++++++++++++++++++++++++++++++++++--------
+ 2 files changed, 44 insertions(+), 9 deletions(-)
+
+diff --git a/src/civetweb.c b/src/civetweb.c
+index 5452b36d..f843300c 100644
+--- a/src/civetweb.c
++++ b/src/civetweb.c
+@@ -7143,11 +7143,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
+@@ -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);
+ 
+@@ -93,6 +93,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;
+@@ -106,7 +107,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);
+ 
+       value_dec_len =
+           mg_url_decode(value, (int)value_len, value_dec, (int)value_len + 1, 
1);
+@@ -111,6 +113,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,
+@@ -130,9 +137,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);
+ }
+@@ -182,6 +193,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 */
+@@ -274,6 +286,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) {
+@@ -308,6 +321,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;
+                                                       }
+ 
+@@ -346,6 +360,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;
+                       }
+ 
+@@ -374,7 +389,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;
+@@ -428,6 +443,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;
+                       }
+ 
+@@ -458,6 +474,15 @@ mg_handle_form_request(struct mg_connection *conn,
+                                       vallen = (ptrdiff_t)strlen(val);
+                                       next = val + vallen;
+                                       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) 
{
+@@ -479,6 +504,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) {
+@@ -539,7 +565,6 @@ mg_handle_form_request(struct mg_connection *conn,
+                                               val = buf;
+                                       }
+                               }
+-
+                       } while (!end_of_key_value_pair_found);
+ 
+ #if !defined(NO_FILESYSTEMS)
+@@ -550,6 +575,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 {
+@@ -563,7 +589,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;
+                       }
+@@ -919,6 +945,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) {
+@@ -995,6 +1022,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) {
+@@ -1023,6 +1051,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 {
+@@ -1041,6 +1070,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;
+                       }
+ 
diff --git a/meta-networking/recipes-connectivity/civetweb/civetweb_git.bb 
b/meta-networking/recipes-connectivity/civetweb/civetweb_git.bb
index 1648d13d99..ed80eac08e 100644
--- a/meta-networking/recipes-connectivity/civetweb/civetweb_git.bb
+++ b/meta-networking/recipes-connectivity/civetweb/civetweb_git.bb
@@ -10,6 +10,7 @@ SRC_URI = 
"git://github.com/civetweb/civetweb.git;branch=master;protocol=https \
            file://0001-Unittest-Link-librt-and-libm-using-l-option.patch \
            file://0001-Sanitize-upload-filename-like-URL.patch \
            
file://0002-handle_form-example-Upload-to-temporary-directory-an.patch \
+           file://CVE-2025-9648.patch \
            "
 
 S = "${WORKDIR}/git"
-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.
View/Reply Online (#123084): 
https://lists.openembedded.org/g/openembedded-devel/message/123084
Mute This Topic: https://lists.openembedded.org/mt/117023468/21656
Group Owner: [email protected]
Unsubscribe: https://lists.openembedded.org/g/openembedded-devel/unsub 
[[email protected]]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to