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

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