Blame SOURCES/0044-translate_slashes-don-t-write-to-string-literals.patch

00e791
From c6bedd5b83529925c3ec08f96a3bf61c81bff0ae Mon Sep 17 00:00:00 2001
00e791
From: Laszlo Ersek <lersek@redhat.com>
00e791
Date: Tue, 28 Jan 2020 23:33:46 +0100
00e791
Subject: [PATCH 44/62] translate_slashes(): don't write to string literals
00e791
00e791
Currently, all three invocations of the translate_slashes() function may
00e791
lead to writes to the string literal that is #defined with the
00e791
DEFAULT_LOADER_CHAR macro. According to ISO C99 6.4.5p6, this is undefined
00e791
behavior ("If the program attempts to modify such an array, the behavior
00e791
is undefined").
00e791
00e791
This bug crashes shim on e.g. the 64-bit ArmVirtQemu platform ("Data
00e791
abort: Permission fault"), where the platform firmware maps the .text
00e791
section (which contains the string literal) read-only.
00e791
00e791
Modify translate_slashes() so that it copies and translates characters
00e791
from an input array of "char" to an output array of "CHAR8".
00e791
00e791
While at it, fix another bug. Before this patch, if translate_slashes()
00e791
ever encountered a double backslash (translating it to a single forward
00e791
slash), then the output would end up shorter than the input. However, the
00e791
output was not NUL-terminated in-place, therefore the original string
00e791
length (and according trailing garbage) would be preserved. After this
00e791
patch, the NUL-termination on contraction is automatic, as the output
00e791
array's contents are indeterminate when entering the function, and so we
00e791
must NUL-terminate it anyway.
00e791
00e791
Fixes: 8e9124227d18475d3bc634c33518963fc8db7c98
00e791
Fixes: e62b69a5b0b87c6df7a4fc23906134945309e927
00e791
Fixes: 3d79bcb2651b9eae809b975b3e03e2f96c067072
00e791
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1795654
00e791
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
00e791
Upstream-commit-id: 9813e8bc8b3
00e791
---
00e791
 httpboot.c    |  4 ++--
00e791
 netboot.c     | 16 +++++++++++-----
00e791
 include/str.h | 14 ++++++++------
00e791
 3 files changed, 21 insertions(+), 13 deletions(-)
00e791
00e791
diff --git a/httpboot.c b/httpboot.c
00e791
index 3622e85867c..2d27e8ed993 100644
00e791
--- a/httpboot.c
00e791
+++ b/httpboot.c
00e791
@@ -743,14 +743,14 @@ httpboot_fetch_buffer (EFI_HANDLE image, VOID **buffer, UINT64 *buf_size)
00e791
 {
00e791
 	EFI_STATUS efi_status;
00e791
 	EFI_HANDLE nic;
00e791
-	CHAR8 *next_loader = NULL;
00e791
+	CHAR8 next_loader[sizeof DEFAULT_LOADER_CHAR];
00e791
 	CHAR8 *next_uri = NULL;
00e791
 	CHAR8 *hostname = NULL;
00e791
 
00e791
 	if (!uri)
00e791
 		return EFI_NOT_READY;
00e791
 
00e791
-	next_loader = translate_slashes(DEFAULT_LOADER_CHAR);
00e791
+	translate_slashes(next_loader, DEFAULT_LOADER_CHAR);
00e791
 
00e791
 	/* Create the URI for the next loader based on the original URI */
00e791
 	efi_status = generate_next_uri(uri, next_loader, &next_uri);
00e791
diff --git a/netboot.c b/netboot.c
00e791
index 58babfb4d2e..4922ef284b1 100644
00e791
--- a/netboot.c
00e791
+++ b/netboot.c
00e791
@@ -189,7 +189,9 @@ static BOOLEAN extract_tftp_info(CHAR8 *url)
00e791
 	CHAR8 *start, *end;
00e791
 	CHAR8 ip6str[40];
00e791
 	CHAR8 ip6inv[16];
00e791
-	CHAR8 *template = (CHAR8 *)translate_slashes(DEFAULT_LOADER_CHAR);
00e791
+	CHAR8 template[sizeof DEFAULT_LOADER_CHAR];
00e791
+
00e791
+	translate_slashes(template, DEFAULT_LOADER_CHAR);
00e791
 
00e791
 	// to check against str2ip6() errors
00e791
 	memset(ip6inv, 0, sizeof(ip6inv));
00e791
@@ -254,10 +256,14 @@ static EFI_STATUS parseDhcp6()
00e791
 
00e791
 static EFI_STATUS parseDhcp4()
00e791
 {
00e791
-	CHAR8 *template = (CHAR8 *)translate_slashes(DEFAULT_LOADER_CHAR);
00e791
-	INTN template_len = strlen(template) + 1;
00e791
+	CHAR8 template[sizeof DEFAULT_LOADER_CHAR];
00e791
+	INTN template_len;
00e791
+	UINTN template_ofs = 0;
00e791
 	EFI_PXE_BASE_CODE_DHCPV4_PACKET* pkt_v4 = (EFI_PXE_BASE_CODE_DHCPV4_PACKET *)&pxe->Mode->DhcpAck.Dhcpv4;
00e791
 
00e791
+	translate_slashes(template, DEFAULT_LOADER_CHAR);
00e791
+	template_len = strlen(template) + 1;
00e791
+
00e791
 	if(pxe->Mode->ProxyOfferReceived) {
00e791
 		/*
00e791
 		 * Proxy should not have precedence.  Check if DhcpAck
00e791
@@ -288,8 +294,8 @@ static EFI_STATUS parseDhcp4()
00e791
 			full_path[dir_len-1] = '\0';
00e791
 	}
00e791
 	if (dir_len == 0 && dir[0] != '/' && template[0] == '/')
00e791
-		template++;
00e791
-	strcata(full_path, template);
00e791
+		template_ofs++;
00e791
+	strcata(full_path, template + template_ofs);
00e791
 	memcpy(&tftp_addr.v4, pkt_v4->BootpSiAddr, 4);
00e791
 
00e791
 	return EFI_SUCCESS;
00e791
diff --git a/include/str.h b/include/str.h
00e791
index 9a748366bd1..f73c6212cd9 100644
00e791
--- a/include/str.h
00e791
+++ b/include/str.h
00e791
@@ -45,21 +45,23 @@ strcata(CHAR8 *dest, const CHAR8 *src)
00e791
 static inline
00e791
 __attribute__((unused))
00e791
 CHAR8 *
00e791
-translate_slashes(char *str)
00e791
+translate_slashes(CHAR8 *out, const char *str)
00e791
 {
00e791
 	int i;
00e791
 	int j;
00e791
-	if (str == NULL)
00e791
-		return (CHAR8 *)str;
00e791
+	if (str == NULL || out == NULL)
00e791
+		return NULL;
00e791
 
00e791
 	for (i = 0, j = 0; str[i] != '\0'; i++, j++) {
00e791
 		if (str[i] == '\\') {
00e791
-			str[j] = '/';
00e791
+			out[j] = '/';
00e791
 			if (str[i+1] == '\\')
00e791
 				i++;
00e791
-		}
00e791
+		} else
00e791
+			out[j] = str[i];
00e791
 	}
00e791
-	return (CHAR8 *)str;
00e791
+	out[j] = '\0';
00e791
+	return out;
00e791
 }
00e791
 
00e791
 #endif /* SHIM_STR_H */
00e791
-- 
00e791
2.26.2
00e791