From nobody Tue Dec 16 19:59:07 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 69073C25B47 for ; Fri, 27 Oct 2023 05:55:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231177AbjJ0Fzq (ORCPT ); Fri, 27 Oct 2023 01:55:46 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42894 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229590AbjJ0Fzo (ORCPT ); Fri, 27 Oct 2023 01:55:44 -0400 Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.131]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9B9EC1A7 for ; Thu, 26 Oct 2023 22:55:41 -0700 (PDT) Received: from pps.filterd (m0279868.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 39R5jfjO009798; Fri, 27 Oct 2023 05:55:30 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; h=from : to : cc : subject : date : message-id : mime-version : content-type; s=qcppdkim1; bh=HcgtgyqVgwVPsC7c5S46Kjt9jM8feIZ/sGbAy6H27hs=; b=lAaK1MXRyMizGTeTDHuDQ3IB6mhS92CNo28axgM7qrmFLIf42/YOsddduGWHnl4qHsia lDqIXPOV69pq1j9H3NDOQ7k4wjkdQlSRZjBCB2vm226hSY/wzF6C9FiyeN6ovbY3quEE qid7g8Bu5ul0MuCe72HsDo3vlIfsYvzlclsE8lh++n/SVbF5VA4ArQLO1HRLV/x2VMz7 INAhl+H38ogBpG++jXBmno76NPPnIsmhME0Ov5d200ADKcSsZs19xTlqgHldIQav2AXk ZsrknQCzbIJi7hzxP6LmzHez69dpX8wo9k33tTDraKJfFAxwFwwoHFPkvKr1S/lDDY1p OA== Received: from nalasppmta05.qualcomm.com (Global_NAT1.qualcomm.com [129.46.96.20]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 3tyxqgh58q-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 27 Oct 2023 05:55:30 +0000 Received: from nalasex01a.na.qualcomm.com (nalasex01a.na.qualcomm.com [10.47.209.196]) by NALASPPMTA05.qualcomm.com (8.17.1.5/8.17.1.5) with ESMTPS id 39R5tTpt019461 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 27 Oct 2023 05:55:29 GMT Received: from hu-yyuwang-lv.qualcomm.com (10.49.16.6) by nalasex01a.na.qualcomm.com (10.47.209.196) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.39; Thu, 26 Oct 2023 22:55:26 -0700 From: Yu Wang To: , , CC: , Subject: [PATCH] Devcoredump: fix use-after-free issue when releasing devcd device Date: Thu, 26 Oct 2023 22:55:21 -0700 Message-ID: <20231027055521.2679-1-quic_yyuwang@quicinc.com> X-Mailer: git-send-email 2.17.1 MIME-Version: 1.0 X-Originating-IP: [10.49.16.6] X-ClientProxiedBy: nalasex01c.na.qualcomm.com (10.47.97.35) To nalasex01a.na.qualcomm.com (10.47.209.196) X-QCInternal: smtphost X-Proofpoint-Virus-Version: vendor=nai engine=6200 definitions=5800 signatures=585085 X-Proofpoint-GUID: hLaacIDROCzwa98lERQF0NoVqnjPPUl8 X-Proofpoint-ORIG-GUID: hLaacIDROCzwa98lERQF0NoVqnjPPUl8 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.272,Aquarius:18.0.987,Hydra:6.0.619,FMLib:17.11.176.26 definitions=2023-10-27_03,2023-10-26_01,2023-05-22_02 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 impostorscore=0 clxscore=1011 lowpriorityscore=0 mlxscore=0 priorityscore=1501 spamscore=0 phishscore=0 mlxlogscore=999 bulkscore=0 suspectscore=0 malwarescore=0 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2310240000 definitions=main-2310270051 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" With sample code as below, it may hit use-after-free issue when releasing devcd device. struct my_coredump_state { struct completion dump_done; ... }; static void my_coredump_free(void *data) { struct my_coredump_state *dump_state =3D data; ... complete(&dump_state->dump_done); } static void my_dev_release(struct device *dev) { kfree(dev); } static void my_coredump() { struct my_coredump_state dump_state; struct device *new_device =3D kzalloc(sizeof(*new_device), GFP_KERNEL); ... new_device->release =3D my_dev_release; device_initialize(new_device); ... device_add(new_device); ... init_completion(&dump_state.dump_done); dev_coredumpm(new_device, NULL, &dump_state, datalen, GFP_KERNEL, my_coredump_read, my_coredump_free); wait_for_completion(&dump_state.dump_done); device_del(new_device); put_device(new_device); } In devcoredump framework, devcd_dev_release() will be called when releasing the devcd device, it will call the free() callback first and try to delete the symlink in sysfs directory of the failing device. Eventhough it has checked 'devcd->failing_dev->kobj.sd' before that, there is no mechanism to ensure it's still available when accessing it in kernfs_find_ns(), refer to the diagram as below: Thread A was waiting for 'dump_state.dump_done' at #A-1-2 after calling dev_coredumpm(). When thread B calling devcd->free() at #B-2-1, it wakes up thread A from point #A-1-2, which will call device_del() to delete the device. If #B-2-2 comes before #A-3-1, but #B-4 comes after #A-4, it will hit use-after-free issue when trying to access 'devcd->failing_dev->kobj.sd'. #A-1-1: dev_coredumpm() #A-1-2: wait_for_completion(&dump_state.dump_done) #A-1-3: device_del() #A-2: kobject_del() #A-3-1: sysfs_remove_dir() --> set kobj->sd=3DNULL #A-3-2: kernfs_put() #A-4: kmem_cache_free() --> free kobj->sd #B-1: devcd_dev_release() #B-2-1: devcd->free(devcd->data) #B-2-2: check devcd->failing_dev->kobj.sd #B-2-3: sysfs_delete_link() #B-3: kernfs_remove_by_name_ns() #B-4: kernfs_find_ns() --> access devcd->failing_dev->kobj.sd To fix this issue, put operations on devcd->failing_dev before calling the free() callback in devcd_dev_release(). Signed-off-by: Yu Wang Reviewed-by: Mukesh Ojha --- drivers/base/devcoredump.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/base/devcoredump.c b/drivers/base/devcoredump.c index 91536ee05f14..35c704ddfeae 100644 --- a/drivers/base/devcoredump.c +++ b/drivers/base/devcoredump.c @@ -83,9 +83,6 @@ static void devcd_dev_release(struct device *dev) { struct devcd_entry *devcd =3D dev_to_devcd(dev); =20 - devcd->free(devcd->data); - module_put(devcd->owner); - /* * this seems racy, but I don't see a notifier or such on * a struct device to know when it goes away? @@ -95,6 +92,8 @@ static void devcd_dev_release(struct device *dev) "devcoredump"); =20 put_device(devcd->failing_dev); + devcd->free(devcd->data); + module_put(devcd->owner); kfree(devcd); } =20 --=20 2.17.1