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

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