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

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