All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jason Gunthorpe <jgg@nvidia.com>
To: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Cc: linux-kernel@vger.kernel.org, iommu@lists.linux.dev,
	joro@8bytes.org, robin.murphy@arm.com, vasant.hegde@amd.com,
	ubizjak@gmail.com, jon.grimm@amd.com, santosh.shukla@amd.com,
	pandoh@google.com, kumaranand@google.com
Subject: Re: [PATCH v3 2/5] iommu/amd: Introduce helper functions to access and update 256-bit DTE
Date: Fri, 6 Sep 2024 14:00:34 -0300	[thread overview]
Message-ID: <20240906170034.GL1358970@nvidia.com> (raw)
In-Reply-To: <20240906121308.5013-3-suravee.suthikulpanit@amd.com>

On Fri, Sep 06, 2024 at 12:13:05PM +0000, Suravee Suthikulpanit wrote:

> +static void update_dte256(struct amd_iommu *iommu, struct iommu_dev_data *dev_data,
> +			  struct dev_table_entry *new)
> +{
> +	struct dev_table_entry *dev_table = get_dev_table(iommu);
> +	struct dev_table_entry *ptr = &dev_table[dev_data->devid];
> +	struct dev_table_entry old;
> +	u128 tmp;
> +
> +	lockdep_assert_held(&dev_data->dte_lock);
> +
> +	old.data128[0] = ptr->data128[0];
> +	old.data128[1] = ptr->data128[1];
> +
> +	tmp = cmpxchg128(&ptr->data128[1], old.data128[1], new->data128[1]);
> +	if (tmp == old.data128[1]) {
> +		if (!try_cmpxchg128(&ptr->data128[0], &old.data128[0], new->data128[0])) {
> +			/* Restore hi 128-bit */
> +			cmpxchg128(&ptr->data128[1], new->data128[1], tmp);

Like I said before, you can't fix this. Just go fowards. Keeping an
old DTE will UAF things, that is much worse than just forcing a new
DTE and loosing some interrupt settings.

> @@ -243,13 +285,28 @@ static int clone_alias(struct pci_dev *pdev, u16 alias, void *data)
>  	if (!iommu)
>  		return 0;
>  
> -	amd_iommu_set_rlookup_table(iommu, alias);
> -	dev_table = get_dev_table(iommu);
> -	memcpy(dev_table[alias].data,
> -	       dev_table[devid].data,
> -	       sizeof(dev_table[alias].data));
> +	/* Get DTE for pdev */
> +	dev_data = dev_iommu_priv_get(&pdev->dev);
> +	if (!dev_data)
> +		return -EINVAL;
>  
> -	return 0;
> +	spin_lock(&dev_data->dte_lock);
> +	get_dte256(iommu, dev_data, &dte);
> +	spin_unlock(&dev_data->dte_lock);

You can't unlock after reading the DTE and the relock it to program
it. The interrupt data can have changed while unlocked.

Put the lock inside update_dte256() and force the interrupt bits
under the lock.

Something like this is what I'm expecting:

static void write_upper(struct dev_table_entry *ptr, struct dev_table_entry *new)
{
	struct dev_table_entry old;

	lockdep_assert_held(&dev_data->dte_lock);

	do {
		old->data128[1] = ptr->data128[1];
		new->data64[2] &= ~INTR_MASK;
		new->data64[2] |= old->data64[2] & INTR_MASK;
	} while (!try_cmpxchg128(&ptr->data128[1], &old.data128[1],
				 new->data128[1]));
}

static void write_lower(struct dev_table_entry *ptr, struct dev_table_entry *new)
{
	struct dev_table_entry old;

	do {
		old->data128[0] = ptr->data128[0];
	} while (!try_cmpxchg128(&ptr->data128[0], &old.data128[0],
				 new->data128[0]));
}

static void update_dte256(struct amd_iommu *iommu,
			  struct iommu_dev_data *dev_data,
			  struct dev_table_entry *new)
{

	spin_lock(&dev_data->dte_lock);
	if (!(ptr->data64[0] & V)) {
		write_upper(ptr, new);
		/* NO FLUSH assume V=0 never cached */
		write_lower(ptr, new);
		/* FLUSH */
	} else if (!(new->data64[0] & V) {
		write_lower(ptr, new);
		/* FLUSH */
		write_upper(ptr, new);
		/* NO FLUSH assume V=0 never cached */
	} else {
		/* both are valid */
		if (FIELD_GET(ptr->data[2], GUEST_PAGING_MODE) ==
		    FIELD_GET(new->data[2], GUEST_PAGING_MODE)) {
			/* Upper doesn't change */
			write_upper(ptr, new);
			write_lower(ptr, new);
			/* FLUSH */
		else if (old has no guest page table) {
			write_upper(ptr, new);
			/* FLUSH */
			write_lower(ptr, new);
			/* FLUSH */
		else if (new has no guest page table) {
			write_lower(ptr, new);
			/* FLUSH */
			write_upper(ptr, new);
			/* FLUSH */
		} else {
			struct dev_table_entry clear = {};

			write_lower(ptr, &clear);
			/* FLUSH to set V=0 */
			write_upper(ptr, new);
			/* NO FLUSH assume V=0 never cached */
			write_lower(ptr, new);
			/* FLUSH */
		}
	}

	spin_unlock(&dev_data->dte_lock);
}

And it probably needs more logic to accomodate the VIOMMU valid bits
in the 2nd 128.

Jason

  parent reply	other threads:[~2024-09-06 17:00 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-09-06 12:13 [PATCH v3 0/5] iommu/amd: Use 128-bit cmpxchg operation to update DTE Suravee Suthikulpanit
2024-09-06 12:13 ` [PATCH v3 1/5] iommu/amd: Disable AMD IOMMU if CMPXCHG16B feature is not supported Suravee Suthikulpanit
2024-09-06 16:38   ` Jason Gunthorpe
2024-09-09 15:16     ` Jason Gunthorpe
2024-09-16 17:19       ` Suthikulpanit, Suravee
2024-09-16 16:11     ` Suthikulpanit, Suravee
2024-09-23 18:13       ` Jason Gunthorpe
2024-09-06 12:13 ` [PATCH v3 2/5] iommu/amd: Introduce helper functions to access and update 256-bit DTE Suravee Suthikulpanit
2024-09-06 15:53   ` Jacob Pan
2024-09-06 17:00   ` Jason Gunthorpe [this message]
2024-09-16 16:12     ` Suthikulpanit, Suravee
     [not found]   ` <66db2589.170a0220.6f57.d691SMTPIN_ADDED_BROKEN@mx.google.com>
2024-09-06 19:31     ` Uros Bizjak
2024-09-07 13:36   ` kernel test robot
2024-09-06 12:13 ` [PATCH v3 3/5] iommu/amd: Modify set_dte_entry() to use 256-bit DTE helpers Suravee Suthikulpanit
2024-09-06 12:13 ` [PATCH v3 4/5] iommu/amd: Modify clear_dte_entry() to avoid in-place update Suravee Suthikulpanit
2024-09-06 18:07   ` Jason Gunthorpe
2024-09-06 12:13 ` [PATCH v3 5/5] iommu/amd: Do not update DTE in-place in amd_iommu_set_dirty_tracking and set_dte_irq_entry Suravee Suthikulpanit

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=20240906170034.GL1358970@nvidia.com \
    --to=jgg@nvidia.com \
    --cc=iommu@lists.linux.dev \
    --cc=jon.grimm@amd.com \
    --cc=joro@8bytes.org \
    --cc=kumaranand@google.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=pandoh@google.com \
    --cc=robin.murphy@arm.com \
    --cc=santosh.shukla@amd.com \
    --cc=suravee.suthikulpanit@amd.com \
    --cc=ubizjak@gmail.com \
    --cc=vasant.hegde@amd.com \
    /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.