CVE-2014-9653: Improper Input Validation (CWE-20)
value: readelf.c in file before 5.22, as used in the Fileinfo component in PHP before 5.4.37, 5.5.x before 5.5.21, and 5.6.x before 5.6.5, does not consider that pread calls sometimes read only a subset of the available data, which allows remote attackers to cause a denial of service (uninitialized memory access) or possibly have unspecified other impact via a crafted ELF file.
CWE description: The product receives input or data, but it does
        not validate or incorrectly validates that the input has the
        properties that are required to process the data safely and
        correctly.
Published: 2015-03-30T10:59Z
Repository: https://github.com/file/file
Language: C
Files changed: src/readelf.c
Commit date: 2014-12-16 20:53:05 +0000
Commit message: Bail out on partial reads, from Alexander Cherepanov

Diff: diff --git a/src/readelf.c b/src/readelf.c
index 429666304..9d54fc973 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -25,11 +25,11 @@
  * SUCH DAMAGE.
  */
 #include "file.h"
 
 #ifndef lint
-FILE_RCSID("@(#)$File: readelf.c,v 1.113 2014/12/11 14:10:53 christos Exp $")
+FILE_RCSID("@(#)$File: readelf.c,v 1.114 2014/12/11 14:19:36 christos Exp $")
 #endif
 
 #ifdef BUILTIN_ELF
 #include <string.h>
 #include <ctype.h>
@@ -317,11 +317,11 @@ dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
 
 	/*
 	 * Loop through all the program headers.
 	 */
 	for ( ; num; num--) {
-		if (pread(fd, xph_addr, xph_sizeof, off) == -1) {
+		if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) {
 			file_badread(ms);
 			return -1;
 		}
 		off += size;
 
@@ -926,35 +926,36 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
 	void *nbuf;
 	off_t noff, coff, name_off;
 	uint64_t cap_hw1 = 0;	/* SunOS 5.x hardware capabilites */
 	uint64_t cap_sf1 = 0;	/* SunOS 5.x software capabilites */
 	char name[50];
+	ssize_t namesize;
 
 	if (size != xsh_sizeof) {
 		if (file_printf(ms, ", corrupted section header size") == -1)
 			return -1;
 		return 0;
 	}
 
 	/* Read offset of name section to be able to read section names later */
-	if (pread(fd, xsh_addr, xsh_sizeof, off + size * strtab) == -1) {
+	if (pread(fd, xsh_addr, xsh_sizeof, off + size * strtab) < (ssize_t)xsh_sizeof) {
 		file_badread(ms);
 		return -1;
 	}
 	name_off = xsh_offset;
 
 	for ( ; num; num--) {
 		/* Read the name of this section. */
-		if (pread(fd, name, sizeof(name), name_off + xsh_name) == -1) {
+		if ((namesize = pread(fd, name, sizeof(name) - 1, name_off + xsh_name)) == -1) {
 			file_badread(ms);
 			return -1;
 		}
-		name[sizeof(name) - 1] = '\0';
+		name[namesize] = '\0';
 		if (strcmp(name, ".debug_info") == 0)
 			stripped = 0;
 
-		if (pread(fd, xsh_addr, xsh_sizeof, off) == -1) {
+		if (pread(fd, xsh_addr, xsh_sizeof, off) < (ssize_t)xsh_sizeof) {
 			file_badread(ms);
 			return -1;
 		}
 		off += size;
 
@@ -980,11 +981,11 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
 			if ((nbuf = malloc(xsh_size)) == NULL) {
 				file_error(ms, errno, "Cannot allocate memory"
 				    " for note");
 				return -1;
 			}
-			if (pread(fd, nbuf, xsh_size, xsh_offset) == -1) {
+			if (pread(fd, nbuf, xsh_size, xsh_offset) < (ssize_t)xsh_size) {
 				file_badread(ms);
 				free(nbuf);
 				return -1;
 			}
 
@@ -1176,11 +1177,11 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
 			return -1;
 		return 0;
 	}
 
   	for ( ; num; num--) {
-		if (pread(fd, xph_addr, xph_sizeof, off) == -1) {
+		if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) {
 			file_badread(ms);
 			return -1;
 		}
 
 		off += size;

Vulnerable code: FILE_RCSID("@(#)$File: readelf.c,v 1.113 2014/12/11 14:10:53 christos Exp $")
		if (pread(fd, xph_addr, xph_sizeof, off) == -1) {
	if (pread(fd, xsh_addr, xsh_sizeof, off + size * strtab) == -1) {
		if (pread(fd, name, sizeof(name), name_off + xsh_name) == -1) {
		name[sizeof(name) - 1] = '\0';
		if (pread(fd, xsh_addr, xsh_sizeof, off) == -1) {
			if (pread(fd, nbuf, xsh_size, xsh_offset) == -1) {
		if (pread(fd, xph_addr, xph_sizeof, off) == -1) {
Fixed code: FILE_RCSID("@(#)$File: readelf.c,v 1.114 2014/12/11 14:19:36 christos Exp $")
		if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) {
	ssize_t namesize;
	if (pread(fd, xsh_addr, xsh_sizeof, off + size * strtab) < (ssize_t)xsh_sizeof) {
		if ((namesize = pread(fd, name, sizeof(name) - 1, name_off + xsh_name)) == -1) {
		name[namesize] = '\0';
		if (pread(fd, xsh_addr, xsh_sizeof, off) < (ssize_t)xsh_sizeof) {
			if (pread(fd, nbuf, xsh_size, xsh_offset) < (ssize_t)xsh_size) {
		if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) {