异常向量表的初始化过程
1.1 标准ARMv8实现
1.1.1 异常向量表的结构
偏移量 | 异常类型 | 说明 |
0x000 | Current EL with SP_EL0, Synchronous | 当前异常等级,使用SP_EL0,同步异常 |
0x080 | Current EL with SP_EL0, IRQ | 当前异常等级,使用SP_EL0,IRQ异常 |
0x100 | Current EL with SP_EL0, FIQ | 当前异常等级,使用SP_EL0,FIQ异常 |
0x180 | Current EL with SP_EL0, SError | 当前异常等级,使用SP_EL0,SError异常 |
0x200 | Current EL with SP_ELx, Synchronous | 当前异常等级,使用SP_ELx,同步异常 |
0x280 | Current EL with SP_ELx, IRQ | 当前异常等级,使用SP_ELx,IRQ异常 |
0x300 | Current EL with SP_ELx, FIQ | 当前异常等级,使用SP_ELx,FIQ异常 |
0x380 | Current EL with SP_ELx, SError | 当前异常等级,使用SP_ELx,SError异常 |
0x400 | Lower EL using AArch64, Synchronous | 低异常等级,使用AArch64,同步异常 |
0x480 | Lower EL using AArch64, IRQ | 低异常等级,使用AArch64,IRQ异常 |
0x500 | Lower EL using AArch64, FIQ | 低异常等级,使用AArch64,FIQ异常 |
0x580 | Lower EL using AArch64, SError | 低异常等级,使用AArch64,SError异常 |
0x600 | Lower EL using AArch32, Synchronous | 低异常等级,使用AArch32,同步异常 |
0x680 | Lower EL using AArch32, IRQ | 低异常等级,使用AArch32,IRQ异常 |
0x700 | Lower EL using AArch32, FIQ | 低异常等级,使用AArch32,FIQ异常 |
0x780 | Lower EL using AArch32, SError | 低异常等级,使用AArch32,SError异常 |
- 定义异常向量表:在汇编代码中定义异常向量表,每个入口包含一条跳转指令,跳转到对应的异常处理函数。
- 设置VBAR_EL3寄存器:将异常向量表的基地址写入VBAR_EL3寄存器。
- 执行ISB指令:确保所有之前的指令都已经执行完成,异常向量表的修改生效。
/* 定义EL3异常向量表 */ .section .vectors, "ax" .align 11 .global bl1_vectors bl1_vectors: .align 7 b sync_exception_sp_el0 .align 7 b irq_exception_sp_el0 .align 7 b fiq_exception_sp_el0 .align 7 b serror_exception_sp_el0 .align 7 b sync_exception_sp_elx .align 7 b irq_exception_sp_elx .align 7 b fiq_exception_sp_elx .align 7 b serror_exception_sp_elx .align 7 b sync_exception_aarch64 .align 7 b irq_exception_aarch64 .align 7 b fiq_exception_aarch64 .align 7 b serror_exception_aarch64 .align 7 b sync_exception_aarch32 .align 7 b irq_exception_aarch32 .align 7 b fiq_exception_aarch32 .align 7 b serror_exception_aarch32 /* 初始化EL3异常向量表 */ ldr x0, =bl1_vectors msr vbar_el3, x0 isb1.1.3 SEL1异常向量表初始化
- 定义异常向量表:在TEE的汇编代码中定义异常向量表。
- 设置VBAR_EL1寄存器:将异常向量表的基地址写入VBAR_EL1寄存器。
- 执行ISB指令:确保异常向量表的修改生效。
/* 定义SEL1异常向量表 */ .section .vectors, "ax" .align 11 .global tee_vectors tee_vectors: /* 异常向量表入口 */ // ... 省略 /* 初始化SEL1异常向量表 */ ldr x0, =tee_vectors msr vbar_el1, x0 isb1.1.4 NSEL1异常向量表初始化
/* 初始化NSEL1异常向量表 */ void __init trap_init(void) { /* 设置VBAR_EL1寄存器 */ write_sysreg(vectors, vbar_el1); isb(); /* 其他初始化 */ // ... }2.2 MT8766定制实现
2.2.1 Preloader中EL3向量表初始化
/* 定义preloader的EL3异常向量表 */ .section .vectors, "ax" .align 11 .global preloader_vectors preloader_vectors: .align 7 b sync_exception .align 7 b irq_exception .align 7 b fiq_exception .align 7 b serror_exception /* 其他入口 */ // ... 省略 /* 初始化EL3异常向量表 */ ldr x0, =preloader_vectors msr vbar_el3, x0 isb2.2.2 Kinibi中SEL1向量表初始化
2.2.3 与标准实现的差异
- 向量表大小不同:标准ATF的异常向量表包含16个入口,而MT8766的preloader只实现了必要的几个入口,以减少代码大小。
- 异常处理不同:MT8766的preloader对异常的处理更加简单,大部分异常都会导致系统复位。
- 向量表位置不同:标准ATF的异常向量表位于单独的.vectors段,而MT8766的preloader将异常向量表与代码放在同一个段中。
3.3 安全风险与漏洞分析
3.3.1 常见漏洞类型
- 异常向量表未保护:异常向量表所在的内存区域没有被设置为只读,攻击者可以篡改异常向量表的入口地址,控制异常处理流程。
- VBAR_ELx寄存器未保护:攻击者可以修改VBAR_ELx寄存器的值,指向自己的恶意异常向量表。
- 异常处理函数漏洞:异常处理函数存在输入验证不足、缓冲区溢出等漏洞,允许攻击者提权。
- 异常注入攻击:攻击者注入异常,触发异常处理流程,利用异常处理函数中的漏洞。
3.3.2 安全加固建议
- 写保护异常向量表:将异常向量表所在的内存区域设置为只读,防止被篡改。
- 保护VBAR_ELx寄存器:禁止低权限代码修改VBAR_ELx寄存器。
- 严格验证异常处理函数的输入:对异常处理函数的输入进行严格的验证,防止缓冲区溢出和指针越界。
- 异常向量表完整性校验:定期校验异常向量表的完整性,确保其没有被篡改。
- 最小化异常处理函数:异常处理函数只包含必要的代码,减少攻击面。