* [PATCH v3 1/4] platform/chrome: cros_ec_chardev: Introduce chardev_data
2026-05-25 5:26 [PATCH v3 0/4] platform/chrome: cros_ec_chardev: Fix a potential UAF Tzung-Bi Shih
@ 2026-05-25 5:26 ` Tzung-Bi Shih
2026-05-25 5:26 ` [PATCH v3 2/4] platform/chrome: cros_ec_chardev: Move data to chardev_pdata Tzung-Bi Shih
` (3 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Tzung-Bi Shih @ 2026-05-25 5:26 UTC (permalink / raw)
To: Benson Leung, Jason Gunthorpe, Greg Kroah-Hartman
Cc: tzungbi, chrome-platform, linux-kernel
Introduce struct chardev_pdata to hold platform driver data.
The platform driver data is allocated by kzalloc() instead of devm
variant, allowing for managed cleanup that can eventually extend beyond
device removal if files are still open.
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Tzung-Bi Shih <tzungbi@kernel.org>
---
v3:
- Add R-b tag.
v2:
- No changes.
v1: https://lore.kernel.org/all/20260427134659.95181-6-tzungbi@kernel.org
drivers/platform/chrome/cros_ec_chardev.c | 51 +++++++++++++++++------
1 file changed, 39 insertions(+), 12 deletions(-)
diff --git a/drivers/platform/chrome/cros_ec_chardev.c b/drivers/platform/chrome/cros_ec_chardev.c
index 002be3352100..e7012e44a006 100644
--- a/drivers/platform/chrome/cros_ec_chardev.c
+++ b/drivers/platform/chrome/cros_ec_chardev.c
@@ -13,6 +13,7 @@
#include <linux/init.h>
#include <linux/device.h>
#include <linux/fs.h>
+#include <linux/kref.h>
#include <linux/miscdevice.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
@@ -31,6 +32,21 @@
/* Arbitrary bounded size for the event queue */
#define CROS_MAX_EVENT_LEN PAGE_SIZE
+/*
+ * Platform device driver data.
+ */
+struct chardev_pdata {
+ struct miscdevice misc;
+ struct kref kref;
+};
+
+static void chardev_pdata_release(struct kref *kref)
+{
+ struct chardev_pdata *pdata = container_of(kref, typeof(*pdata), kref);
+
+ kfree(pdata);
+}
+
struct chardev_priv {
struct cros_ec_device *ec_dev;
struct notifier_block notifier;
@@ -374,28 +390,39 @@ static int cros_ec_chardev_probe(struct platform_device *pdev)
{
struct cros_ec_dev *ec = dev_get_drvdata(pdev->dev.parent);
struct cros_ec_platform *ec_platform = dev_get_platdata(ec->dev);
- struct miscdevice *misc;
+ struct chardev_pdata *pdata;
+ int ret;
- /* Create a char device: we want to create it anew */
- misc = devm_kzalloc(&pdev->dev, sizeof(*misc), GFP_KERNEL);
- if (!misc)
+ pdata = kzalloc_obj(*pdata);
+ if (!pdata)
return -ENOMEM;
- misc->minor = MISC_DYNAMIC_MINOR;
- misc->fops = &chardev_fops;
- misc->name = ec_platform->ec_name;
- misc->parent = pdev->dev.parent;
+ platform_set_drvdata(pdev, pdata);
+ kref_init(&pdata->kref);
- dev_set_drvdata(&pdev->dev, misc);
+ pdata->misc.minor = MISC_DYNAMIC_MINOR;
+ pdata->misc.fops = &chardev_fops;
+ pdata->misc.name = ec_platform->ec_name;
+ pdata->misc.parent = pdev->dev.parent;
- return misc_register(misc);
+ ret = misc_register(&pdata->misc);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register misc device\n");
+ goto err_put_pdata;
+ }
+
+ return 0;
+err_put_pdata:
+ kref_put(&pdata->kref, chardev_pdata_release);
+ return ret;
}
static void cros_ec_chardev_remove(struct platform_device *pdev)
{
- struct miscdevice *misc = dev_get_drvdata(&pdev->dev);
+ struct chardev_pdata *pdata = platform_get_drvdata(pdev);
- misc_deregister(misc);
+ misc_deregister(&pdata->misc);
+ kref_put(&pdata->kref, chardev_pdata_release);
}
static const struct platform_device_id cros_ec_chardev_id[] = {
--
2.54.0.794.g4f17f83d09-goog
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH v3 2/4] platform/chrome: cros_ec_chardev: Move data to chardev_pdata
2026-05-25 5:26 [PATCH v3 0/4] platform/chrome: cros_ec_chardev: Fix a potential UAF Tzung-Bi Shih
2026-05-25 5:26 ` [PATCH v3 1/4] platform/chrome: cros_ec_chardev: Introduce chardev_data Tzung-Bi Shih
@ 2026-05-25 5:26 ` Tzung-Bi Shih
2026-05-25 5:26 ` [PATCH v3 3/4] platform/chrome: cros_ec_chardev: Add event relayer Tzung-Bi Shih
` (2 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Tzung-Bi Shih @ 2026-05-25 5:26 UTC (permalink / raw)
To: Benson Leung, Jason Gunthorpe, Greg Kroah-Hartman
Cc: tzungbi, chrome-platform, linux-kernel
Move `ec_dev` and `cmd_offset` from `chardev_priv` to `chardev_pdata` as
they are per-device properties but not per-open-file properties.
Hold a reference to `chardev_pdata` for each open file to ensure the
data remains valid even if the underlying platform device is removed.
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Tzung-Bi Shih <tzungbi@kernel.org>
---
v3:
- Add R-b tag.
v2:
- No changes.
v1: https://lore.kernel.org/all/20260427134659.95181-7-tzungbi@kernel.org
drivers/platform/chrome/cros_ec_chardev.c | 36 +++++++++++++----------
1 file changed, 20 insertions(+), 16 deletions(-)
diff --git a/drivers/platform/chrome/cros_ec_chardev.c b/drivers/platform/chrome/cros_ec_chardev.c
index e7012e44a006..352d61a2f3c6 100644
--- a/drivers/platform/chrome/cros_ec_chardev.c
+++ b/drivers/platform/chrome/cros_ec_chardev.c
@@ -38,6 +38,8 @@
struct chardev_pdata {
struct miscdevice misc;
struct kref kref;
+ struct cros_ec_device *ec_dev;
+ u16 cmd_offset;
};
static void chardev_pdata_release(struct kref *kref)
@@ -48,13 +50,12 @@ static void chardev_pdata_release(struct kref *kref)
}
struct chardev_priv {
- struct cros_ec_device *ec_dev;
struct notifier_block notifier;
wait_queue_head_t wait_event;
unsigned long event_mask;
struct list_head events;
size_t event_len;
- u16 cmd_offset;
+ struct chardev_pdata *pdata;
};
struct ec_event {
@@ -77,10 +78,10 @@ static int ec_get_version(struct chardev_priv *priv, char *str, int maxlen)
if (!msg)
return -ENOMEM;
- msg->command = EC_CMD_GET_VERSION + priv->cmd_offset;
+ msg->command = EC_CMD_GET_VERSION + priv->pdata->cmd_offset;
msg->insize = sizeof(*resp);
- ret = cros_ec_cmd_xfer_status(priv->ec_dev, msg);
+ ret = cros_ec_cmd_xfer_status(priv->pdata->ec_dev, msg);
if (ret < 0) {
snprintf(str, maxlen,
"Unknown EC version, returned error: %d\n",
@@ -108,7 +109,7 @@ static int cros_ec_chardev_mkbp_event(struct notifier_block *nb,
{
struct chardev_priv *priv = container_of(nb, struct chardev_priv,
notifier);
- struct cros_ec_device *ec_dev = priv->ec_dev;
+ struct cros_ec_device *ec_dev = priv->pdata->ec_dev;
struct ec_event *event;
unsigned long event_bit = 1 << ec_dev->event_data.event_type;
int total_size = sizeof(*event) + ec_dev->event_size;
@@ -173,8 +174,7 @@ static struct ec_event *cros_ec_chardev_fetch_event(struct chardev_priv *priv,
static int cros_ec_chardev_open(struct inode *inode, struct file *filp)
{
struct miscdevice *mdev = filp->private_data;
- struct cros_ec_dev *ec = dev_get_drvdata(mdev->parent);
- struct cros_ec_device *ec_dev = ec->ec_dev;
+ struct chardev_pdata *pdata = container_of(mdev, typeof(*pdata), misc);
struct chardev_priv *priv;
int ret;
@@ -182,18 +182,20 @@ static int cros_ec_chardev_open(struct inode *inode, struct file *filp)
if (!priv)
return -ENOMEM;
- priv->ec_dev = ec_dev;
- priv->cmd_offset = ec->cmd_offset;
+ priv->pdata = pdata;
+ kref_get(&pdata->kref);
filp->private_data = priv;
INIT_LIST_HEAD(&priv->events);
init_waitqueue_head(&priv->wait_event);
nonseekable_open(inode, filp);
priv->notifier.notifier_call = cros_ec_chardev_mkbp_event;
- ret = blocking_notifier_chain_register(&ec_dev->event_notifier,
+ ret = blocking_notifier_chain_register(&pdata->ec_dev->event_notifier,
&priv->notifier);
if (ret) {
- dev_err(ec_dev->dev, "failed to register event notifier\n");
+ dev_err(pdata->ec_dev->dev,
+ "failed to register event notifier\n");
+ kref_put(&priv->pdata->kref, chardev_pdata_release);
kfree(priv);
}
@@ -267,11 +269,11 @@ static ssize_t cros_ec_chardev_read(struct file *filp, char __user *buffer,
static int cros_ec_chardev_release(struct inode *inode, struct file *filp)
{
struct chardev_priv *priv = filp->private_data;
- struct cros_ec_device *ec_dev = priv->ec_dev;
struct ec_event *event, *e;
- blocking_notifier_chain_unregister(&ec_dev->event_notifier,
+ blocking_notifier_chain_unregister(&priv->pdata->ec_dev->event_notifier,
&priv->notifier);
+ kref_put(&priv->pdata->kref, chardev_pdata_release);
list_for_each_entry_safe(event, e, &priv->events, node) {
list_del(&event->node);
@@ -314,8 +316,8 @@ static long cros_ec_chardev_ioctl_xcmd(struct chardev_priv *priv, void __user *a
goto exit;
}
- s_cmd->command += priv->cmd_offset;
- ret = cros_ec_cmd_xfer(priv->ec_dev, s_cmd);
+ s_cmd->command += priv->pdata->cmd_offset;
+ ret = cros_ec_cmd_xfer(priv->pdata->ec_dev, s_cmd);
/* Only copy data to userland if data was received. */
if (ret < 0)
goto exit;
@@ -329,7 +331,7 @@ static long cros_ec_chardev_ioctl_xcmd(struct chardev_priv *priv, void __user *a
static long cros_ec_chardev_ioctl_readmem(struct chardev_priv *priv, void __user *arg)
{
- struct cros_ec_device *ec_dev = priv->ec_dev;
+ struct cros_ec_device *ec_dev = priv->pdata->ec_dev;
struct cros_ec_readmem s_mem = { };
long num;
@@ -399,6 +401,8 @@ static int cros_ec_chardev_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, pdata);
kref_init(&pdata->kref);
+ pdata->ec_dev = ec->ec_dev;
+ pdata->cmd_offset = ec->cmd_offset;
pdata->misc.minor = MISC_DYNAMIC_MINOR;
pdata->misc.fops = &chardev_fops;
--
2.54.0.794.g4f17f83d09-goog
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH v3 3/4] platform/chrome: cros_ec_chardev: Add event relayer
2026-05-25 5:26 [PATCH v3 0/4] platform/chrome: cros_ec_chardev: Fix a potential UAF Tzung-Bi Shih
2026-05-25 5:26 ` [PATCH v3 1/4] platform/chrome: cros_ec_chardev: Introduce chardev_data Tzung-Bi Shih
2026-05-25 5:26 ` [PATCH v3 2/4] platform/chrome: cros_ec_chardev: Move data to chardev_pdata Tzung-Bi Shih
@ 2026-05-25 5:26 ` Tzung-Bi Shih
2026-05-25 5:26 ` [PATCH v3 4/4] platform/chrome: cros_ec_chardev: Introduce rwsem for protecting ec_dev Tzung-Bi Shih
2026-05-28 2:21 ` [PATCH v3 0/4] platform/chrome: cros_ec_chardev: Fix a potential UAF Tzung-Bi Shih
4 siblings, 0 replies; 7+ messages in thread
From: Tzung-Bi Shih @ 2026-05-25 5:26 UTC (permalink / raw)
To: Benson Leung, Jason Gunthorpe, Greg Kroah-Hartman
Cc: tzungbi, chrome-platform, linux-kernel
Introduce an event relayer mechanism. Instead of each open file
registering directly with `ec_dev->event_notifier`, the platform device
registers a single relayer notifier. Individual files then register
with a local subscribers list in `chardev_pdata`.
This allows the driver to safely disconnect from the event chain
`ec_dev->event_notifier` during cros_ec_chardev_remove(), preventing
events from being delivered to open files after the device is removed,
while still allowing those files to be closed safely later.
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Tzung-Bi Shih <tzungbi@kernel.org>
---
This is an implementation of the idea from [1].
[1] https://lore.kernel.org/all/20251117153301.GD10864@nvidia.com/
---
v3:
- Add R-b tag.
v2:
- No changes.
v1: https://lore.kernel.org/all/20260427134659.95181-8-tzungbi@kernel.org
drivers/platform/chrome/cros_ec_chardev.c | 32 ++++++++++++++++++++---
1 file changed, 29 insertions(+), 3 deletions(-)
diff --git a/drivers/platform/chrome/cros_ec_chardev.c b/drivers/platform/chrome/cros_ec_chardev.c
index 352d61a2f3c6..7e046fc56998 100644
--- a/drivers/platform/chrome/cros_ec_chardev.c
+++ b/drivers/platform/chrome/cros_ec_chardev.c
@@ -40,6 +40,8 @@ struct chardev_pdata {
struct kref kref;
struct cros_ec_device *ec_dev;
u16 cmd_offset;
+ struct blocking_notifier_head subscribers;
+ struct notifier_block relay;
};
static void chardev_pdata_release(struct kref *kref)
@@ -49,6 +51,17 @@ static void chardev_pdata_release(struct kref *kref)
kfree(pdata);
}
+static int cros_ec_chardev_relay_event(struct notifier_block *nb,
+ unsigned long queued_during_suspend,
+ void *_notify)
+{
+ struct chardev_pdata *pdata = container_of(nb, typeof(*pdata), relay);
+
+ blocking_notifier_call_chain(&pdata->subscribers, queued_during_suspend,
+ _notify);
+ return NOTIFY_OK;
+}
+
struct chardev_priv {
struct notifier_block notifier;
wait_queue_head_t wait_event;
@@ -190,7 +203,7 @@ static int cros_ec_chardev_open(struct inode *inode, struct file *filp)
nonseekable_open(inode, filp);
priv->notifier.notifier_call = cros_ec_chardev_mkbp_event;
- ret = blocking_notifier_chain_register(&pdata->ec_dev->event_notifier,
+ ret = blocking_notifier_chain_register(&pdata->subscribers,
&priv->notifier);
if (ret) {
dev_err(pdata->ec_dev->dev,
@@ -271,7 +284,7 @@ static int cros_ec_chardev_release(struct inode *inode, struct file *filp)
struct chardev_priv *priv = filp->private_data;
struct ec_event *event, *e;
- blocking_notifier_chain_unregister(&priv->pdata->ec_dev->event_notifier,
+ blocking_notifier_chain_unregister(&priv->pdata->subscribers,
&priv->notifier);
kref_put(&priv->pdata->kref, chardev_pdata_release);
@@ -403,6 +416,14 @@ static int cros_ec_chardev_probe(struct platform_device *pdev)
kref_init(&pdata->kref);
pdata->ec_dev = ec->ec_dev;
pdata->cmd_offset = ec->cmd_offset;
+ BLOCKING_INIT_NOTIFIER_HEAD(&pdata->subscribers);
+ pdata->relay.notifier_call = cros_ec_chardev_relay_event;
+ ret = blocking_notifier_chain_register(&pdata->ec_dev->event_notifier,
+ &pdata->relay);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register event notifier\n");
+ goto err_put_pdata;
+ }
pdata->misc.minor = MISC_DYNAMIC_MINOR;
pdata->misc.fops = &chardev_fops;
@@ -412,10 +433,13 @@ static int cros_ec_chardev_probe(struct platform_device *pdev)
ret = misc_register(&pdata->misc);
if (ret) {
dev_err(&pdev->dev, "failed to register misc device\n");
- goto err_put_pdata;
+ goto err_unregister_notifier;
}
return 0;
+err_unregister_notifier:
+ blocking_notifier_chain_unregister(&pdata->ec_dev->event_notifier,
+ &pdata->relay);
err_put_pdata:
kref_put(&pdata->kref, chardev_pdata_release);
return ret;
@@ -425,6 +449,8 @@ static void cros_ec_chardev_remove(struct platform_device *pdev)
{
struct chardev_pdata *pdata = platform_get_drvdata(pdev);
+ blocking_notifier_chain_unregister(&pdata->ec_dev->event_notifier,
+ &pdata->relay);
misc_deregister(&pdata->misc);
kref_put(&pdata->kref, chardev_pdata_release);
}
--
2.54.0.794.g4f17f83d09-goog
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH v3 4/4] platform/chrome: cros_ec_chardev: Introduce rwsem for protecting ec_dev
2026-05-25 5:26 [PATCH v3 0/4] platform/chrome: cros_ec_chardev: Fix a potential UAF Tzung-Bi Shih
` (2 preceding siblings ...)
2026-05-25 5:26 ` [PATCH v3 3/4] platform/chrome: cros_ec_chardev: Add event relayer Tzung-Bi Shih
@ 2026-05-25 5:26 ` Tzung-Bi Shih
2026-05-28 4:33 ` Tzung-Bi Shih
2026-05-28 2:21 ` [PATCH v3 0/4] platform/chrome: cros_ec_chardev: Fix a potential UAF Tzung-Bi Shih
4 siblings, 1 reply; 7+ messages in thread
From: Tzung-Bi Shih @ 2026-05-25 5:26 UTC (permalink / raw)
To: Benson Leung, Jason Gunthorpe, Greg Kroah-Hartman
Cc: tzungbi, chrome-platform, linux-kernel
Introduce a rwsem for protecting `ec_dev` to prevent Use-After-Free on
the `ec_dev`.
- Writers: In driver's probe() and remove().
- Readers: In file operations.
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Tzung-Bi Shih <tzungbi@kernel.org>
---
v3:
- Check availability of `ec_dev` at the top of fops.
- Fix removal order in .remove().
- Add R-b tag.
v2:
- New to the series.
v1: Doesn't exist.
drivers/platform/chrome/cros_ec_chardev.c | 39 ++++++++++++++++++++---
1 file changed, 34 insertions(+), 5 deletions(-)
diff --git a/drivers/platform/chrome/cros_ec_chardev.c b/drivers/platform/chrome/cros_ec_chardev.c
index 7e046fc56998..25ad409523b8 100644
--- a/drivers/platform/chrome/cros_ec_chardev.c
+++ b/drivers/platform/chrome/cros_ec_chardev.c
@@ -23,6 +23,7 @@
#include <linux/platform_data/cros_ec_proto.h>
#include <linux/platform_device.h>
#include <linux/poll.h>
+#include <linux/rwsem.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/uaccess.h>
@@ -38,6 +39,7 @@
struct chardev_pdata {
struct miscdevice misc;
struct kref kref;
+ struct rw_semaphore ec_dev_sem;
struct cros_ec_device *ec_dev;
u16 cmd_offset;
struct blocking_notifier_head subscribers;
@@ -122,10 +124,18 @@ static int cros_ec_chardev_mkbp_event(struct notifier_block *nb,
{
struct chardev_priv *priv = container_of(nb, struct chardev_priv,
notifier);
- struct cros_ec_device *ec_dev = priv->pdata->ec_dev;
+ struct cros_ec_device *ec_dev;
struct ec_event *event;
- unsigned long event_bit = 1 << ec_dev->event_data.event_type;
- int total_size = sizeof(*event) + ec_dev->event_size;
+ unsigned long event_bit;
+ int total_size;
+
+ guard(rwsem_read)(&priv->pdata->ec_dev_sem);
+ if (!priv->pdata->ec_dev)
+ return NOTIFY_DONE;
+ ec_dev = priv->pdata->ec_dev;
+
+ event_bit = 1 << ec_dev->event_data.event_type;
+ total_size = sizeof(*event) + ec_dev->event_size;
if (!(event_bit & priv->event_mask) ||
(priv->event_len + total_size) > CROS_MAX_EVENT_LEN)
@@ -219,6 +229,10 @@ static __poll_t cros_ec_chardev_poll(struct file *filp, poll_table *wait)
{
struct chardev_priv *priv = filp->private_data;
+ guard(rwsem_read)(&priv->pdata->ec_dev_sem);
+ if (!priv->pdata->ec_dev)
+ return -ENODEV;
+
poll_wait(filp, &priv->wait_event, wait);
if (list_empty(&priv->events))
@@ -236,6 +250,10 @@ static ssize_t cros_ec_chardev_read(struct file *filp, char __user *buffer,
size_t count;
int ret;
+ guard(rwsem_read)(&priv->pdata->ec_dev_sem);
+ if (!priv->pdata->ec_dev)
+ return -ENODEV;
+
if (priv->event_mask) { /* queued MKBP event */
struct ec_event *event;
@@ -374,6 +392,10 @@ static long cros_ec_chardev_ioctl(struct file *filp, unsigned int cmd,
{
struct chardev_priv *priv = filp->private_data;
+ guard(rwsem_read)(&priv->pdata->ec_dev_sem);
+ if (!priv->pdata->ec_dev)
+ return -ENODEV;
+
if (_IOC_TYPE(cmd) != CROS_EC_DEV_IOC)
return -ENOTTY;
@@ -414,6 +436,7 @@ static int cros_ec_chardev_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, pdata);
kref_init(&pdata->kref);
+ init_rwsem(&pdata->ec_dev_sem);
pdata->ec_dev = ec->ec_dev;
pdata->cmd_offset = ec->cmd_offset;
BLOCKING_INIT_NOTIFIER_HEAD(&pdata->subscribers);
@@ -448,10 +471,16 @@ static int cros_ec_chardev_probe(struct platform_device *pdev)
static void cros_ec_chardev_remove(struct platform_device *pdev)
{
struct chardev_pdata *pdata = platform_get_drvdata(pdev);
+ struct cros_ec_device *ec_dev = pdata->ec_dev;
- blocking_notifier_chain_unregister(&pdata->ec_dev->event_notifier,
- &pdata->relay);
+ /* stop new fops from being created */
misc_deregister(&pdata->misc);
+ /* stop existing fops from running */
+ scoped_guard(rwsem_write, &pdata->ec_dev_sem)
+ pdata->ec_dev = NULL;
+
+ blocking_notifier_chain_unregister(&ec_dev->event_notifier,
+ &pdata->relay);
kref_put(&pdata->kref, chardev_pdata_release);
}
--
2.54.0.794.g4f17f83d09-goog
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PATCH v3 4/4] platform/chrome: cros_ec_chardev: Introduce rwsem for protecting ec_dev
2026-05-25 5:26 ` [PATCH v3 4/4] platform/chrome: cros_ec_chardev: Introduce rwsem for protecting ec_dev Tzung-Bi Shih
@ 2026-05-28 4:33 ` Tzung-Bi Shih
0 siblings, 0 replies; 7+ messages in thread
From: Tzung-Bi Shih @ 2026-05-28 4:33 UTC (permalink / raw)
To: Benson Leung, Jason Gunthorpe, Greg Kroah-Hartman
Cc: chrome-platform, linux-kernel
On Mon, May 25, 2026 at 05:26:54AM +0000, Tzung-Bi Shih wrote:
> diff --git a/drivers/platform/chrome/cros_ec_chardev.c b/drivers/platform/chrome/cros_ec_chardev.c
> index 7e046fc56998..25ad409523b8 100644
...
> @@ -219,6 +229,10 @@ static __poll_t cros_ec_chardev_poll(struct file *filp, poll_table *wait)
> {
> struct chardev_priv *priv = filp->private_data;
>
> + guard(rwsem_read)(&priv->pdata->ec_dev_sem);
> + if (!priv->pdata->ec_dev)
> + return -ENODEV;
FWIW: I realized -ENODEV isn't a correct return value for poll().
Return EPOLLHUP instead, and squash into the patch.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v3 0/4] platform/chrome: cros_ec_chardev: Fix a potential UAF
2026-05-25 5:26 [PATCH v3 0/4] platform/chrome: cros_ec_chardev: Fix a potential UAF Tzung-Bi Shih
` (3 preceding siblings ...)
2026-05-25 5:26 ` [PATCH v3 4/4] platform/chrome: cros_ec_chardev: Introduce rwsem for protecting ec_dev Tzung-Bi Shih
@ 2026-05-28 2:21 ` Tzung-Bi Shih
4 siblings, 0 replies; 7+ messages in thread
From: Tzung-Bi Shih @ 2026-05-28 2:21 UTC (permalink / raw)
To: Benson Leung, Jason Gunthorpe, Greg Kroah-Hartman
Cc: chrome-platform, linux-kernel
On Mon, May 25, 2026 at 05:26:50AM +0000, Tzung-Bi Shih wrote:
> This series addresses a potential Use-After-Free error when a device is
> deregistered while file operations are still in progress or files remain
> open in cros_ec_chardev.
>
> - Patches 1 to 3 are preparation steps in cros_ec_chardev driver. They
> introduce reference counting for platform driver data and an event
> relayer. This removes the direct access to `ec_dev->event_notifier`
> in `cros_ec_chardev_release()`.
> - Patch 4 introduces a rwsem for protecting `ec_dev` to prevent the UAF
> error.
>
> [...]
Applied to
https://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux.git for-next
[1/4] platform/chrome: cros_ec_chardev: Introduce chardev_data
commit: 5ad1406881102bc3e94fd25311d1728dfaf435a2
[2/4] platform/chrome: cros_ec_chardev: Move data to chardev_pdata
commit: 74aa0d4008051878c632530f2a2c13cff8e9b171
[3/4] platform/chrome: cros_ec_chardev: Add event relayer
commit: 6c1977b1f760d7ec71da78781f1d9eeb7a0e21f2
[4/4] platform/chrome: cros_ec_chardev: Introduce rwsem for protecting ec_dev
commit: 77750c0d8d837f59ad6ecde0157fd245ff3f3421
Thanks!
^ permalink raw reply [flat|nested] 7+ messages in thread