Blame SOURCES/libproxy-0.4.15-fix-pac-buffer-overflow.patch

b51580
From 4411b523545b22022b4be7d0cac25aa170ae1d3e Mon Sep 17 00:00:00 2001
b51580
From: Fei Li <lifeibiren@gmail.com>
b51580
Date: Fri, 17 Jul 2020 02:18:37 +0800
b51580
Subject: [PATCH] Fix buffer overflow when PAC is enabled
b51580
b51580
The bug was found on Windows 10 (MINGW64) when PAC is enabled. It turned
b51580
out to be the large PAC file (more than 102400 bytes) returned by a
b51580
local proxy program with no content-length present.
b51580
---
b51580
 libproxy/url.cpp | 44 +++++++++++++++++++++++++++++++-------------
b51580
 1 file changed, 31 insertions(+), 13 deletions(-)
b51580
b51580
diff --git a/libproxy/url.cpp b/libproxy/url.cpp
b51580
index ee776b2..8684086 100644
b51580
--- a/libproxy/url.cpp
b51580
+++ b/libproxy/url.cpp
b51580
@@ -54,7 +54,7 @@ using namespace std;
b51580
 #define PAC_MIME_TYPE_FB "text/plain"
b51580
 
b51580
 // This is the maximum pac size (to avoid memory attacks)
b51580
-#define PAC_MAX_SIZE 102400
b51580
+#define PAC_MAX_SIZE 0x800000
b51580
 // This is the default block size to use when receiving via HTTP
b51580
 #define PAC_HTTP_BLOCK_SIZE 512
b51580
 
b51580
@@ -478,15 +478,13 @@ char* url::get_pac() {
b51580
 		}
b51580
 
b51580
 		// Get content
b51580
-		unsigned int recvd = 0;
b51580
-		buffer = new char[PAC_MAX_SIZE];
b51580
-		memset(buffer, 0, PAC_MAX_SIZE);
b51580
+		std::vector<char> dynamic_buffer;
b51580
 		do {
b51580
 			unsigned int chunk_length;
b51580
 
b51580
 			if (chunked) {
b51580
 				// Discard the empty line if we received a previous chunk
b51580
-				if (recvd > 0) recvline(sock);
b51580
+				if (!dynamic_buffer.empty()) recvline(sock);
b51580
 
b51580
 				// Get the chunk-length line as an integer
b51580
 				if (sscanf(recvline(sock).c_str(), "%x", &chunk_length) != 1 || chunk_length == 0) break;
b51580
@@ -498,21 +496,41 @@ char* url::get_pac() {
b51580
 
b51580
 			if (content_length >= PAC_MAX_SIZE) break;
b51580
 
b51580
-			while (content_length == 0 || recvd != content_length) {
b51580
-				int r = recv(sock, buffer + recvd,
b51580
-				             content_length == 0 ? PAC_HTTP_BLOCK_SIZE
b51580
-				                                 : content_length - recvd, 0);
b51580
+			while (content_length == 0 || dynamic_buffer.size() != content_length) {
b51580
+				// Calculate length to recv
b51580
+				unsigned int length_to_read = PAC_HTTP_BLOCK_SIZE;
b51580
+				if (content_length > 0)
b51580
+					length_to_read = content_length - dynamic_buffer.size();
b51580
+
b51580
+				// Prepare buffer
b51580
+				dynamic_buffer.resize(dynamic_buffer.size() + length_to_read);
b51580
+
b51580
+				int r = recv(sock, dynamic_buffer.data() + dynamic_buffer.size() - length_to_read, length_to_read, 0);
b51580
+
b51580
+				// Shrink buffer to fit
b51580
+				if (r >= 0)
b51580
+					dynamic_buffer.resize(dynamic_buffer.size() - length_to_read + r);
b51580
+
b51580
+				// PAC size too large, discard
b51580
+				if (dynamic_buffer.size() >= PAC_MAX_SIZE) {
b51580
+					chunked = false;
b51580
+					dynamic_buffer.clear();
b51580
+					break;
b51580
+				}
b51580
+
b51580
 				if (r <= 0) {
b51580
 					chunked = false;
b51580
 					break;
b51580
 				}
b51580
-				recvd += r;
b51580
 			}
b51580
 		} while (chunked);
b51580
 
b51580
-		if (content_length != 0 && string(buffer).size() != content_length) {
b51580
-			delete[] buffer;
b51580
-			buffer = NULL;
b51580
+		if (content_length == 0 || content_length == dynamic_buffer.size()) {
b51580
+			buffer = new char[dynamic_buffer.size() + 1];
b51580
+			if (!dynamic_buffer.empty()) {
b51580
+				memcpy(buffer, dynamic_buffer.data(), dynamic_buffer.size());
b51580
+			}
b51580
+			buffer[dynamic_buffer.size()] = '\0';
b51580
 		}
b51580
 	}
b51580