drm/xe: Add bounds check on pat_index to prevent OOB kernel read in madvise
authorJia Yao <jia.yao@intel.com>
Thu, 5 Feb 2026 16:15:29 +0000 (16:15 +0000)
committerRodrigo Vivi <rodrigo.vivi@intel.com>
Wed, 18 Feb 2026 00:39:04 +0000 (19:39 -0500)
When user provides a bogus pat_index value through the madvise IOCTL, the
xe_pat_index_get_coh_mode() function performs an array access without
validating bounds. This allows a malicious user to trigger an out-of-bounds
kernel read from the xe->pat.table array.

The vulnerability exists because the validation in madvise_args_are_sane()
directly calls xe_pat_index_get_coh_mode(xe, args->pat_index.val) without
first checking if pat_index is within [0, xe->pat.n_entries).

Although xe_pat_index_get_coh_mode() has a WARN_ON to catch this in debug
builds, it still performs the unsafe array access in production kernels.

v2(Matthew Auld)
- Using array_index_nospec() to mitigate spectre attacks when the value
is used

v3(Matthew Auld)
- Put the declarations at the start of the block

Fixes: ada7486c5668 ("drm/xe: Implement madvise ioctl for xe")
Reviewed-by: Matthew Auld <matthew.auld@intel.com>
Cc: <stable@vger.kernel.org> # v6.18+
Cc: Matthew Brost <matthew.brost@intel.com>
Cc: Shuicheng Lin <shuicheng.lin@intel.com>
Cc: Himal Prasad Ghimiray <himal.prasad.ghimiray@intel.com>
Cc: "Thomas Hellström" <thomas.hellstrom@linux.intel.com>
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: Matthew Auld <matthew.auld@intel.com>
Signed-off-by: Jia Yao <jia.yao@intel.com>
Signed-off-by: Matthew Auld <matthew.auld@intel.com>
Link: https://patch.msgid.link/20260205161529.1819276-1-jia.yao@intel.com
(cherry picked from commit 944a3329b05510d55c69c2ef455136e2fc02de29)
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
drivers/gpu/drm/xe/xe_vm_madvise.c

index add9a6c..52147f5 100644 (file)
@@ -291,8 +291,13 @@ static bool madvise_args_are_sane(struct xe_device *xe, const struct drm_xe_madv
                break;
        case DRM_XE_MEM_RANGE_ATTR_PAT:
        {
-               u16 coh_mode = xe_pat_index_get_coh_mode(xe, args->pat_index.val);
+               u16 pat_index, coh_mode;
 
+               if (XE_IOCTL_DBG(xe, args->pat_index.val >= xe->pat.n_entries))
+                       return false;
+
+               pat_index = array_index_nospec(args->pat_index.val, xe->pat.n_entries);
+               coh_mode = xe_pat_index_get_coh_mode(xe, pat_index);
                if (XE_IOCTL_DBG(xe, !coh_mode))
                        return false;