ARM TrustZone:从安全监视器运行时服务访问非安全缓冲区
ARM TrustZone: Accessing a non-secure buffer from a secure monitor runtime service
我的设置包括一个 STM32MP157C-DK2,它使用 Trusted Firmware-A 将 SP-MIN 加载为 BL32,将 uBoot+Linux 加载为 BL33。
我正在尝试获取一个小示例,在该示例中,我从 Linux 内核创建一个 SMC,该内核传递对非安全内存的引用。该位置的数据应由处理 SMC 的运行时服务更改。
我面临的问题是,我找不到任何关于将虚拟地址从 NS:EL1 的 Linux 内核转换为转换机制所需步骤的信息EL3.
我的运行时服务代码如下所示:
static int32_t my_svc_setup(void)
{
return 0;
}
static uintptr_t my_svc_smc_handler(uint32_t smc_fid,
u_register_t x1,
u_register_t x2,
u_register_t x3,
u_register_t x4,
void *cookie,
void *handle,
u_register_t flags)
{
uint16_t smc_function_number = (uint16_t) smc_fid;
uint32_t *data;
switch(smc_function_number){
case 123:
data = (uint32_t *) x1;
// Address Translation Magic ...
*data = 42;
SMC_RET1(handle, 1);
default:
SMC_RET1(handle, SMC_UNK);
}
}
DECLARE_RT_SVC(
my_svc,
OEN_OEM_START,
OEN_OEM_END,
SMC_TYPE_FAST,
my_svc_setup,
my_svc_smc_handler
);
SMC 毫无问题地到达处理程序,但是一旦我尝试取消引用我通过 x1 传递的物理地址,CPU(显然)崩溃了。如果有人可以帮助我填写剩余的必需步骤以获得有效参考,将不胜感激。
The problem I'm facing is that I can't find any information on what steps are required in order to translate the virtual address from the Linux Kernel at NS:EL1 to the translation regime of EL3.
TrustZone 保护基于物理地址。对于 NS:EL1
或 EL3
,您可以通过多种方式使用 MMU 进行映射,但两者都必须映射到相同的物理地址。对于 Linux 内核,您需要添加一个由物理地址支持的共享内存的映射。您可以使用 virt_to_phys()
和这样的映射来查找物理地址。
您需要在 EL3
中提供相同的映射。最简单的是有一个平面 virt==phys 与部分和超部分的映射。
另一部分是您必须 将 TZASC 设置为具有世界共享的物理部分的权限。 code manipulating TZASC 的例子。这取决于您的硬件,通常此信息仅在与芯片制造商的 NDA 下提供。
另一个警告是您应该将内存映射为不可缓存的或者您依赖刷新,这很容易出错并且可能是一个安全问题,如果系统有 VIVT 缓存。某些 ARM CPU 具有 VIPT 缓存,并且可以在这些系统上使用缓存内存。
我还建议您不要通过 SMC API 传递地址。您知道固定的世界可共享缓冲区大小。因此,最好传递一个 0..extent-1
的索引,如果地址超出范围则立即报错。这样,只有您的初始 Linux 代码需要创建映射,然后您可以使用给定的虚拟地址并仅传递索引。天真地这似乎更安全。大多数针对 TrustZone 的攻击将针对 API 本身。
相关:DMA and TrustZone,
我的设置包括一个 STM32MP157C-DK2,它使用 Trusted Firmware-A 将 SP-MIN 加载为 BL32,将 uBoot+Linux 加载为 BL33。
我正在尝试获取一个小示例,在该示例中,我从 Linux 内核创建一个 SMC,该内核传递对非安全内存的引用。该位置的数据应由处理 SMC 的运行时服务更改。
我面临的问题是,我找不到任何关于将虚拟地址从 NS:EL1 的 Linux 内核转换为转换机制所需步骤的信息EL3.
我的运行时服务代码如下所示:
static int32_t my_svc_setup(void)
{
return 0;
}
static uintptr_t my_svc_smc_handler(uint32_t smc_fid,
u_register_t x1,
u_register_t x2,
u_register_t x3,
u_register_t x4,
void *cookie,
void *handle,
u_register_t flags)
{
uint16_t smc_function_number = (uint16_t) smc_fid;
uint32_t *data;
switch(smc_function_number){
case 123:
data = (uint32_t *) x1;
// Address Translation Magic ...
*data = 42;
SMC_RET1(handle, 1);
default:
SMC_RET1(handle, SMC_UNK);
}
}
DECLARE_RT_SVC(
my_svc,
OEN_OEM_START,
OEN_OEM_END,
SMC_TYPE_FAST,
my_svc_setup,
my_svc_smc_handler
);
SMC 毫无问题地到达处理程序,但是一旦我尝试取消引用我通过 x1 传递的物理地址,CPU(显然)崩溃了。如果有人可以帮助我填写剩余的必需步骤以获得有效参考,将不胜感激。
The problem I'm facing is that I can't find any information on what steps are required in order to translate the virtual address from the Linux Kernel at NS:EL1 to the translation regime of EL3.
TrustZone 保护基于物理地址。对于 NS:EL1
或 EL3
,您可以通过多种方式使用 MMU 进行映射,但两者都必须映射到相同的物理地址。对于 Linux 内核,您需要添加一个由物理地址支持的共享内存的映射。您可以使用 virt_to_phys()
和这样的映射来查找物理地址。
您需要在 EL3
中提供相同的映射。最简单的是有一个平面 virt==phys 与部分和超部分的映射。
另一部分是您必须 将 TZASC 设置为具有世界共享的物理部分的权限。 code manipulating TZASC 的例子。这取决于您的硬件,通常此信息仅在与芯片制造商的 NDA 下提供。
另一个警告是您应该将内存映射为不可缓存的或者您依赖刷新,这很容易出错并且可能是一个安全问题,如果系统有 VIVT 缓存。某些 ARM CPU 具有 VIPT 缓存,并且可以在这些系统上使用缓存内存。
我还建议您不要通过 SMC API 传递地址。您知道固定的世界可共享缓冲区大小。因此,最好传递一个 0..extent-1
的索引,如果地址超出范围则立即报错。这样,只有您的初始 Linux 代码需要创建映射,然后您可以使用给定的虚拟地址并仅传递索引。天真地这似乎更安全。大多数针对 TrustZone 的攻击将针对 API 本身。
相关:DMA and TrustZone,