summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve Langasek <steve.langasek@canonical.com>2014-10-08 06:40:28 +0000
committerSteve Langasek <steve.langasek@canonical.com>2014-10-08 06:40:28 +0000
commit3586772f0c502d7233e07335c5245b3b0d37e771 (patch)
tree5ad37625d94a58512faa14c20b88c4a6da438278
parentbc9b5d63863a5de26b02a33858462481334ac1c5 (diff)
downloadefi-boot-shim-3586772f0c502d7233e07335c5245b3b0d37e771.tar.gz
efi-boot-shim-3586772f0c502d7233e07335c5245b3b0d37e771.zip
* SECURITY UPDATE: heap overflow and out-of-bounds read access when
parsing DHCPv6 information - debian/patches/CVE-2014-3675.patch: apply proper bounds checking when parsing data provided in DHCPv6 packets. - CVE-2014-3675 - CVE-2014-3676 * SECURITY UPDATE: memory corruption when processing user-provided key lists - debian/patches/CVE-2014-3677.patch: detect malformed machine owner key (MOK) lists and ignore them, avoiding possible memory corruption. - CVE-2014-3677
-rw-r--r--.pc/CVE-2014-3675.patch/netboot.c379
-rw-r--r--.pc/applied-patches1
-rw-r--r--debian/changelog16
-rw-r--r--debian/patches/CVE-2014-3675.patch161
-rw-r--r--debian/patches/CVE-2014-3677.patch75
-rw-r--r--debian/patches/series1
-rw-r--r--netboot.c102
7 files changed, 695 insertions, 40 deletions
diff --git a/.pc/CVE-2014-3675.patch/netboot.c b/.pc/CVE-2014-3675.patch/netboot.c
new file mode 100644
index 00000000..a83c82ae
--- /dev/null
+++ b/.pc/CVE-2014-3675.patch/netboot.c
@@ -0,0 +1,379 @@
+/*
+ * netboot - trivial UEFI first-stage bootloader netboot support
+ *
+ * Copyright 2012 Red Hat, Inc <mjg@redhat.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Significant portions of this code are derived from Tianocore
+ * (http://tianocore.sf.net) and are Copyright 2009-2012 Intel
+ * Corporation.
+ */
+
+#include <efi.h>
+#include <efilib.h>
+#include <string.h>
+#include "shim.h"
+#include "netboot.h"
+
+static inline unsigned short int __swap16(unsigned short int x)
+{
+ __asm__("xchgb %b0,%h0"
+ : "=q" (x)
+ : "0" (x));
+ return x;
+}
+
+#define ntohs(x) __swap16(x)
+#define htons(x) ntohs(x)
+
+static EFI_PXE_BASE_CODE *pxe;
+static EFI_IP_ADDRESS tftp_addr;
+static CHAR8 *full_path;
+
+
+typedef struct {
+ UINT16 OpCode;
+ UINT16 Length;
+ UINT8 Data[1];
+} EFI_DHCP6_PACKET_OPTION;
+
+static CHAR8 *
+translate_slashes(char *str)
+{
+ int i;
+ int j;
+ if (str == NULL)
+ return (CHAR8 *)str;
+
+ for (i = 0, j = 0; str[i] != '\0'; i++, j++) {
+ if (str[i] == '\\') {
+ str[j] = '/';
+ if (str[i+1] == '\\')
+ i++;
+ }
+ }
+ return (CHAR8 *)str;
+}
+
+/*
+ * usingNetboot
+ * Returns TRUE if we identify a protocol that is enabled and Providing us with
+ * the needed information to fetch a grubx64.efi image
+ */
+BOOLEAN findNetboot(EFI_HANDLE image_handle)
+{
+ UINTN bs = sizeof(EFI_HANDLE);
+ EFI_GUID pxe_base_code_protocol = EFI_PXE_BASE_CODE_PROTOCOL;
+ EFI_HANDLE *hbuf;
+ BOOLEAN rc = FALSE;
+ void *buffer = AllocatePool(bs);
+ UINTN errcnt = 0;
+ UINTN i;
+ EFI_STATUS status;
+
+ if (!buffer)
+ return FALSE;
+
+try_again:
+ status = uefi_call_wrapper(BS->LocateHandle,5, ByProtocol,
+ &pxe_base_code_protocol, NULL, &bs,
+ buffer);
+
+ if (status == EFI_BUFFER_TOO_SMALL) {
+ errcnt++;
+ FreePool(buffer);
+ if (errcnt > 1)
+ return FALSE;
+ buffer = AllocatePool(bs);
+ if (!buffer)
+ return FALSE;
+ goto try_again;
+ }
+
+ if (status == EFI_NOT_FOUND) {
+ FreePool(buffer);
+ return FALSE;
+ }
+
+ /*
+ * We have a list of pxe supporting protocols, lets see if any are
+ * active
+ */
+ hbuf = buffer;
+ pxe = NULL;
+ for (i=0; i < (bs / sizeof(EFI_HANDLE)); i++) {
+ status = uefi_call_wrapper(BS->OpenProtocol, 6, hbuf[i],
+ &pxe_base_code_protocol,
+ (void **)&pxe, image_handle, NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+
+ if (status != EFI_SUCCESS) {
+ pxe = NULL;
+ continue;
+ }
+
+ if (!pxe || !pxe->Mode) {
+ pxe = NULL;
+ continue;
+ }
+
+ if (pxe->Mode->Started && pxe->Mode->DhcpAckReceived) {
+ /*
+ * We've located a pxe protocol handle thats been
+ * started and has received an ACK, meaning its
+ * something we'll be able to get tftp server info
+ * out of
+ */
+ rc = TRUE;
+ break;
+ }
+
+ }
+
+ FreePool(buffer);
+ return rc;
+}
+
+static CHAR8 *get_v6_bootfile_url(EFI_PXE_BASE_CODE_DHCPV6_PACKET *pkt)
+{
+ void *optr;
+ EFI_DHCP6_PACKET_OPTION *option;
+ CHAR8 *url;
+ UINT32 urllen;
+
+ optr = pkt->DhcpOptions;
+
+ for(;;) {
+ option = (EFI_DHCP6_PACKET_OPTION *)optr;
+
+ if (ntohs(option->OpCode) == 0)
+ return NULL;
+
+ if (ntohs(option->OpCode) == 59) {
+ /* This is the bootfile url option */
+ urllen = ntohs(option->Length);
+ url = AllocateZeroPool(urllen+1);
+ if (!url)
+ return NULL;
+ memcpy(url, option->Data, urllen);
+ return url;
+ }
+ optr += 4 + ntohs(option->Length);
+ }
+
+ return NULL;
+}
+
+static CHAR16 str2ns(CHAR8 *str)
+{
+ CHAR16 ret = 0;
+ CHAR8 v;
+ for(;*str;str++) {
+ if ('0' <= *str && *str <= '9')
+ v = *str - '0';
+ else if ('A' <= *str && *str <= 'F')
+ v = *str - 'A' + 10;
+ else if ('a' <= *str && *str <= 'f')
+ v = *str - 'a' + 10;
+ else
+ v = 0;
+ ret = (ret << 4) + v;
+ }
+ return htons(ret);
+}
+
+static CHAR8 *str2ip6(CHAR8 *str)
+{
+ UINT8 i, j, p;
+ size_t len;
+ CHAR8 *a, *b, t;
+ static UINT16 ip[8];
+
+ for(i=0; i < 8; i++) {
+ ip[i] = 0;
+ }
+ len = strlen(str);
+ a = b = str;
+ for(i=p=0; i < len; i++, b++) {
+ if (*b != ':')
+ continue;
+ *b = '\0';
+ ip[p++] = str2ns(a);
+ *b = ':';
+ a = b + 1;
+ if ( *(b+1) == ':' )
+ break;
+ }
+ a = b = (str + len);
+ for(j=len, p=7; j > i; j--, a--) {
+ if (*a != ':')
+ continue;
+ t = *b;
+ *b = '\0';
+ ip[p--] = str2ns(a+1);
+ *b = t;
+ b = a;
+ }
+ return (CHAR8 *)ip;
+}
+
+static BOOLEAN extract_tftp_info(CHAR8 *url)
+{
+ CHAR8 *start, *end;
+ CHAR8 ip6str[40];
+ CHAR8 *template = (CHAR8 *)translate_slashes(DEFAULT_LOADER_CHAR);
+
+ if (strncmp((UINT8 *)url, (UINT8 *)"tftp://", 7)) {
+ Print(L"URLS MUST START WITH tftp://\n");
+ return FALSE;
+ }
+ start = url + 7;
+ if (*start != '[') {
+ Print(L"TFTP SERVER MUST BE ENCLOSED IN [..]\n");
+ return FALSE;
+ }
+
+ start++;
+ end = start;
+ while ((*end != '\0') && (*end != ']')) {
+ end++;
+ if (end - start > 39) {
+ Print(L"TFTP URL includes malformed IPv6 address\n");
+ return FALSE;
+ }
+ }
+ if (end == '\0') {
+ Print(L"TFTP SERVER MUST BE ENCLOSED IN [..]\n");
+ return FALSE;
+ }
+ memset(ip6str, 0, 40);
+ memcpy(ip6str, start, end - start);
+ end++;
+ memcpy(&tftp_addr.v6, str2ip6(ip6str), 16);
+ full_path = AllocateZeroPool(strlen(end)+strlen(template)+1);
+ if (!full_path)
+ return FALSE;
+ memcpy(full_path, end, strlen(end));
+ end = (CHAR8 *)strrchr((char *)full_path, '/');
+ if (!end)
+ end = (CHAR8 *)full_path;
+ memcpy(end, template, strlen(template));
+ end[strlen(template)] = '\0';
+
+ return TRUE;
+}
+
+static EFI_STATUS parseDhcp6()
+{
+ EFI_PXE_BASE_CODE_DHCPV6_PACKET *packet = (EFI_PXE_BASE_CODE_DHCPV6_PACKET *)&pxe->Mode->DhcpAck.Raw;
+ CHAR8 *bootfile_url;
+
+ bootfile_url = get_v6_bootfile_url(packet);
+ if (!bootfile_url)
+ return EFI_NOT_FOUND;
+ if (extract_tftp_info(bootfile_url) == FALSE) {
+ FreePool(bootfile_url);
+ return EFI_NOT_FOUND;
+ }
+ FreePool(bootfile_url);
+ return EFI_SUCCESS;
+}
+
+static EFI_STATUS parseDhcp4()
+{
+ CHAR8 *template = (CHAR8 *)DEFAULT_LOADER_CHAR;
+ full_path = AllocateZeroPool(strlen(template)+1);
+
+ if (!full_path)
+ return EFI_OUT_OF_RESOURCES;
+
+ memcpy(&tftp_addr.v4, pxe->Mode->DhcpAck.Dhcpv4.BootpSiAddr, 4);
+
+ memcpy(full_path, template, strlen(template));
+
+ /* Note we don't capture the filename option here because we know its shim.efi
+ * We instead assume the filename at the end of the path is going to be grubx64.efi
+ */
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS parseNetbootinfo(EFI_HANDLE image_handle)
+{
+
+ EFI_STATUS rc;
+
+ if (!pxe)
+ return EFI_NOT_READY;
+
+ memset((UINT8 *)&tftp_addr, 0, sizeof(tftp_addr));
+
+ /*
+ * If we've discovered an active pxe protocol figure out
+ * if its ipv4 or ipv6
+ */
+ if (pxe->Mode->UsingIpv6){
+ rc = parseDhcp6();
+ } else
+ rc = parseDhcp4();
+ return rc;
+}
+
+EFI_STATUS FetchNetbootimage(EFI_HANDLE image_handle, VOID **buffer, UINT64 *bufsiz)
+{
+ EFI_STATUS rc;
+ EFI_PXE_BASE_CODE_TFTP_OPCODE read = EFI_PXE_BASE_CODE_TFTP_READ_FILE;
+ BOOLEAN overwrite = FALSE;
+ BOOLEAN nobuffer = FALSE;
+ UINTN blksz = 512;
+
+ Print(L"Fetching Netboot Image\n");
+ if (*buffer == NULL) {
+ *buffer = AllocatePool(4096 * 1024);
+ if (!*buffer)
+ return EFI_OUT_OF_RESOURCES;
+ *bufsiz = 4096 * 1024;
+ }
+
+try_again:
+ rc = uefi_call_wrapper(pxe->Mtftp, 10, pxe, read, *buffer, overwrite,
+ bufsiz, &blksz, &tftp_addr, full_path, NULL, nobuffer);
+
+ if (rc == EFI_BUFFER_TOO_SMALL) {
+ /* try again, doubling buf size */
+ *bufsiz *= 2;
+ FreePool(*buffer);
+ *buffer = AllocatePool(*bufsiz);
+ if (!*buffer)
+ return EFI_OUT_OF_RESOURCES;
+ goto try_again;
+ }
+
+ if (rc != EFI_SUCCESS && *buffer) {
+ FreePool(*buffer);
+ }
+ return rc;
+}
diff --git a/.pc/applied-patches b/.pc/applied-patches
index 49e56d23..fa2ce82d 100644
--- a/.pc/applied-patches
+++ b/.pc/applied-patches
@@ -2,3 +2,4 @@ prototypes
second-stage-path
sbsigntool-not-pesign
0001-Update-openssl-to-0.9.8za.patch
+CVE-2014-3675.patch
diff --git a/debian/changelog b/debian/changelog
index 42eab115..f42e5e82 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,19 @@
+shim (0.7-0ubuntu3) UNRELEASED; urgency=medium
+
+ * SECURITY UPDATE: heap overflow and out-of-bounds read access when
+ parsing DHCPv6 information
+ - debian/patches/CVE-2014-3675.patch: apply proper bounds checking
+ when parsing data provided in DHCPv6 packets.
+ - CVE-2014-3675
+ - CVE-2014-3676
+ * SECURITY UPDATE: memory corruption when processing user-provided key
+ lists
+ - debian/patches/CVE-2014-3677.patch: detect malformed machine owner
+ key (MOK) lists and ignore them, avoiding possible memory corruption.
+ - CVE-2014-3677
+
+ -- Steve Langasek <steve.langasek@ubuntu.com> Tue, 07 Oct 2014 23:28:39 -0700
+
shim (0.7-0ubuntu2) utopic; urgency=medium
* Restore debian/patches/prototypes, which still is needed on shim 0.7
diff --git a/debian/patches/CVE-2014-3675.patch b/debian/patches/CVE-2014-3675.patch
new file mode 100644
index 00000000..67b50fd6
--- /dev/null
+++ b/debian/patches/CVE-2014-3675.patch
@@ -0,0 +1,161 @@
+diff --git a/netboot.c b/netboot.c
+index 5ef53f7..f01a9bc 100644
+--- a/netboot.c
++++ b/netboot.c
+@@ -116,29 +116,34 @@ BOOLEAN findNetboot(EFI_HANDLE device)
+
+ static CHAR8 *get_v6_bootfile_url(EFI_PXE_BASE_CODE_DHCPV6_PACKET *pkt)
+ {
+- void *optr;
+- EFI_DHCP6_PACKET_OPTION *option;
+- CHAR8 *url;
+- UINT32 urllen;
++ void *optr = NULL, *end = NULL;
++ EFI_DHCP6_PACKET_OPTION *option = NULL;
++ CHAR8 *url = NULL;
++ UINT32 urllen = 0;
+
+ optr = pkt->DhcpOptions;
++ end = optr + sizeof(pkt->DhcpOptions);
+
+- for(;;) {
++ for (;;) {
+ option = (EFI_DHCP6_PACKET_OPTION *)optr;
+
+ if (ntohs(option->OpCode) == 0)
+- return NULL;
++ break;
+
+ if (ntohs(option->OpCode) == 59) {
+ /* This is the bootfile url option */
+ urllen = ntohs(option->Length);
+- url = AllocateZeroPool(urllen+1);
++ if ((void *)(option->Data + urllen) > end)
++ break;
++ url = AllocateZeroPool(urllen + 1);
+ if (!url)
+- return NULL;
++ break;
+ memcpy(url, option->Data, urllen);
+ return url;
+ }
+ optr += 4 + ntohs(option->Length);
++ if (optr + sizeof(EFI_DHCP6_PACKET_OPTION) > end)
++ break;
+ }
+
+ return NULL;
+@@ -164,45 +169,60 @@ static CHAR16 str2ns(CHAR8 *str)
+
+ static CHAR8 *str2ip6(CHAR8 *str)
+ {
+- UINT8 i, j, p;
+- size_t len;
+- CHAR8 *a, *b, t;
+- static UINT16 ip[8];
++ UINT8 i = 0, j = 0, p = 0;
++ size_t len = 0, dotcount = 0;
++ enum { MAX_IP6_DOTS = 7 };
++ CHAR8 *a = NULL, *b = NULL, t = 0;
++ static UINT16 ip[8];
+
+- for(i=0; i < 8; i++) {
+- ip[i] = 0;
+- }
+- len = strlen(str);
+- a = b = str;
+- for(i=p=0; i < len; i++, b++) {
+- if (*b != ':')
+- continue;
+- *b = '\0';
+- ip[p++] = str2ns(a);
+- *b = ':';
+- a = b + 1;
+- if ( *(b+1) == ':' )
+- break;
+- }
+- a = b = (str + len);
+- for(j=len, p=7; j > i; j--, a--) {
+- if (*a != ':')
+- continue;
+- t = *b;
+- *b = '\0';
+- ip[p--] = str2ns(a+1);
+- *b = t;
+- b = a;
+- }
+- return (CHAR8 *)ip;
++ memset(ip, 0, sizeof(ip));
++
++ /* Count amount of ':' to prevent overflows.
++ * max. count = 7. Returns an invalid ip6 that
++ * can be checked against
++ */
++ for (a = str; *a != 0; ++a) {
++ if (*a == ':')
++ ++dotcount;
++ }
++ if (dotcount > MAX_IP6_DOTS)
++ return (CHAR8 *)ip;
++
++ len = strlen(str);
++ a = b = str;
++ for (i = p = 0; i < len; i++, b++) {
++ if (*b != ':')
++ continue;
++ *b = '\0';
++ ip[p++] = str2ns(a);
++ *b = ':';
++ a = b + 1;
++ if (b[1] == ':' )
++ break;
++ }
++ a = b = (str + len);
++ for (j = len, p = 7; j > i; j--, a--) {
++ if (*a != ':')
++ continue;
++ t = *b;
++ *b = '\0';
++ ip[p--] = str2ns(a+1);
++ *b = t;
++ b = a;
++ }
++ return (CHAR8 *)ip;
+ }
+
+ static BOOLEAN extract_tftp_info(CHAR8 *url)
+ {
+ CHAR8 *start, *end;
+ CHAR8 ip6str[40];
++ CHAR8 ip6inv[16];
+ CHAR8 *template = (CHAR8 *)translate_slashes(DEFAULT_LOADER_CHAR);
+
++ // to check against str2ip6() errors
++ memset(ip6inv, 0, sizeof(ip6inv));
++
+ if (strncmp((UINT8 *)url, (UINT8 *)"tftp://", 7)) {
+ Print(L"URLS MUST START WITH tftp://\n");
+ return FALSE;
+@@ -217,7 +237,7 @@ static BOOLEAN extract_tftp_info(CHAR8 *url)
+ end = start;
+ while ((*end != '\0') && (*end != ']')) {
+ end++;
+- if (end - start > 39) {
++ if (end - start >= (int)sizeof(ip6str)) {
+ Print(L"TFTP URL includes malformed IPv6 address\n");
+ return FALSE;
+ }
+@@ -226,10 +246,12 @@ static BOOLEAN extract_tftp_info(CHAR8 *url)
+ Print(L"TFTP SERVER MUST BE ENCLOSED IN [..]\n");
+ return FALSE;
+ }
+- memset(ip6str, 0, 40);
++ memset(ip6str, 0, sizeof(ip6str));
+ memcpy(ip6str, start, end - start);
+ end++;
+ memcpy(&tftp_addr.v6, str2ip6(ip6str), 16);
++ if (memcmp(&tftp_addr.v6, ip6inv, sizeof(ip6inv)) == 0)
++ return FALSE;
+ full_path = AllocateZeroPool(strlen(end)+strlen(template)+1);
+ if (!full_path)
+ return FALSE;
diff --git a/debian/patches/CVE-2014-3677.patch b/debian/patches/CVE-2014-3677.patch
new file mode 100644
index 00000000..4d05f05c
--- /dev/null
+++ b/debian/patches/CVE-2014-3677.patch
@@ -0,0 +1,75 @@
+diff --git a/MokManager.c b/MokManager.c
+index 50cb9d7..73d8ff4 100644
+--- a/MokManager.c
++++ b/MokManager.c
+@@ -100,8 +100,18 @@ static UINT32 count_keys(void *Data, UINTN DataSize)
+ EFI_GUID HashType = EFI_CERT_SHA256_GUID;
+ UINTN dbsize = DataSize;
+ UINT32 MokNum = 0;
++ void *end = Data + DataSize;
+
+ while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) {
++
++ /* Use ptr arithmetics to ensure bounded access. Do not allow 0
++ * SignatureListSize that will cause endless loop.
++ */
++ if ((void *)(CertList + 1) > end || CertList->SignatureListSize == 0) {
++ console_notify(L"Invalid MOK detected! Ignoring MOK List.");
++ return 0;
++ }
++
+ if ((CompareGuid (&CertList->SignatureType, &CertType) != 0) &&
+ (CompareGuid (&CertList->SignatureType, &HashType) != 0)) {
+ console_notify(L"Doesn't look like a key or hash");
+@@ -137,6 +147,7 @@ static MokListNode *build_mok_list(UINT32 num, void *Data, UINTN DataSize) {
+ EFI_GUID HashType = EFI_CERT_SHA256_GUID;
+ UINTN dbsize = DataSize;
+ UINTN count = 0;
++ void *end = Data + DataSize;
+
+ list = AllocatePool(sizeof(MokListNode) * num);
+
+@@ -146,6 +157,11 @@ static MokListNode *build_mok_list(UINT32 num, void *Data, UINTN DataSize) {
+ }
+
+ while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) {
++ /* CertList out of bounds? */
++ if ((void *)(CertList + 1) > end || CertList->SignatureListSize == 0) {
++ FreePool(list);
++ return NULL;
++ }
+ if ((CompareGuid (&CertList->SignatureType, &CertType) != 0) &&
+ (CompareGuid (&CertList->SignatureType, &HashType) != 0)) {
+ dbsize -= CertList->SignatureListSize;
+@@ -165,10 +181,22 @@ static MokListNode *build_mok_list(UINT32 num, void *Data, UINTN DataSize) {
+ Cert = (EFI_SIGNATURE_DATA *) (((UINT8 *) CertList) +
+ sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
+
++ /* Cert out of bounds? */
++ if ((void *)(Cert + 1) > end || CertList->SignatureSize <= sizeof(EFI_GUID)) {
++ FreePool(list);
++ return NULL;
++ }
++
+ list[count].MokSize = CertList->SignatureSize - sizeof(EFI_GUID);
+ list[count].Mok = (void *)Cert->SignatureData;
+ list[count].Type = CertList->SignatureType;
+
++ /* MOK out of bounds? */
++ if (list[count].MokSize > end - (void *)list[count].Mok) {
++ FreePool(list);
++ return NULL;
++ }
++
+ count++;
+ dbsize -= CertList->SignatureListSize;
+ CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList +
+@@ -449,6 +477,8 @@ static EFI_STATUS list_keys (void *KeyList, UINTN KeyListSize, CHAR16 *title)
+ }
+
+ MokNum = count_keys(KeyList, KeyListSize);
++ if (MokNum == 0)
++ return 0;
+ keys = build_mok_list(MokNum, KeyList, KeyListSize);
+
+ if (!keys) {
diff --git a/debian/patches/series b/debian/patches/series
index 49e56d23..fa2ce82d 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -2,3 +2,4 @@ prototypes
second-stage-path
sbsigntool-not-pesign
0001-Update-openssl-to-0.9.8za.patch
+CVE-2014-3675.patch
diff --git a/netboot.c b/netboot.c
index a83c82ae..072118ad 100644
--- a/netboot.c
+++ b/netboot.c
@@ -160,29 +160,34 @@ try_again:
static CHAR8 *get_v6_bootfile_url(EFI_PXE_BASE_CODE_DHCPV6_PACKET *pkt)
{
- void *optr;
- EFI_DHCP6_PACKET_OPTION *option;
- CHAR8 *url;
- UINT32 urllen;
+ void *optr = NULL, *end = NULL;
+ EFI_DHCP6_PACKET_OPTION *option = NULL;
+ CHAR8 *url = NULL;
+ UINT32 urllen = 0;
optr = pkt->DhcpOptions;
+ end = optr + sizeof(pkt->DhcpOptions);
- for(;;) {
+ for (;;) {
option = (EFI_DHCP6_PACKET_OPTION *)optr;
if (ntohs(option->OpCode) == 0)
- return NULL;
+ break;
if (ntohs(option->OpCode) == 59) {
/* This is the bootfile url option */
urllen = ntohs(option->Length);
- url = AllocateZeroPool(urllen+1);
+ if ((void *)(option->Data + urllen) > end)
+ break;
+ url = AllocateZeroPool(urllen + 1);
if (!url)
- return NULL;
+ break;
memcpy(url, option->Data, urllen);
return url;
}
optr += 4 + ntohs(option->Length);
+ if (optr + sizeof(EFI_DHCP6_PACKET_OPTION) > end)
+ break;
}
return NULL;
@@ -208,45 +213,60 @@ static CHAR16 str2ns(CHAR8 *str)
static CHAR8 *str2ip6(CHAR8 *str)
{
- UINT8 i, j, p;
- size_t len;
- CHAR8 *a, *b, t;
- static UINT16 ip[8];
+ UINT8 i = 0, j = 0, p = 0;
+ size_t len = 0, dotcount = 0;
+ enum { MAX_IP6_DOTS = 7 };
+ CHAR8 *a = NULL, *b = NULL, t = 0;
+ static UINT16 ip[8];
- for(i=0; i < 8; i++) {
- ip[i] = 0;
- }
- len = strlen(str);
- a = b = str;
- for(i=p=0; i < len; i++, b++) {
- if (*b != ':')
- continue;
- *b = '\0';
- ip[p++] = str2ns(a);
- *b = ':';
- a = b + 1;
- if ( *(b+1) == ':' )
- break;
- }
- a = b = (str + len);
- for(j=len, p=7; j > i; j--, a--) {
- if (*a != ':')
- continue;
- t = *b;
- *b = '\0';
- ip[p--] = str2ns(a+1);
- *b = t;
- b = a;
- }
- return (CHAR8 *)ip;
+ memset(ip, 0, sizeof(ip));
+
+ /* Count amount of ':' to prevent overflows.
+ * max. count = 7. Returns an invalid ip6 that
+ * can be checked against
+ */
+ for (a = str; *a != 0; ++a) {
+ if (*a == ':')
+ ++dotcount;
+ }
+ if (dotcount > MAX_IP6_DOTS)
+ return (CHAR8 *)ip;
+
+ len = strlen(str);
+ a = b = str;
+ for (i = p = 0; i < len; i++, b++) {
+ if (*b != ':')
+ continue;
+ *b = '\0';
+ ip[p++] = str2ns(a);
+ *b = ':';
+ a = b + 1;
+ if (b[1] == ':' )
+ break;
+ }
+ a = b = (str + len);
+ for (j = len, p = 7; j > i; j--, a--) {
+ if (*a != ':')
+ continue;
+ t = *b;
+ *b = '\0';
+ ip[p--] = str2ns(a+1);
+ *b = t;
+ b = a;
+ }
+ return (CHAR8 *)ip;
}
static BOOLEAN extract_tftp_info(CHAR8 *url)
{
CHAR8 *start, *end;
CHAR8 ip6str[40];
+ CHAR8 ip6inv[16];
CHAR8 *template = (CHAR8 *)translate_slashes(DEFAULT_LOADER_CHAR);
+ // to check against str2ip6() errors
+ memset(ip6inv, 0, sizeof(ip6inv));
+
if (strncmp((UINT8 *)url, (UINT8 *)"tftp://", 7)) {
Print(L"URLS MUST START WITH tftp://\n");
return FALSE;
@@ -261,7 +281,7 @@ static BOOLEAN extract_tftp_info(CHAR8 *url)
end = start;
while ((*end != '\0') && (*end != ']')) {
end++;
- if (end - start > 39) {
+ if (end - start >= (int)sizeof(ip6str)) {
Print(L"TFTP URL includes malformed IPv6 address\n");
return FALSE;
}
@@ -270,10 +290,12 @@ static BOOLEAN extract_tftp_info(CHAR8 *url)
Print(L"TFTP SERVER MUST BE ENCLOSED IN [..]\n");
return FALSE;
}
- memset(ip6str, 0, 40);
+ memset(ip6str, 0, sizeof(ip6str));
memcpy(ip6str, start, end - start);
end++;
memcpy(&tftp_addr.v6, str2ip6(ip6str), 16);
+ if (memcmp(&tftp_addr.v6, ip6inv, sizeof(ip6inv)) == 0)
+ return FALSE;
full_path = AllocateZeroPool(strlen(end)+strlen(template)+1);
if (!full_path)
return FALSE;