c++ shadow stack c++ intel cet如何防范rop攻击

风晨君_7162

风晨君_7162

2026-03-24

711人浏览

原创

intel cet 的 shadow stack 是硬件强制的只写独立栈,专存返回地址,cpu 执行 ret 时校验主栈与 shadow stack 顶部地址一致性,不一致则触发 #cp 异常;它仅防护函数返回路径,不防 jmp/call/间接跳转、堆 rop 或 jit spray。

c++ shadow stack c++ intel cet如何防范rop攻击

Intel CET 的 shadow stack 是什么,它真能拦住 ROP?

它不是万能盾牌,但确实是目前 x86_64 上最实用的 ROP 缓解机制之一。CET 的 shadow stack(影子栈)通过硬件强制维护一个只写、只用于存返回地址的独立栈,让攻击者无法用常规栈溢出篡改 ret 指令要跳转的目标——因为 CPU 在执行 ret 时会同时校验主栈和 shadow stack 顶部的地址是否一致,不一致就触发 #CP 异常。

注意:它只保护「函数返回」这一跳转路径,对 jmp、call、间接跳转(如 jmp rax)完全不设防;也不防堆上构造的 ROP 链或 JIT spray。所以别把它当成“开了就安全”的开关。

启用 CET shadow stack 需要哪些编译+链接步骤?

必须全链路配合:源码编译、链接、运行时加载都得支持,缺一不可。常见漏掉的是链接器没加 --shstk 或没启用 -fcf-protection=full。

  • 编译时加 -fcf-protection=full(GCC/Clang),这会插入 endbr64 指令并为每个函数生成 shadow stack 同步逻辑
  • 链接时加 -Wl,-z,shstk(告诉链接器生成含 CET 元数据的 ELF)
  • 可选但推荐:加 -mshstk(显式启用 shadow stack 指令支持,避免某些旧 binutils 报错)
  • 运行前确认内核支持:cat /proc/cpuinfo | grep cet_report 有输出,且 sysctl kernel.unprivileged_userfaultfd 不影响 CET(它不依赖 userfaultfd)

为什么开了 CET 还 crash 在 __cet_report_failure?

这不是 bug,是 CET 正常拦截到非法返回行为后调用的终止函数。常见原因有三类:

  • 手写汇编里用了 ret 但没同步更新 shadow stack(比如 inline asm 中直接 pop %rax; ret)
  • 异常处理流程绕过了编译器生成的 shadow stack 恢复逻辑(如 longjmp、setjmp 跨 CET 编译模块时未统一启用)
  • 第三方库(尤其闭源或静态链接的老库)没编译 CET 支持,它的函数返回时 shadow stack 和主栈不匹配

查问题最快方式:用 gdb 断在 __cet_report_failure,看 $rsp 和 $r15(shadow stack pointer,默认由内核设为 0x7ffffffff000 附近)的值差异,再回溯调用栈里哪个函数没走编译器生成的 shstk 入口/出口序列。

C++ Code Review Master
C++ Code Review Master

组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。

下载

C++ 对象生命周期和异常会不会破坏 shadow stack?

标准 C++ 异常机制本身不破坏 shadow stack,但前提是整个调用链(包括 libstdc++ 或 libc++)都用 -fcf-protection=full 编译。否则 throw/catch 过程中某一层调用的 runtime 函数(如 __cxa_throw)若没 CET 支持,就会导致 shadow stack 失步。

更隐蔽的问题是 RAII + 栈展开混合场景:如果析构函数里调用了未启用 CET 的回调函数(比如通过 std::function 绑定的裸函数指针),而该函数又执行了 ret,那它不会做 shadow stack 同步——因为编译器不知道这个函数需要保护。

建议:所有参与异常传播路径的代码(包括 STL 实现、自定义分配器、回调注册点)统一开启 CET;避免在析构函数里调用不可控的外部 C 接口。

复杂点在于,CET 的 shadow stack 是 per-thread 的,且由内核在 clone 时初始化。如果你用 pthread_create 创建线程但没链接 -lpthread(或用 musl libc),某些场景下 shadow stack pointer 可能没被正确设置,导致线程一执行 ret 就崩——这种问题只能靠 strace -e clone,arch_prctl 观察系统调用流来定位。

C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!

相关文章

c++速学教程(入门到精通)
c++速学教程(入门到精通)

c++怎么学习?c++怎么入门?c++在哪学?c++怎么学才快?不用担心,这里为大家提供了c++速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

c++

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
C++ 智能指针与现代内存管理
C++ 智能指针与现代内存管理

深入讲解 C++ 现代内存管理的核心工具——智能指针,涵盖 unique_ptr 独占所有权语义、shared_ptr 引用计数机制与循环引用问题、weak_ptr 弱引用的应用场景、make_unique/make_shared 工厂函数的性能优势、自定义删除器的编写、RAII 资源管理思想的实践,以及从裸指针迁移到智能指针的重构策略,帮助开发者编写安全无泄漏的现代 C++ 代码。

2026.04.23

339

31

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

2023.10.19

3088

3

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

2025.10.17

4609

12

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2025.12.29

3729

9

java接口相关教程
java接口相关教程

本专题整合了java接口相关内容,阅读专题下面的文章了解更多详细内容。

2026.01.19

426

15

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

2023.07.18

5267

5

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

2023.08.10

2328

6

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

2023.07.18

5267

5

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

2023.08.10

2328

6

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Conan 2 Essentials 免费课程
Conan 2 Essentials 免费课程

共0课时 | 0人学习

CMake 与 Conan 集成实践
CMake 与 Conan 集成实践

共0课时 | 0人学习

Conan 2 高级依赖模型介绍
Conan 2 高级依赖模型介绍

共0课时 | 0人学习