首页 星云 工具 资源 星选 资讯 热门工具
:

PDF转图片 完全免费 小红书视频下载 无水印 抖音视频下载 无水印 数字星空

Linux Kernel CFI机制简介及测试禁用

编程知识
2024年07月28日 17:51

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],测试正常跳转

rep_img

  我们传入参数1,执行fn_arr.i0[1],测试传入参数原型不匹配(本来应该调用hello_cfi_i,实际调用hello_cfi_f)

rep_img

  测试数组越界访问

rep_img




后记


  从上面来看,kCFI一般会对调用类型、调用的目标地址进行判断,更多细节,去看CFI的具体原理。

参考文献




打赏、订阅、收藏、丢香蕉、硬币,请关注公众号(攻城狮的搬砖之路)
qrc_img

PS: 请尊重原创,不喜勿喷。

PS: 要转载请注明出处,本人版权所有。

PS: 有问题请留言,看到后我会第一时间回复。

From:https://www.cnblogs.com/Iflyinsky/p/18328698
本文地址: http://shuzixingkong.net/article/526
0评论
提交 加载更多评论
其他文章 设计模式:代理、装饰和适配器模式的区别
结构对比 讲实话,博主当初学习完整设计模式时,这三种设计模式单独摘哪一种都是十分清晰和明确的,但是随着模式种类的增加,在实际使用的时候竟然会出现恍惚,例如读开源代码时,遇到不以模式命名规范的代码时,一时难以说清具体是使用的这三种里的哪一种。 之所以会出现混淆的原因是,三种模式的实现都是基于面向接口这
设计模式:代理、装饰和适配器模式的区别 设计模式:代理、装饰和适配器模式的区别 设计模式:代理、装饰和适配器模式的区别
Nuxt.js 路由管理:useRouter 方法与路由中间件应用
title: Nuxt.js 路由管理:useRouter 方法与路由中间件应用 date: 2024/7/28 updated: 2024/7/28 author: cmdragon excerpt: 摘要:本文介绍了Nuxt 3中useRouter方法及其在路由管理和中间件应用中的功能。内容包括
Nuxt.js  路由管理:useRouter 方法与路由中间件应用 Nuxt.js  路由管理:useRouter 方法与路由中间件应用
Jenkins如何使用CrumbIssuer防御CSRF攻击
1、CSRF(跨站请求伪造)概述 在讲解Jenkins的跨站请求伪造(CSRF)保护机制之前,让我们首先对CSRF这一安全威胁及其重要性进行简明扼要的概述。 1.1 CSRF(跨站请求伪造)的原理 CSRF(即跨站请求伪造)是指利用受害者尚未失效的身份认证信息、(cookie、会话等),诱骗其点击恶
Jenkins如何使用CrumbIssuer防御CSRF攻击 Jenkins如何使用CrumbIssuer防御CSRF攻击 Jenkins如何使用CrumbIssuer防御CSRF攻击
ComfyUI插件:ComfyUI Impact 节点(二)
前言: 学习ComfyUI是一场持久战,而 ComfyUI Impact 是一个庞大的模块节点库,内置许多非常实用且强大的功能节点 ,例如检测器、细节强化器、预览桥、通配符、Hook、图片发送器、图片接收器等等。通过这些节点的组合运用,我们可以实现的工作有很多,例如自动人脸检测和优化修复、区域增强、
ComfyUI插件:ComfyUI Impact 节点(二) ComfyUI插件:ComfyUI Impact 节点(二) ComfyUI插件:ComfyUI Impact 节点(二)
智能家居如何把老款定频空调变成智能“变频”空调#米家#智能家居#HA
背景 最近长沙的天气暴热,室内达到了34-35度,天气预报最高温度上了40度,这么酷热的天气,离开了空调,基本上就是一身汗,全身湿透,特别难受,然后不得不开启家里的一台将近10年的老式定频空调,输入功率970W,OMG,一小时将近一度电,假设一天吹10小时,就是10度电,一个月三十天,10*30=3
智能家居如何把老款定频空调变成智能“变频”空调#米家#智能家居#HA 智能家居如何把老款定频空调变成智能“变频”空调#米家#智能家居#HA 智能家居如何把老款定频空调变成智能“变频”空调#米家#智能家居#HA
Python 代码中的 yield 到底是什么?
在Python编程中,有一个强大而神秘的关键字,那就是yield。初学者常常被它搞得晕头转向,而高级开发者则借助它实现高效的代码。到底yield是什么?它又是如何在Python代码中发挥作用的呢?让我们一起来揭开它的面纱。 Python里的一个非常重要但也颇具迷惑性的关键词——yield。 什么是y
Python 代码中的 yield 到底是什么? Python 代码中的 yield 到底是什么? Python 代码中的 yield 到底是什么?
408数据结构树算法
第四章 树 4.1 二叉树的顺序存储 #define MAXSIZE 16 typedef int ElemType; typedef struct { ElemType data[MAXSIZE]; int size; }Tree; //初始化二叉树 void initTree(Tree&amp;
408数据结构树算法 408数据结构树算法
萌新的装机体验(持续更新)
萌新的装机体验 起因 作为一名 OIer,平日划水的方式无非就是看看 edge 首页和知乎(当然如果教练不在就上 B 站了)。有一天在 edge 主页上忽然看到了一个 5000 元主机的装机体验,看完之后就想换台电脑了。 家里的那台电脑是我小学毕业的时候和我爸自己装的。当时什么都不懂(但以为自己很懂