irqchip/gic-v3-its: Fix potential race condition in its_vlpi_prop_update()
Subsystems (2)
PATCH v3 1/1 irqchip/gic-v3-its: Fix potential race condition in its_vlpi_prop_update()
its_vlpi_prop_update() calls lpi_write_config() which obtains the mapping information for a VLPI without lock held. So it could race with its_vlpi_unmap().
Since all calls from its_irq_set_vcpu_affinity() require the same lock to be held. So instead of peppering the locking all over the place, we hoist the locking into its_irq_set_vcpu_affinity().
This bug was discovered and resolved using Coverity Static Analysis Security Testing (SAST) by Synopsys, Inc.
Fixes 015ec0386ab6 ("irqchip/gic-v3-its: Add VLPI configuration handling")
Suggested-by Marc Zyngier <[email protected]>
Signed-off-by Hagar Hemdan <[email protected]>
---
v2: moved the lock to its_irq_set_vcpu_affinity(). Only compile-tested, no access to HW.
--- drivers/irqchip/irq-gic-v3-its.c | 65 +++++++++++++------------------- 1 file changed, 27 insertions(+), 38 deletions(-)
drivers/irqchip/irq-gic-v3-its.c +27 -38
@@ -1846,28 +1846,22 @@ static int its_vlpi_map(struct irq_data *d, struct its_cmd_info *info) {struct its_device *its_dev =irq_data_get_irq_chip_data (d);u32 event =its_get_event_id (d); -int ret =0 ;if (!info->map)return -EINVAL ; -raw_spin_lock (&its_dev->event_map.vlpi_lock); -if (!its_dev->event_map.vm) {struct its_vlpi_map *maps; maps =kcalloc (its_dev->event_map.nr_lpis,sizeof (*maps),GFP_ATOMIC ); -if (!maps) { - ret = -ENOMEM ; - goto out; - } +if (!maps) +return -ENOMEM ; its_dev->event_map.vm = info->map->vm; its_dev->event_map.vlpi_maps = maps; }else if (its_dev->event_map.vm != info->map->vm) { - ret = -EINVAL ; - goto out; +return -EINVAL ; }/* Get our private copy of the mapping information */
@@ -1899,46 +1893,32 @@ static int its_vlpi_map(struct irq_data *d, struct its_cmd_info *info) its_dev->event_map.nr_vlpis++; } -out: -raw_spin_unlock (&its_dev->event_map.vlpi_lock); -return ret; +return 0 ; }static int its_vlpi_get (struct irq_data *d,struct its_cmd_info *info) {struct its_device *its_dev =irq_data_get_irq_chip_data (d);struct its_vlpi_map *map; -int ret =0 ; - -raw_spin_lock (&its_dev->event_map.vlpi_lock); map =get_vlpi_map (d); -if (!its_dev->event_map.vm || !map) { - ret = -EINVAL ; - goto out; - } +if (!its_dev->event_map.vm || !map) +return -EINVAL ;/* Copy our mapping information to the incoming request */ *info->map = *map; -out: -raw_spin_unlock (&its_dev->event_map.vlpi_lock); -return ret; +return 0 ; }static int its_vlpi_unmap (struct irq_data *d) {struct its_device *its_dev =irq_data_get_irq_chip_data (d);u32 event =its_get_event_id (d); -int ret =0 ; -raw_spin_lock (&its_dev->event_map.vlpi_lock); - -if (!its_dev->event_map.vm || !irqd_is_forwarded_to_vcpu (d)) { - ret = -EINVAL ; - goto out; - } +if (!its_dev->event_map.vm || !irqd_is_forwarded_to_vcpu (d)) +return -EINVAL ;/* Drop the virtual mapping */ its_send_discard (its_dev, event);
@@ -1962,9 +1942,7 @@ static int its_vlpi_unmap(struct irq_data *d)kfree (its_dev->event_map.vlpi_maps); } -out: -raw_spin_unlock (&its_dev->event_map.vlpi_lock); -return ret; +return 0 ; }static int its_vlpi_prop_update (struct irq_data *d,struct its_cmd_info *info)
@@ -1987,29 +1965,40 @@ static int its_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu_info) {struct its_device *its_dev =irq_data_get_irq_chip_data (d);struct its_cmd_info *info = vcpu_info; +int ret;/* Need a v4 ITS */ if (!is_v4 (its_dev->its))return -EINVAL ; +raw_spin_lock (&its_dev->event_map.vlpi_lock); +/* Unmap request? */ -if (!info) -return its_vlpi_unmap (d); +if (!info) { + ret =its_vlpi_unmap (d); + goto out; + }switch (info->cmd_type) {case MAP_VLPI : -return its_vlpi_map (d, info); + ret =its_vlpi_map (d, info); +break ;case GET_VLPI : -return its_vlpi_get (d, info); + ret =its_vlpi_get (d, info); +break ;case PROP_UPDATE_VLPI :case PROP_UPDATE_AND_INV_VLPI : -return its_vlpi_prop_update (d, info); + ret =its_vlpi_prop_update (d, info); +break ;default : -return -EINVAL ; + ret = -EINVAL ; } +out: +raw_spin_unlock (&its_dev->event_map.vlpi_lock); +return ret; }static struct irq_chip its_irq_chip = {
Signature · 1 line
2.40.1