Vulnerability: The ELF parser in file 5.16 through 5.21 allows remote attackers to cause a denial of service via a long string.
Vulnerability ID: CVE-2014-9621
CWE: CWE-399
Severity score: 2.9
Project: https://github.com/file/file
Published: 2015-01-21
File: src/readelf.c
Commit message: Limit string printing to 100 chars, and add flags I forgot in the previous
commit.
Commit author: Christos Zoulas

Vulnerable version (before fix):
 #include "file.h"  #ifndef lint FILE_RCSID("@(#)$File: readelf.c,v 1.115 2014/12/16 20:53:05 christos Exp $") #endif  #ifdef BUILTIN_ELF donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size, 	}  	if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) { 		switch (xnh_type) { 	    	case NT_NETBSD_VERSION: 			return size; 		case NT_NETBSD_MARCH: 			if (*flags & FLAGS_DID_NETBSD_MARCH) 				return size; 			if (file_printf(ms, ", compiled for: %.*s", (int)descsz, 			    (const char *)&nbuf[doff]) == -1) 				return size; 			break; 		case NT_NETBSD_CMODEL: 			if (*flags & FLAGS_DID_NETBSD_CMODEL) 				return size; 			if (file_printf(ms, ", compiler model: %.*s", 			    (int)descsz, (const char *)&nbuf[doff]) == -1) 				return size; 			break; 		default: 			if (*flags & FLAGS_DID_NETBSD_UNKNOWN) 				return size; 			if (file_printf(ms, ", note=%u", xnh_type) == -1) 				return size; 			break;

Fixed version (after fix):
 #include "file.h"  #ifndef lint FILE_RCSID("@(#)$File: readelf.c,v 1.116 2014/12/16 23:18:40 christos Exp $") #endif  #ifdef BUILTIN_ELF donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size, 	}  	if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) { 		if (descsz > 100) 			descsz = 100; 		switch (xnh_type) { 	    	case NT_NETBSD_VERSION: 			return size; 		case NT_NETBSD_MARCH: 			if (*flags & FLAGS_DID_NETBSD_MARCH) 				return size; 			*flags |= FLAGS_DID_NETBSD_MARCH; 			if (file_printf(ms, ", compiled for: %.*s", 			    (int)descsz, (const char *)&nbuf[doff]) == -1) 				return size; 			break; 		case NT_NETBSD_CMODEL: 			if (*flags & FLAGS_DID_NETBSD_CMODEL) 				return size; 			*flags |= FLAGS_DID_NETBSD_CMODEL; 			if (file_printf(ms, ", compiler model: %.*s", 			    (int)descsz, (const char *)&nbuf[doff]) == -1) 				return size; 			break; 		default: 			if (*flags & FLAGS_DID_NETBSD_UNKNOWN) 				return size; 			*flags |= FLAGS_DID_NETBSD_UNKNOWN; 			if (file_printf(ms, ", note=%u", xnh_type) == -1) 				return size; 			break;

Patch:
patch: @@ -27,7 +27,7 @@
 #include "file.h"
 
 #ifndef lint
-FILE_RCSID("@(#)$File: readelf.c,v 1.115 2014/12/16 20:53:05 christos Exp $")
+FILE_RCSID("@(#)$File: readelf.c,v 1.116 2014/12/16 23:18:40 christos Exp $")
 #endif
 
 #ifdef BUILTIN_ELF
@@ -900,26 +900,31 @@ donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size,
 	}
 
 	if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) {
+		if (descsz > 100)
+			descsz = 100;
 		switch (xnh_type) {
 	    	case NT_NETBSD_VERSION:
 			return size;
 		case NT_NETBSD_MARCH:
 			if (*flags & FLAGS_DID_NETBSD_MARCH)
 				return size;
-			if (file_printf(ms, ", compiled for: %.*s", (int)descsz,
-			    (const char *)&nbuf[doff]) == -1)
+			*flags |= FLAGS_DID_NETBSD_MARCH;
+			if (file_printf(ms, ", compiled for: %.*s",
+			    (int)descsz, (const char *)&nbuf[doff]) == -1)
 				return size;
 			break;
 		case NT_NETBSD_CMODEL:
 			if (*flags & FLAGS_DID_NETBSD_CMODEL)
 				return size;
+			*flags |= FLAGS_DID_NETBSD_CMODEL;
 			if (file_printf(ms, ", compiler model: %.*s",
 			    (int)descsz, (const char *)&nbuf[doff]) == -1)
 				return size;
 			break;
 		default:
 			if (*flags & FLAGS_DID_NETBSD_UNKNOWN)
 				return size;
+			*flags |= FLAGS_DID_NETBSD_UNKNOWN;
 			if (file_printf(ms, ", note=%u", xnh_type) == -1)
 				return size;
 			break;
path: src/readelf.c