foreach: assertion failure on trailing IN
Summary
During fuzzing of CMake, a critical assertion failure vulnerability was discovered in the CMake foreach command processing. The vulnerability occurs in the cmForEachFunctionBlocker::ReplayItems
function within cmForEachCommand.cxx
at line 112, where an assertion check fails due to unexpected iteration variable count, leading to program termination via SIGABRT
.
Technical Details
- Vulnerability Type: Assertion Failure
-
Affected Function:
cmForEachFunctionBlocker::ReplayItems
-
Source File:
cmForEachCommand.cxx
- Line Number: 112
- Signal: SIGABRT (6)
- Component: CMake Core
Mechanism and Root Cause
This assertion failure vulnerability is caused by improper validation of iteration variable counts in the foreach command processing logic. The root issue lies in the cmForEachFunctionBlocker::ReplayItems
function where the assertion expects exactly one iteration variable but encounters a different count.
The vulnerability occurs when:
- CMake processes a malformed CMakeLists.txt file containing foreach constructs
- The foreach command parser encounters syntax errors or malformed arguments
- The parser creates a foreach function blocker with an unexpected iteration variable count
- When
ReplayItems
is called, the assertion"Unexpected number of iteration variables" && this->IterationVarsCount == 1
fails - The program terminates immediately with SIGABRT
This creates a denial of service condition where CMake cannot process the input file and crashes with an assertion failure. The vulnerability affects CMake's ability to parse and process CMakeLists.txt files containing malformed foreach constructs.
GDB Debug Report
Program received signal SIGABRT, Aborted.
__pthread_kill_implementation (no_tid=0, signo=6, threadid=140737348078528) at ./nptl/pthread_kill.c:44
#0 __pthread_kill_implementation (no_tid=0, signo=6, threadid=140737348078528) at ./nptl/pthread_kill.c:44
#1 __pthread_kill_internal (signo=6, threadid=140737348078528) at ./nptl/pthread_kill.c:78
#2 __GI___pthread_kill (threadid=140737348078528, signo=signo@entry=6) at ./nptl/pthread_kill.c:89
#3 0x00007ffff7a7f476 in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
#4 0x00007ffff7a657f3 in __GI_abort () at ./stdlib/abort.c:79
#5 0x00007ffff7a6571b in __assert_fail_base (fmt=0x7ffff7c1a130 "%s%s%s:%u: %s%sAssertion `%s' failed.\n%n", assertion=0x5555557dbb80 <str.32> "\"Unexpected number of iteration variables\" && this->IterationVarsCount == 1", file=0x5555557db540 <str.8> "/workspace/program/cmake-4.1.20250725-gb5cce23/Source/cmForEachCommand.cxx", line=112, function=<optimized out>) at ./assert/assert.c:94
#6 0x00007ffff7a76e96 in __GI___assert_fail (assertion=0x5555557dbb80 <str.32> "\"Unexpected number of iteration variables\" && this->IterationVarsCount == 1", file=0x5555557db540 <str.8> "/workspace/program/cmake-4.1.20250725-gb5cce23/Source/cmForEachCommand.cxx", line=112, function=0x5555557dbc00 <__PRETTY_FUNCTION__._ZN12_GLOBAL__N_124cmForEachFunctionBlocker11ReplayItemsERKSt6vectorI18cmListFileFunctionSaIS2_EER17cmExecutionStatus> "bool (anonymous namespace)::cmForEachFunctionBlocker::ReplayItems(const std::vector<cmListFileFunction> &, cmExecutionStatus &)") at ./assert/assert.c:103
#7 0x00005555563aaa06 in (anonymous namespace)::cmForEachFunctionBlocker::ReplayItems (this=0x611000002ac0, functions=std::vector of length 8, capacity 8 = {...}, inStatus=...) at /workspace/program/cmake-4.1.20250725-gb5cce23/Source/cmForEachCommand.cxx:111
#8 (anonymous namespace)::cmForEachFunctionBlocker::Replay (this=0x611000002ac0, functions=std::vector of length -6648609374956, capacity -6648609374956 = {...}, inStatus=...) at /workspace/program/cmake-4.1.20250725-gb5cce23/Source/cmForEachCommand.cxx:104
#9 0x00005555563be471 in cmFunctionBlocker::IsFunctionBlocked (this=<optimized out>, lff=..., status=...) at /workspace/program/cmake-4.1.20250725-gb5cce23/Source/cmFunctionBlocker.cxx:52
#10 0x0000555556e3a3b4 in cmMakefile::IsFunctionBlocked (this=0x7ffff6007160, lff=..., status=...) at /workspace/program/cmake-4.1.20250725-gb5cce23/Source/cmMakefile.cxx:2896
#11 cmMakefile::ExecuteCommand (this=0x7ffff6007160, lff=..., status=..., deferId=std::optional<std::string> = {...}) at /workspace/program/cmake-4.1.20250725-gb5cce23/Source/cmMakefile.cxx:542
#12 0x0000555556e494e2 in cmMakefile::RunListFile (this=0x7ffff6007160, listFile=..., filenametoread=..., defer=<optimized out>) at /workspace/program/cmake-4.1.20250725-gb5cce23/Source/cmMakefile.cxx:869
#13 0x0000555556e50723 in cmMakefile::ReadListFile (this=0x7ffff6007160, filename="POC_cmake_foreach_assertion_failure") at /workspace/program/cmake-4.1.20250725-gb5cce23/Source/cmMakefile.cxx:823
#14 0x00005555573fa78b in cmake::ReadListFile (this=<optimized out>, args=..., path=...) at /workspace/program/cmake-4.1.20250725-gb5cce23/Source/cmake.cxx:811
#15 0x00005555573e0e35 in cmake::SetCacheArgs(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&)::$_3::operator()(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, cmake*) const (this=0x619000009908, path="POC_cmake_foreach_assertion_failure", state=0x7ffff6201bd0) at /workspace/program/cmake-4.1.20250725-gb5cce23/Source/cmake.cxx:666
cmake: /workspace/program/cmake-4.1.20250725-gb5cce23/Source/cmForEachCommand.cxx:112: bool (anonymous namespace)::cmForEachFunctionBlocker::ReplayItems(const std::vector<cmListFileFunction> &, cmExecutionStatus &): Assertion `"Unexpected number of iteration variables" && this->IterationVarsCount == 1' failed.
Proof of Concept
The vulnerability can be triggered by processing the malformed CMakeLists.txt file provided as POC_cmake_foreach_assertion_failure
. This file contains specific foreach constructs with malformed syntax that cause the assertion failure.
POC Download: POC_cmake_foreach_assertion_failure
Reproduction Steps
- Compile CMake with debug assertions enabled (or use the provided binary)
- Execute:
cmake -P POC_cmake_foreach_assertion_failure
- The program will crash with an assertion failure at cmForEachCommand.cxx:112
Affected Versions
CMake version 4.1.20250725-gb5cce23 and potentially other recent versions of the 4.x series.
Credit
- Xudong Cao (UCAS)
- Meng Xu (UW)