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的具体原理。

参考文献


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

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

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

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

Linux Kernel CFI机制简介及测试禁用的更多相关文章

  1. Linux kernel workqueue机制分析

    Linux kernel workqueue机制分析 在内核编程中,workqueue机制是最常用的异步处理方式.本文主要基于linux kernel 3.10.108的workqueue文档分析其基 ...

  2. Linux kernel 同步机制

    Linux kernel同步机制(上篇) https://mp.weixin.qq.com/s/mosYi_W-Rp1-HgdtxUqSEgLinux kernel 同步机制(下篇) https:// ...

  3. Linux kernel workqueue机制分析【转】

    转自:http://www.linuxsir.org/linuxjcjs/15346.html 在内核编程中,workqueue机制是最常用的异步处理方式.本文主要基于linux kernel 3.1 ...

  4. linux netlink通信机制简介

    一.什么是Netlink通信机制  Netlink套接字是用以实现用户进程与内核进程通信的一种特殊的进程间通信(IPC) ,也是网络应用程序与内核通信的最常用的接口. Netlink 是一种特殊的 s ...

  5. linux kernel同步机制的思考

    在学习内核同步机制的时候,书中介绍了同步方法:原子操作(atomic).自旋锁(spinlock).信号量(semaphore).互斥锁(mutex).完成变量(completion).大内核(BLK ...

  6. Android休眠唤醒机制简介(一)【转】

    本文转载自:http://blog.csdn.net/zhaoxiaoqiang10_/article/details/24408129 Android休眠唤醒机制简介(一) ************ ...

  7. Linux Kernel 0.12 启动简介,调试记录(Ubuntu1804, Bochs, gdb)

    PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明   本文作为本人csdn blog的主站的备份.(Bl ...

  8. 【嵌入式开发】 Linux Kernel 下载 配置 编译 安装 及 驱动简介

    作者 : 韩曙亮 转载请出名出处 : http://blog.csdn.net/shulianghan/article/details/38636827 一. Linux 内核简介 1. 内核功能简介 ...

  9. linux kernel内存回收机制

    转:http://www.wowotech.net/linux_kenrel/233.html linux kernel内存回收机制 作者:itrocker 发布于:2015-11-12 20:37 ...

  10. Android HAL层与Linux Kernel层驱动开发简介

    近日稍微对Android中的驱动开发做了一些简要的了解. HAL:Hardware Abstract Layer 硬件抽象层,由于Linux Kernel需要遵循GPL开源协议,硬件厂商为了保护自己硬 ...

随机推荐

  1. react 样式继承 属性传递

    # 样式 import styled from 'styled-components' const Button = styled.button` font-size: 20px; border: 1 ...

  2. jquery的绑定和删除

            // 基本语法形式 $().on( 事件类型 , 事件处理函数 )         // 删除事件处理函数         // 必须绑定的是 函数名称 才能删除 绑定的事件处理函数 ...

  3. 面试必会 --> MyBatis篇

    什么是MyBatis Mybatis是一个半ORM(对象关系映射)框架,它内部封装了JDBC,开发时只需要关注SQL语句本身,不需要花费精力去处理加载驱动.创建连接.创建statement等繁杂的过程 ...

  4. LeetCode 621. 任务调度器 (Java)

    题目: 给定一个用字符数组表示的 CPU 需要执行的任务列表.其中包含使用大写的 A - Z 字母表示的26 种不同种类的任务.任务可以以任意顺序执行,并且每个任务都可以在 1 个单位时间内执行完.C ...

  5. Java实际工作里用到的几种加密方式

    1.Base64加密 最简单的加密方式,甚至可以说不是加密,只是一种用64个字符表示任意二进制数据的方法.Base64编码原理是将输入字符串按字节切分,取得每个字节对应的二进制值(若不足8比特则高位补 ...

  6. java多线程编程:你真的了解线程中断吗?

    java.lang.Thread类有一个 interrupt 方法,该方法直接对线程调用.当被interrupt的线程正在sleep或wait时,会抛出 InterruptedException 异常 ...

  7. 关于Compilation failed: internal java compiler error的解决方法(Idea)

    关于Compilation failed: internal java compiler error的解决方法(Idea) idea编译项目时出现java: Compilation failed: i ...

  8. Fastjson基础环境配置与Java基础概念

    Preface 此篇系列文章将会从 Java 的基础语法开始,以 Fastjson 的各个反序列化漏洞分析为结尾,详细记录如何从一个具有基础面向对象编程但毫无 Java 基础的小白成长为了解 Fast ...

  9. python 方法调用另一个方法报错,捕获的异常只有message,优化为trackback捕获详细的报错信息

    A方法加了try...expect... B方法也加了try....expect... B方法调用了A方法,A方法查找元素,找不到报超时异常,实际B捕获到的异常,只有message\n,没有办法看出是 ...

  10. 日志之log4j2和springboot

    log4j2比logback好用. 现在之所有以spring采用logback,根据我个人的理解应该是某种非常特殊的理由.否则log4j2的性能比logback更好,且异步性能极好! 异步日志是log ...