aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorJuergen Gross <jgross@suse.com>2014-10-17 07:16:06 -0400
committerDavid Vrabel <david.vrabel@citrix.com>2014-10-23 11:24:02 -0400
commit3a0e94f8ead4a58b9719db0f78e13d02d059604f (patch)
tree4f74cec939084816caf4056097f0b382ea413ad5 /arch/x86
parent2c185687ab016954557aac80074f5d7f7f5d275c (diff)
x86/xen: avoid race in p2m handling
When a new p2m leaf is allocated this leaf is linked into the p2m tree via cmpxchg. Unfortunately the compare value for checking the success of the update is read after checking for the need of a new leaf. It is possible that a new leaf has been linked into the tree concurrently in between. This could lead to a leaked memory page and to the loss of some p2m entries. Avoid the race by using the read compare value for checking the need of a new p2m leaf and use ACCESS_ONCE() to get it. There are other places which seem to need ACCESS_ONCE() to ensure proper operation. Change them accordingly. Signed-off-by: Juergen Gross <jgross@suse.com> Signed-off-by: David Vrabel <david.vrabel@citrix.com>
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/xen/p2m.c10
1 files changed, 5 insertions, 5 deletions
diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c
index d1b3da2960ab..b456b048eca9 100644
--- a/arch/x86/xen/p2m.c
+++ b/arch/x86/xen/p2m.c
@@ -532,12 +532,13 @@ static bool alloc_p2m(unsigned long pfn)
532 unsigned topidx, mididx; 532 unsigned topidx, mididx;
533 unsigned long ***top_p, **mid; 533 unsigned long ***top_p, **mid;
534 unsigned long *top_mfn_p, *mid_mfn; 534 unsigned long *top_mfn_p, *mid_mfn;
535 unsigned long *p2m_orig;
535 536
536 topidx = p2m_top_index(pfn); 537 topidx = p2m_top_index(pfn);
537 mididx = p2m_mid_index(pfn); 538 mididx = p2m_mid_index(pfn);
538 539
539 top_p = &p2m_top[topidx]; 540 top_p = &p2m_top[topidx];
540 mid = *top_p; 541 mid = ACCESS_ONCE(*top_p);
541 542
542 if (mid == p2m_mid_missing) { 543 if (mid == p2m_mid_missing) {
543 /* Mid level is missing, allocate a new one */ 544 /* Mid level is missing, allocate a new one */
@@ -552,7 +553,7 @@ static bool alloc_p2m(unsigned long pfn)
552 } 553 }
553 554
554 top_mfn_p = &p2m_top_mfn[topidx]; 555 top_mfn_p = &p2m_top_mfn[topidx];
555 mid_mfn = p2m_top_mfn_p[topidx]; 556 mid_mfn = ACCESS_ONCE(p2m_top_mfn_p[topidx]);
556 557
557 BUG_ON(virt_to_mfn(mid_mfn) != *top_mfn_p); 558 BUG_ON(virt_to_mfn(mid_mfn) != *top_mfn_p);
558 559
@@ -579,11 +580,10 @@ static bool alloc_p2m(unsigned long pfn)
579 } 580 }
580 } 581 }
581 582
582 if (p2m_top[topidx][mididx] == p2m_identity || 583 p2m_orig = ACCESS_ONCE(p2m_top[topidx][mididx]);
583 p2m_top[topidx][mididx] == p2m_missing) { 584 if (p2m_orig == p2m_identity || p2m_orig == p2m_missing) {
584 /* p2m leaf page is missing */ 585 /* p2m leaf page is missing */
585 unsigned long *p2m; 586 unsigned long *p2m;
586 unsigned long *p2m_orig = p2m_top[topidx][mididx];
587 587
588 p2m = alloc_p2m_page(); 588 p2m = alloc_p2m_page();
589 if (!p2m) 589 if (!p2m)