* gnu/packages/patches/upx-protect-against-bad-crafted-input.patch: New file. * gnu/packages/compression.scm (upx)[source]: Use it. * gnu/local.mk (dist_patch_DATA): Add it. Signed-off-by: Ludovic Courtès <ludo@gnu.org>
		
			
				
	
	
		
			96 lines
		
	
	
	
		
			3.6 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			96 lines
		
	
	
	
		
			3.6 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
From 3e0c2966dffb5dadb512a476ef4be3d0cc51c2be Mon Sep 17 00:00:00 2001
 | 
						|
From: Pierre Neidhardt <ambrevar@gmail.com>
 | 
						|
Date: Sat, 16 Jun 2018 16:35:00 +0200
 | 
						|
Subject: [PATCH] Protect against bad crafted input
 | 
						|
 | 
						|
Also check for wrap-around when checking oversize involving e_shoff and e_shnum.
 | 
						|
 | 
						|
raised by https://github.com/upx/upx/pull/190
 | 
						|
	modified:   p_lx_elf.cpp
 | 
						|
---
 | 
						|
 src/p_lx_elf.cpp | 30 ++++++++++++++++++++++++++++++
 | 
						|
 1 file changed, 30 insertions(+)
 | 
						|
 | 
						|
diff --git a/src/p_lx_elf.cpp b/src/p_lx_elf.cpp
 | 
						|
index 822a7652..41e805ee 100644
 | 
						|
--- a/src/p_lx_elf.cpp
 | 
						|
+++ b/src/p_lx_elf.cpp
 | 
						|
@@ -235,8 +235,17 @@ PackLinuxElf32::PackLinuxElf32help1(InputFile *f)
 | 
						|
         sz_phdrs = 0;
 | 
						|
         return;
 | 
						|
     }
 | 
						|
+    if (0==e_phnum) throwCantUnpack("0==e_phnum");
 | 
						|
     e_phoff = get_te32(&ehdri.e_phoff);
 | 
						|
+    unsigned const last_Phdr = e_phoff + e_phnum * sizeof(Elf32_Phdr);
 | 
						|
+    if (last_Phdr < e_phoff || (unsigned long)file_size < last_Phdr) {
 | 
						|
+        throwCantUnpack("bad e_phoff");
 | 
						|
+    }
 | 
						|
     e_shoff = get_te32(&ehdri.e_shoff);
 | 
						|
+    unsigned const last_Shdr = e_shoff + e_shnum * sizeof(Elf32_Shdr);
 | 
						|
+    if (last_Shdr < e_shoff || (unsigned long)file_size < last_Shdr) {
 | 
						|
+        throwCantUnpack("bad e_shoff");
 | 
						|
+    }
 | 
						|
     sz_phdrs = e_phnum * e_phentsize;
 | 
						|
 
 | 
						|
     if (f && Elf32_Ehdr::ET_DYN!=e_type) {
 | 
						|
@@ -599,8 +608,17 @@ PackLinuxElf64::PackLinuxElf64help1(InputFile *f)
 | 
						|
         sz_phdrs = 0;
 | 
						|
         return;
 | 
						|
     }
 | 
						|
+    if (0==e_phnum) throwCantUnpack("0==e_phnum");
 | 
						|
     e_phoff = get_te64(&ehdri.e_phoff);
 | 
						|
+    upx_uint64_t const last_Phdr = e_phoff + e_phnum * sizeof(Elf64_Phdr);
 | 
						|
+    if (last_Phdr < e_phoff || (unsigned long)file_size < last_Phdr) {
 | 
						|
+        throwCantUnpack("bad e_phoff");
 | 
						|
+    }
 | 
						|
     e_shoff = get_te64(&ehdri.e_shoff);
 | 
						|
+    upx_uint64_t const last_Shdr = e_shoff + e_shnum * sizeof(Elf64_Shdr);
 | 
						|
+    if (last_Shdr < e_shoff || (unsigned long)file_size < last_Shdr) {
 | 
						|
+        throwCantUnpack("bad e_shoff");
 | 
						|
+    }
 | 
						|
     sz_phdrs = e_phnum * e_phentsize;
 | 
						|
 
 | 
						|
     if (f && Elf64_Ehdr::ET_DYN!=e_type) {
 | 
						|
@@ -3763,6 +3781,9 @@ void PackLinuxElf64::pack4(OutputFile *fo, Filter &ft)
 | 
						|
 
 | 
						|
 void PackLinuxElf64::unpack(OutputFile *fo)
 | 
						|
 {
 | 
						|
+    if (e_phoff != sizeof(Elf64_Ehdr)) {// Phdrs not contiguous with Ehdr
 | 
						|
+        throwCantUnpack("bad e_phoff");
 | 
						|
+    }
 | 
						|
     unsigned const c_phnum = get_te16(&ehdri.e_phnum);
 | 
						|
     upx_uint64_t old_data_off = 0;
 | 
						|
     upx_uint64_t old_data_len = 0;
 | 
						|
@@ -3828,6 +3849,9 @@ void PackLinuxElf64::unpack(OutputFile *fo)
 | 
						|
     unsigned total_out = 0;
 | 
						|
     unsigned c_adler = upx_adler32(NULL, 0);
 | 
						|
     unsigned u_adler = upx_adler32(NULL, 0);
 | 
						|
+    if ((MAX_ELF_HDR - sizeof(Elf64_Ehdr))/sizeof(Elf64_Phdr) < u_phnum) {
 | 
						|
+        throwCantUnpack("bad compressed e_phnum");
 | 
						|
+    }
 | 
						|
 
 | 
						|
     // Packed ET_EXE has no PT_DYNAMIC.
 | 
						|
     // Packed ET_DYN has original PT_DYNAMIC for info needed by rtld.
 | 
						|
@@ -4383,6 +4407,9 @@ Elf64_Sym const *PackLinuxElf64::elf_lookup(char const *name) const
 | 
						|
 
 | 
						|
 void PackLinuxElf32::unpack(OutputFile *fo)
 | 
						|
 {
 | 
						|
+    if (e_phoff != sizeof(Elf32_Ehdr)) {// Phdrs not contiguous with Ehdr
 | 
						|
+        throwCantUnpack("bad e_phoff");
 | 
						|
+    }
 | 
						|
     unsigned const c_phnum = get_te16(&ehdri.e_phnum);
 | 
						|
     unsigned old_data_off = 0;
 | 
						|
     unsigned old_data_len = 0;
 | 
						|
@@ -4449,6 +4476,9 @@ void PackLinuxElf32::unpack(OutputFile *fo)
 | 
						|
     unsigned total_out = 0;
 | 
						|
     unsigned c_adler = upx_adler32(NULL, 0);
 | 
						|
     unsigned u_adler = upx_adler32(NULL, 0);
 | 
						|
+    if ((MAX_ELF_HDR - sizeof(Elf32_Ehdr))/sizeof(Elf32_Phdr) < u_phnum) {
 | 
						|
+        throwCantUnpack("bad compressed e_phnum");
 | 
						|
+    }
 | 
						|
 
 | 
						|
     // Packed ET_EXE has no PT_DYNAMIC.
 | 
						|
     // Packed ET_DYN has original PT_DYNAMIC for info needed by rtld.
 | 
						|
-- 
 | 
						|
2.17.0
 | 
						|
 |