Linux Kernel CFI机制简介及测试禁用
PS:要转载请注明出处,本人版权所有。
PS: 这个只是基于《我自己》的理解,
如果和你的原则及想法相冲突,请谅解,勿喷。
环境说明
无
前言
当我们为android移植linux的驱动程序的时候,总会遇到一些错误,这些错误有一部分就是android 内核开启的安全的机制导致的。本文就会介绍一种内核的安全机制:Kernel Control Flow Integrity(kCFI)。
此外,这里还要说明一下,Control Flow Integrity(CFI)与 Kernel Control Flow Integrity(kCFI)是不一样的,kCFI只检查函数指针,CFI还具备其他很多的检查,详情请参考:https://clang.llvm.org/docs/ControlFlowIntegrity.html 。
Kernel Control Flow Integrity(kCFI)原理简单介绍
Control Flow Integrity的翻译是控制流完整性,从直译来看,其实就是用一些方法保证来保证我们的指令执行到正确的位置。我们从clang官方文档知道,kCFI只检查函数指针,那么其实kCFI就是保证函数指针跳转到正确的位置,并且返回到正确的位置。
从这里来看,其实我们可以看到对于函数指针来说,我们需要保护两个地方:跳转到正确的位置、返回到正确的位置。这两个地方有两个专有名词:
- forward-edge
- backward-edge
此外,我们还应该知道,在编写代码的时候,分为直接函数调用(direct function call),间接函数调用(indirect function call)。他们的示例如下:
void target(void)
{
//... ...
}
typedef void(*fn)(void);
int main(int argc, char * argv[])
{
// direct function call
target();
//indirect function call
fn _id_fn = target;
_id_fn();
}
从示例可以知道,indirect function call其实就是函数指针这种调用形式。
此外,我们还要知道,如果我们想破坏代码的执行流,那么我们必须在可写、可读、可执行的内存里面写入shellcode,并跳转到这个shellcode,否则我们的代码是无法工作的。那么显而易见的事情是,通过函数指针来调用函数,我们的目标是明确的,因此我们可以校验这些目标的原型、地址等等信息。
因为我们需要验证目标的原型、地址等等信息,所以,当我们在生成可执行文件的时候,需要知道所有的函数目标的信息,这个时候,就需要一个叫做Link Time Optimization(LTO)的功能,因为只有最终可执行文件链接时,才知道所有的函数目标信息。
kCFI演示示例
首先在qemu中运行一个arm64的linux模拟器,然后为linux内核配置如下内核选项:
# General architecture-dependent options -> LTO
CONFIG_CFI_CLANG=y
CONFIG_CFI_PERMISSIVE=y
我们的测试驱动例子:
#include <linux/module.h> // 必须的头文件,定义了MODULE_*宏
#include <linux/kernel.h> // 包含内核信息头文件
#include <linux/init.h> // 包含 __init 和 __exit 宏
static int param_int = 0;
module_param(param_int, int, 0644);
static void hello_cfi_i(int i){
printk(KERN_INFO "hello_cfi_i\n");
}
static void hello_cfi_f(float i){
printk(KERN_INFO "hello_cfi_f\n");
}
typedef void (*hello_cfi_func_i)(int);
typedef void (*hello_cfi_func_f)(float);
struct node {
hello_cfi_func_i i0[1];
hello_cfi_func_f f0[1];
hello_cfi_func_i i1[1];
hello_cfi_func_f f1[1];
hello_cfi_func_i i2[1];
hello_cfi_func_f f2[1];
};
struct node fn_arr = {
.i0 = {hello_cfi_i},
.f0 = {hello_cfi_f},
.i1 = {hello_cfi_i},
.f1 = {hello_cfi_f},
.i2 = {hello_cfi_i},
.f2 = {hello_cfi_f},
};
// 模块初始化函数
static int __init hello_init(void)
{
fn_arr.i0[param_int](param_int);
printk(KERN_INFO "Hello, World!\n");
return 0; // 返回0表示加载成功
}
// 模块清理函数
static void __exit hello_exit(void)
{
printk(KERN_INFO "Goodbye, World!\n");
}
// 注册模块初始化和清理函数
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL"); // 模块许可证
MODULE_AUTHOR("Your Name"); // 模块作者
MODULE_DESCRIPTION("A simple Hello World Module"); // 模块描述
我们传入参数0,执行fn_arr.i0[0],测试正常跳转
我们传入参数1,执行fn_arr.i0[1],测试传入参数原型不匹配(本来应该调用hello_cfi_i,实际调用hello_cfi_f)
测试数组越界访问
后记
从上面来看,kCFI一般会对调用类型、调用的目标地址进行判断,更多细节,去看CFI的具体原理。
参考文献
- https://clang.llvm.org/docs/ControlFlowIntegrity.html
- https://source.android.com/docs/security/test/kcfi
- https://outflux.net/slides/2020/lca/cfi.pdf
打赏、订阅、收藏、丢香蕉、硬币,请关注公众号(攻城狮的搬砖之路)
PS: 请尊重原创,不喜勿喷。
PS: 要转载请注明出处,本人版权所有。
PS: 有问题请留言,看到后我会第一时间回复。
Linux Kernel CFI机制简介及测试禁用的更多相关文章
- Linux kernel workqueue机制分析
Linux kernel workqueue机制分析 在内核编程中,workqueue机制是最常用的异步处理方式.本文主要基于linux kernel 3.10.108的workqueue文档分析其基 ...
- Linux kernel 同步机制
Linux kernel同步机制(上篇) https://mp.weixin.qq.com/s/mosYi_W-Rp1-HgdtxUqSEgLinux kernel 同步机制(下篇) https:// ...
- Linux kernel workqueue机制分析【转】
转自:http://www.linuxsir.org/linuxjcjs/15346.html 在内核编程中,workqueue机制是最常用的异步处理方式.本文主要基于linux kernel 3.1 ...
- linux netlink通信机制简介
一.什么是Netlink通信机制 Netlink套接字是用以实现用户进程与内核进程通信的一种特殊的进程间通信(IPC) ,也是网络应用程序与内核通信的最常用的接口. Netlink 是一种特殊的 s ...
- linux kernel同步机制的思考
在学习内核同步机制的时候,书中介绍了同步方法:原子操作(atomic).自旋锁(spinlock).信号量(semaphore).互斥锁(mutex).完成变量(completion).大内核(BLK ...
- Android休眠唤醒机制简介(一)【转】
本文转载自:http://blog.csdn.net/zhaoxiaoqiang10_/article/details/24408129 Android休眠唤醒机制简介(一) ************ ...
- Linux Kernel 0.12 启动简介,调试记录(Ubuntu1804, Bochs, gdb)
PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明 本文作为本人csdn blog的主站的备份.(Bl ...
- 【嵌入式开发】 Linux Kernel 下载 配置 编译 安装 及 驱动简介
作者 : 韩曙亮 转载请出名出处 : http://blog.csdn.net/shulianghan/article/details/38636827 一. Linux 内核简介 1. 内核功能简介 ...
- linux kernel内存回收机制
转:http://www.wowotech.net/linux_kenrel/233.html linux kernel内存回收机制 作者:itrocker 发布于:2015-11-12 20:37 ...
- Android HAL层与Linux Kernel层驱动开发简介
近日稍微对Android中的驱动开发做了一些简要的了解. HAL:Hardware Abstract Layer 硬件抽象层,由于Linux Kernel需要遵循GPL开源协议,硬件厂商为了保护自己硬 ...
随机推荐
- Java爬虫-爬取疫苗批次信息
今年3月份开始,就接到通知, 根据<关于开展有关人群第二剂次脊髓灰质炎灭活疫苗补种工作的通知>国疾控卫免发[2024]1号文件要求,在2016年3月1日至2019年9月30日之间出生的儿童 ...
- VmWare虚拟机和主机配置为同一网段IP
参考博客:将虚拟机IP与主机IP设置在同一网段的方法 - 天懿 - 博客园 (cnblogs.com) 主机地址 主机通过WiFi连接,地址信息为: 虚拟机配置 选择编辑-->虚拟网络编辑器-- ...
- Mesh快连
Mesh快连 一.名词解释 Mesh快连是一种由多个节点组成的网络系统,这些节点可以相互连接,形成一个"网状"的结构. 二.如何使用 有线Mesh: 网络拓扑: 设备版本:3.7. ...
- 纯css+html做emoji动态表情
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8& ...
- java.io.File类中分隔符区别
1.separator File.separator是系统默认的文件分隔符号,在UNIX系统上,这个字段的值是'/';在Microsoft Windows系统上,它是''. 类型:String 2.s ...
- OpenSearch 与 Elasticsearch:哪个开源搜索引擎适合您?
当谈论到搜索引擎产品时,Elasticsearch 和 OpenSearch 是两个备受关注的选择.它们都以其出色的功能和灵活性而闻名,但在一些方面存在一些差异.在本文中,我们将从功能和延展性.工具与 ...
- post请求方式 - 使用restTemplate而不使用httpClient,headers.setContentType(MediaType.APPLICATION_JSON_UTF8)
public static String doPostForJson(String url, String json,String byteAuthorization) { RestTemplate ...
- 洛谷 P1216 数字三角形
题目链接:数字三角形 思路 dp:金字塔顶的元素为起点,金字塔每行的最左侧数字只能从上一层的最左侧数字到达,如7 -> 3 -> 8 -> 2 -> 4,这些数字中的每一个(除 ...
- 【动手学深度学习】第三章笔记:线性回归、SoftMax 回归、交叉熵损失
这章感觉没什么需要特别记住的东西,感觉忘了回来翻一翻代码就好. 3.1 线性回归 3.1.1 线性回归的基本元素 1. 线性模型 \(\boldsymbol{x}^{(i)}\) 是一个列向量,表示第 ...
- 用基础Array数组实现动态数组、链表、栈和队列
代码地址: https://gitee.com/Tom-shushu/Algorithm-and-Data-Structure.git 一.ArrayList自定义封装 package com.zho ...