异常向量表的初始化过程异常向量表是异常处理的入口每个异常等级都有自己独立的异常向量表。异常向量表的初始化是系统启动过程中最重要的步骤之一直接关系到系统的稳定性和安全性。1.1 标准ARMv8实现1.1.1 异常向量表的结构ARMv8架构的异常向量表包含16个入口每个入口对应一种异常类型。每个入口的大小为128字节最多可以包含32条AArch64指令。异常向量表必须对齐到2KB边界因为VBAR_ELx寄存器的低11位是保留的。异常向量表的结构如下偏移量异常类型说明0x000Current EL with SP_EL0, Synchronous当前异常等级使用SP_EL0同步异常0x080Current EL with SP_EL0, IRQ当前异常等级使用SP_EL0IRQ异常0x100Current EL with SP_EL0, FIQ当前异常等级使用SP_EL0FIQ异常0x180Current EL with SP_EL0, SError当前异常等级使用SP_EL0SError异常0x200Current EL with SP_ELx, Synchronous当前异常等级使用SP_ELx同步异常0x280Current EL with SP_ELx, IRQ当前异常等级使用SP_ELxIRQ异常0x300Current EL with SP_ELx, FIQ当前异常等级使用SP_ELxFIQ异常0x380Current EL with SP_ELx, SError当前异常等级使用SP_ELxSError异常0x400Lower EL using AArch64, Synchronous低异常等级使用AArch64同步异常0x480Lower EL using AArch64, IRQ低异常等级使用AArch64IRQ异常0x500Lower EL using AArch64, FIQ低异常等级使用AArch64FIQ异常0x580Lower EL using AArch64, SError低异常等级使用AArch64SError异常0x600Lower EL using AArch32, Synchronous低异常等级使用AArch32同步异常0x680Lower EL using AArch32, IRQ低异常等级使用AArch32IRQ异常0x700Lower EL using AArch32, FIQ低异常等级使用AArch32FIQ异常0x780Lower EL using AArch32, SError低异常等级使用AArch32SError异常1.1.2 EL3异常向量表初始化EL3的异常向量表是系统中第一个被初始化的异常向量表由BL1在启动时初始化。初始化步骤如下定义异常向量表在汇编代码中定义异常向量表每个入口包含一条跳转指令跳转到对应的异常处理函数。设置VBAR_EL3寄存器将异常向量表的基地址写入VBAR_EL3寄存器。执行ISB指令确保所有之前的指令都已经执行完成异常向量表的修改生效。代码示例文件bl1/aarch64/bl1_entrypoint.S/* 定义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异常向量表初始化SEL1的异常向量表由TEE操作系统在启动时初始化。初始化步骤与EL3类似定义异常向量表在TEE的汇编代码中定义异常向量表。设置VBAR_EL1寄存器将异常向量表的基地址写入VBAR_EL1寄存器。执行ISB指令确保异常向量表的修改生效。代码示例OP-TEE/* 定义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的异常向量表由Linux内核在启动时初始化。Linux内核的异常向量表定义在arch/arm64/kernel/entry.S文件中初始化代码在arch/arm64/kernel/traps.c文件中。代码示例/* 初始化NSEL1异常向量表 */ void __init trap_init(void) { /* 设置VBAR_EL1寄存器 */ write_sysreg(vectors, vbar_el1); isb(); /* 其他初始化 */ // ... }2.2 MT8766定制实现MT8766的异常向量表初始化流程与标准ATF基本一致但在preloader和Kinibi中做了一些定制化修改。2.2.1 Preloader中EL3向量表初始化MT8766的preloader运行在EL3它会在启动时初始化自己的异常向量表。preloader的异常向量表定义在plat/mediatek/common/aarch64/exception.S文件中。代码示例/* 定义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向量表初始化Kinibi TEE的异常向量表是闭源的但根据MTK公开的技术文档其初始化流程与标准TEE基本一致。Kinibi会在启动时设置VBAR_EL1寄存器指向自己的异常向量表。2.2.3 与标准实现的差异MT8766的异常向量表初始化与标准ATF有以下几个关键差异向量表大小不同标准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寄存器。严格验证异常处理函数的输入对异常处理函数的输入进行严格的验证防止缓冲区溢出和指针越界。异常向量表完整性校验定期校验异常向量表的完整性确保其没有被篡改。最小化异常处理函数异常处理函数只包含必要的代码减少攻击面。
ARMv8异常向量表初始化
异常向量表的初始化过程异常向量表是异常处理的入口每个异常等级都有自己独立的异常向量表。异常向量表的初始化是系统启动过程中最重要的步骤之一直接关系到系统的稳定性和安全性。1.1 标准ARMv8实现1.1.1 异常向量表的结构ARMv8架构的异常向量表包含16个入口每个入口对应一种异常类型。每个入口的大小为128字节最多可以包含32条AArch64指令。异常向量表必须对齐到2KB边界因为VBAR_ELx寄存器的低11位是保留的。异常向量表的结构如下偏移量异常类型说明0x000Current EL with SP_EL0, Synchronous当前异常等级使用SP_EL0同步异常0x080Current EL with SP_EL0, IRQ当前异常等级使用SP_EL0IRQ异常0x100Current EL with SP_EL0, FIQ当前异常等级使用SP_EL0FIQ异常0x180Current EL with SP_EL0, SError当前异常等级使用SP_EL0SError异常0x200Current EL with SP_ELx, Synchronous当前异常等级使用SP_ELx同步异常0x280Current EL with SP_ELx, IRQ当前异常等级使用SP_ELxIRQ异常0x300Current EL with SP_ELx, FIQ当前异常等级使用SP_ELxFIQ异常0x380Current EL with SP_ELx, SError当前异常等级使用SP_ELxSError异常0x400Lower EL using AArch64, Synchronous低异常等级使用AArch64同步异常0x480Lower EL using AArch64, IRQ低异常等级使用AArch64IRQ异常0x500Lower EL using AArch64, FIQ低异常等级使用AArch64FIQ异常0x580Lower EL using AArch64, SError低异常等级使用AArch64SError异常0x600Lower EL using AArch32, Synchronous低异常等级使用AArch32同步异常0x680Lower EL using AArch32, IRQ低异常等级使用AArch32IRQ异常0x700Lower EL using AArch32, FIQ低异常等级使用AArch32FIQ异常0x780Lower EL using AArch32, SError低异常等级使用AArch32SError异常1.1.2 EL3异常向量表初始化EL3的异常向量表是系统中第一个被初始化的异常向量表由BL1在启动时初始化。初始化步骤如下定义异常向量表在汇编代码中定义异常向量表每个入口包含一条跳转指令跳转到对应的异常处理函数。设置VBAR_EL3寄存器将异常向量表的基地址写入VBAR_EL3寄存器。执行ISB指令确保所有之前的指令都已经执行完成异常向量表的修改生效。代码示例文件bl1/aarch64/bl1_entrypoint.S/* 定义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异常向量表初始化SEL1的异常向量表由TEE操作系统在启动时初始化。初始化步骤与EL3类似定义异常向量表在TEE的汇编代码中定义异常向量表。设置VBAR_EL1寄存器将异常向量表的基地址写入VBAR_EL1寄存器。执行ISB指令确保异常向量表的修改生效。代码示例OP-TEE/* 定义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的异常向量表由Linux内核在启动时初始化。Linux内核的异常向量表定义在arch/arm64/kernel/entry.S文件中初始化代码在arch/arm64/kernel/traps.c文件中。代码示例/* 初始化NSEL1异常向量表 */ void __init trap_init(void) { /* 设置VBAR_EL1寄存器 */ write_sysreg(vectors, vbar_el1); isb(); /* 其他初始化 */ // ... }2.2 MT8766定制实现MT8766的异常向量表初始化流程与标准ATF基本一致但在preloader和Kinibi中做了一些定制化修改。2.2.1 Preloader中EL3向量表初始化MT8766的preloader运行在EL3它会在启动时初始化自己的异常向量表。preloader的异常向量表定义在plat/mediatek/common/aarch64/exception.S文件中。代码示例/* 定义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向量表初始化Kinibi TEE的异常向量表是闭源的但根据MTK公开的技术文档其初始化流程与标准TEE基本一致。Kinibi会在启动时设置VBAR_EL1寄存器指向自己的异常向量表。2.2.3 与标准实现的差异MT8766的异常向量表初始化与标准ATF有以下几个关键差异向量表大小不同标准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寄存器。严格验证异常处理函数的输入对异常处理函数的输入进行严格的验证防止缓冲区溢出和指针越界。异常向量表完整性校验定期校验异常向量表的完整性确保其没有被篡改。最小化异常处理函数异常处理函数只包含必要的代码减少攻击面。