Skip to content

Commit

Permalink
iio: trigger: close race condition in acquiring trigger reference
Browse files Browse the repository at this point in the history
In iio_trigger_write_current() we find the trigger we want while
holding mutex on the list of triggers, but we don't actually do a
get on it while holding mutex.  We wait until further validations
are completed and we're sure it's the one we want.  Race condition
is that it could be freed by the time we do the get.

Solution is to grab the trigger (iio_trigger_get) as soon as we
find it while holding mutex on the list of triggers.  If later
we decide it's not the right one, put it back. (iio_trigger_put).

Signed-off-by: Alison Schofield <amsfield22@gmail.com>
Suggested-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
  • Loading branch information
AlisonSchofield authored and jic23 committed Jan 22, 2017
1 parent dfebd8d commit d5d24bc
Showing 1 changed file with 13 additions and 8 deletions.
21 changes: 13 additions & 8 deletions drivers/iio/industrialio-trigger.c
Original file line number Diff line number Diff line change
Expand Up @@ -147,15 +147,15 @@ static struct iio_trigger *__iio_trigger_find_by_name(const char *name)
return NULL;
}

static struct iio_trigger *iio_trigger_find_by_name(const char *name,
size_t len)
static struct iio_trigger *iio_trigger_acquire_by_name(const char *name)
{
struct iio_trigger *trig = NULL, *iter;

mutex_lock(&iio_trigger_list_lock);
list_for_each_entry(iter, &iio_trigger_list, list)
if (sysfs_streq(iter->name, name)) {
trig = iter;
iio_trigger_get(trig);
break;
}
mutex_unlock(&iio_trigger_list_lock);
Expand Down Expand Up @@ -416,20 +416,22 @@ static ssize_t iio_trigger_write_current(struct device *dev,
}
mutex_unlock(&indio_dev->mlock);

trig = iio_trigger_find_by_name(buf, len);
if (oldtrig == trig)
return len;
trig = iio_trigger_acquire_by_name(buf);
if (oldtrig == trig) {
ret = len;
goto out_trigger_put;
}

if (trig && indio_dev->info->validate_trigger) {
ret = indio_dev->info->validate_trigger(indio_dev, trig);
if (ret)
return ret;
goto out_trigger_put;
}

if (trig && trig->ops->validate_device) {
ret = trig->ops->validate_device(trig, indio_dev);
if (ret)
return ret;
goto out_trigger_put;
}

indio_dev->trig = trig;
Expand All @@ -441,13 +443,16 @@ static ssize_t iio_trigger_write_current(struct device *dev,
iio_trigger_put(oldtrig);
}
if (indio_dev->trig) {
iio_trigger_get(indio_dev->trig);
if (indio_dev->modes & INDIO_EVENT_TRIGGERED)
iio_trigger_attach_poll_func(indio_dev->trig,
indio_dev->pollfunc_event);
}

return len;

out_trigger_put:
iio_trigger_put(trig);
return ret;
}

static DEVICE_ATTR(current_trigger, S_IRUGO | S_IWUSR,
Expand Down

0 comments on commit d5d24bc

Please sign in to comment.