From 7deeafc02b29cc51d51079e66f4f43f986ff9cc5 Mon Sep 17 00:00:00 2001
From: Andrea Mazzoleni <amadvance@gmail.com>
Date: Mon, 12 Feb 2018 22:10:14 +0100
Subject: [PATCH] Fix a crash condition due invalid ZIP data

---
 HISTORY         |  3 ++-
 doc/history.1   |  4 +++-
 doc/history.d   |  3 ++-
 doc/history.txt |  3 ++-
 zip.cc          | 20 +++++++++++++++-----
 zip.h           |  4 ++--
 6 files changed, 26 insertions(+), 11 deletions(-)

Index: advancecomp-1.18/zip.cc
===================================================================
--- advancecomp-1.18.orig/zip.cc	2018-02-13 07:38:26.135474939 -0500
+++ advancecomp-1.18/zip.cc	2018-02-13 07:38:26.131474940 -0500
@@ -456,13 +456,15 @@ string zip_entry::name_get() const
 }
 
 /** Check central directory entry. */
-void zip_entry::check_cent(const unsigned char* buf) const
+void zip_entry::check_cent(const unsigned char* buf, unsigned buf_size) const
 {
+	if (buf_size < ZIP_CO_FIXED) {
+		throw error_invalid() << "Invalid central directory data";
+	}
 	// check signature
 	if (le_uint32_read(buf+ZIP_CO_central_file_header_signature) != ZIP_C_signature) {
 		throw error_invalid() << "Invalid central directory signature";
 	}
-
 	// check filename_length > 0, can't exist a file without a name
 	if (le_uint16_read(buf+ZIP_CO_filename_length) == 0) {
 		throw error_invalid() << "Empty filename in central directory";
@@ -690,11 +692,11 @@ void zip_entry::save_local(FILE* f)
  * \param buf Fixed size cent dir.
  * \param f File seeked after the fixed size cent dir.
  */
-void zip_entry::load_cent(const unsigned char* buf, unsigned& skip)
+void zip_entry::load_cent(const unsigned char* buf, unsigned buf_size, unsigned& skip)
 {
 	const unsigned char* o_buf = buf;
 
-	check_cent(buf);
+	check_cent(buf, buf_size);
 
 	// read header
 	info.version_made_by = le_uint8_read(buf+ZIP_CO_version_made_by);
@@ -716,6 +718,14 @@ void zip_entry::load_cent(const unsigned
 	info.relative_offset_of_local_header = le_uint32_read(buf+ZIP_CO_relative_offset_of_local_header);
 	buf += ZIP_CO_FIXED;
 
+	if (buf_size < info.filename_length
+		|| buf_size < info.central_extra_field_length
+		|| buf_size < info.file_comment_length
+		|| buf_size < ZIP_CO_FIXED + info.filename_length + info.central_extra_field_length + info.file_comment_length
+	) {
+		throw error_invalid() << "Invalid central directory data";
+	}
+
 	// read filename
 	data_free(file_name);
 	file_name = data_alloc(info.filename_length);
@@ -864,7 +874,7 @@ void zip::open()
 
 			unsigned skip = 0;
 			try {
-				i->load_cent(data + data_pos, skip);
+				i->load_cent(data + data_pos, data_size - data_pos, skip);
 			} catch (...) {
 				map.erase(i);
 				throw;
Index: advancecomp-1.18/zip.h
===================================================================
--- advancecomp-1.18.orig/zip.h	2018-02-13 07:38:26.135474939 -0500
+++ advancecomp-1.18/zip.h	2018-02-13 07:38:26.135474939 -0500
@@ -187,7 +187,7 @@ private:
 	unsigned char* central_extra_field;
 	unsigned char* data;
 
-	void check_cent(const unsigned char* buf) const;
+	void check_cent(const unsigned char* buf, unsigned buf_size) const;
 	void check_local(const unsigned char* buf) const;
 	void check_descriptor(const unsigned char* buf) const;
 
@@ -203,7 +203,7 @@ public:
 
 	void load_local(const unsigned char* buf, FILE* f, unsigned size);
 	void save_local(FILE* f);
-	void load_cent(const unsigned char* buf, unsigned& skip);
+	void load_cent(const unsigned char* buf, unsigned size, unsigned& skip);
 	void save_cent(FILE* f);
 	void unload();
 
