{"id":2228941,"url":"http://patchwork.ozlabs.org/api/1.1/patches/2228941/?format=json","web_url":"http://patchwork.ozlabs.org/project/linux-gpio/patch/20260427135841.96266-10-tzungbi@kernel.org/","project":{"id":42,"url":"http://patchwork.ozlabs.org/api/1.1/projects/42/?format=json","name":"Linux GPIO development","link_name":"linux-gpio","list_id":"linux-gpio.vger.kernel.org","list_email":"linux-gpio@vger.kernel.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20260427135841.96266-10-tzungbi@kernel.org>","date":"2026-04-27T13:58:41","name":"[v9,9/9] platform/chrome: cros_ec_chardev: Consume cros_ec_device via revocable","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"8aec34050f54275a1129e8db89a739a4daf1df4b","submitter":{"id":83557,"url":"http://patchwork.ozlabs.org/api/1.1/people/83557/?format=json","name":"Tzung-Bi Shih","email":"tzungbi@kernel.org"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/linux-gpio/patch/20260427135841.96266-10-tzungbi@kernel.org/mbox/","series":[{"id":501655,"url":"http://patchwork.ozlabs.org/api/1.1/series/501655/?format=json","web_url":"http://patchwork.ozlabs.org/project/linux-gpio/list/?series=501655","date":"2026-04-27T13:58:32","name":"drivers/base: Introduce revocable","version":9,"mbox":"http://patchwork.ozlabs.org/series/501655/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2228941/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2228941/checks/","tags":{},"headers":{"Return-Path":"\n <linux-gpio+bounces-35582-incoming=patchwork.ozlabs.org@vger.kernel.org>","X-Original-To":["incoming@patchwork.ozlabs.org","linux-gpio@vger.kernel.org"],"Delivered-To":"patchwork-incoming@legolas.ozlabs.org","Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256\n header.s=k20201202 header.b=XZVjs1KP;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=2600:3c0a:e001:db::12fc:5321; helo=sea.lore.kernel.org;\n envelope-from=linux-gpio+bounces-35582-incoming=patchwork.ozlabs.org@vger.kernel.org;\n receiver=patchwork.ozlabs.org)","smtp.subspace.kernel.org;\n\tdkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org\n header.b=\"XZVjs1KP\"","smtp.subspace.kernel.org;\n arc=none smtp.client-ip=10.30.226.201"],"Received":["from sea.lore.kernel.org (sea.lore.kernel.org\n [IPv6:2600:3c0a:e001:db::12fc:5321])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g453T3xBSz1xvV\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 28 Apr 2026 00:07:01 +1000 (AEST)","from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby sea.lore.kernel.org (Postfix) with ESMTP id D4CAB303A85E\n\tfor <incoming@patchwork.ozlabs.org>; Mon, 27 Apr 2026 14:00:30 +0000 (UTC)","from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id 645463D3D1E;\n\tMon, 27 Apr 2026 14:00:05 +0000 (UTC)","from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org\n [10.30.226.201])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id 234BE3D3D08;\n\tMon, 27 Apr 2026 14:00:05 +0000 (UTC)","by smtp.kernel.org (Postfix) with ESMTPSA id 58B7AC19425;\n\tMon, 27 Apr 2026 14:00:01 +0000 (UTC)"],"ARC-Seal":"i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1777298405; cv=none;\n b=FYsRUiq5SQWKj6gWsVjX+ouXB0ZyNnXWFEtraDoYxKa8wc3BhpaOCggCaol8UdqCHmgeLTheDi3r/OrxUnRECPknpa6DTml+GcOJWxefeiw4bc5mNcCVtd0k5kTHQHYfVe0Hss7beP/1qoqT8x6NTEwlAduW8WFvyK4TQuxstwg=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1777298405; c=relaxed/simple;\n\tbh=1M7X8jOCHkeLS6fn4xzZWtWs67rOTDG2AL/8546NOlk=;\n\th=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:\n\t MIME-Version;\n b=FATFuPpyLc+BACxXi7d8AGSdVfx8Og1ECWGmdTDdWetNhpqCRVIRZiHEqLQbyiiqSHYpjgoU8Nz9x7qo5Oa3hO5+sR1/jJ/7DHWNJGJYqGtVzvo+di7w2oGs/c1k3+uzYK8viIILpX53DTmxG8S8oGBwUzFiPzRG1oXk74f4J6k=","ARC-Authentication-Results":"i=1; smtp.subspace.kernel.org;\n dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org\n header.b=XZVjs1KP; arc=none smtp.client-ip=10.30.226.201","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org;\n\ts=k20201202; t=1777298405;\n\tbh=1M7X8jOCHkeLS6fn4xzZWtWs67rOTDG2AL/8546NOlk=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=XZVjs1KPQbSj9+RUKCOXJI1F/eTohGWVETAO4evJbYcbtUxFKs5RJynM0j9ejwFAf\n\t 0jgut4X+sdR7AToiMV9NyVJl5tkD79BLCfYXUxyXjECd/hL8ODyNqSF48s4vivIfUD\n\t epZxGxpb2jvXFxQeSGXRTer8E0Vq/uzHQU4hBUn5Rc1N7Sopw/wxShbS+JzaFFYs1l\n\t o7FtLFoLTXY5hqzAg4y6VOYt6zvm/X82ysLFmhTVB4Zpk41E4/P0YTZY/Bvdu/l4hr\n\t GT4HaTFNfyCSjHS3xnMSeICctwD16/ZyGhKW6a91+d1Aup5GRwcJfgs7Rt19gA4phi\n\t qaAemgtOjOVJA==","From":"Tzung-Bi Shih <tzungbi@kernel.org>","To":"Arnd Bergmann <arnd@arndb.de>,\n\tGreg Kroah-Hartman <gregkh@linuxfoundation.org>,\n\tBartosz Golaszewski <brgl@kernel.org>,\n\tLinus Walleij <linusw@kernel.org>","Cc":"Benson Leung <bleung@chromium.org>,\n\ttzungbi@kernel.org,\n\tlinux-kernel@vger.kernel.org,\n\tchrome-platform@lists.linux.dev,\n\tdriver-core@lists.linux.dev,\n\tlinux-doc@vger.kernel.org,\n\tlinux-gpio@vger.kernel.org,\n\t\"Rafael J. Wysocki\" <rafael@kernel.org>,\n\tDanilo Krummrich <dakr@kernel.org>,\n\tJonathan Corbet <corbet@lwn.net>,\n\tShuah Khan <shuah@kernel.org>,\n\tLaurent Pinchart <laurent.pinchart@ideasonboard.com>,\n\tWolfram Sang <wsa+renesas@sang-engineering.com>,\n\tJason Gunthorpe <jgg@nvidia.com>,\n\tJohan Hovold <johan@kernel.org>,\n\t\"Paul E . McKenney\" <paulmck@kernel.org>,\n\tDan Williams <dan.j.williams@intel.com>","Subject":"[PATCH v9 9/9] platform/chrome: cros_ec_chardev: Consume\n cros_ec_device via revocable","Date":"Mon, 27 Apr 2026 21:58:41 +0800","Message-ID":"<20260427135841.96266-10-tzungbi@kernel.org>","X-Mailer":"git-send-email 2.51.0","In-Reply-To":"<20260427135841.96266-1-tzungbi@kernel.org>","References":"<20260427135841.96266-1-tzungbi@kernel.org>","Precedence":"bulk","X-Mailing-List":"linux-gpio@vger.kernel.org","List-Id":"<linux-gpio.vger.kernel.org>","List-Subscribe":"<mailto:linux-gpio+subscribe@vger.kernel.org>","List-Unsubscribe":"<mailto:linux-gpio+unsubscribe@vger.kernel.org>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit"},"content":"The cros_ec_chardev driver provides a character device interface to the\nChromeOS EC.  A file handle to this device can remain open in userspace\neven if the underlying EC device is removed.\n\nThis creates a classic use-after-free vulnerability.  Any file operation\n(ioctl, release, etc.) on the open handle after the EC device has gone\nwould access a stale pointer, leading to a system crash.\n\nTo prevent this, leverage the revocable and convert cros_ec_chardev to a\nresource consumer of cros_ec_device.\n\nSigned-off-by: Tzung-Bi Shih <tzungbi@kernel.org>\n---\nv9:\n- New to the series.\n- Change revocable API usages accordingly.\n\nv4 - v8:\n- Doesn't exist.\n\nv3: https://lore.kernel.org/all/20250912081718.3827390-6-tzungbi@kernel.org\n- Use specific labels for different cleanup in cros_ec_chardev_open().\n\nv2: https://lore.kernel.org/all/20250820081645.847919-6-tzungbi@kernel.org\n- Rename \"ref_proxy\" -> \"revocable\".\n- Fix a sparse warning by removing the redundant __rcu annotation.\n\nv1: https://lore.kernel.org/all/20250814091020.1302888-4-tzungbi@kernel.org\n\n---\n drivers/platform/chrome/cros_ec_chardev.c | 80 +++++++++++++++++------\n 1 file changed, 61 insertions(+), 19 deletions(-)","diff":"diff --git a/drivers/platform/chrome/cros_ec_chardev.c b/drivers/platform/chrome/cros_ec_chardev.c\nindex 002be3352100..c597dc92d519 100644\n--- a/drivers/platform/chrome/cros_ec_chardev.c\n+++ b/drivers/platform/chrome/cros_ec_chardev.c\n@@ -22,6 +22,7 @@\n #include <linux/platform_data/cros_ec_proto.h>\n #include <linux/platform_device.h>\n #include <linux/poll.h>\n+#include <linux/revocable.h>\n #include <linux/slab.h>\n #include <linux/types.h>\n #include <linux/uaccess.h>\n@@ -32,7 +33,7 @@\n #define CROS_MAX_EVENT_LEN\tPAGE_SIZE\n \n struct chardev_priv {\n-\tstruct cros_ec_device *ec_dev;\n+\tstruct revocable *rev;\n \tstruct notifier_block notifier;\n \twait_queue_head_t wait_event;\n \tunsigned long event_mask;\n@@ -55,6 +56,7 @@ static int ec_get_version(struct chardev_priv *priv, char *str, int maxlen)\n \t};\n \tstruct ec_response_get_version *resp;\n \tstruct cros_ec_command *msg;\n+\tstruct cros_ec_device *ec_dev;\n \tint ret;\n \n \tmsg = kzalloc(sizeof(*msg) + sizeof(*resp), GFP_KERNEL);\n@@ -64,12 +66,19 @@ static int ec_get_version(struct chardev_priv *priv, char *str, int maxlen)\n \tmsg->command = EC_CMD_GET_VERSION + priv->cmd_offset;\n \tmsg->insize = sizeof(*resp);\n \n-\tret = cros_ec_cmd_xfer_status(priv->ec_dev, msg);\n-\tif (ret < 0) {\n-\t\tsnprintf(str, maxlen,\n-\t\t\t \"Unknown EC version, returned error: %d\\n\",\n-\t\t\t msg->result);\n-\t\tgoto exit;\n+\trevocable_try_access_with_scoped(priv->rev, ec_dev) {\n+\t\tif (!ec_dev) {\n+\t\t\tret = -ENODEV;\n+\t\t\tgoto exit;\n+\t\t}\n+\n+\t\tret = cros_ec_cmd_xfer_status(ec_dev, msg);\n+\t\tif (ret < 0) {\n+\t\t\tsnprintf(str, maxlen,\n+\t\t\t\t \"Unknown EC version, returned error: %d\\n\",\n+\t\t\t\t msg->result);\n+\t\t\tgoto exit;\n+\t\t}\n \t}\n \n \tresp = (struct ec_response_get_version *)msg->data;\n@@ -92,10 +101,15 @@ static int cros_ec_chardev_mkbp_event(struct notifier_block *nb,\n {\n \tstruct chardev_priv *priv = container_of(nb, struct chardev_priv,\n \t\t\t\t\t\t notifier);\n-\tstruct cros_ec_device *ec_dev = priv->ec_dev;\n+\tstruct cros_ec_device *ec_dev;\n \tstruct ec_event *event;\n-\tunsigned long event_bit = 1 << ec_dev->event_data.event_type;\n-\tint total_size = sizeof(*event) + ec_dev->event_size;\n+\tunsigned long event_bit;\n+\tint total_size;\n+\n+\trevocable_try_access_or_return_err(priv->rev, ec_dev, NOTIFY_DONE);\n+\n+\tevent_bit = 1 << ec_dev->event_data.event_type;\n+\ttotal_size = sizeof(*event) + ec_dev->event_size;\n \n \tif (!(event_bit & priv->event_mask) ||\n \t    (priv->event_len + total_size) > CROS_MAX_EVENT_LEN)\n@@ -166,7 +180,8 @@ static int cros_ec_chardev_open(struct inode *inode, struct file *filp)\n \tif (!priv)\n \t\treturn -ENOMEM;\n \n-\tpriv->ec_dev = ec_dev;\n+\tpriv->rev = ec_dev->its_rev;\n+\trevocable_get(priv->rev);\n \tpriv->cmd_offset = ec->cmd_offset;\n \tfilp->private_data = priv;\n \tINIT_LIST_HEAD(&priv->events);\n@@ -178,6 +193,7 @@ static int cros_ec_chardev_open(struct inode *inode, struct file *filp)\n \t\t\t\t\t       &priv->notifier);\n \tif (ret) {\n \t\tdev_err(ec_dev->dev, \"failed to register event notifier\\n\");\n+\t\trevocable_put(priv->rev);\n \t\tkfree(priv);\n \t}\n \n@@ -251,11 +267,13 @@ static ssize_t cros_ec_chardev_read(struct file *filp, char __user *buffer,\n static int cros_ec_chardev_release(struct inode *inode, struct file *filp)\n {\n \tstruct chardev_priv *priv = filp->private_data;\n-\tstruct cros_ec_device *ec_dev = priv->ec_dev;\n+\tstruct cros_ec_device *ec_dev;\n \tstruct ec_event *event, *e;\n \n-\tblocking_notifier_chain_unregister(&ec_dev->event_notifier,\n-\t\t\t\t\t   &priv->notifier);\n+\trevocable_try_access_or_skip_scoped(priv->rev, ec_dev)\n+\t\tblocking_notifier_chain_unregister(&ec_dev->event_notifier,\n+\t\t\t\t\t\t   &priv->notifier);\n+\trevocable_put(priv->rev);\n \n \tlist_for_each_entry_safe(event, e, &priv->events, node) {\n \t\tlist_del(&event->node);\n@@ -273,6 +291,7 @@ static long cros_ec_chardev_ioctl_xcmd(struct chardev_priv *priv, void __user *a\n {\n \tstruct cros_ec_command *s_cmd;\n \tstruct cros_ec_command u_cmd;\n+\tstruct cros_ec_device *ec_dev;\n \tlong ret;\n \n \tif (copy_from_user(&u_cmd, arg, sizeof(u_cmd)))\n@@ -299,10 +318,17 @@ static long cros_ec_chardev_ioctl_xcmd(struct chardev_priv *priv, void __user *a\n \t}\n \n \ts_cmd->command += priv->cmd_offset;\n-\tret = cros_ec_cmd_xfer(priv->ec_dev, s_cmd);\n-\t/* Only copy data to userland if data was received. */\n-\tif (ret < 0)\n-\t\tgoto exit;\n+\trevocable_try_access_with_scoped(priv->rev, ec_dev) {\n+\t\tif (!ec_dev) {\n+\t\t\tret = -ENODEV;\n+\t\t\tgoto exit;\n+\t\t}\n+\n+\t\tret = cros_ec_cmd_xfer(ec_dev, s_cmd);\n+\t\t/* Only copy data to userland if data was received. */\n+\t\tif (ret < 0)\n+\t\t\tgoto exit;\n+\t}\n \n \tif (copy_to_user(arg, s_cmd, sizeof(*s_cmd) + s_cmd->insize))\n \t\tret = -EFAULT;\n@@ -313,10 +339,12 @@ static long cros_ec_chardev_ioctl_xcmd(struct chardev_priv *priv, void __user *a\n \n static long cros_ec_chardev_ioctl_readmem(struct chardev_priv *priv, void __user *arg)\n {\n-\tstruct cros_ec_device *ec_dev = priv->ec_dev;\n+\tstruct cros_ec_device *ec_dev;\n \tstruct cros_ec_readmem s_mem = { };\n \tlong num;\n \n+\trevocable_try_access_or_return(priv->rev, ec_dev);\n+\n \t/* Not every platform supports direct reads */\n \tif (!ec_dev->cmd_readmem)\n \t\treturn -ENOTTY;\n@@ -370,11 +398,25 @@ static const struct file_operations chardev_fops = {\n #endif\n };\n \n+static void cros_ec_chardev_free(void *data)\n+{\n+\tstruct revocable *rev = data;\n+\n+\trevocable_put(rev);\n+}\n+\n static int cros_ec_chardev_probe(struct platform_device *pdev)\n {\n \tstruct cros_ec_dev *ec = dev_get_drvdata(pdev->dev.parent);\n \tstruct cros_ec_platform *ec_platform = dev_get_platdata(ec->dev);\n+\tstruct revocable *rev = ec->ec_dev->its_rev;\n \tstruct miscdevice *misc;\n+\tint ret;\n+\n+\trevocable_get(rev);\n+\tret = devm_add_action_or_reset(&pdev->dev, cros_ec_chardev_free, rev);\n+\tif (ret)\n+\t\treturn ret;\n \n \t/* Create a char device: we want to create it anew */\n \tmisc = devm_kzalloc(&pdev->dev, sizeof(*misc), GFP_KERNEL);\n","prefixes":["v9","9/9"]}