From 2fb126eef436389a2dc48d4225b4a9888b0625a8 Mon Sep 17 00:00:00 2001
From: Jean Delvare <jdelvare@suse.de>
Date: Tue, 27 Jun 2023 10:58:11 +0000
Subject: [PATCH 5/5] Don't read beyond sysfs entry point buffer

Functions smbios_decode() and smbios3_decode() include a check
against buffer overrun. This check assumes that the buffer length is
always 32 bytes. This is true when reading from /dev/mem or from a
dump file, however when reading from sysfs, the buffer length is the
size of the actual sysfs attribute file, typically 31 bytes for an
SMBIOS 2.x entry point and 24 bytes for an SMBIOS 3.x entry point.

In the unlikely event of a malformed entry point, with encoded length
larger than expected but smaller than or equal to 32, we would hit a
buffer overrun. So properly pass the actual buffer length as an
argument and perform the check against it.

In practice, this will never happen, because on the Linux kernel
side, the size of the sysfs attribute file is decided from the entry
point length field. So it is technically impossible for them not to
match. But user-space code should not make such assumptions.

Signed-off-by: Jean Delvare <jdelvare@suse.de>

CVE: CVE-2023-30630

Upstream-Status: Backport
[https://git.savannah.nongnu.org/cgit/dmidecode.git/commit/?id=2b83c4b898f8325313162f588765411e8e3e5561]

Signed-off-by: Yogita Urade <yogita.urade@windriver.com>
---
 dmidecode.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/dmidecode.c b/dmidecode.c
index 9a691e0..e725801 100644
--- a/dmidecode.c
+++ b/dmidecode.c
@@ -5398,14 +5398,14 @@ static void overwrite_smbios3_address(u8 *buf)
 	buf[0x17] = 0;
 }
 
-static int smbios3_decode(u8 *buf, const char *devmem, u32 flags)
+static int smbios3_decode(u8 *buf, size_t buf_len, const char *devmem, u32 flags)
 {
 	u32 ver, len;
 	u64 offset;
 	u8 *table;
 
 	/* Don't let checksum run beyond the buffer */
-	if (buf[0x06] > 0x20)
+        if (buf[0x06] > buf_len)
 	{
 		fprintf(stderr,
 			"Entry point length too large (%u bytes, expected %u).\n",
@@ -5455,14 +5455,14 @@ static int smbios3_decode(u8 *buf, const char *devmem, u32 flags)
 	return 1;
 }
 
-static int smbios_decode(u8 *buf, const char *devmem, u32 flags)
+static int smbios_decode(u8 *buf, size_t buf_len, const char *devmem, u32 flags)
 {
 	u16 ver, num;
 	u32 len;
 	u8 *table;
 
 	/* Don't let checksum run beyond the buffer */
-	if (buf[0x05] > 0x20)
+        if (buf[0x05] > buf_len)
 	{
 		fprintf(stderr,
 			"Entry point length too large (%u bytes, expected %u).\n",
@@ -5714,12 +5714,12 @@ int main(int argc, char * const argv[])
 
 		if (memcmp(buf, "_SM3_", 5) == 0)
 		{
-			if (smbios3_decode(buf, opt.dumpfile, 0))
+                        if (smbios3_decode(buf, size, opt.dumpfile, 0))
 				found++;
 		}
 		else if (memcmp(buf, "_SM_", 4) == 0)
 		{
-			if (smbios_decode(buf, opt.dumpfile, 0))
+                        if (smbios_decode(buf, size, opt.dumpfile, 0))
 				found++;
 		}
 		else if (memcmp(buf, "_DMI_", 5) == 0)
@@ -5742,12 +5742,12 @@ int main(int argc, char * const argv[])
 			pr_info("Getting SMBIOS data from sysfs.");
 		if (size >= 24 && memcmp(buf, "_SM3_", 5) == 0)
 		{
-			if (smbios3_decode(buf, SYS_TABLE_FILE, FLAG_NO_FILE_OFFSET))
+                        if (smbios3_decode(buf, size, SYS_TABLE_FILE, FLAG_NO_FILE_OFFSET))
 				found++;
 		}
 		else if (size >= 31 && memcmp(buf, "_SM_", 4) == 0)
 		{
-			if (smbios_decode(buf, SYS_TABLE_FILE, FLAG_NO_FILE_OFFSET))
+                        if (smbios_decode(buf, size, SYS_TABLE_FILE, FLAG_NO_FILE_OFFSET))
 				found++;
 		}
 		else if (size >= 15 && memcmp(buf, "_DMI_", 5) == 0)
@@ -5784,12 +5784,12 @@ int main(int argc, char * const argv[])
 
 	if (memcmp(buf, "_SM3_", 5) == 0)
 	{
-		if (smbios3_decode(buf, opt.devmem, 0))
+                if (smbios3_decode(buf, 0x20, opt.devmem, 0))
 			found++;
 	}
 	else if (memcmp(buf, "_SM_", 4) == 0)
 	{
-		if (smbios_decode(buf, opt.devmem, 0))
+                if (smbios_decode(buf, 0x20, opt.devmem, 0))
 			found++;
 	}
 	goto done;
@@ -5810,7 +5810,7 @@ memory_scan:
 	{
 		if (memcmp(buf + fp, "_SM3_", 5) == 0)
 		{
-			if (smbios3_decode(buf + fp, opt.devmem, 0))
+                        if (smbios3_decode(buf + fp, 0x20, opt.devmem, 0))
 			{
 				found++;
 				goto done;
@@ -5823,7 +5823,7 @@ memory_scan:
 	{
 		if (memcmp(buf + fp, "_SM_", 4) == 0 && fp <= 0xFFE0)
 		{
-			if (smbios_decode(buf + fp, opt.devmem, 0))
+                        if (smbios_decode(buf + fp, 0x20, opt.devmem, 0))
 			{
 				found++;
 				goto done;
-- 
2.41.0

