]> git.proxmox.com Git - efi-boot-shim.git/commitdiff
debian/patches/netboot-cleanup: roll-up of miscellaneous fixes to
authorSteve Langasek <steve.langasek@canonical.com>
Mon, 23 Sep 2013 07:29:29 +0000 (00:29 -0700)
committerSteve Langasek <steve.langasek@canonical.com>
Mon, 23 Sep 2013 07:29:29 +0000 (00:29 -0700)
the netboot code.

.pc/applied-patches
.pc/netboot-cleanup/netboot.c [new file with mode: 0644]
debian/changelog
debian/patches/netboot-cleanup [new file with mode: 0644]
debian/patches/series
debian/patches/tftp-proper-nul-termination
netboot.c

index cd7c501248bd0605c192a743bc3b184fd48a1dcb..f37a5e398537e6dccfa50fe6b4592f90a87a97a2 100644 (file)
@@ -7,3 +7,4 @@ fix-tftp-prototype
 build-with-Werror
 fix-compiler-warnings
 tftp-proper-nul-termination
+netboot-cleanup
diff --git a/.pc/netboot-cleanup/netboot.c b/.pc/netboot-cleanup/netboot.c
new file mode 100644 (file)
index 0000000..e543363
--- /dev/null
@@ -0,0 +1,355 @@
+/*
+ * 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 UINT8 *full_path;
+
+
+typedef struct {
+       UINT16 OpCode;
+       UINT16 Length;
+       UINT8 Data[1];
+} EFI_DHCP6_PACKET_OPTION;
+
+/*
+ * 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 char *get_v6_bootfile_url(EFI_PXE_BASE_CODE_DHCPV6_PACKET *pkt)
+{
+       void *optr;
+       EFI_DHCP6_PACKET_OPTION *option;
+       char *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 = AllocatePool(urllen+2);
+                       if (!url)
+                               return NULL;
+                       memset(url, 0, urllen+2);
+                       memcpy(url, option->Data, urllen);
+                       return url;
+               }
+               optr += 4 + ntohs(option->Length);
+       }
+
+       return NULL;
+}
+
+static UINT16 str2ns(UINT8 *str)
+{
+        UINT16 ret = 0;
+        UINT8 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 UINT8 *str2ip6(char *str)
+{
+        UINT8 i, j, p;
+       size_t len;
+        UINT8 *a, *b, t;
+        static UINT16 ip[8];
+
+        for(i=0; i < 8; i++) {
+                ip[i] = 0;
+        }
+        len = strlen((UINT8 *)str);
+        a = b = (UINT8 *)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 = (UINT8 *)(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 (UINT8 *)ip;
+}
+
+static BOOLEAN extract_tftp_info(char *url)
+{
+       CHAR8 *start, *end;
+       char ip6str[128];
+       CHAR8 *template = (CHAR8 *)"/grubx64.efi";
+
+       if (strncmp((UINT8 *)url, (UINT8 *)"tftp://", 7)) {
+               Print(L"URLS MUST START WITH tftp://\n");
+               return FALSE;
+       }
+       start = (CHAR8 *)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 == '\0') {
+               Print(L"TFTP SERVER MUST BE ENCLOSED IN [..]\n");
+               return FALSE;
+       }
+       memset(ip6str, 0, 128);
+       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;
+       char *bootfile_url;
+
+
+       bootfile_url = get_v6_bootfile_url(packet);
+       if (extract_tftp_info(bootfile_url) == FALSE)
+               return EFI_NOT_FOUND;
+       if (!bootfile_url)
+               return EFI_NOT_FOUND;
+       return EFI_SUCCESS;
+}
+
+static EFI_STATUS parseDhcp4()
+{
+       CHAR8 *template = (CHAR8 *)"/grubx64.efi";
+       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;
+       }
+
+       return rc;
+
+}
index 16791a5028ece4e646e9ce1d4a0322f3506a875b..33f1bee190daad03040f50e91d383808fa0236f9 100644 (file)
@@ -8,6 +8,8 @@ shim (0.4-0ubuntu4) UNRELEASED; urgency=low
     warnings in netboot.c.
   * debian/patches/tftp-proper-nul-termination: fix nul termination
     errors in filenames passed to tftp.
+  * debian/patches/netboot-cleanup: roll-up of miscellaneous fixes to
+    the netboot code.
 
  -- Steve Langasek <steve.langasek@ubuntu.com>  Fri, 20 Sep 2013 14:43:23 +0000
 
diff --git a/debian/patches/netboot-cleanup b/debian/patches/netboot-cleanup
new file mode 100644 (file)
index 0000000..e94e2c7
--- /dev/null
@@ -0,0 +1,106 @@
+Description: roll-up of miscellaneous fixes to the netboot code
+ Pull of various fixes from
+ <https://github.com/vorlonofportland/shim/tree/netboot-cleanup>, currently
+ awaiting merge upstream.
+Author: Steve Langasek <steve.langasek@ubuntu.com>
+
+Index: shim/netboot.c
+===================================================================
+--- shim.orig/netboot.c
++++ shim/netboot.c
+@@ -141,11 +141,11 @@
+       return rc;
+ }
+-static char *get_v6_bootfile_url(EFI_PXE_BASE_CODE_DHCPV6_PACKET *pkt)
++static CHAR8 *get_v6_bootfile_url(EFI_PXE_BASE_CODE_DHCPV6_PACKET *pkt)
+ {
+       void *optr;
+       EFI_DHCP6_PACKET_OPTION *option;
+-      char *url;
++      CHAR8 *url;
+       UINT32 urllen;
+       optr = pkt->DhcpOptions;
+@@ -159,10 +159,9 @@
+               if (ntohs(option->OpCode) == 59) {
+                       /* This is the bootfile url option */
+                       urllen = ntohs(option->Length);
+-                      url = AllocatePool(urllen+2);
++                      url = AllocateZeroPool(urllen+1);
+                       if (!url)
+                               return NULL;
+-                      memset(url, 0, urllen+2);
+                       memcpy(url, option->Data, urllen);
+                       return url;
+               }
+@@ -225,17 +224,17 @@
+         return (UINT8 *)ip;
+ }
+-static BOOLEAN extract_tftp_info(char *url)
++static BOOLEAN extract_tftp_info(CHAR8 *url)
+ {
+       CHAR8 *start, *end;
+-      char ip6str[128];
++      char ip6str[40];
+       CHAR8 *template = (CHAR8 *)"/grubx64.efi";
+       if (strncmp((UINT8 *)url, (UINT8 *)"tftp://", 7)) {
+               Print(L"URLS MUST START WITH tftp://\n");
+               return FALSE;
+       }
+-      start = (CHAR8 *)url + 7;
++      start = url + 7;
+       if (*start != '[') {
+               Print(L"TFTP SERVER MUST BE ENCLOSED IN [..]\n");
+               return FALSE;
+@@ -245,12 +244,16 @@
+       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, 128);
++      memset(ip6str, 0, 40);
+       memcpy(ip6str, start, end - start);
+       end++;
+       memcpy(&tftp_addr.v6, str2ip6(ip6str), 16);
+@@ -270,14 +273,16 @@
+ static EFI_STATUS parseDhcp6()
+ {
+       EFI_PXE_BASE_CODE_DHCPV6_PACKET *packet = (EFI_PXE_BASE_CODE_DHCPV6_PACKET *)&pxe->Mode->DhcpAck.Raw;
+-      char *bootfile_url;
+-
++      CHAR8 *bootfile_url;
+       bootfile_url = get_v6_bootfile_url(packet);
+-      if (extract_tftp_info(bootfile_url) == FALSE)
+-              return EFI_NOT_FOUND;
+       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;
+ }
+@@ -350,6 +355,8 @@
+               goto try_again;
+       }
++      if (rc != EFI_SUCCESS && *buffer) {
++              FreePool(*buffer);
++      }
+       return rc;
+-
+ }
index cd7c501248bd0605c192a743bc3b184fd48a1dcb..f37a5e398537e6dccfa50fe6b4592f90a87a97a2 100644 (file)
@@ -7,3 +7,4 @@ fix-tftp-prototype
 build-with-Werror
 fix-compiler-warnings
 tftp-proper-nul-termination
+netboot-cleanup
index 7345cfc5e8773e2e32bf576347c511faed831f6e..0a105d862c8de72489fae3b91ed19a33d0f35c07 100644 (file)
@@ -34,7 +34,7 @@ Index: shim/netboot.c
        memset(ip6str, 0, 128);
 -      memcpy(ip6str, start, strlen((UINT8 *)start));
 -      *end = ']';
-+      memcpy(ip6str, start, end + 1 - start);
++      memcpy(ip6str, start, end - start);
        end++;
        memcpy(&tftp_addr.v6, str2ip6(ip6str), 16);
 -      full_path = AllocatePool(strlen((UINT8 *)end)+strlen((UINT8 *)template)+1);
index e5433639d84f16c6b682c31f866c688dac9318fe..a8904fd86b5a05c38a42a0d79f626c998327cb56 100644 (file)
--- a/netboot.c
+++ b/netboot.c
@@ -141,11 +141,11 @@ try_again:
        return rc;
 }
 
-static char *get_v6_bootfile_url(EFI_PXE_BASE_CODE_DHCPV6_PACKET *pkt)
+static CHAR8 *get_v6_bootfile_url(EFI_PXE_BASE_CODE_DHCPV6_PACKET *pkt)
 {
        void *optr;
        EFI_DHCP6_PACKET_OPTION *option;
-       char *url;
+       CHAR8 *url;
        UINT32 urllen;
 
        optr = pkt->DhcpOptions;
@@ -159,10 +159,9 @@ static char *get_v6_bootfile_url(EFI_PXE_BASE_CODE_DHCPV6_PACKET *pkt)
                if (ntohs(option->OpCode) == 59) {
                        /* This is the bootfile url option */
                        urllen = ntohs(option->Length);
-                       url = AllocatePool(urllen+2);
+                       url = AllocateZeroPool(urllen+1);
                        if (!url)
                                return NULL;
-                       memset(url, 0, urllen+2);
                        memcpy(url, option->Data, urllen);
                        return url;
                }
@@ -225,17 +224,17 @@ static UINT8 *str2ip6(char *str)
         return (UINT8 *)ip;
 }
 
-static BOOLEAN extract_tftp_info(char *url)
+static BOOLEAN extract_tftp_info(CHAR8 *url)
 {
        CHAR8 *start, *end;
-       char ip6str[128];
+       char ip6str[40];
        CHAR8 *template = (CHAR8 *)"/grubx64.efi";
 
        if (strncmp((UINT8 *)url, (UINT8 *)"tftp://", 7)) {
                Print(L"URLS MUST START WITH tftp://\n");
                return FALSE;
        }
-       start = (CHAR8 *)url + 7;
+       start = url + 7;
        if (*start != '[') {
                Print(L"TFTP SERVER MUST BE ENCLOSED IN [..]\n");
                return FALSE;
@@ -245,12 +244,16 @@ static BOOLEAN extract_tftp_info(char *url)
        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, 128);
+       memset(ip6str, 0, 40);
        memcpy(ip6str, start, end - start);
        end++;
        memcpy(&tftp_addr.v6, str2ip6(ip6str), 16);
@@ -270,14 +273,16 @@ static BOOLEAN extract_tftp_info(char *url)
 static EFI_STATUS parseDhcp6()
 {
        EFI_PXE_BASE_CODE_DHCPV6_PACKET *packet = (EFI_PXE_BASE_CODE_DHCPV6_PACKET *)&pxe->Mode->DhcpAck.Raw;
-       char *bootfile_url;
-
+       CHAR8 *bootfile_url;
 
        bootfile_url = get_v6_bootfile_url(packet);
-       if (extract_tftp_info(bootfile_url) == FALSE)
-               return EFI_NOT_FOUND;
        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;
 }
 
@@ -350,6 +355,8 @@ try_again:
                goto try_again;
        }
 
+       if (rc != EFI_SUCCESS && *buffer) {
+               FreePool(*buffer);
+       }
        return rc;
-
 }