Skip to content

fix signed-integer overflow in git_config_parse_int64() - #7344

Merged
ethomson merged 1 commit into
libgit2:mainfrom
yvonnelxxxx:fix/signed-int-overflow-config-parse-int64
Aug 12, 2026
Merged

fix signed-integer overflow in git_config_parse_int64()#7344
ethomson merged 1 commit into
libgit2:mainfrom
yvonnelxxxx:fix/signed-int-overflow-config-parse-int64

Conversation

@yvonnelxxxx

Copy link
Copy Markdown
Contributor

This PR attempts to fix #7343

Problem

git_config_parse_int64() in src/libgit2/config.c applies a k/m/g size suffix through a fallthrough switch that runs num *= 1024 up to three times with no overflow check:

// src/libgit2/config.c:1462-1476
switch (*num_end) {
case 'g':
case 'G':
    num *= 1024;          /* :1465 — no overflow check */
    /* fallthrough */
case 'm':
case 'M':
    num *= 1024;          /* :1470 — no overflow check */
    /* fallthrough */
case 'k':
case 'K':
    num *= 1024;          /* :1475 — no overflow check */
    ...
}

When an input parses cleanly as an int64_t but its suffix-scaled result exceeds INT64_MAX, this is signed-integer overflow (UB, flagged by UBSan), and — worse — the function falls through to *out = num; return 0;, returning success with a silently-wrapped garbage value:

src/libgit2/config.c:1475:7: runtime error: signed integer overflow:
54043195528445952 * 1024 cannot be represented in type 'int64_t' (aka 'long')
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior src/libgit2/config.c:1475:7

Fix

Gate each num *= 1024 on the existing git__multiply_int64_overflow helper — the same one git__strntol64 uses for digit accumulation — and bail to the existing fail_parse label on overflow:

// src/libgit2/config.c — git_config_parse_int64(), switch body

	switch (*num_end) {
	case 'g':
	case 'G':
		if (git__multiply_int64_overflow(&num, num, 1024))
			goto fail_parse;
		/* fallthrough */

	case 'm':
	case 'M':
		if (git__multiply_int64_overflow(&num, num, 1024))
			goto fail_parse;
		/* fallthrough */

	case 'k':
	case 'K':
		if (git__multiply_int64_overflow(&num, num, 1024))
			goto fail_parse;

		/* check that that there are no more characters after the
		 * given modifier suffix */
		if (num_end[1] != '\0')
			return -1;

		/* fallthrough */

	case '\0':
		*out = num;
		return 0;

	default:
		goto fail_parse;
	}

This uses the helper rather than a hand-rolled if (num > INT64_MAX / 1024) guard for two reasons:

  1. Negative values. Config values can be negative (-5gnum < 0). A positive-only INT64_MAX / 1024 bound would not catch INT64_MIN * 1024 underflow. git__multiply_int64_overflow is defined for the full signed range.
  2. Consistency. The digit-parsing half of this same function already uses these helpers; reusing them keeps one idiom and inherits the compiler-intrinsic / division-based fallback (src/util/integer.h) for free.

No new #include is needed — git__strntol64 is already called in this function, so the integer helpers are already in scope. Routing overflow through the existing fail_parse label keeps the error message consistent with other parse failures ("failed to parse '...' as an integer") and returns -1, exactly the documented "error code" outcome.

In-range values are unchanged; only the previously-UB cases now return -1. git_config_parse_int32 is fixed transitively.

input before after
1G ret=0, out=1073741824 ret=0, out=1073741824 (unchanged)
51539607552G ret=0, out=0 (UB, garbage) ret=-1 (error)
9223372036854775807G ret=0, out=-1073741824 (UB, garbage) ret=-1 (error)

Verification

Sanitizer rebuild

Rebuilt libgit2 with AddressSanitizer and UndefinedBehaviorSanitizer to confirm the overflow is gone:

export CC=clang CXX=clang++ LD=clang++
export CFLAGS="-fsanitize=address,undefined -fno-sanitize=function \
  -fsanitize-address-use-after-scope -g -O0 -fstandalone-debug -w -fPIC \
  -fno-inline -fno-omit-frame-pointer -fno-optimize-sibling-calls \
  -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION"
export CXXFLAGS="$CFLAGS" LDFLAGS="$CXXFLAGS"
cmake -S . -B build-san -DCMAKE_INSTALL_PREFIX="$PWD/build-sanitizer" \
  -DCMAKE_C_COMPILER="$CC" -DCMAKE_C_FLAGS="$CFLAGS" \
  -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DBUILD_SHARED_LIBS=OFF \
  -DBUILD_TESTS=OFF -DBUILD_BENCHMARKS=OFF -DBUILD_CLI=OFF \
  -DBUILD_EXAMPLES=OFF -DBUILD_FUZZERS=OFF \
  -DUSE_SSH=OFF -DUSE_HTTPS=OFF -DUSE_SHA1=builtin -DUSE_SHA256=builtin \
  -DUSE_HTTP_PARSER=builtin -DUSE_REGEX=builtin -DUSE_COMPRESSION=builtin
cmake --build build-san -j && cmake --install build-san

Before fix:

src/libgit2/config.c:1475:7: runtime error: signed integer overflow:
54043195528445952 * 1024 cannot be represented in type 'int64_t' (aka 'long')
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior src/libgit2/config.c:1475:7

After fix:

(clean exit, no sanitizer errors — git_config_parse_int64 returns -1 for the overflowing inputs)

Test-suite results

Ran the libgit2 test suite under ASan + UBSan with halt_on_error=1:

ASAN_OPTIONS=halt_on_error=1 UBSAN_OPTIONS=halt_on_error=1 \
  ctest --test-dir build-san --output-on-failure
Test Result
libgit2_clar (config parsing tests) Passed
libgit2_clar (full suite) Passed

All tests pass with the fix applied; existing in-range suffix behavior (1g, 512m, etc.) is unchanged.

@yvonnelxxxx yvonnelxxxx changed the title fix signed-int-overflow inconfig_parse_int64 fix signed-integer overflow in git_config_parse_int64() Aug 12, 2026
@ethomson

Copy link
Copy Markdown
Member

Thanks. This is one of the better AI generated bug reports so far, in terms of clarity, readability, and actionability.

@ethomson
ethomson merged commit b0057d0 into libgit2:main Aug 12, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Signed-integer overflow in git_config_parse_int64() suffix multiplier (k/m/g) — returns success with corrupted value

2 participants