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, hoist the locking there instead of sprinkling the
locking all over the place.

This bug was discovered using Coverity Static Analysis Security Testing
(SAST) by Synopsys, Inc.

[ tglx: Use guard() instead of goto ]

Fixes: 015ec0386ab6 ("irqchip/gic-v3-its: Add VLPI configuration handling")
Suggested-by: Marc Zyngier <maz@kernel.org>
Signed-off-by: Hagar Hemdan <hagarhem@amazon.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: stable@vger.kernel.org
Reviewed-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20240531162144.28650-1-hagarhem@amazon.com

authored by Hagar Hemdan and committed by Thomas Gleixner b97e8a2f e306a894

+12 -32
+12 -32
drivers/irqchip/irq-gic-v3-its.c
··· 1846 { 1847 struct its_device *its_dev = irq_data_get_irq_chip_data(d); 1848 u32 event = its_get_event_id(d); 1849 - int ret = 0; 1850 1851 if (!info->map) 1852 return -EINVAL; 1853 - 1854 - raw_spin_lock(&its_dev->event_map.vlpi_lock); 1855 1856 if (!its_dev->event_map.vm) { 1857 struct its_vlpi_map *maps; 1858 1859 maps = kcalloc(its_dev->event_map.nr_lpis, sizeof(*maps), 1860 GFP_ATOMIC); 1861 - if (!maps) { 1862 - ret = -ENOMEM; 1863 - goto out; 1864 - } 1865 1866 its_dev->event_map.vm = info->map->vm; 1867 its_dev->event_map.vlpi_maps = maps; 1868 } else if (its_dev->event_map.vm != info->map->vm) { 1869 - ret = -EINVAL; 1870 - goto out; 1871 } 1872 1873 /* Get our private copy of the mapping information */ ··· 1893 its_dev->event_map.nr_vlpis++; 1894 } 1895 1896 - out: 1897 - raw_spin_unlock(&its_dev->event_map.vlpi_lock); 1898 - return ret; 1899 } 1900 1901 static int its_vlpi_get(struct irq_data *d, struct its_cmd_info *info) 1902 { 1903 struct its_device *its_dev = irq_data_get_irq_chip_data(d); 1904 struct its_vlpi_map *map; 1905 - int ret = 0; 1906 - 1907 - raw_spin_lock(&its_dev->event_map.vlpi_lock); 1908 1909 map = get_vlpi_map(d); 1910 1911 - if (!its_dev->event_map.vm || !map) { 1912 - ret = -EINVAL; 1913 - goto out; 1914 - } 1915 1916 /* Copy our mapping information to the incoming request */ 1917 *info->map = *map; 1918 1919 - out: 1920 - raw_spin_unlock(&its_dev->event_map.vlpi_lock); 1921 - return ret; 1922 } 1923 1924 static int its_vlpi_unmap(struct irq_data *d) 1925 { 1926 struct its_device *its_dev = irq_data_get_irq_chip_data(d); 1927 u32 event = its_get_event_id(d); 1928 - int ret = 0; 1929 1930 - raw_spin_lock(&its_dev->event_map.vlpi_lock); 1931 - 1932 - if (!its_dev->event_map.vm || !irqd_is_forwarded_to_vcpu(d)) { 1933 - ret = -EINVAL; 1934 - goto out; 1935 - } 1936 1937 /* Drop the virtual mapping */ 1938 its_send_discard(its_dev, event); ··· 1942 kfree(its_dev->event_map.vlpi_maps); 1943 } 1944 1945 - out: 1946 - raw_spin_unlock(&its_dev->event_map.vlpi_lock); 1947 - return ret; 1948 } 1949 1950 static int its_vlpi_prop_update(struct irq_data *d, struct its_cmd_info *info) ··· 1969 /* Need a v4 ITS */ 1970 if (!is_v4(its_dev->its)) 1971 return -EINVAL; 1972 1973 /* Unmap request? */ 1974 if (!info)
··· 1846 { 1847 struct its_device *its_dev = irq_data_get_irq_chip_data(d); 1848 u32 event = its_get_event_id(d); 1849 1850 if (!info->map) 1851 return -EINVAL; 1852 1853 if (!its_dev->event_map.vm) { 1854 struct its_vlpi_map *maps; 1855 1856 maps = kcalloc(its_dev->event_map.nr_lpis, sizeof(*maps), 1857 GFP_ATOMIC); 1858 + if (!maps) 1859 + return -ENOMEM; 1860 1861 its_dev->event_map.vm = info->map->vm; 1862 its_dev->event_map.vlpi_maps = maps; 1863 } else if (its_dev->event_map.vm != info->map->vm) { 1864 + return -EINVAL; 1865 } 1866 1867 /* Get our private copy of the mapping information */ ··· 1899 its_dev->event_map.nr_vlpis++; 1900 } 1901 1902 + return 0; 1903 } 1904 1905 static int its_vlpi_get(struct irq_data *d, struct its_cmd_info *info) 1906 { 1907 struct its_device *its_dev = irq_data_get_irq_chip_data(d); 1908 struct its_vlpi_map *map; 1909 1910 map = get_vlpi_map(d); 1911 1912 + if (!its_dev->event_map.vm || !map) 1913 + return -EINVAL; 1914 1915 /* Copy our mapping information to the incoming request */ 1916 *info->map = *map; 1917 1918 + return 0; 1919 } 1920 1921 static int its_vlpi_unmap(struct irq_data *d) 1922 { 1923 struct its_device *its_dev = irq_data_get_irq_chip_data(d); 1924 u32 event = its_get_event_id(d); 1925 1926 + if (!its_dev->event_map.vm || !irqd_is_forwarded_to_vcpu(d)) 1927 + return -EINVAL; 1928 1929 /* Drop the virtual mapping */ 1930 its_send_discard(its_dev, event); ··· 1962 kfree(its_dev->event_map.vlpi_maps); 1963 } 1964 1965 + return 0; 1966 } 1967 1968 static int its_vlpi_prop_update(struct irq_data *d, struct its_cmd_info *info) ··· 1991 /* Need a v4 ITS */ 1992 if (!is_v4(its_dev->its)) 1993 return -EINVAL; 1994 + 1995 + guard(raw_spinlock_irq)(&its_dev->event_map.vlpi_lock); 1996 1997 /* Unmap request? */ 1998 if (!info)