[go: up one dir, main page]

Skip to content

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:

  1. CMake processes a malformed CMakeLists.txt file containing foreach constructs
  2. The foreach command parser encounters syntax errors or malformed arguments
  3. The parser creates a foreach function blocker with an unexpected iteration variable count
  4. When ReplayItems is called, the assertion "Unexpected number of iteration variables" && this->IterationVarsCount == 1 fails
  5. 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

  1. Compile CMake with debug assertions enabled (or use the provided binary)
  2. Execute: cmake -P POC_cmake_foreach_assertion_failure
  3. 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)
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information