1
0
mirror of https://github.com/unrealircd/unrealircd.git synced 2026-06-12 17:14:46 +02:00

url_unreal: limit chunked transfer header length (hardening)

This commit is contained in:
Bram Matthys
2026-05-17 10:07:14 +02:00
parent 1250b7f014
commit 8b93339e42
+28 -1
View File
@@ -36,6 +36,16 @@
#pragma GCC diagnostic ignored "-Wdeprecated-declarations" #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif #endif
/* Maximum length of a single chunked-transfer chunk header
* (the line announcing a chunk, eg. "7f\r\n", optionally with
* chunk extensions like "7f;name=value\r\n"). This is NOT the
* size of the chunk data itself.
* Caps how much we will buffer while waiting for the terminating
* LF so a server that streams a chunk header with no LF cannot
* grow handle->lefttoparse without bound.
*/
#define HTTPS_MAX_CHUNK_HEADER_LEN 256
/* Structs */ /* Structs */
/* Stores information about the async transfer. /* Stores information about the async transfer.
@@ -914,7 +924,7 @@ int https_handle_response_body(Download *handle, char *readbuf, int pktsize)
} else } else
{ {
int gotlf = 0; int gotlf = 0;
int i; long long i;
/* First check if it is a (trailing) empty line, /* First check if it is a (trailing) empty line,
* eg from a previous chunk. Skip over. * eg from a previous chunk. Skip over.
@@ -948,6 +958,16 @@ int https_handle_response_body(Download *handle, char *readbuf, int pktsize)
* as it does not contain an \n. Wait for more data * as it does not contain an \n. Wait for more data
* from the network socket. * from the network socket.
*/ */
if (n > HTTPS_MAX_CHUNK_HEADER_LEN)
{
/* A chunk-size line should never be this long;
* refuse to keep buffering otherwise a malicious
* server can grow lefttoparse without bound.
*/
https_cancel(handle, "Chunk size line too long (%lld bytes, no LF)", n);
safe_free(free_this_buffer);
return 0;
}
if (n > 0) if (n > 0)
{ {
/* Store what we have first.. */ /* Store what we have first.. */
@@ -960,7 +980,14 @@ int https_handle_response_body(Download *handle, char *readbuf, int pktsize)
} }
buf[i] = '\0'; /* cut at LF */ buf[i] = '\0'; /* cut at LF */
i++; /* point to next data */ i++; /* point to next data */
errno = 0;
handle->chunk_remaining = strtoll(buf, NULL, 16); handle->chunk_remaining = strtoll(buf, NULL, 16);
if (errno == ERANGE)
{
https_cancel(handle, "Chunk size out of range: '%s'", buf);
safe_free(free_this_buffer);
return 0;
}
if (handle->chunk_remaining < 0) if (handle->chunk_remaining < 0)
{ {
https_cancel(handle, "Negative chunk encountered (%lld)", handle->chunk_remaining); https_cancel(handle, "Negative chunk encountered (%lld)", handle->chunk_remaining);