gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[libmicrohttpd] branch master updated (ad9fc5c6 -> 385b4df1)


From: gnunet
Subject: [libmicrohttpd] branch master updated (ad9fc5c6 -> 385b4df1)
Date: Wed, 24 Nov 2021 19:57:09 +0100

This is an automated email from the git hooks/post-receive script.

karlson2k pushed a change to branch master
in repository libmicrohttpd.

    from ad9fc5c6 process_request_body(): added assert
     new 27cd3745 process_request_body(): fixed one byte buffer overrun
     new 482ca8e1 process_request_body(): fixed: do allow sizes with more than 
16 digits
     new a6e53c36 process_request_body(): rewritten chunk size detection; fixes
     new e9e6a5f9 parse_connection_headers(): simplified 'Content-Length' 
processing
     new 06251c90 Fixed builds without messages
     new 385b4df1 parse_connection_headers(): report if client payload is too 
large.

The 6 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 src/microhttpd/connection.c | 209 ++++++++++++++++++++++++++++++--------------
 1 file changed, 144 insertions(+), 65 deletions(-)

diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c
index bbe363bd..a009cddf 100644
--- a/src/microhttpd/connection.c
+++ b/src/microhttpd/connection.c
@@ -114,6 +114,27 @@
 #define REQUEST_CHUNKED_MALFORMED ""
 #endif
 
+/**
+ * Response text used when the request HTTP chunk is too large.
+ */
+#ifdef HAVE_MESSAGES
+#define REQUEST_CHUNK_TOO_LARGE \
+  "<html><head><title>Request content too large</title></head><body>The chunk 
size used in your HTTP chunked encoded request is too large.</body></html>"
+#else
+#define REQUEST_CHUNK_TOO_LARGE ""
+#endif
+
+/**
+ * Response text used when the request HTTP content is too large.
+ */
+#ifdef HAVE_MESSAGES
+#define REQUEST_CONTENTLENGTH_TOOLARGE \
+  "<html><head><title>Request content too large</title></head>" \
+  "<body>Your HTTP request has too large value for <b>Content-Length</b> 
header.</body></html>"
+#else
+#define REQUEST_CONTENTLENGTH_TOOLARGE ""
+#endif
+
 /**
  * Response text used when the request HTTP chunked encoding is
  * malformed.
@@ -123,7 +144,7 @@
   "<html><head><title>Request malformed</title></head>" \
   "<body>Your HTTP request has wrong value for <b>Content-Length</b> 
header.</body></html>"
 #else
-#define REQUEST_CHUNKED_MALFORMED ""
+#define REQUEST_CONTENTLENGTH_MALFORMED ""
 #endif
 
 /**
@@ -3164,74 +3185,114 @@ process_request_body (struct MHD_Connection 
*connection)
       else
       {
         size_t i;
-        size_t end_size;
+        /** The length of the string with the number of the chunk size */
+        size_t chunk_size_len;
+        bool found_chunk_size_str;
         bool malformed;
 
         /* we need to read chunk boundaries */
         i = 0;
-        while (i < available)
-        {
-          if ( ('\r' == buffer_head[i]) ||
-               ('\n' == buffer_head[i]) ||
-               (';' == buffer_head[i]) )
-            break;
-          i++;
-          if (i >= 16)
-            break;
-        }
-        end_size = i;
-        /* find beginning of CRLF (skip over chunk extensions) */
-        if (';' == buffer_head[i])
+        found_chunk_size_str = false;
+        chunk_size_len = 0;
+        mhd_assert (0 != available);
+        do
         {
-          while (i < available)
+          if ('\n' == buffer_head[i])
           {
-            if ( ('\r' == buffer_head[i]) ||
-                 ('\n' == buffer_head[i]) )
-              break;
-            i++;
+            if ((0 < i) && ('\r' == buffer_head[i - 1]))
+            { /* CRLF */
+              if (! found_chunk_size_str)
+                chunk_size_len = i - 1;
+            }
+            else
+            { /* bare LF */
+              /* TODO: Add an option to disallow bare LF */
+              if (! found_chunk_size_str)
+                chunk_size_len = i;
+            }
+            found_chunk_size_str = true;
+            break; /* Found the end of the string */
           }
-        }
-        /* take '\n' into account; if '\n' is the unavailable
-           character, we will need to wait until we have it
-           before going further */
-        if (i + 1 >= available)
-          break;                /* need more data... */
-        i++;
-        malformed = (end_size >= 16);
+          else if (! found_chunk_size_str && (';' == buffer_head[i]))
+          { /* Found chunk extension */
+            chunk_size_len = i;
+            found_chunk_size_str = true;
+          }
+        } while (available > ++i);
+        mhd_assert ((i == available) || found_chunk_size_str);
+        mhd_assert ((0 == chunk_size_len) || found_chunk_size_str);
+        malformed = ((0 == chunk_size_len) && found_chunk_size_str);
         if (! malformed)
         {
-          size_t num_dig = MHD_strx_to_uint64_n_ (buffer_head,
-                                                  end_size,
-                                                  &connection->
-                                                  current_chunk_size);
-          malformed = (end_size != num_dig);
+          /* Check whether size is valid hexadecimal number
+           * even if end of the string is not found yet. */
+          size_t num_dig;
+          uint64_t chunk_size;
+          mhd_assert (0 < i);
+          if (! found_chunk_size_str)
+          {
+            mhd_assert (i == available);
+            /* Check already available part of the size string for valid
+             * hexadecimal digits. */
+            chunk_size_len = i;
+            if ('\r' == buffer_head[i - 1])
+            {
+              chunk_size_len--;
+              malformed = (0 == chunk_size_len);
+            }
+          }
+          num_dig = MHD_strx_to_uint64_n_ (buffer_head,
+                                           chunk_size_len,
+                                           &chunk_size);
+          malformed = malformed || (chunk_size_len != num_dig);
+
+          if ((available != i) && ! malformed)
+          {
+            /* Found end of the string and the size of the chunk is valid */
+
+            mhd_assert (found_chunk_size_str);
+            /* Start reading payload data of the chunk */
+            connection->current_chunk_offset = 0;
+            connection->current_chunk_size = chunk_size;
+            i++; /* Consume the last checked char */
+            available -= i;
+            buffer_head += i;
+
+            if (0 == connection->current_chunk_size)
+            { /* The final (termination) chunk */
+              connection->remaining_upload_size = 0;
+              break;
+            }
+            if (available > 0)
+              instant_retry = true;
+            continue;
+          }
+
+          if ((0 == num_dig) && (0 != chunk_size_len))
+          { /* Check whether result is invalid due to uint64_t overflow */
+            /* At least one byte is always available
+             * in the input buffer here. */
+            const char d = buffer_head[0]; /**< first digit */
+            if ((('0' <= d) && ('9' >= d)) ||
+                (('A' <= d) && ('F' >= d)) ||
+                (('a' <= d) && ('f' >= d)))
+            { /* The first char is a valid hexadecimal digit */
+              transmit_error_response_static (connection,
+                                              MHD_HTTP_CONTENT_TOO_LARGE,
+                                              REQUEST_CHUNK_TOO_LARGE);
+              return;
+            }
+          }
         }
         if (malformed)
         {
-          /* malformed encoding */
           transmit_error_response_static (connection,
                                           MHD_HTTP_BAD_REQUEST,
                                           REQUEST_CHUNKED_MALFORMED);
           return;
         }
-        /* skip 2nd part of line feed */
-        if ( (i < available) &&
-             ( ('\r' == buffer_head[i]) ||
-               ('\n' == buffer_head[i]) ) )
-          i++;
-
-        buffer_head += i;
-        available -= i;
-        connection->current_chunk_offset = 0;
-
-        if (available > 0)
-          instant_retry = true;
-        if (0LLU == connection->current_chunk_size)
-        {
-          connection->remaining_upload_size = 0;
-          break;
-        }
-        continue;
+        mhd_assert (available == i);
+        break; /* The end of the string not found, need more upload data */
       }
     }
     else
@@ -3493,7 +3554,7 @@ parse_connection_headers (struct MHD_Connection 
*connection)
 {
   const char *clen;
   const char *enc;
-  const char *end;
+  size_t val_len;
 
   parse_cookie_header (connection);
   if ( (1 <= connection->daemon->strict_for_client) &&
@@ -3539,23 +3600,41 @@ parse_connection_headers (struct MHD_Connection 
*connection)
                                                  MHD_STATICSTR_LEN_ (
                                                    
MHD_HTTP_HEADER_CONTENT_LENGTH),
                                                  &clen,
-                                                 NULL))
+                                                 &val_len))
     {
-      end = clen + MHD_str_to_uint64_ (clen,
-                                       &connection->remaining_upload_size);
-      if ( (clen == end) ||
-           ('\0' != *end) )
+      size_t num_digits;
+
+      num_digits = MHD_str_to_uint64_n_ (clen,
+                                         val_len,
+                                         &connection->remaining_upload_size);
+      if ( (val_len != num_digits) ||
+           (0 == num_digits) )
       {
         connection->remaining_upload_size = 0;
+        if ((0 == num_digits) &&
+            (0 != val_len) &&
+            ('0' <= clen[0]) && ('9' >= clen[0]))
+        {
 #ifdef HAVE_MESSAGES
-        MHD_DLOG (connection->daemon,
-                  _ (
-                    "Failed to parse `Content-Length' header. Closing 
connection.\n"));
+          MHD_DLOG (connection->daemon,
+                    _ ("Too large value of 'Content-Length' header. " \
+                       "Closing connection.\n"));
 #endif
-        transmit_error_response_static (connection,
-                                        MHD_HTTP_BAD_REQUEST,
-                                        REQUEST_CONTENTLENGTH_MALFORMED);
-        return;
+          transmit_error_response_static (connection,
+                                          MHD_HTTP_CONTENT_TOO_LARGE,
+                                          REQUEST_CONTENTLENGTH_TOOLARGE);
+        }
+        else
+        {
+#ifdef HAVE_MESSAGES
+          MHD_DLOG (connection->daemon,
+                    _ ("Failed to parse `Content-Length' header. " \
+                       "Closing connection.\n"));
+#endif
+          transmit_error_response_static (connection,
+                                          MHD_HTTP_BAD_REQUEST,
+                                          REQUEST_CONTENTLENGTH_MALFORMED);
+        }
       }
     }
   }

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]