From nobody Wed Jul 1 03:07:30 2026 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 9060CC433EF for ; Mon, 3 Jan 2022 05:02:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230236AbiACFCC (ORCPT ); Mon, 3 Jan 2022 00:02:02 -0500 Received: from out5-smtp.messagingengine.com ([66.111.4.29]:58933 "EHLO out5-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229798AbiACFCB (ORCPT ); Mon, 3 Jan 2022 00:02:01 -0500 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.nyi.internal (Postfix) with ESMTP id 89A2F5C00CF; Mon, 3 Jan 2022 00:02:00 -0500 (EST) Received: from mailfrontend2 ([10.202.2.163]) by compute3.internal (MEProxy); Mon, 03 Jan 2022 00:02:00 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dxuuu.xyz; h= from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=fm2; bh=aWpRUtqkhfwjQ Nuu0fj1GCDAGVOQI3zf2uNEDVscA6E=; b=dwp20hTiOd5WxzTAfIBBZpsermCHv c94esFRROgEANow1uaiNf+qU+QA3+rM2eJR7F+gUdPhfYw0MiC2Cq9sHSdnHDMoE h1Iyip0k0pE8bf5jVKspyDlIbL5EDOpPwJOxO1WtIOsm4/ugmaPdd6QCCjSNtvDi Ch8ZsxcWHorQP+d6UAy5PBzwdrKLQkG3ppR5MHIM2hEJuWXF44tNO1LU7ZNnXmwF MX4P7QAdZa2CR2BxMmhlBzqFhWeOemPsFx/QSPiTn8i34AAfJXPFymSq0ij7NN3Q VQ27MoDLx8u9BKqlYe2r2gjsPggycsffbsJomy8nnuD2jpef437piAMeQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm1; bh=aWpRUtqkhfwjQNuu0fj1GCDAGVOQI3zf2uNEDVscA6E=; b=PqvifSnW hD2g85qzK8pM6SH4eC7vP1Nk1RZW6IBA0nOoCxMK5k2ll2SL7SuW8/fwGKPN5qct BPwTT2kCrEF+xxyU8vAP2blAz1iX3Yi9DdJy3ohtFGhe8LYgMkVIVh8Kjz6w2Qc4 UdeVDdF8PjDEB6s7dBg+Vf5tt4JrsgECrlgsxoK6Kgmsu3uLW+yFRdGClsVnZG37 4yFeLtFPrklNsoZ7T9fzXX4Souxr3sLgcfz3WOJ7beSkvj4e61VuvUVtVtC9DUtZ i2y6/dGqWkptphmnRhNs774ukqB//cRUQyP4SXw1CS6IuCFik86BsayGAz4ImOeM v4NZhZbtohsYcw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvuddrudeftddgjeejucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucgfrhhlucfvnfffucdljedtmdenucfjughrpefhvf fufffkofgjfhgggfestdekredtredttdenucfhrhhomhepffgrnhhivghlucgiuhcuoegu gihusegugihuuhhurdighiiiqeenucggtffrrghtthgvrhhnpefgkeduleekhfetvefhge fgvdegfeejfefguedvuddthffggffhhedtueeuteefieenucevlhhushhtvghrufhiiigv pedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpegugihusegugihuuhhurdighiii X-ME-Proxy: Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 3 Jan 2022 00:01:57 -0500 (EST) From: Daniel Xu To: arnd@arndb.de, gregkh@linuxfoundation.org, giometti@enneenne.com, linux-kernel@vger.kernel.org Cc: Daniel Xu , thesven73@gmail.com, ojeda@kernel.org Subject: [RFC char-misc-next 1/2] cdev: Add private pointer to struct cdev Date: Sun, 2 Jan 2022 21:01:39 -0800 Message-Id: <34157f5e8dbaa1063dd76608e1e57244305460e8.1641185192.git.dxu@dxuuu.xyz> X-Mailer: git-send-email 2.34.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" struct cdev is a kobject managed struct, meaning kobject is ultimately responsible for deciding when the object is freed. Because kobject uses reference counts, it also means a cdev object isn't guaranteed to be cleaned up with a call to cdev_del() -- the cleanup may occur later. Unfortunately, this can result in subtle use-after-free bugs when struct cdev is embedded in another struct, and the larger struct is freed immediately after cdev_del(). For example: struct contains_cdev { struct cdev cdev; } void init(struct contains_cdev *cc) { cdev_init(&cc->cdev); } void cleanup(struct contains_cdev *cc) { cdev_del(&cc->cdev); kfree(cc); } This kind of code can reliably trigger a KASAN splat with CONFIG_KASAN=3Dy and CONFIG_DEBUG_KOBJECT_RELEASE=3Dy. A fairly palatable workaround is replacing cdev_init() with cdev_alloc() and storing a pointer instead. For example, this is totally fine: struct contains_cdev_ptr { struct cdev *cdev; } int init(struct contains_cdev_ptr *cc) { cc->cdev =3D cdev_alloc(); if (!cc->cdev) { return -ENOMEM; } return 0; } void cleanup(struct contains_cdev_ptr *cc) { cdev_del(cc->cdev); kfree(cc); } The only downside from this workaround (other than the extra allocation) is that container_of() upcasts no longer work. This is quite unfortunate for any code that implements struct file_operations and wants to store extra data with a struct cdev. With cdev_alloc() pointer, it's no longer possible to do something like: struct contains_cdev *cc =3D container_of(inode->i_cdev, struct contains_cdev, cdev); Thus, I propose to add a void *private field to struct cdev so that callers can store a pointer to the containing struct instead of using container_of(). Signed-off-by: Daniel Xu --- include/linux/cdev.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/cdev.h b/include/linux/cdev.h index 0e8cd6293deb..0e674e900512 100644 --- a/include/linux/cdev.h +++ b/include/linux/cdev.h @@ -18,6 +18,7 @@ struct cdev { struct list_head list; dev_t dev; unsigned int count; + void *private; } __randomize_layout; =20 void cdev_init(struct cdev *, const struct file_operations *); --=20 2.34.1 From nobody Wed Jul 1 03:07:30 2026 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 A8EF2C433F5 for ; Mon, 3 Jan 2022 05:02:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230520AbiACFCG (ORCPT ); Mon, 3 Jan 2022 00:02:06 -0500 Received: from out5-smtp.messagingengine.com ([66.111.4.29]:38733 "EHLO out5-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229798AbiACFCF (ORCPT ); Mon, 3 Jan 2022 00:02:05 -0500 Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) by mailout.nyi.internal (Postfix) with ESMTP id 6309A5C00CF; Mon, 3 Jan 2022 00:02:05 -0500 (EST) Received: from mailfrontend2 ([10.202.2.163]) by compute1.internal (MEProxy); Mon, 03 Jan 2022 00:02:05 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dxuuu.xyz; h= from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=fm2; bh=4cqX3FuXJ8tSL ZGo1UClYYGPuduo/dAwTou1Y4V29To=; b=U1hbj/+XAL8c5MWhzKvyfKVYUXLkC 8HIppp2gjmHuqJ5tRrvQgn58O5obx38K+/ju7I50dKVVF/o4QJcxpfhx4VKrv4aD cSmBOxFAa5Tz72ZHV6Q02riPb0ifYbQVwEAtilK84XqSceIXmpTJtIzIDP110eis iNunBlGamdPAb2gSfs6G6bAGjbbG19HzVi87DeS77SjNW49xAupm1I6M1NGgBcOV nkV3bUUggYBJEyRw+ce3y8H5ut9tAofbb4DnQ2FitRYAzkR9/T6tgpKdszP1+wfS p/BJDta/uSCes8NiIwTN/TS+ukm/qxEMFGvw+XK4GxWpHMqYQyFcKpamQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm1; bh=4cqX3FuXJ8tSLZGo1UClYYGPuduo/dAwTou1Y4V29To=; b=IXFbuoRE W9Yyuq7tQ0oTWYs4BKhY/cbPGBsZ1yAs84b5RS8/JU/T7JWdE7cZZqjcYUjMMW29 KqSEfJ29r7SCUwpAAtu/V5cv+ag5syGPp+Jv4GxvbnWO513jxfRiXg34eu2TLezn 786DOHR5OpnUpi+fu3+WF9YNuezR0sgcPefa33UaoILxhoAY3ZH00ilKgaryUrAn JGuASAZAF/CCJ+NI3ZdxxEkTvZmMd+kgGK6Nq0rIFpPoe41HFUKUn1StO6qkqfr3 qHxc7SG0ZxpGuN5pyFe+iekIU0sf+6/mFBBtY3vvOP85LkGmOGsJ51JROobgOXVu vscdaXc+WAy9fg== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvuddrudeftddgjeejucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucgfrhhlucfvnfffucdljedtmdenucfjughrpefhvf fufffkofgjfhgggfestdekredtredttdenucfhrhhomhepffgrnhhivghlucgiuhcuoegu gihusegugihuuhhurdighiiiqeenucggtffrrghtthgvrhhnpefgkeduleekhfetvefhge fgvdegfeejfefguedvuddthffggffhhedtueeuteefieenucevlhhushhtvghrufhiiigv pedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpegugihusegugihuuhhurdighiii X-ME-Proxy: Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 3 Jan 2022 00:02:00 -0500 (EST) From: Daniel Xu To: arnd@arndb.de, gregkh@linuxfoundation.org, giometti@enneenne.com, linux-kernel@vger.kernel.org Cc: Daniel Xu , thesven73@gmail.com, ojeda@kernel.org Subject: [RFC char-misc-next 2/2] pps: Fix use-after-free cdev bug on module unload Date: Sun, 2 Jan 2022 21:01:40 -0800 Message-Id: X-Mailer: git-send-email 2.34.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Previously, a use-after-free KASAN splat could be reliably triggered with: # insmod ./pps-ktimer.ko # rmmod pps-ktimer.ko and CONFIG_DEBUG_KOBJECT_RELEASE=3Dy. This commit moves the driver to use cdev_alloc() instead of cdev_init() to decouple the lifetime of struct cdev from struct pps_device. We also make use of the previous commit's new cdev->private field to store a pointer to the containing struct. We have to do this because container_of() does not work when we store a pointer to struct cdev. Signed-off-by: Daniel Xu --- drivers/pps/pps.c | 20 +++++++++++--------- include/linux/pps_kernel.h | 2 +- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c index 22a65ad4e46e..97ce26f67806 100644 --- a/drivers/pps/pps.c +++ b/drivers/pps/pps.c @@ -298,8 +298,7 @@ static long pps_cdev_compat_ioctl(struct file *file, =20 static int pps_cdev_open(struct inode *inode, struct file *file) { - struct pps_device *pps =3D container_of(inode->i_cdev, - struct pps_device, cdev); + struct pps_device *pps =3D inode->i_cdev->private; file->private_data =3D pps; kobject_get(&pps->dev->kobj); return 0; @@ -307,8 +306,7 @@ static int pps_cdev_open(struct inode *inode, struct fi= le *file) =20 static int pps_cdev_release(struct inode *inode, struct file *file) { - struct pps_device *pps =3D container_of(inode->i_cdev, - struct pps_device, cdev); + struct pps_device *pps =3D inode->i_cdev->private; kobject_put(&pps->dev->kobj); return 0; } @@ -332,7 +330,7 @@ static void pps_device_destruct(struct device *dev) { struct pps_device *pps =3D dev_get_drvdata(dev); =20 - cdev_del(&pps->cdev); + cdev_del(pps->cdev); =20 /* Now we can release the ID for re-use */ pr_debug("deallocating pps%d\n", pps->id); @@ -368,10 +366,14 @@ int pps_register_cdev(struct pps_device *pps) =20 devt =3D MKDEV(MAJOR(pps_devt), pps->id); =20 - cdev_init(&pps->cdev, &pps_cdev_fops); - pps->cdev.owner =3D pps->info.owner; + pps->cdev =3D cdev_alloc(); + if (!pps->cdev) + goto free_idr; + pps->cdev->owner =3D pps->info.owner; + pps->cdev->ops =3D &pps_cdev_fops; + pps->cdev->private =3D pps; =20 - err =3D cdev_add(&pps->cdev, devt, 1); + err =3D cdev_add(pps->cdev, devt, 1); if (err) { pr_err("%s: failed to add char device %d:%d\n", pps->info.name, MAJOR(pps_devt), pps->id); @@ -393,7 +395,7 @@ int pps_register_cdev(struct pps_device *pps) return 0; =20 del_cdev: - cdev_del(&pps->cdev); + cdev_del(pps->cdev); =20 free_idr: mutex_lock(&pps_idr_lock); diff --git a/include/linux/pps_kernel.h b/include/linux/pps_kernel.h index 78c8ac4951b5..4e401793880f 100644 --- a/include/linux/pps_kernel.h +++ b/include/linux/pps_kernel.h @@ -56,7 +56,7 @@ struct pps_device { =20 unsigned int id; /* PPS source unique ID */ void const *lookup_cookie; /* For pps_lookup_dev() only */ - struct cdev cdev; + struct cdev *cdev; struct device *dev; struct fasync_struct *async_queue; /* fasync method */ spinlock_t lock; --=20 2.34.1