[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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.