diff options
Diffstat (limited to 'system/xen/xsa/xsa347-4.13-2.patch')
-rw-r--r-- | system/xen/xsa/xsa347-4.13-2.patch | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/system/xen/xsa/xsa347-4.13-2.patch b/system/xen/xsa/xsa347-4.13-2.patch new file mode 100644 index 0000000000000..fbe7461636071 --- /dev/null +++ b/system/xen/xsa/xsa347-4.13-2.patch @@ -0,0 +1,72 @@ +From: Jan Beulich <jbeulich@suse.com> +Subject: AMD/IOMMU: update live PTEs atomically + +Updating a live PTE bitfield by bitfield risks the compiler re-ordering +the individual updates as well as splitting individual updates into +multiple memory writes. Construct the new entry fully in a local +variable, do the check to determine the flushing needs on the thus +established new entry, and then write the new entry by a single insn. + +Similarly using memset() to clear a PTE is unsafe, as the order of +writes the function does is, at least in principle, undefined. + +This is part of XSA-347. + +Signed-off-by: Jan Beulich <jbeulich@suse.com> +Reviewed-by: Paul Durrant <paul@xen.org> + +--- a/xen/drivers/passthrough/amd/iommu_map.c ++++ b/xen/drivers/passthrough/amd/iommu_map.c +@@ -45,7 +45,7 @@ static unsigned int clear_iommu_pte_pres + pte = &table[pfn_to_pde_idx(dfn, 1)]; + + flush_flags = pte->pr ? IOMMU_FLUSHF_modified : 0; +- memset(pte, 0, sizeof(*pte)); ++ write_atomic(&pte->raw, 0); + + unmap_domain_page(table); + +@@ -57,26 +57,30 @@ static unsigned int set_iommu_pde_presen + unsigned int next_level, bool iw, + bool ir) + { ++ union amd_iommu_pte new = {}, old; + unsigned int flush_flags = IOMMU_FLUSHF_added; + +- if ( pte->pr && +- (pte->mfn != next_mfn || +- pte->iw != iw || +- pte->ir != ir || +- pte->next_level != next_level) ) +- flush_flags |= IOMMU_FLUSHF_modified; +- + /* + * FC bit should be enabled in PTE, this helps to solve potential + * issues with ATS devices + */ +- pte->fc = !next_level; ++ new.fc = !next_level; ++ ++ new.mfn = next_mfn; ++ new.iw = iw; ++ new.ir = ir; ++ new.next_level = next_level; ++ new.pr = true; ++ ++ old.raw = read_atomic(&pte->raw); ++ old.ign0 = 0; ++ old.ign1 = 0; ++ old.ign2 = 0; ++ ++ if ( old.pr && old.raw != new.raw ) ++ flush_flags |= IOMMU_FLUSHF_modified; + +- pte->mfn = next_mfn; +- pte->iw = iw; +- pte->ir = ir; +- pte->next_level = next_level; +- pte->pr = 1; ++ write_atomic(&pte->raw, new.raw); + + return flush_flags; + } |