diff options
author | Dominique Leuenberger <dimstar@opensuse.org> | 2020-11-10 15:50:29 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-11-10 15:50:29 +0100 |
commit | 6d342b50366a048d3d543952e2be271b5742c5f8 (patch) | |
tree | 2cf14907f07f3a93d829ec1ea3c260cf0fd8e91e | |
parent | 00b982d0378e941368ba95dbcd80f35ed9fb7052 (diff) | |
parent | 4411b523545b22022b4be7d0cac25aa170ae1d3e (diff) | |
download | libproxy-git-6d342b50366a048d3d543952e2be271b5742c5f8.tar.gz |
Merge pull request #126 from lifeibiren/fix-overflow-with-large-pac
Fix buffer overflow when PAC is enabled
-rw-r--r-- | libproxy/url.cpp | 44 |
1 files changed, 31 insertions, 13 deletions
diff --git a/libproxy/url.cpp b/libproxy/url.cpp index cbbe6bb..7839afa 100644 --- a/libproxy/url.cpp +++ b/libproxy/url.cpp @@ -51,7 +51,7 @@ using namespace std; #define PAC_MIME_TYPE_FB "text/plain" // This is the maximum pac size (to avoid memory attacks) -#define PAC_MAX_SIZE 102400 +#define PAC_MAX_SIZE 0x800000 // This is the default block size to use when receiving via HTTP #define PAC_HTTP_BLOCK_SIZE 512 @@ -483,15 +483,13 @@ char* url::get_pac() { } // Get content - unsigned int recvd = 0; - buffer = new char[PAC_MAX_SIZE]; - memset(buffer, 0, PAC_MAX_SIZE); + std::vector<char> dynamic_buffer; do { unsigned int chunk_length; if (chunked) { // Discard the empty line if we received a previous chunk - if (recvd > 0) recvline(sock); + if (!dynamic_buffer.empty()) recvline(sock); // Get the chunk-length line as an integer if (sscanf(recvline(sock).c_str(), "%x", &chunk_length) != 1 || chunk_length == 0) break; @@ -503,21 +501,41 @@ char* url::get_pac() { if (content_length >= PAC_MAX_SIZE) break; - while (content_length == 0 || recvd != content_length) { - int r = recv(sock, buffer + recvd, - content_length == 0 ? PAC_HTTP_BLOCK_SIZE - : content_length - recvd, 0); + while (content_length == 0 || dynamic_buffer.size() != content_length) { + // Calculate length to recv + unsigned int length_to_read = PAC_HTTP_BLOCK_SIZE; + if (content_length > 0) + length_to_read = content_length - dynamic_buffer.size(); + + // Prepare buffer + dynamic_buffer.resize(dynamic_buffer.size() + length_to_read); + + int r = recv(sock, dynamic_buffer.data() + dynamic_buffer.size() - length_to_read, length_to_read, 0); + + // Shrink buffer to fit + if (r >= 0) + dynamic_buffer.resize(dynamic_buffer.size() - length_to_read + r); + + // PAC size too large, discard + if (dynamic_buffer.size() >= PAC_MAX_SIZE) { + chunked = false; + dynamic_buffer.clear(); + break; + } + if (r <= 0) { chunked = false; break; } - recvd += r; } } while (chunked); - if (content_length != 0 && string(buffer).size() != content_length) { - delete[] buffer; - buffer = NULL; + if (content_length == 0 || content_length == dynamic_buffer.size()) { + buffer = new char[dynamic_buffer.size() + 1]; + if (!dynamic_buffer.empty()) { + memcpy(buffer, dynamic_buffer.data(), dynamic_buffer.size()); + } + buffer[dynamic_buffer.size()] = '\0'; } } |