C++ coroutines prone to code-reuse attack despite control flow integrity

Celebrity Gig
CFOP: Hijacking C++ Coroutines. Credit: CISPA

A code-reuse attack named coroutine frame-oriented programming (CFOP) is capable of exploiting C++ coroutines across three major compilers, namely Clang/LLVM, GCC and MSVC. CFOP even succeeds in environments that are protected by control flow integrity (CFI), exposing relevant gaps in 15 of these defense schemes.

Rather than injecting new code, CFOP chains together existing functions, achieving arbitrary code execution after corrupting coroutine-internal memory structures. This new exploitation technique has been discovered by researchers at the CISPA Helmholtz Center for Information Security, who have been the first to study C++ coroutines from a security perspective.

Devising a novel code-reuse attack, CISPA-researchers Marcos Sanchez Bajo and Professor Dr. Christian Rossow have demonstrated that all existing implementations of C++ coroutines can be exploited to bypass state-of-the-art CFI protections in both Linux and Windows. Called coroutine frame-oriented programming (CFOP), the attack results in a corruption of heap memory, allowing attackers to manipulate data and assume complete control over applications.

A relatively recent addition to C++, coroutines are already present in more than 130 unique popular GitHub repositories. “They’re being used to pause and resume functions,” Bajo explains, “which is very useful for asynchronous programming, for example in servers, databases and web browsers.”

Connecting C++ coroutine functions to corrupt heap memory

In more concrete terms, coroutines can, for instance, be used to create generators that produce a sequence of elements. Imagine a Fibonacci series, where each new number in the series is the sum of the two numbers that have gone before. After each new number in the series, the coroutine is paused until it is called to generate the next one.

READ ALSO:  Ban left turns at intersections

In CFOP, entire C++ coroutines and other existing functions are used to create a code-reuse attack, as Bajo explains: “With code-reuse attacks in general, attackers take snippets of code that belong to the application anyway, so no new code is injected. They then form chains of these code snippets to manipulate the program’s execution flow. But bypassing CFI protections is a little more difficult. Instead of just taking snippets of code and creating chains, you have to take full coroutine functions and connect them in smart ways.”

Once the CFI protections are circumvented by hijacking a coroutine function in this manner, any other existing function can be submitted to a code-reuse attack.

CFI schemes fail to protect C++ coroutines

Introduced to protect against code-reuse attacks, CFI schemes ensure that the correct program execution flow is observed. Programming languages, however, evolve dynamically, while CFI schemes only protect the programming paradigms that were present at the time of their creation, as Bajo points out. “The main problem with CFI is that this defense is static in time, meaning that it only covers the possibilities of a programming language as is. If new features are introduced to the programming language later on, CFI does not recognize them and cannot deal with them because it was created based on an older version of the programming language.”

READ ALSO:  Grok 4's new AI companions offer 'pornographic productivity' for a price

In their study, Bajo and Rossow found that only 7 out of the 15 CFI schemes they considered initially were compatible with coroutines. Of these seven, only two (IBT and Control Flow Guard) provided partial protection against the exploitation of coroutines, while the remaining five provided none. “In the end,” Bajo says, “we were able to bypass all of them. With CFOP, you can still do all the things that were possible previous to CFI.”

Patching CFOP is a structural issue

The fact that C++ coroutines are enjoying increasing popularity exacerbates the potential reach of CFOP. Bajo says, “Coroutines were introduced to C++ in 2020 and, since then, developers have been using them more and more. Unfortunately, we found that coroutines have certain structures in memory that can be targeted by attackers. To the best of our knowledge, this has not yet been exploited in real life.”

READ ALSO:  Underwater exploration boosted with image enhancer

Essentially, CFOP is possible because the three major compilers implement C++ coroutines in a way that renders them structurally vulnerable. Bajo says, “Mitigating this exploitation technique is not as easy as patching the code—this is a structural issue and you need to rethink how the application works internally.”

Bajo and Rossow have developed successful implementation alternatives for C++ coroutines and reported these mitigations to Clang/LLVM, GCC and MSVC in November 2024. The CISPA research on CFOP will be presented at Black Hat USA 2025 in Las Vegas on August 7.

More information:
Marcos Sanchez Bajo et al, Await() a Second: Evading Control Flow Integrity by Hijacking C++ Coroutines, CISPA (2025). DOI: 10.60882/cispa.28718642.v1

Provided by
CISPA Helmholtz Center for Information Security

Citation:
C++ coroutines prone to code-reuse attack despite control flow integrity (2025, August 4)
retrieved 4 August 2025
from

This document is subject to copyright. Apart from any fair dealing for the purpose of private study or research, no
part may be reproduced without the written permission. The content is provided for information purposes only.

Categories

Share This Article
Leave a comment