ARM64内核研究(五)
2023-9-8
| 2023-9-8
0  |  阅读时长 0 分钟
type
status
date
slug
summary
tags
category
icon
password
Property
Sep 8, 2023 12:19 PM

参考

ARMv8-A Architecture Reference Manual
 
内核源码:
  • include/linux/hw_breakpoint.h
  • kernel/events/hw_breakpoint.c
  • arch/arm64/include/asm/hw_breakpoint.h
  • arch/arm64/kernel/hw_breakpoint.c

前置知识

ARM64 异常简介

异常等级

ARM64 包含4个异常等级:
  1. EL0:非特权模式,应用层
  1. EL1:特权模式,内核
  1. EL2:虚拟化程序,比如 Hypervisor
  1. EL3:安全监视器,比如 Secure Monitor
notion image

硬件断点简介

硬件断点(Hardware Breakpoint)是一种调试技术,它可以帮助程序员在程序运行时监视内存地址和数据。它是通过在处理器中设置特殊寄存器来实现的,当指定的内存地址被访问时,处理器会触发一个中断,从而停止程序的执行。与软件断点相比,硬件断点的优势在于处理器可以在硬件级别上检测到中断,因此无需在程序中插入中断指令,从而减少对程序的影响(难以检测)。

硬件断点相关的寄存器

ID_AA64DFR0_EL1:AArch64 Debug Feature Register 0

该寄存器包含了调试相关的信息,其中有关的是两个字段:
  1. WRPs:Watchpoint 个数,Android上一般4个(读写断点)
  1. BRPs: Breakpoint 个数,Android上一般6个(执行断点)
notion image

DBGBCR<n>_EL1:Breakpoint Control Register

具体信息请参考 Reference Manual D13.3.2
该寄存器包含断点的控制信息,比如是否开启。
notion image
E:Enable 开关
为0时禁用
为1时启用
PMC:Privilege mode control
BAS:Byte address select
HMC:Higher mode control
SSC:Security state control
LBN:Linked breakpoint number
BT:Breakpoint Type 断点类型
说明
0b0000
Unlinked instruction address match. DBGBVR<n>_EL1 is the address of an instruction.
0b0001
As 0b0000, but linked to a Context matching breakpoint
0b0010
Unlinked Context ID match. When FEAT_VHE is implemented, EL2 is using AArch64, and the Effective value of HCR_EL2.E2H is 1, if either the PE is executing at EL0 with HCR_EL2.TGE set to 1 or the PE is executing at EL2, then DBGBVR<n>_EL1.ContextID must match the CONTEXTIDR_EL2 value. Otherwise, DBGBVR<n>_EL1.ContextID must match the CONTEXTIDR_EL1 value
0b0011
As 0b0010, with linking enabled
0b0110
Unlinked CONTEXTIDR_EL1 match. DBGBVR<n>_EL1.ContextID is a Context ID compared against CONTEXTIDR_EL1.
0b0111
As 0b0110, with linking enabled.
0b1000
Unlinked VMID match. DBGBVR<n>_EL1.VMID is a VMID compared against VTTBR_EL2.VMID.
0b1001
As 0b1000, with linking enabled.
0b1010
Unlinked VMID and Context ID match. DBGBVR<n>_EL1.ContextID is a Context ID compared against CONTEXTIDR_EL1, and DBGBVR<n>_EL1.VMID is a VMID compared against VTTBR_EL2.VMID.
0b1011
As 0b1010, with linking enabled.
0b1100
Unlinked CONTEXTIDR_EL2 match. DBGBVR<n>_EL1.ContextID2 is a Context ID compared against CONTEXTIDR_EL2.
0b1101
As 0b1100, with linking enabled.
0b1110
Unlinked Full Context ID match. DBGBVR<n>_EL1.ContextID is compared against CONTEXTIDR_EL1, and DBGBVR<n>_EL1.ContextID2 is compared against CONTEXTIDR_EL2.
0b1111
As 0b1110, with linking enabled.

DBGBVR<n>_EL1:Breakpoint Value Register

具体信息请参考 Reference Manual D13.3.3
该寄存器包含断点的值信息,可以是:
  1. 指令虚拟地址
  1. Context ID值
  1. VMID值
  1. VMID值与Context ID值的组合
DBGBCR<n>_EL1 与 DBGBVR<n>_EL1 成对使用,来控制断点。<n>为断点序号

DBGWCR<n>_EL1:Watchpoint Control Register

具体信息请参考 D13.3.11
该寄存器包含观察点的控制信息
notion image
MASK:地址掩码,最大监控2GB

DBGWVR<n>_EL1:Watchpoint Value Register

具体信息请参考 D13.3.12
该寄存器包含观察点匹配的虚拟地址
DBGWCR<n>_EL1 与 DBGWVR<n>_EL1 成对使用,来控制断点。<n>为断点序号

硬件断点的实现流程

配置好硬件断点相关的寄存器后,CPU会在触发断点后产生一个同步异常,然后从 Linux 设置的异常向量表中找到处理同步异常的服务程序(el1_sync),转过去执行它。Linux 内核会在异常处理函数(el1_sync_handler)中根据异常类型(ESR_ELx_EC_BREAKPT_CUR/ESR_ELx_EC_WATCHPT_CUR)来交给对应异常类型的函数(el1_dbg)处理,处理完成后,CPU继续运行。
notion image

Linux 内核中的硬件断点

在 Linux 内核之中,内核断点是和 perf 子系统紧密结合的。想要分析内核的硬件断点,我们可以参考 samples/hw_breakpoint/data_breakpoint.c 也可以从 ptrace 注册硬件断点开始分析。

了解硬件断点API

我们从 sample 和 ptrace 入手,初步了解内核硬件断点的API设计。
从代码片段中可以了解到内核创建硬件断点的一个流程:
  1. hw_breakpoint_init:初始化 attr
  1. register_wide_hw_breakpoint:注册内核空间硬件断点
  1. unregister_wide_hw_breakpoint:取消注册内核空间硬件断点
再去看看 ptrace 相关的接口:
一直往下跟 hw_break_set → ptrace_hbp_set_addr/ptrace_hbp_set_ctrl → ptrace_hbp_get_initialised_bp → ptrace_hbp_create → register_user_hw_breakpoint
我们可以知道,ptrace是使用
  1. register_user_hw_breakpoint:注册用户空间硬件断点
  1. unregister_hw_breakpoint:取消注册用户空间硬件断点
 

分析硬件断点相关源码

硬件断点的初始化

按照顺序来说,首先是 perf_event 的初始化 perf_event_init(),其次才是 arch_initcall(arch_hw_breakpoint_init)
perf_event的初始化
硬件断点相关的初始化在 perf_event_initinit_hw_breakpoint
arch_hw_breakpoint_init的初始化
这里是架构相关的初始化硬件断点

硬件断点的注册

这里我们只关注架构方面的实现,与 perf_event 接口相关的自己查找一下引用即可。
arch_install_hw_breakpointhw_breakpoint_control

硬件断点的触发

  1. 硬件断点触发
  1. CPU 查找异常向量表,执行 el1_sync (汇编)
  1. 跳转到 el1_sync_handler 处理(C层)
  1. 事件类型为 ESR_ELx_EC_BREAKPT_CUR / ESR_ELx_EC_WATCHPT_CUR
  1. 跳到 el1_dbg 处理
  1. 执行 do_debug_exception
  1. 从 esr_to_debug_fault_info 获取到 arch_hw_breakpoint_init 注册的 handler
  1. 执行 breakpoint_handler / watchpoint_handler
  1. 跳到 perf_bp_event
  1. 跳到 perf_swevent_event
  1. 跳到 perf_swevent_overflow
  1. 跳到 __perf_event_overflow
  1. 在 READ_ONCE(event->overflow_handler)(event, data, regs); 执行我们注册的逻辑

Android 上的硬件断点应用

stackplz

notion image

Android_Kernel_hwBreakPoint

notion image
KernelSU 将在未来加入硬件断点功能(s♾️️n)
 
  • Android
  • Kernel
  • 迁移域名ARM64 OLLVM反混淆之虚假控制流
    • Giscus
    目录