已关闭
【runtime】TPRT-001: 不可信指针解引用导致任意代码执行 #823
佳祺创建于 25 天前关闭于 1 天前
ykl999
24 天前 评论:
24 天前 评论:
/assign @Reyn52166


24 天前 将 Reyn52166 设为负责人
ykl999
24 天前 评论:
24 天前 评论:
你好,该问题已收到。不可信指针解引用导致任意代码执行问题我们将会根据issue描述查看代码,尽快答复


guo-yanjun
11 天前 评论:
11 天前 评论:
@syaunfang 感谢反馈。针对该问题,我们已完成初步分析并形成统一整改方案:计划将 libxpu_tprt.so 调整为仅构建期使用的静态库,内部链接到 Runtime v100/v200,同时隐藏 Tprt*、cce::tprt::*等动态符号,并清理相关安装及打包清单,确保交付包不再包含 libxpu_tprt.so 或 libxpu_tprt.a。
该方案将收口 TprtCqReportRecv、TprtSqPushTask 等内部接口通过动态链接或 dlsym 被外部直接调用的路径,并保留现有 Runtime 内部调用链。后续还将补充必要的输入健壮性检查,并完成动态依赖、符号表、安装包、功能回归及升级回滚验证。目前正在修改代码并进行依赖和兼容性确认,有进一步进展会及时同步。


guo-yanjun
1 天前 评论:
1 天前 评论:
@syaunfang 您好,TPRT 内部接口暴露问题已完成整改和验证,相关修改已提交代码仓,如果您后续有新的进展或诉求,欢迎随时重新开启此 Issue 或提交新的 Issue,我们会继续为您跟进。


1 天前 issue状态由 待办的 改变为 已解决
1 天前 关闭了 issue
1 天前 issue状态由 已解决 改变为 已完成
1 天前 添加了label:resolved
【runtime】TPRT-001: 不可信指针解引用导致任意代码执行
基本信息
src/tprt/feature/src/tprt_sqhandle.ccTprtExeAicpuTask(第47-56行)漏洞描述
tprt_sqhandle.cc中的TprtExeAicpuTask函数将用户可控的uint64_t值(来自 SQE 结构的startPcAddr字段)直接通过reinterpret_cast转换为函数指针并调用,整个数据流路径上不存在任何地址合法性验证。攻击者可通过构造恶意 SQE 控制程序执行流,实现任意代码执行。漏洞代码
// tprt_sqhandle.cc:47-56 static uint32_t TprtExeAicpuTask(const TprtSqe_t* sqe) { uint64_t pcStart = sqe->aicpuSqe.startPcAddr; // 用户可控值 uint64_t argsAddr = sqe->aicpuSqe.argsAddr; // 用户可控值 if ((pcStart == 0UL) || (argsAddr == 0UL)) { // 仅检查非零 return TPRT_SQE_PARA_IS_INVALID; } PfnAicpuSqeFunc aicpuFunc = TprtValueToPtr<PfnAicpuSqeFunc>(pcStart); // 直接 reinterpret_cast return aicpuFunc(argsAddr); // 调用攻击者控制的地址 }TprtValueToPtr的实现(tprt_base.hpp:90-93):template <typename TO> inline TO TprtValueToPtr(const uint64_t value) { return reinterpret_cast<TO>(static_cast<uintptr_t>(value)); // 无任何验证 }完整数据流分析
攻击路径
合法数据流对比
在正常执行路径中,
startPcAddr由 runtime 内部设置:// xpu_kernel_task.cc:56 sqe->startPcAddr = RtPtrToValue( aicpuTaskInfo->kernel->GetFuncNameDevAddr(taskInfo->stream->Device_()->Id_()) );合法值来自
GetFuncNameDevAddr(),返回设备上的内核函数地址。但TprtSqPushTask作为公开 C API,无法区分合法调用者和直接构造 SQE 的攻击者。攻击面分析
入口点
TprtSqPushTask声明于src/tprt/inc/external/tprt_api.h,以extern "C"导出,是公开 API:// tprt_api.h:21 uint32_t TprtSqPushTask(const uint32_t devId, const TprtTaskSendInfo_t* sendInfo);攻击前提
libtprt.so)TprtDeviceOpen和TprtSqCqCreate创建了设备和 SQ/CQTprtSqe_t,设置:aicpuSqe.header.type = TPRT_SQE_TYPE_AICPU(值为 0)aicpuSqe.startPcAddr = <目标地址>(任意非零值)aicpuSqe.argsAddr = <参数地址>(任意非零值)SQE 结构定义
// tprt_sqe_cqe.h:51-63 struct TprtStarsAicpuSqe { TprtStarsSqeHeader_t header; // word0-1: type, sqId, taskSn 等 uint64_t startPcAddr; // word2-3: 函数地址 ← 攻击者控制 uint64_t argsAddr; // word4-5: 参数地址 ← 攻击者控制 uint32_t timeout; // word6 uint32_t res[9]; // word7-15 };缺失的安全验证
startPcAddr != 0startPcAddr地址范围检查startPcAddr白名单校验argsAddr地址范围检查影响评估
argsAddr,攻击者可读取任意内存内容修复建议
方案一:地址白名单验证(推荐)
在
TprtExeAicpuTask中增加startPcAddr白名单校验:static uint32_t TprtExeAicpuTask(const TprtSqe_t* sqe) { uint64_t pcStart = sqe->aicpuSqe.startPcAddr; uint64_t argsAddr = sqe->aicpuSqe.argsAddr; if ((pcStart == 0UL) || (argsAddr == 0UL)) { return TPRT_SQE_PARA_IS_INVALID; } // 验证 startPcAddr 是否在已注册的 AICPU 函数地址集合中 if (!TprtManage::Instance()->IsValidAicpuFuncAddr(pcStart)) { TPRT_LOG(TPRT_LOG_ERROR, "Invalid startPcAddr: 0x%" PRIx64, pcStart); return TPRT_SQE_PARA_IS_INVALID; } PfnAicpuSqeFunc aicpuFunc = TprtValueToPtr<PfnAicpuSqeFunc>(pcStart); return aicpuFunc(argsAddr); }方案二:间接调用表
将函数指针替换为索引,通过内部调度表间接调用:
// SQE 中传递函数索引而非直接地址 uint32_t funcIndex = sqe->aicpuSqe.funcIndex; if (funcIndex >= registeredFuncCount) { return TPRT_SQE_PARA_IS_INVALID; } return registeredAicpuFuncs[funcIndex](argsAddr);方案三:API 访问控制
限制
TprtSqPushTask仅允许内部调用,不对外暴露该 C API,改为内部函数调用。验证方法
TprtSqe_t,设置startPcAddr为已知测试函数地址以外的值,验证是否被拒绝startPcAddr和argsAddr进行随机值注入,验证不会执行非预期地址TprtValueToPtr调用点均有配套的地址验证逻辑