Skip to content

Buffer Overflow (OOB Write/Read) in Hardware and Revision Parsing #407

Description

@mhansen

I found this while trying to figure out why I was getting errors when running under strict checks (#402). While this wasn't the cause of my errors, I think it's a real (separate) bug.

The /proc/cpuinfo parser in src/arm/linux/cpuinfo.c has a logic error when handling Hardware and Revision values that are equal to or longer than the maximum buffer size (CPUINFO_HARDWARE_VALUE_MAX and CPUINFO_REVISION_VALUE_MAX, both 64).

This leads to:

  1. Out-of-bounds write of 1 byte (null terminator) if the value length is exactly 64.
  2. Lack of null-termination (potentially leading to out-of-bounds reads later) if the value length is greater than 64.

Affected Code

In src/arm/linux/cpuinfo.c:

} else if (memcmp(line_start, "Hardware", key_length) == 0) {
size_t value_length = value_end - value_start;
if (value_length > CPUINFO_HARDWARE_VALUE_MAX) {
cpuinfo_log_warning(
"length of Hardware value \"%.*s\" in /proc/cpuinfo exceeds limit (%d): truncating to the limit",
(int)value_length,
value_start,
CPUINFO_HARDWARE_VALUE_MAX);
value_length = CPUINFO_HARDWARE_VALUE_MAX;
} else {
state->hardware[value_length] = '\0';
}
memcpy(state->hardware, value_start, value_length);

Scenario 1: value_length == 64 (equal to CPUINFO_HARDWARE_VALUE_MAX)

  • The if condition value_length > 64 is false.
  • The else branch is executed: state->hardware[64] = '\0';.
  • Since state->hardware is char hardware[64], index 64 is out of bounds (valid indices are 0-63). This is a 1-byte OOB write.

Scenario 2: value_length > 64 (e.g., 70)

  • The if condition is true.
  • value_length is truncated to 64.
  • The else branch is skipped, so no null terminator is written.
  • memcpy copies 64 bytes to state->hardware.
  • state->hardware is left non-null-terminated. If it is later read as a C-string, it will cause an OOB read.

The same logic error exists for the Revision field.

Suggested Fix

Check for value_length >= LIMIT. If so, truncate to LIMIT - 1 and warn. Always write the null terminator at value_length after truncation/copying.

--- a/src/arm/linux/cpuinfo.c
+++ b/src/arm/linux/cpuinfo.c
@@ -872,31 +873,29 @@
 				/* BogoMIPS is useless, don't parse */
 			} else if (memcmp(line_start, "Hardware", key_length) == 0) {
 				size_t value_length = value_end - value_start;
-				if (value_length > CPUINFO_HARDWARE_VALUE_MAX) {
+				if (value_length >= CPUINFO_HARDWARE_VALUE_MAX) {
 					cpuinfo_log_warning(
 						"length of Hardware value \"%.*s\" in /proc/cpuinfo exceeds limit (%d): truncating to the limit",
 						(int)value_length,
 						value_start,
-						CPUINFO_HARDWARE_VALUE_MAX);
-					value_length = CPUINFO_HARDWARE_VALUE_MAX;
-				} else {
-					state->hardware[value_length] = '\0';
+						CPUINFO_HARDWARE_VALUE_MAX - 1);
+					value_length = CPUINFO_HARDWARE_VALUE_MAX - 1;
 				}
+				state->hardware[value_length] = '\0';
 				memcpy(state->hardware, value_start, value_length);
 				cpuinfo_log_debug(
 					"parsed /proc/cpuinfo Hardware = \"%.*s\"", (int)value_length, value_start);
 			} else if (memcmp(line_start, "Revision", key_length) == 0) {
 				size_t value_length = value_end - value_start;
-				if (value_length > CPUINFO_REVISION_VALUE_MAX) {
+				if (value_length >= CPUINFO_REVISION_VALUE_MAX) {
 					cpuinfo_log_warning(
 						"length of Revision value \"%.*s\" in /proc/cpuinfo exceeds limit (%d): truncating to the limit",
 						(int)value_length,
 						value_start,
-						CPUINFO_REVISION_VALUE_MAX);
-					value_length = CPUINFO_REVISION_VALUE_MAX;
-				} else {
-					state->revision[value_length] = '\0';
+						CPUINFO_REVISION_VALUE_MAX - 1);
+					value_length = CPUINFO_REVISION_VALUE_MAX - 1;
 				}
+				state->revision[value_length] = '\0';
 				memcpy(state->revision, value_start, value_length);

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions