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

drm/msm: Fix a null pointer access in msm_gem_shrinker_count()

Adding an msm_gem_object object to the inactive_list before completing
its initialization is a bad idea because shrinker may pick it up from the
inactive_list. Fix this by making sure that the initialization is complete
before moving the msm_obj object to the inactive list.

This patch fixes the below error:
[10027.553044] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000068
[10027.573305] Mem abort info:
[10027.590160] ESR = 0x96000006
[10027.597905] EC = 0x25: DABT (current EL), IL = 32 bits
[10027.614430] SET = 0, FnV = 0
[10027.624427] EA = 0, S1PTW = 0
[10027.632722] Data abort info:
[10027.638039] ISV = 0, ISS = 0x00000006
[10027.647459] CM = 0, WnR = 0
[10027.654345] user pgtable: 4k pages, 39-bit VAs, pgdp=00000001e3a6a000
[10027.672681] [0000000000000068] pgd=0000000198c31003, pud=0000000198c31003, pmd=0000000000000000
[10027.693900] Internal error: Oops: 96000006 [#1] PREEMPT SMP
[10027.738261] CPU: 3 PID: 214 Comm: kswapd0 Tainted: G S 5.4.40 #1
[10027.745766] Hardware name: Qualcomm Technologies, Inc. SC7180 IDP (DT)
[10027.752472] pstate: 80c00009 (Nzcv daif +PAN +UAO)
[10027.757409] pc : mutex_is_locked+0x14/0x2c
[10027.761626] lr : msm_gem_shrinker_count+0x70/0xec
[10027.766454] sp : ffffffc011323ad0
[10027.769867] x29: ffffffc011323ad0 x28: ffffffe677e4b878
[10027.775324] x27: 0000000000000cc0 x26: 0000000000000000
[10027.780783] x25: ffffff817114a708 x24: 0000000000000008
[10027.786242] x23: ffffff8023ab7170 x22: 0000000000000001
[10027.791701] x21: ffffff817114a080 x20: 0000000000000119
[10027.797160] x19: 0000000000000068 x18: 00000000000003bc
[10027.802621] x17: 0000000004a34210 x16: 00000000000000c0
[10027.808083] x15: 0000000000000000 x14: 0000000000000000
[10027.813542] x13: ffffffe677e0a3c0 x12: 0000000000000000
[10027.819000] x11: 0000000000000000 x10: ffffff8174b94340
[10027.824461] x9 : 0000000000000000 x8 : 0000000000000000
[10027.829919] x7 : 00000000000001fc x6 : ffffffc011323c88
[10027.835373] x5 : 0000000000000001 x4 : ffffffc011323d80
[10027.840832] x3 : ffffffff0477b348 x2 : 0000000000000000
[10027.846290] x1 : ffffffc011323b68 x0 : 0000000000000068
[10027.851748] Call trace:
[10027.854264] mutex_is_locked+0x14/0x2c
[10027.858121] msm_gem_shrinker_count+0x70/0xec
[10027.862603] shrink_slab+0xc0/0x4b4
[10027.866187] shrink_node+0x4a8/0x818
[10027.869860] kswapd+0x624/0x890
[10027.873097] kthread+0x11c/0x12c
[10027.876424] ret_from_fork+0x10/0x18
[10027.880102] Code: f9000bf3 910003fd aa0003f3 d503201f (f9400268)
[10027.886362] ---[ end trace df5849a1a3543251 ]---
[10027.891518] Kernel panic - not syncing: Fatal exception

Signed-off-by: Akhil P Oommen <akhilpo@codeaurora.org>
Signed-off-by: Rob Clark <robdclark@chromium.org>

authored by

Akhil P Oommen and committed by
Rob Clark
3cbdc8d8 3c128638

+21 -15
+21 -15
drivers/gpu/drm/msm/msm_gem.c
··· 996 996 997 997 static int msm_gem_new_impl(struct drm_device *dev, 998 998 uint32_t size, uint32_t flags, 999 - struct drm_gem_object **obj, 1000 - bool struct_mutex_locked) 999 + struct drm_gem_object **obj) 1001 1000 { 1002 - struct msm_drm_private *priv = dev->dev_private; 1003 1001 struct msm_gem_object *msm_obj; 1004 1002 1005 1003 switch (flags & MSM_BO_CACHE_MASK) { ··· 1023 1025 INIT_LIST_HEAD(&msm_obj->submit_entry); 1024 1026 INIT_LIST_HEAD(&msm_obj->vmas); 1025 1027 1026 - if (struct_mutex_locked) { 1027 - WARN_ON(!mutex_is_locked(&dev->struct_mutex)); 1028 - list_add_tail(&msm_obj->mm_list, &priv->inactive_list); 1029 - } else { 1030 - mutex_lock(&dev->struct_mutex); 1031 - list_add_tail(&msm_obj->mm_list, &priv->inactive_list); 1032 - mutex_unlock(&dev->struct_mutex); 1033 - } 1034 - 1035 1028 *obj = &msm_obj->base; 1036 1029 1037 1030 return 0; ··· 1032 1043 uint32_t size, uint32_t flags, bool struct_mutex_locked) 1033 1044 { 1034 1045 struct msm_drm_private *priv = dev->dev_private; 1046 + struct msm_gem_object *msm_obj; 1035 1047 struct drm_gem_object *obj = NULL; 1036 1048 bool use_vram = false; 1037 1049 int ret; ··· 1053 1063 if (size == 0) 1054 1064 return ERR_PTR(-EINVAL); 1055 1065 1056 - ret = msm_gem_new_impl(dev, size, flags, &obj, struct_mutex_locked); 1066 + ret = msm_gem_new_impl(dev, size, flags, &obj); 1057 1067 if (ret) 1058 1068 goto fail; 1069 + 1070 + msm_obj = to_msm_bo(obj); 1059 1071 1060 1072 if (use_vram) { 1061 1073 struct msm_gem_vma *vma; 1062 1074 struct page **pages; 1063 - struct msm_gem_object *msm_obj = to_msm_bo(obj); 1064 1075 1065 1076 mutex_lock(&msm_obj->lock); 1066 1077 ··· 1096 1105 mapping_set_gfp_mask(obj->filp->f_mapping, GFP_HIGHUSER); 1097 1106 } 1098 1107 1108 + if (struct_mutex_locked) { 1109 + WARN_ON(!mutex_is_locked(&dev->struct_mutex)); 1110 + list_add_tail(&msm_obj->mm_list, &priv->inactive_list); 1111 + } else { 1112 + mutex_lock(&dev->struct_mutex); 1113 + list_add_tail(&msm_obj->mm_list, &priv->inactive_list); 1114 + mutex_unlock(&dev->struct_mutex); 1115 + } 1116 + 1099 1117 return obj; 1100 1118 1101 1119 fail: ··· 1127 1127 struct drm_gem_object *msm_gem_import(struct drm_device *dev, 1128 1128 struct dma_buf *dmabuf, struct sg_table *sgt) 1129 1129 { 1130 + struct msm_drm_private *priv = dev->dev_private; 1130 1131 struct msm_gem_object *msm_obj; 1131 1132 struct drm_gem_object *obj; 1132 1133 uint32_t size; ··· 1141 1140 1142 1141 size = PAGE_ALIGN(dmabuf->size); 1143 1142 1144 - ret = msm_gem_new_impl(dev, size, MSM_BO_WC, &obj, false); 1143 + ret = msm_gem_new_impl(dev, size, MSM_BO_WC, &obj); 1145 1144 if (ret) 1146 1145 goto fail; 1147 1146 ··· 1166 1165 } 1167 1166 1168 1167 mutex_unlock(&msm_obj->lock); 1168 + 1169 + mutex_lock(&dev->struct_mutex); 1170 + list_add_tail(&msm_obj->mm_list, &priv->inactive_list); 1171 + mutex_unlock(&dev->struct_mutex); 1172 + 1169 1173 return obj; 1170 1174 1171 1175 fail: