[PATCH linux dev-4.10 1/2] drivers (fsi): sbefifo: Fix xfr deletion in lists
Eddie James
eajames at linux.vnet.ibm.com
Fri Oct 27 07:15:12 AEDT 2017
From: "Edward A. James" <eajames at us.ibm.com>
Deleting an element of a list while iterating means that you'll access
recently freed memory when getting the next list element.
Signed-off-by: Edward A. James <eajames at us.ibm.com>
---
drivers/fsi/fsi-sbefifo.c | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/drivers/fsi/fsi-sbefifo.c b/drivers/fsi/fsi-sbefifo.c
index f756822..088172c 100644
--- a/drivers/fsi/fsi-sbefifo.c
+++ b/drivers/fsi/fsi-sbefifo.c
@@ -316,14 +316,15 @@ static void sbefifo_client_release(struct kref *kref)
{
struct sbefifo *sbefifo;
struct sbefifo_client *client;
- struct sbefifo_xfr *xfr;
+ struct sbefifo_xfr *xfr, *tmp;
client = container_of(kref, struct sbefifo_client, kref);
sbefifo = client->dev;
if (!READ_ONCE(sbefifo->rc)) {
- list_for_each_entry(xfr, &client->xfrs, client) {
+ list_for_each_entry_safe(xfr, tmp, &client->xfrs, client) {
if (test_bit(SBEFIFO_XFR_COMPLETE, &xfr->flags)) {
+ list_del(&xfr->client);
kfree(xfr);
continue;
}
@@ -376,7 +377,7 @@ static void sbefifo_poll_timer(unsigned long data)
static const unsigned long EOT_MASK = 0x000000ff;
struct sbefifo *sbefifo = (void *)data;
struct sbefifo_buf *rbuf, *wbuf;
- struct sbefifo_xfr *xfr = NULL;
+ struct sbefifo_xfr *xfr, *tmp;
struct sbefifo_buf drain;
size_t devn, bufn;
int eot = 0;
@@ -491,8 +492,10 @@ static void sbefifo_poll_timer(unsigned long data)
sbefifo->rc = ret;
dev_err(&sbefifo->fsi_dev->dev,
"Fatal bus access failure: %d\n", ret);
- list_for_each_entry(xfr, &sbefifo->xfrs, xfrs)
+ list_for_each_entry_safe(xfr, tmp, &sbefifo->xfrs, xfrs) {
+ list_del(&xfr->xfrs);
kfree(xfr);
+ }
INIT_LIST_HEAD(&sbefifo->xfrs);
} else if (eot && sbefifo_next_xfr(sbefifo)) {
@@ -620,8 +623,8 @@ static ssize_t sbefifo_read_common(struct sbefifo_client *client,
if (mod_timer(&client->dev->poll_timer, jiffies))
sbefifo_put(sbefifo);
} else {
- kfree(xfr);
list_del(&xfr->client);
+ kfree(xfr);
wake_up_interruptible(&sbefifo->wait);
}
}
@@ -940,13 +943,15 @@ static int sbefifo_probe(struct device *dev)
static int sbefifo_remove(struct device *dev)
{
struct sbefifo *sbefifo = dev_get_drvdata(dev);
- struct sbefifo_xfr *xfr;
+ struct sbefifo_xfr *xfr, *tmp;
spin_lock(&sbefifo->lock);
WRITE_ONCE(sbefifo->rc, -ENODEV);
- list_for_each_entry(xfr, &sbefifo->xfrs, xfrs)
+ list_for_each_entry_safe(xfr, tmp, &sbefifo->xfrs, xfrs) {
+ list_del(&xfr->xfrs);
kfree(xfr);
+ }
INIT_LIST_HEAD(&sbefifo->xfrs);
--
1.8.3.1
More information about the openbmc
mailing list