mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
ipack: ipoctal: add rwsem to guard against TOCTOU in remove path
The "removed" flag check in each tty op has a TOCTOU race with __ipoctal_remove(): the device could be removed between the flag check and the subsequent access to hardware resources (channel registers via iowrite8, or xmit_buf in write_tty). Close this race by introducing a read-write semaphore (remove_sem). The tty ops acquire the read lock via guard(rwsem_read) for the full duration of the operation, while __ipoctal_remove() acquires the write lock via scoped_guard(rwsem_write) when setting the removed flag. This ensures that once removed is true, no in-flight tty op can still be accessing resources that are about to be freed by the remove path. Signed-off-by: Pei Xiao <xiaopei01@kylinos.cn> Link: https://patch.msgid.link/fbce75010a0f0a3a3709a5e06fd0ffd19ca0a0ed.1782870760.git.xiaopei01@kylinos.cn Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
b6b5d64cb1
commit
7d3a708af7
@@ -11,6 +11,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/rwsem.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/serial.h>
|
||||
@@ -54,6 +55,7 @@ struct ipoctal {
|
||||
u8 __iomem *int_space;
|
||||
struct kref kref;
|
||||
struct module *carrier_owner;
|
||||
struct rw_semaphore remove_sem;
|
||||
bool removed;
|
||||
};
|
||||
|
||||
@@ -81,7 +83,7 @@ static int ipoctal_port_activate(struct tty_port *port, struct tty_struct *tty)
|
||||
channel = dev_get_drvdata(tty->dev);
|
||||
ipoctal = chan_to_ipoctal(channel, tty->index);
|
||||
|
||||
|
||||
guard(rwsem_read)(&ipoctal->remove_sem);
|
||||
if (ipoctal->removed)
|
||||
return -ENODEV;
|
||||
|
||||
@@ -476,7 +478,7 @@ static ssize_t ipoctal_write_tty(struct tty_struct *tty, const u8 *buf,
|
||||
struct ipoctal *ipoctal = chan_to_ipoctal(channel, tty->index);
|
||||
size_t char_copied;
|
||||
|
||||
|
||||
guard(rwsem_read)(&ipoctal->remove_sem);
|
||||
if (ipoctal->removed || !channel->tty_port.xmit_buf)
|
||||
return 0;
|
||||
|
||||
@@ -522,7 +524,7 @@ static void ipoctal_set_termios(struct tty_struct *tty,
|
||||
struct ipoctal *ipoctal = chan_to_ipoctal(channel, tty->index);
|
||||
speed_t baud;
|
||||
|
||||
|
||||
guard(rwsem_read)(&ipoctal->remove_sem);
|
||||
if (ipoctal->removed)
|
||||
return;
|
||||
|
||||
@@ -660,7 +662,7 @@ static void ipoctal_hangup(struct tty_struct *tty)
|
||||
return;
|
||||
|
||||
ipoctal = chan_to_ipoctal(channel, tty->index);
|
||||
|
||||
guard(rwsem_read)(&ipoctal->remove_sem);
|
||||
if (ipoctal->removed)
|
||||
return;
|
||||
|
||||
@@ -686,7 +688,7 @@ static void ipoctal_shutdown(struct tty_struct *tty)
|
||||
return;
|
||||
|
||||
ipoctal = chan_to_ipoctal(channel, tty->index);
|
||||
|
||||
guard(rwsem_read)(&ipoctal->remove_sem);
|
||||
if (ipoctal->removed)
|
||||
return;
|
||||
|
||||
@@ -736,6 +738,7 @@ static int ipoctal_probe(struct ipack_device *dev)
|
||||
return -ENOMEM;
|
||||
|
||||
kref_init(&ipoctal->kref);
|
||||
init_rwsem(&ipoctal->remove_sem);
|
||||
|
||||
ipoctal->dev = dev;
|
||||
ipoctal->carrier_owner = dev->bus->owner;
|
||||
@@ -755,7 +758,8 @@ static void __ipoctal_remove(struct ipoctal *ipoctal)
|
||||
{
|
||||
int i;
|
||||
|
||||
ipoctal->removed = true;
|
||||
scoped_guard(rwsem_write, &ipoctal->remove_sem)
|
||||
ipoctal->removed = true;
|
||||
|
||||
ipoctal->dev->bus->ops->free_irq(ipoctal->dev);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user