Control: tags 1118285 + patch
Control: tags 1118285 + pending

Dear maintainer,

I've prepared an NMU for civetweb (versioned as 1.16+dfsg-3.1) and 
uploaded it to DELAYED/2. Please feel free to tell me if I should
cancel it.

cu
Adrian
diffstat for civetweb-1.16+dfsg civetweb-1.16+dfsg

 changelog                                                        |    8 
 patches/0001-Make-parsing-of-URL-encoded-forms-more-robust.patch |  246 ++++++++++
 patches/series                                                   |    1 
 3 files changed, 255 insertions(+)

diff -Nru civetweb-1.16+dfsg/debian/changelog civetweb-1.16+dfsg/debian/changelog
--- civetweb-1.16+dfsg/debian/changelog	2025-09-27 02:10:04.000000000 +0300
+++ civetweb-1.16+dfsg/debian/changelog	2026-03-04 18:59:54.000000000 +0200
@@ -1,3 +1,11 @@
+civetweb (1.16+dfsg-3.1) unstable; urgency=medium
+
+  * Non-maintainer upload.
+  * CVE-2025-9648: Infinite loop in mg_handle_form_request
+    (Closes: #1118285)
+
+ -- Adrian Bunk <[email protected]>  Wed, 04 Mar 2026 18:59:54 +0200
+
 civetweb (1.16+dfsg-3) unstable; urgency=medium
 
   * Team upload.
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-04 18:59:54.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/series civetweb-1.16+dfsg/debian/patches/series
--- civetweb-1.16+dfsg/debian/patches/series	2025-09-27 02:09:29.000000000 +0300
+++ civetweb-1.16+dfsg/debian/patches/series	2026-03-04 18:59:54.000000000 +0200
@@ -1,3 +1,4 @@
 soversion
 webdav-uploads
 CVE-2025-55763.patch
+0001-Make-parsing-of-URL-encoded-forms-more-robust.patch

Reply via email to