efi/http: Enclose literal IPv6 addresses in square brackets
authorJavier Martinez Canillas <javierm@redhat.com>
Mon, 9 Jan 2023 23:30:42 +0000 (18:30 -0500)
committerFelix Zielcke <fzielcke@z-51.de>
Wed, 11 Jun 2025 15:42:34 +0000 (17:42 +0200)
According to RFC 2732 (https://www.ietf.org/rfc/rfc2732.txt), literal IPv6
addresses must be enclosed in square brackets. But GRUB currently does not
do this and is causing HTTP servers to send Bad Request (400) responses.

For example, the following is the HTTP stream when fetching a config file:

HEAD /EFI/BOOT/grub.cfg HTTP/1.1
Host: 2000:dead:beef:a::1
Accept: */*
User-Agent: UefiHttpBoot/1.0

HTTP/1.1 400 Bad Request
Date: Thu, 05 Mar 2020 14:46:02 GMT
Server: Apache/2.4.41 (Fedora) OpenSSL/1.1.1d
Connection: close
Content-Type: text/html; charset=iso-8859-1

and after enclosing the IPv6 address the HTTP request is successful:

HEAD /EFI/BOOT/grub.cfg HTTP/1.1
Host: [2000:dead:beef:a::1]
Accept: */*
User-Agent: UefiHttpBoot/1.0

HTTP/1.1 200 OK
Date: Thu, 05 Mar 2020 14:48:04 GMT
Server: Apache/2.4.41 (Fedora) OpenSSL/1.1.1d
Last-Modified: Thu, 27 Feb 2020 17:45:58 GMT
ETag: "206-59f924b24b1da"
Accept-Ranges: bytes
Content-Length: 518

Resolves: rhbz#1732765

Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
Gbp-Pq: Topic network
Gbp-Pq: Name efi-http-enclose-literal-ipv6-addresses-in-square-br.patch

grub-core/net/efi/http.c

index c739392d0cd66af9d7c8f74d83e83afdaa16d9d2..22d135209084400718023adf0b85ccf6e25be839 100644 (file)
@@ -147,13 +147,7 @@ efihttp_request (grub_efi_http_t *http, char *server, char *name, int use_https,
   grub_efi_status_t status;
   grub_efi_boot_services_t *b = grub_efi_system_table->boot_services;
   char *url = NULL;
-
-  request_headers[0].field_name = (grub_efi_char8_t *) "Host";
-  request_headers[0].field_value = (grub_efi_char8_t *) server;
-  request_headers[1].field_name = (grub_efi_char8_t *) "Accept";
-  request_headers[1].field_value = (grub_efi_char8_t *) "*/*";
-  request_headers[2].field_name = (grub_efi_char8_t *) "User-Agent";
-  request_headers[2].field_value = (grub_efi_char8_t *) "UefiHttpBoot/1.0";
+  char *hostname = NULL;
 
   {
     grub_efi_ipv6_address_t address;
@@ -163,9 +157,24 @@ efihttp_request (grub_efi_http_t *http, char *server, char *name, int use_https,
     const char *protocol = (use_https == 1) ? "https" : "http";
 
     if (grub_efi_string_to_ip6_address (server, &address, &rest) && *rest == 0)
-      url = grub_xasprintf ("%s://[%s]%s", protocol, server, name);
+      {
+        hostname = grub_xasprintf ("[%s]", server);
+        if (!hostname)
+          return GRUB_ERR_OUT_OF_MEMORY;
+
+        server = hostname;
+
+        url = grub_xasprintf ("%s://%s%s", protocol, server, name);
+        if (!url)
+          {
+            grub_free (hostname);
+            return GRUB_ERR_OUT_OF_MEMORY;
+          }
+      }
     else
-      url = grub_xasprintf ("%s://%s%s", protocol, server, name);
+      {
+        url = grub_xasprintf ("%s://%s%s", protocol, server, name);
+      }
 
     if (!url)
       {
@@ -190,6 +199,13 @@ efihttp_request (grub_efi_http_t *http, char *server, char *name, int use_https,
     request_data.url = ucs2_url;
   }
 
+  request_headers[0].field_name = (grub_efi_char8_t *) "Host";
+  request_headers[0].field_value = (grub_efi_char8_t *) server;
+  request_headers[1].field_name = (grub_efi_char8_t *) "Accept";
+  request_headers[1].field_value = (grub_efi_char8_t *) "*/*";
+  request_headers[2].field_name = (grub_efi_char8_t *) "User-Agent";
+  request_headers[2].field_value = (grub_efi_char8_t *) "UefiHttpBoot/1.0";
+
   request_data.method = (headeronly > 0) ? GRUB_EFI_HTTPMETHODHEAD : GRUB_EFI_HTTPMETHODGET;
 
   request_message.data.request = &request_data;
@@ -218,6 +234,9 @@ efihttp_request (grub_efi_http_t *http, char *server, char *name, int use_https,
 
   status = http->request (http, &request_token);
 
+  if (hostname)
+    grub_free (hostname);
+
   if (status != GRUB_EFI_SUCCESS)
     {
       b->close_event (request_token.event);