All of lore.kernel.org
 help / color / mirror / Atom feed
From: Marc Zyngier <maz@kernel.org>
To: Hagar Hemdan <hagarhem@amazon.com>
Cc: Maximilian Heyne <mheyne@amazon.de>,
	Norbert Manthey <nmanthey@amazon.de>,
	"Thomas\ Gleixner" <tglx@linutronix.de>,
	Eric Auger <eric.auger@redhat.com>,
	<linux-arm-kernel@lists.infradead.org>,
	<linux-kernel@vger.kernel.org>
Subject: Re: [PATCH] irqchip/gic-v3-its: Fix potential race condition in its_vlpi_prop_update()
Date: Thu, 30 May 2024 16:40:37 +0100	[thread overview]
Message-ID: <86v82vl34a.wl-maz@kernel.org> (raw)
In-Reply-To: <20240530105713.18552-1-hagarhem@amazon.com>

Hi Hagar,

On Thu, 30 May 2024 11:57:13 +0100,
Hagar Hemdan <hagarhem@amazon.com> wrote:
> 
> Similar to commit 046b5054f566 ("irqchip/gic-v3-its: Lock VLPI map array
> before translating it"), its_vlpi_prop_update() calls lpi_write_config()
> which obtains the mapping information for a VLPI.
> This should always be done with vlpi_lock for this device held. Otherwise,
> its_vlpi_prop_update() could race with its_vlpi_unmap().

Thanks for reporting this. Note that this issue is not the same as the
one you refer to (what you have here is a total absence of locking,
while 046b5054f566 fixed a call to get_vlpi_map() outside of an
existing critical section).

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

Should we get a scrolling banner for this kind of advertisements? ;-)

> 
> Fixes: 015ec0386ab6 ("irqchip/gic-v3-its: Add VLPI configuration handling")
> Signed-off-by: Hagar Hemdan <hagarhem@amazon.com>
> ---
>  drivers/irqchip/irq-gic-v3-its.c | 12 +++++++++---
>  1 file changed, 9 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
> index 40ebf1726393..ecaad1786345 100644
> --- a/drivers/irqchip/irq-gic-v3-its.c
> +++ b/drivers/irqchip/irq-gic-v3-its.c
> @@ -1970,9 +1970,13 @@ static int its_vlpi_unmap(struct irq_data *d)
>  static int its_vlpi_prop_update(struct irq_data *d, struct its_cmd_info *info)
>  {
>  	struct its_device *its_dev = irq_data_get_irq_chip_data(d);
> +	int ret = 0;
>  
> -	if (!its_dev->event_map.vm || !irqd_is_forwarded_to_vcpu(d))
> -		return -EINVAL;
> +	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 (info->cmd_type == PROP_UPDATE_AND_INV_VLPI)
>  		lpi_update_config(d, 0xff, info->config);
> @@ -1980,7 +1984,9 @@ static int its_vlpi_prop_update(struct irq_data *d, struct its_cmd_info *info)
>  		lpi_write_config(d, 0xff, info->config);
>  	its_vlpi_set_doorbell(d, !!(info->config & LPI_PROP_ENABLED));
>  
> -	return 0;
> +out:
> +	raw_spin_unlock(&its_dev->event_map.vlpi_lock);
> +	return ret;
>  }
>  
>  static int its_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu_info)

As it turns out, all the 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 could (should?) hoist the locking into
its_irq_set_vcpu_affinity() and avoid future bugs. It also results in
a negative diffstat.

Something like the hack below (compile-tested only), which I'm sure
the "Coverity Static Analysis Security Testing (SAST) by Synopsys,
Inc" will be able to verify...

	M.

diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 40ebf1726393..abc1fb360ce4 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -1851,23 +1851,18 @@ static int its_vlpi_map(struct irq_data *d, struct its_cmd_info *info)
 	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,8 +1894,6 @@ 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;
 }
 
@@ -1910,20 +1903,14 @@ static int its_vlpi_get(struct irq_data *d, struct its_cmd_info *info)
 	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;
 }
 
@@ -1933,12 +1920,8 @@ static int its_vlpi_unmap(struct irq_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,8 +1945,6 @@ 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;
 }
 
@@ -1987,29 +1968,41 @@ 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 = {

-- 
Without deviation from the norm, progress is not possible.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

WARNING: multiple messages have this Message-ID (diff)
From: Marc Zyngier <maz@kernel.org>
To: Hagar Hemdan <hagarhem@amazon.com>
Cc: Maximilian Heyne <mheyne@amazon.de>,
	Norbert Manthey <nmanthey@amazon.de>,
	"Thomas\ Gleixner" <tglx@linutronix.de>,
	Eric Auger <eric.auger@redhat.com>,
	<linux-arm-kernel@lists.infradead.org>,
	<linux-kernel@vger.kernel.org>
Subject: Re: [PATCH] irqchip/gic-v3-its: Fix potential race condition in its_vlpi_prop_update()
Date: Thu, 30 May 2024 16:40:37 +0100	[thread overview]
Message-ID: <86v82vl34a.wl-maz@kernel.org> (raw)
In-Reply-To: <20240530105713.18552-1-hagarhem@amazon.com>

Hi Hagar,

On Thu, 30 May 2024 11:57:13 +0100,
Hagar Hemdan <hagarhem@amazon.com> wrote:
> 
> Similar to commit 046b5054f566 ("irqchip/gic-v3-its: Lock VLPI map array
> before translating it"), its_vlpi_prop_update() calls lpi_write_config()
> which obtains the mapping information for a VLPI.
> This should always be done with vlpi_lock for this device held. Otherwise,
> its_vlpi_prop_update() could race with its_vlpi_unmap().

Thanks for reporting this. Note that this issue is not the same as the
one you refer to (what you have here is a total absence of locking,
while 046b5054f566 fixed a call to get_vlpi_map() outside of an
existing critical section).

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

Should we get a scrolling banner for this kind of advertisements? ;-)

> 
> Fixes: 015ec0386ab6 ("irqchip/gic-v3-its: Add VLPI configuration handling")
> Signed-off-by: Hagar Hemdan <hagarhem@amazon.com>
> ---
>  drivers/irqchip/irq-gic-v3-its.c | 12 +++++++++---
>  1 file changed, 9 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
> index 40ebf1726393..ecaad1786345 100644
> --- a/drivers/irqchip/irq-gic-v3-its.c
> +++ b/drivers/irqchip/irq-gic-v3-its.c
> @@ -1970,9 +1970,13 @@ static int its_vlpi_unmap(struct irq_data *d)
>  static int its_vlpi_prop_update(struct irq_data *d, struct its_cmd_info *info)
>  {
>  	struct its_device *its_dev = irq_data_get_irq_chip_data(d);
> +	int ret = 0;
>  
> -	if (!its_dev->event_map.vm || !irqd_is_forwarded_to_vcpu(d))
> -		return -EINVAL;
> +	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 (info->cmd_type == PROP_UPDATE_AND_INV_VLPI)
>  		lpi_update_config(d, 0xff, info->config);
> @@ -1980,7 +1984,9 @@ static int its_vlpi_prop_update(struct irq_data *d, struct its_cmd_info *info)
>  		lpi_write_config(d, 0xff, info->config);
>  	its_vlpi_set_doorbell(d, !!(info->config & LPI_PROP_ENABLED));
>  
> -	return 0;
> +out:
> +	raw_spin_unlock(&its_dev->event_map.vlpi_lock);
> +	return ret;
>  }
>  
>  static int its_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu_info)

As it turns out, all the 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 could (should?) hoist the locking into
its_irq_set_vcpu_affinity() and avoid future bugs. It also results in
a negative diffstat.

Something like the hack below (compile-tested only), which I'm sure
the "Coverity Static Analysis Security Testing (SAST) by Synopsys,
Inc" will be able to verify...

	M.

diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 40ebf1726393..abc1fb360ce4 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -1851,23 +1851,18 @@ static int its_vlpi_map(struct irq_data *d, struct its_cmd_info *info)
 	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,8 +1894,6 @@ 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;
 }
 
@@ -1910,20 +1903,14 @@ static int its_vlpi_get(struct irq_data *d, struct its_cmd_info *info)
 	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;
 }
 
@@ -1933,12 +1920,8 @@ static int its_vlpi_unmap(struct irq_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,8 +1945,6 @@ 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;
 }
 
@@ -1987,29 +1968,41 @@ 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 = {

-- 
Without deviation from the norm, progress is not possible.

  reply	other threads:[~2024-05-30 15:41 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-05-30 10:57 [PATCH] irqchip/gic-v3-its: Fix potential race condition in its_vlpi_prop_update() Hagar Hemdan
2024-05-30 10:57 ` Hagar Hemdan
2024-05-30 15:40 ` Marc Zyngier [this message]
2024-05-30 15:40   ` Marc Zyngier
2024-05-31  4:58   ` Hagar Hemdan
2024-05-31  4:58     ` Hagar Hemdan
2024-05-31  9:45   ` Hagar Hemdan
2024-05-31  9:45     ` Hagar Hemdan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=86v82vl34a.wl-maz@kernel.org \
    --to=maz@kernel.org \
    --cc=eric.auger@redhat.com \
    --cc=hagarhem@amazon.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mheyne@amazon.de \
    --cc=nmanthey@amazon.de \
    --cc=tglx@linutronix.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.