[PATCH, v2] drm/xe/migrate: Bound pgtable update loops by current_op
Jagmeet Randhawa <[email protected]>
| Newsgroups | org.kernel.vger.stable,org.freedesktop.lists.intel-xe |
|---|---|
| Message-ID | <[email protected]> |
xe_vma_ops_alloc() sizes the pt_update_ops->ops array with num_ops, the
number of operations reserved, and allocates it with kmalloc_objs(), so
the entries come back uninitialized. Only the first current_op entries
are ever populated. xe_pt.c reflects this and bounds its loops by
current_op, and xe_pt_update_ops_prepare() states the invariant
explicitly:
xe_tile_assert(tile, pt_update_ops->current_op <=
pt_update_ops->num_ops);
xe_migrate.c instead iterates num_ops. When fewer operations are
populated than were reserved, both the CPU and GPU page table update
paths walk past the populated entries into memory that was never
initialized, read a garbage pointer out of it and dereference it.
A syzkaller reproducer triggers this with a VM_BIND / MADVISE / VM_BIND
sequence that reserves five operations and populates two:
UBSAN: invalid-load in drivers/gpu/drm/xe/xe_migrate.c:1836:13
load of value 107 is not a valid value for type '_Bool'
Oops: general protection fault, probably for non-canonical address
0xed6d696d6d6d6d6e
KASAN: maybe wild-memory-access in range
[0x6b6b6b6b6b6b6b70-0x6b6b6b6b6b6b6b77]
RIP: 0010:xe_vm_populate_pgtable+0xd0/0x380 [xe]
Call Trace:
xe_migrate_update_pgtables+0x32b/0x2c90 [xe]
xe_pt_update_ops_run+0x835/0x25e0 [xe]
ops_execute+0x691/0x2630 [xe]
vm_bind_ioctl_ops_execute+0x46d/0x1820 [xe]
xe_vm_bind_ioctl+0x3d5f/0x45f0 [xe]
The value 107 is 0x6b, POISON_FREE, left behind in the unpopulated
entries by the slab allocator.
Bound all five loops in xe_migrate.c by current_op so that only
populated entries are consumed.
v2:
- Add Fixes tag, Cc stable (Matthew Brost)
Fixes: e8babb280b5e ("drm/xe: Convert multiple bind ops into single job")
Cc: [email protected]
Signed-off-by: Jagmeet Randhawa <[email protected]>
Reviewed-by: Matthew Brost <[email protected]>
---
drivers/gpu/drm/xe/xe_migrate.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/xe/xe_migrate.c b/drivers/gpu/drm/xe/xe_migrate.c
index f79d0047bec6..6c95c51c5156 100644
--- a/drivers/gpu/drm/xe/xe_migrate.c
+++ b/drivers/gpu/drm/xe/xe_migrate.c
@@ -1827,7 +1827,7 @@ xe_migrate_update_pgtables_cpu(struct xe_migrate *m,
return ERR_PTR(err);
}
- for (i = 0; i < pt_update_ops->num_ops; ++i) {
+ for (i = 0; i < pt_update_ops->current_op; ++i) {
const struct xe_vm_pgtable_update_op *pt_op =
&pt_update_ops->ops[i];
@@ -1873,7 +1873,7 @@ __xe_migrate_update_pgtables(struct xe_migrate *m,
bool is_migrate = pt_update_ops->q == m->q;
bool usm = is_migrate && xe->info.has_usm;
- for (i = 0; i < pt_update_ops->num_ops; ++i) {
+ for (i = 0; i < pt_update_ops->current_op; ++i) {
struct xe_vm_pgtable_update_op *pt_op = &pt_update_ops->ops[i];
struct xe_vm_pgtable_update *updates = pt_op->entries;
@@ -1941,7 +1941,7 @@ __xe_migrate_update_pgtables(struct xe_migrate *m,
bb->cs[bb->len++] = ofs;
bb->cs[bb->len++] = 0; /* upper_32_bits */
- for (; i < pt_update_ops->num_ops; ++i) {
+ for (; i < pt_update_ops->current_op; ++i) {
struct xe_vm_pgtable_update_op *pt_op =
&pt_update_ops->ops[i];
struct xe_vm_pgtable_update *updates = pt_op->entries;
@@ -1978,7 +1978,7 @@ __xe_migrate_update_pgtables(struct xe_migrate *m,
addr = xe_migrate_vm_addr(ppgtt_ofs, 0) +
(page_ofs / sizeof(u64)) * XE_PAGE_SIZE;
- for (i = 0; i < pt_update_ops->num_ops; ++i) {
+ for (i = 0; i < pt_update_ops->current_op; ++i) {
struct xe_vm_pgtable_update_op *pt_op =
&pt_update_ops->ops[i];
struct xe_vm_pgtable_update *updates = pt_op->entries;
@@ -1996,7 +1996,7 @@ __xe_migrate_update_pgtables(struct xe_migrate *m,
bb->cs[bb->len++] = MI_BATCH_BUFFER_END;
update_idx = bb->len;
- for (i = 0; i < pt_update_ops->num_ops; ++i) {
+ for (i = 0; i < pt_update_ops->current_op; ++i) {
struct xe_vm_pgtable_update_op *pt_op =
&pt_update_ops->ops[i];
struct xe_vm_pgtable_update *updates = pt_op->entries;
--
2.53.0