一、CFI简介
GCC的CFI(Control Flow Integrity,控制流完整性)机制是一种用于防止针对函数指针和虚函数表的攻击的保护机制。它通过在编译时对程序进行加固,限制了程序中可能的跳转目标,以提高程序运行时的安全性。下面将全面深入介绍GCC CFI机制的工作原理和实现方式:
1. 工作原理:
- 插入检查:GCC CFI机制通过在源代码的函数调用和间接跳转处插入检查来实现控制流完整性。这些检查用于验证函数指针和虚函数表的正确性,确保它们只会指向预期的目标函数。
- 检查目标函数:GCC CFI对所有间接函数调用进行检查,以确保调用的目标函数是有效的。这意味着每次进行间接函数调用时,都会执行一些额外的代码来验证目标函数的有效性。
- 限制跳转目标:GCC CFI限制了函数指针和虚函数表可以跳转的目标范围。每个函数指针和虚函数表都会被分配一个唯一的ID,跳转目标只能是具有相应ID的函数。
2. 实现方式:
- 基于Type Metadata:GCC CFI利用类型元数据来实现控制流完整性。在编译过程中,它会生成类型元数据并将其嵌入到生成的可执行文件中。类型元数据包含函数指针和虚函数表的类型信息,包括函数签名和返回类型等。在运行时,通过对比函数指针和虚函数表中的类型元数据,可以验证它们指向的目标是否是正确的。
- 插入检查:GCC CFI插入了一些额外的代码来进行控制流完整性的检查。在函数调用和间接跳转的代码中,会插入检查代码,用于验证目标函数的有效性。如果目标函数无效,将触发一个安全异常并采取相应的防护措施。
- 在链接时优化(Link-Time Optimization,LTO