[PATCH 4/8] char: xillybus: Rely on FMODE flags in poll method

From: Eli Billauer

Date: Mon Nov 09 2026 - 06:34:09 EST


The poll method of xillyusb.c previously tested chan->in_fifo and
chan->out_ep for being NULL in order to determine if the file is opened
for read and/or write, respectively. This works incorrectly if two files
are opened on the same device file, one for read and one for write.

In particular, if the release method is called for the file opened for
read while a poll is called for the file opened for write (and vice
versa), a race condition could lead to access of freed memory.

Relying on the FMODE flags as a guarantee for the validity of
chan->in_fifo and chan->out_ep as pointers to allocated memory is safe,
as the allocation and deallocation occurs with the open and release
methods for each file.

Assisted-by: Sashiko-0.2.5:gemini-3.1-pro-preview
Link: https://sashiko.dev/#/patchset/20260724094302.50761-1-eli.billauer@xxxxxxxxx
Signed-off-by: Eli Billauer <eli.billauer@xxxxxxxxx>
---
drivers/char/xillybus/xillyusb.c | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/drivers/char/xillybus/xillyusb.c b/drivers/char/xillybus/xillyusb.c
index 45612fd760f0..73e26f254693 100644
--- a/drivers/char/xillybus/xillyusb.c
+++ b/drivers/char/xillybus/xillyusb.c
@@ -1856,10 +1856,13 @@ static __poll_t xillyusb_poll(struct file *filp, poll_table *wait)
struct xillyusb_channel *chan = filp->private_data;
__poll_t mask = 0;

- if (chan->in_fifo)
+ bool open_for_read = !!(filp->f_mode & FMODE_READ);
+ bool open_for_write = !!(filp->f_mode & FMODE_WRITE);
+
+ if (open_for_read)
poll_wait(filp, &chan->in_fifo->waitq, wait);

- if (chan->out_ep)
+ if (open_for_write)
poll_wait(filp, &chan->out_ep->fifo.waitq, wait);

/*
@@ -1872,7 +1875,7 @@ static __poll_t xillyusb_poll(struct file *filp, poll_table *wait)
* wait queue.
*/

- if (!chan->poll_used && chan->in_fifo) {
+ if (!chan->poll_used && open_for_read) {
chan->poll_used = 1;
request_read_anything(chan, OPCODE_SET_PUSH);
}
@@ -1884,11 +1887,11 @@ static __poll_t xillyusb_poll(struct file *filp, poll_table *wait)
* which it may not. So make it never work.
*/

- if (chan->in_fifo && !chan->in_synchronous &&
+ if (open_for_read && !chan->in_synchronous &&
(READ_ONCE(chan->in_fifo->fill) || !chan->read_data_ok))
mask |= EPOLLIN | EPOLLRDNORM;

- if (chan->out_ep &&
+ if (open_for_write &&
(READ_ONCE(chan->out_ep->fifo.fill) != chan->out_ep->fifo.size))
mask |= EPOLLOUT | EPOLLWRNORM;

--
2.17.1