arrfab / rpms / shim

Forked from rpms/shim 5 years ago
Clone

Blame SOURCES/0070-shim-buffer-overflow-on-ipv6-option-parsing.patch

e97c83
From e253c2a2c07bc526de1528ed9839b2b584025fa2 Mon Sep 17 00:00:00 2001
e97c83
From: Sebastian Krahmer <krahmer@suse.com>
e97c83
Date: Tue, 29 Jul 2014 09:55:00 +0000
e97c83
Subject: [PATCH 70/74] shim buffer overflow on ipv6 option parsing
e97c83
e97c83
---
e97c83
 netboot.c | 102 ++++++++++++++++++++++++++++++++++++++------------------------
e97c83
 1 file changed, 62 insertions(+), 40 deletions(-)
e97c83
e97c83
diff --git a/netboot.c b/netboot.c
e97c83
index 238937d..f884cba 100644
e97c83
--- a/netboot.c
e97c83
+++ b/netboot.c
e97c83
@@ -108,29 +108,34 @@ BOOLEAN findNetboot(EFI_HANDLE device)
e97c83
 
e97c83
 static CHAR8 *get_v6_bootfile_url(EFI_PXE_BASE_CODE_DHCPV6_PACKET *pkt)
e97c83
 {
e97c83
-	void *optr;
e97c83
-	EFI_DHCP6_PACKET_OPTION *option;
e97c83
-	CHAR8 *url;
e97c83
-	UINT32 urllen;
e97c83
+	void *optr = NULL, *end = NULL;
e97c83
+	EFI_DHCP6_PACKET_OPTION *option = NULL;
e97c83
+	CHAR8 *url = NULL;
e97c83
+	UINT32 urllen = 0;
e97c83
 
e97c83
 	optr = pkt->DhcpOptions;
e97c83
+	end = optr + sizeof(pkt->DhcpOptions);
e97c83
 
e97c83
-	for(;;) {
e97c83
+	for (;;) {
e97c83
 		option = (EFI_DHCP6_PACKET_OPTION *)optr;
e97c83
 
e97c83
 		if (ntohs(option->OpCode) == 0)
e97c83
-			return NULL;
e97c83
+			break;
e97c83
 
e97c83
 		if (ntohs(option->OpCode) == 59) {
e97c83
 			/* This is the bootfile url option */
e97c83
 			urllen = ntohs(option->Length);
e97c83
-			url = AllocateZeroPool(urllen+1);
e97c83
+			if ((void *)(option->Data + urllen) > end)
e97c83
+				break;
e97c83
+			url = AllocateZeroPool(urllen + 1);
e97c83
 			if (!url)
e97c83
-				return NULL;
e97c83
+				break;
e97c83
 			memcpy(url, option->Data, urllen);
e97c83
 			return url;
e97c83
 		}
e97c83
 		optr += 4 + ntohs(option->Length);
e97c83
+		if (optr + sizeof(EFI_DHCP6_PACKET_OPTION) > end)
e97c83
+			break;
e97c83
 	}
e97c83
 
e97c83
 	return NULL;
e97c83
@@ -156,45 +161,60 @@ static CHAR16 str2ns(CHAR8 *str)
e97c83
 
e97c83
 static CHAR8 *str2ip6(CHAR8 *str)
e97c83
 {
e97c83
-        UINT8 i, j, p;
e97c83
-	size_t len;
e97c83
-        CHAR8 *a, *b, t;
e97c83
-        static UINT16 ip[8];
e97c83
+	UINT8 i = 0, j = 0, p = 0;
e97c83
+	size_t len = 0, dotcount = 0;
e97c83
+	enum { MAX_IP6_DOTS = 7 };
e97c83
+	CHAR8 *a = NULL, *b = NULL, t = 0;
e97c83
+	static UINT16 ip[8];
e97c83
 
e97c83
-        for(i=0; i < 8; i++) {
e97c83
-                ip[i] = 0;
e97c83
-        }
e97c83
-        len = strlen(str);
e97c83
-        a = b = str;
e97c83
-        for(i=p=0; i < len; i++, b++) {
e97c83
-                if (*b != ':')
e97c83
-                        continue;
e97c83
-                *b = '\0';
e97c83
-                ip[p++] = str2ns(a);
e97c83
-                *b = ':';
e97c83
-                a = b + 1;
e97c83
-                if ( *(b+1) == ':' )
e97c83
-                        break;
e97c83
-        }
e97c83
-        a = b = (str + len);
e97c83
-        for(j=len, p=7; j > i; j--, a--) {
e97c83
-                if (*a != ':')
e97c83
-                        continue;
e97c83
-                t = *b;
e97c83
-                *b = '\0';
e97c83
-                ip[p--] = str2ns(a+1);
e97c83
-                *b = t;
e97c83
-                b = a;
e97c83
-        }
e97c83
-        return (CHAR8 *)ip;
e97c83
+	memset(ip, 0, sizeof(ip));
e97c83
+
e97c83
+	/* Count amount of ':' to prevent overflows.
e97c83
+	 * max. count = 7. Returns an invalid ip6 that
e97c83
+	 * can be checked against
e97c83
+	 */
e97c83
+	for (a = str; *a != 0; ++a) {
e97c83
+		if (*a == ':')
e97c83
+			++dotcount;
e97c83
+	}
e97c83
+	if (dotcount > MAX_IP6_DOTS)
e97c83
+		return (CHAR8 *)ip;
e97c83
+
e97c83
+	len = strlen(str);
e97c83
+	a = b = str;
e97c83
+	for (i = p = 0; i < len; i++, b++) {
e97c83
+		if (*b != ':')
e97c83
+			continue;
e97c83
+		*b = '\0';
e97c83
+		ip[p++] = str2ns(a);
e97c83
+		*b = ':';
e97c83
+		a = b + 1;
e97c83
+		if (b[1] == ':' )
e97c83
+			break;
e97c83
+	}
e97c83
+	a = b = (str + len);
e97c83
+	for (j = len, p = 7; j > i; j--, a--) {
e97c83
+		if (*a != ':')
e97c83
+			continue;
e97c83
+		t = *b;
e97c83
+		*b = '\0';
e97c83
+		ip[p--] = str2ns(a+1);
e97c83
+		*b = t;
e97c83
+		b = a;
e97c83
+	}
e97c83
+	return (CHAR8 *)ip;
e97c83
 }
e97c83
 
e97c83
 static BOOLEAN extract_tftp_info(CHAR8 *url)
e97c83
 {
e97c83
 	CHAR8 *start, *end;
e97c83
 	CHAR8 ip6str[40];
e97c83
+	CHAR8 ip6inv[16];
e97c83
 	CHAR8 *template = (CHAR8 *)translate_slashes(DEFAULT_LOADER_CHAR);
e97c83
 
e97c83
+	// to check against str2ip6() errors
e97c83
+	memset(ip6inv, 0, sizeof(ip6inv));
e97c83
+
e97c83
 	if (strncmp((UINT8 *)url, (UINT8 *)"tftp://", 7)) {
e97c83
 		Print(L"URLS MUST START WITH tftp://\n");
e97c83
 		return FALSE;
e97c83
@@ -209,7 +229,7 @@ static BOOLEAN extract_tftp_info(CHAR8 *url)
e97c83
 	end = start;
e97c83
 	while ((*end != '\0') && (*end != ']')) {
e97c83
 		end++;
e97c83
-		if (end - start > 39) {
e97c83
+		if (end - start >= (int)sizeof(ip6str)) {
e97c83
 			Print(L"TFTP URL includes malformed IPv6 address\n");
e97c83
 			return FALSE;
e97c83
 		}
e97c83
@@ -218,10 +238,12 @@ static BOOLEAN extract_tftp_info(CHAR8 *url)
e97c83
 		Print(L"TFTP SERVER MUST BE ENCLOSED IN [..]\n");
e97c83
 		return FALSE;
e97c83
 	}
e97c83
-	memset(ip6str, 0, 40);
e97c83
+	memset(ip6str, 0, sizeof(ip6str));
e97c83
 	memcpy(ip6str, start, end - start);
e97c83
 	end++;
e97c83
 	memcpy(&tftp_addr.v6, str2ip6(ip6str), 16);
e97c83
+	if (memcmp(&tftp_addr.v6, ip6inv, sizeof(ip6inv)) == 0)
e97c83
+		return FALSE;
e97c83
 	full_path = AllocateZeroPool(strlen(end)+strlen(template)+1);
e97c83
 	if (!full_path)
e97c83
 		return FALSE;
e97c83
-- 
e97c83
1.9.3
e97c83