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

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