Vulnerability: Null pointer dereference was found in upx PackLinuxElf::canUnpack() in p_lx_elf.cpp,in version UPX 4.0.0. That allow attackers to execute arbitrary code and cause a denial of service via a crafted file.
Vulnerability ID: CVE-2021-30500
CWE: CWE-476
Severity score: 6.4
Project: https://github.com/upx/upx
Published: 2021-05-27
File: src/p_lx_elf.cpp
Commit message: PackLinuxElf::canUnpack must checkEhdr() for ELF input

https://github.com/upx/upx/issues/485
	modified:   p_lx_elf.cpp
Commit author: John Reiser

Vulnerable version (before fix):
 bool PackLinuxElf32::calls_crt1(Elf32_Rel const *rel, int sz)  int PackLinuxElf32::canUnpack() {     if (super::canUnpack()) {         return true;     }     if (Elf32_Ehdr::ET_DYN==get_te16(&ehdri.e_type)) {         PackLinuxElf32help1(fi);     }     return false; }  proceed: ;  int PackLinuxElf64::canUnpack() {     if (super::canUnpack()) {         return true;     }     if (Elf64_Ehdr::ET_DYN==get_te16(&ehdri.e_type)) {         PackLinuxElf64help1(fi); int PackLinuxElf64::canUnpack()         fi->seek(filesz+offset, SEEK_SET);         MemBuffer buf(32 + sizeof(overlay_offset));         fi->readx(buf, buf.getSize());         return PackUnix::find_overlay_offset(buf);     }     return false; }

Fixed version (after fix):
 bool PackLinuxElf32::calls_crt1(Elf32_Rel const *rel, int sz)  int PackLinuxElf32::canUnpack() {     if (checkEhdr(&ehdri)) {         return false;     }     // FIXME: ET_DYN same as 64-bit canUnpack ??     if (Elf32_Ehdr::ET_DYN==get_te16(&ehdri.e_type)) {         PackLinuxElf32help1(fi);     }     if (super::canUnpack()) {         return true;     }     return false; }  proceed: ;  int PackLinuxElf64::canUnpack() {     if (checkEhdr(&ehdri)) {         return false;     }     if (Elf64_Ehdr::ET_DYN==get_te16(&ehdri.e_type)) {         PackLinuxElf64help1(fi); int PackLinuxElf64::canUnpack()         fi->seek(filesz+offset, SEEK_SET);         MemBuffer buf(32 + sizeof(overlay_offset));         fi->readx(buf, buf.getSize());         unsigned x = PackUnix::find_overlay_offset(buf);         if (x) {             return x;         }     }     if (super::canUnpack()) {         return true;     }     return false; }

Patch:
patch: @@ -1971,12 +1971,16 @@ bool PackLinuxElf32::calls_crt1(Elf32_Rel const *rel, int sz)
 
 int PackLinuxElf32::canUnpack()
 {
-    if (super::canUnpack()) {
-        return true;
+    if (checkEhdr(&ehdri)) {
+        return false;
     }
+    // FIXME: ET_DYN same as 64-bit canUnpack ??
     if (Elf32_Ehdr::ET_DYN==get_te16(&ehdri.e_type)) {
         PackLinuxElf32help1(fi);
     }
+    if (super::canUnpack()) {
+        return true;
+    }
     return false;
 }
 
@@ -2396,8 +2400,8 @@ proceed: ;
 
 int PackLinuxElf64::canUnpack()
 {
-    if (super::canUnpack()) {
-        return true;
+    if (checkEhdr(&ehdri)) {
+        return false;
     }
     if (Elf64_Ehdr::ET_DYN==get_te16(&ehdri.e_type)) {
         PackLinuxElf64help1(fi);
@@ -2413,7 +2417,13 @@ int PackLinuxElf64::canUnpack()
         fi->seek(filesz+offset, SEEK_SET);
         MemBuffer buf(32 + sizeof(overlay_offset));
         fi->readx(buf, buf.getSize());
-        return PackUnix::find_overlay_offset(buf);
+        unsigned x = PackUnix::find_overlay_offset(buf);
+        if (x) {
+            return x;
+        }
+    }
+    if (super::canUnpack()) {
+        return true;
     }
     return false;
 }
path: src/p_lx_elf.cpp