summaryrefslogtreecommitdiffstats
path: root/drivers/counter/counter-chrdev.c
diff options
context:
space:
mode:
authorWilliam Breathitt Gray <vilhelm.gray@gmail.com>2021-10-21 19:35:40 +0900
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2021-10-21 13:02:47 +0200
commit8ac33b8b6841e99a624ace543d92cbf598a91381 (patch)
treebfbb42f1f6f41bc9fb8cae0098746d382196ad67 /drivers/counter/counter-chrdev.c
parent310e75c72fefa3b0b4535f669c8b37c963a2dba5 (diff)
downloadlinux-8ac33b8b6841e99a624ace543d92cbf598a91381.tar.bz2
counter: Fix use-after-free race condition for events_queue_size write
A race condition is possible when writing to events_queue_size where the events kfifo is freed during the execution of a kfifo_in(), resulting in a use-after-free. This patch prevents such a scenario by protecting the events queue in operation with a spinlock and locking before performing the events queue size adjustment. The existing events_lock mutex is renamed to events_out_lock to reflect that it only protects events queue out operations. Because the events queue in operations can occur in an interrupt context, a new events_in_lock spinlock is introduced and utilized. Fixes: feff17a550c7 ("counter: Implement events_queue_size sysfs attribute") Cc: David Lechner <david@lechnology.com> Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com> Link: https://lore.kernel.org/r/20211021103540.955639-1-vilhelm.gray@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/counter/counter-chrdev.c')
-rw-r--r--drivers/counter/counter-chrdev.c10
1 files changed, 6 insertions, 4 deletions
diff --git a/drivers/counter/counter-chrdev.c b/drivers/counter/counter-chrdev.c
index 0c82613582f1..b7c62f957a6a 100644
--- a/drivers/counter/counter-chrdev.c
+++ b/drivers/counter/counter-chrdev.c
@@ -81,10 +81,10 @@ static ssize_t counter_chrdev_read(struct file *filp, char __user *buf,
return -ENODEV;
}
- if (mutex_lock_interruptible(&counter->events_lock))
+ if (mutex_lock_interruptible(&counter->events_out_lock))
return -ERESTARTSYS;
err = kfifo_to_user(&counter->events, buf, len, &copied);
- mutex_unlock(&counter->events_lock);
+ mutex_unlock(&counter->events_out_lock);
if (err < 0)
return err;
} while (!copied);
@@ -436,7 +436,8 @@ int counter_chrdev_add(struct counter_device *const counter)
spin_lock_init(&counter->events_list_lock);
mutex_init(&counter->n_events_list_lock);
init_waitqueue_head(&counter->events_wait);
- mutex_init(&counter->events_lock);
+ spin_lock_init(&counter->events_in_lock);
+ mutex_init(&counter->events_out_lock);
/* Initialize character device */
cdev_init(&counter->chrdev, &counter_fops);
@@ -559,7 +560,8 @@ void counter_push_event(struct counter_device *const counter, const u8 event,
ev.watch.component = comp_node->component;
ev.status = -counter_get_data(counter, comp_node, &ev.value);
- copied += kfifo_in(&counter->events, &ev, 1);
+ copied += kfifo_in_spinlocked_noirqsave(&counter->events, &ev,
+ 1, &counter->events_in_lock);
}
exit_early: