Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/xe/reg_sr: Remove register pool

That pool implementation doesn't really work: if the krealloc happens to
move the memory and return another address, the entries in the xarray
become invalid, leading to use-after-free later:

BUG: KASAN: slab-use-after-free in xe_reg_sr_apply_mmio+0x570/0x760 [xe]
Read of size 4 at addr ffff8881244b2590 by task modprobe/2753

Allocated by task 2753:
kasan_save_stack+0x39/0x70
kasan_save_track+0x14/0x40
kasan_save_alloc_info+0x37/0x60
__kasan_kmalloc+0xc3/0xd0
__kmalloc_node_track_caller_noprof+0x200/0x6d0
krealloc_noprof+0x229/0x380

Simplify the code to fix the bug. A better pooling strategy may be added
back later if needed.

Fixes: dd08ebf6c352 ("drm/xe: Introduce a new DRM driver for Intel GPUs")
Reviewed-by: Matt Roper <matthew.d.roper@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20241209232739.147417-2-lucas.demarchi@intel.com
Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>

+6 -31
+6 -25
drivers/gpu/drm/xe/xe_reg_sr.c
··· 27 27 #include "xe_reg_whitelist.h" 28 28 #include "xe_rtp_types.h" 29 29 30 - #define XE_REG_SR_GROW_STEP_DEFAULT 16 31 - 32 30 static void reg_sr_fini(struct drm_device *drm, void *arg) 33 31 { 34 32 struct xe_reg_sr *sr = arg; 33 + struct xe_reg_sr_entry *entry; 34 + unsigned long reg; 35 + 36 + xa_for_each(&sr->xa, reg, entry) 37 + kfree(entry); 35 38 36 39 xa_destroy(&sr->xa); 37 - kfree(sr->pool.arr); 38 - memset(&sr->pool, 0, sizeof(sr->pool)); 39 40 } 40 41 41 42 int xe_reg_sr_init(struct xe_reg_sr *sr, const char *name, struct xe_device *xe) 42 43 { 43 44 xa_init(&sr->xa); 44 - memset(&sr->pool, 0, sizeof(sr->pool)); 45 - sr->pool.grow_step = XE_REG_SR_GROW_STEP_DEFAULT; 46 45 sr->name = name; 47 46 48 47 return drmm_add_action_or_reset(&xe->drm, reg_sr_fini, sr); 49 48 } 50 49 EXPORT_SYMBOL_IF_KUNIT(xe_reg_sr_init); 51 - 52 - static struct xe_reg_sr_entry *alloc_entry(struct xe_reg_sr *sr) 53 - { 54 - if (sr->pool.used == sr->pool.allocated) { 55 - struct xe_reg_sr_entry *arr; 56 - 57 - arr = krealloc_array(sr->pool.arr, 58 - ALIGN(sr->pool.allocated + 1, sr->pool.grow_step), 59 - sizeof(*arr), GFP_KERNEL); 60 - if (!arr) 61 - return NULL; 62 - 63 - sr->pool.arr = arr; 64 - sr->pool.allocated += sr->pool.grow_step; 65 - } 66 - 67 - return &sr->pool.arr[sr->pool.used++]; 68 - } 69 50 70 51 static bool compatible_entries(const struct xe_reg_sr_entry *e1, 71 52 const struct xe_reg_sr_entry *e2) ··· 93 112 return 0; 94 113 } 95 114 96 - pentry = alloc_entry(sr); 115 + pentry = kmalloc(sizeof(*pentry), GFP_KERNEL); 97 116 if (!pentry) { 98 117 ret = -ENOMEM; 99 118 goto fail;
-6
drivers/gpu/drm/xe/xe_reg_sr_types.h
··· 20 20 }; 21 21 22 22 struct xe_reg_sr { 23 - struct { 24 - struct xe_reg_sr_entry *arr; 25 - unsigned int used; 26 - unsigned int allocated; 27 - unsigned int grow_step; 28 - } pool; 29 23 struct xarray xa; 30 24 const char *name; 31 25