diff options
| author | Steve Langasek <steve.langasek@canonical.com> | 2013-09-23 00:29:29 -0700 |
|---|---|---|
| committer | Steve Langasek <steve.langasek@canonical.com> | 2013-09-23 00:29:29 -0700 |
| commit | 84a3bbdf33245609abaa2b016ee336f397429d59 (patch) | |
| tree | 529e3b3ba6f68fb71c748c00aa48b2a02e7d5fb5 | |
| parent | 0c74470db4e4a5f1f06e72c7202730bfea8b5f8e (diff) | |
| download | efi-boot-shim-84a3bbdf33245609abaa2b016ee336f397429d59.tar.gz efi-boot-shim-84a3bbdf33245609abaa2b016ee336f397429d59.zip | |
debian/patches/netboot-cleanup: roll-up of miscellaneous fixes to
the netboot code.
| -rw-r--r-- | .pc/applied-patches | 1 | ||||
| -rw-r--r-- | .pc/netboot-cleanup/netboot.c | 355 | ||||
| -rw-r--r-- | debian/changelog | 2 | ||||
| -rw-r--r-- | debian/patches/netboot-cleanup | 106 | ||||
| -rw-r--r-- | debian/patches/series | 1 | ||||
| -rw-r--r-- | debian/patches/tftp-proper-nul-termination | 2 | ||||
| -rw-r--r-- | netboot.c | 33 |
7 files changed, 486 insertions, 14 deletions
diff --git a/.pc/applied-patches b/.pc/applied-patches index cd7c5012..f37a5e39 100644 --- a/.pc/applied-patches +++ b/.pc/applied-patches @@ -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 index 00000000..e5433639 --- /dev/null +++ b/.pc/netboot-cleanup/netboot.c @@ -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; + +} diff --git a/debian/changelog b/debian/changelog index 16791a50..33f1bee1 100644 --- a/debian/changelog +++ b/debian/changelog @@ -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 index 00000000..e94e2c7d --- /dev/null +++ b/debian/patches/netboot-cleanup @@ -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; +- + } diff --git a/debian/patches/series b/debian/patches/series index cd7c5012..f37a5e39 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -7,3 +7,4 @@ fix-tftp-prototype build-with-Werror fix-compiler-warnings tftp-proper-nul-termination +netboot-cleanup diff --git a/debian/patches/tftp-proper-nul-termination b/debian/patches/tftp-proper-nul-termination index 7345cfc5..0a105d86 100644 --- a/debian/patches/tftp-proper-nul-termination +++ b/debian/patches/tftp-proper-nul-termination @@ -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); @@ -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; - } |
