]>
Commit | Line | Data |
---|---|---|
53dece81 JK |
1 | commit babcef372ae2ca9c4f4212398803015eb250f764 |
2 | Author: Jan Beulich <jbeulich@suse.com> | |
3 | Date: Tue Mar 25 17:20:47 2014 +0100 | |
4 | ||
5 | x86: enforce preemption in HVM_set_mem_access / p2m_set_mem_access() | |
6 | ||
7 | Processing up to 4G PFNs may take almost arbitrarily long, so | |
8 | preemption is needed here. | |
9 | ||
10 | This is CVE-2014-2599 / XSA-89. | |
11 | ||
12 | Signed-off-by: Jan Beulich <jbeulich@suse.com> | |
13 | Reviewed-by: Tim Deegan <tim@xen.org> | |
14 | master commit: 0fe53c4f279e1a8ef913e71ed000236d21ce96de | |
15 | master date: 2014-03-25 15:23:57 +0100 | |
16 | ||
17 | diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c | |
18 | index 69f7e74..6150899 100644 | |
19 | --- a/xen/arch/x86/hvm/hvm.c | |
20 | +++ b/xen/arch/x86/hvm/hvm.c | |
21 | @@ -4465,6 +4465,15 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg) | |
22 | goto param_fail5; | |
23 | ||
24 | rc = p2m_set_mem_access(d, a.first_pfn, a.nr, a.hvmmem_access); | |
25 | + if ( rc > 0 ) | |
26 | + { | |
27 | + a.first_pfn += a.nr - rc; | |
28 | + a.nr = rc; | |
29 | + if ( __copy_to_guest(arg, &a, 1) ) | |
30 | + rc = -EFAULT; | |
31 | + else | |
32 | + rc = -EAGAIN; | |
33 | + } | |
34 | ||
35 | param_fail5: | |
36 | rcu_unlock_domain(d); | |
37 | diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c | |
38 | index 8f380ed..e0e5840 100644 | |
39 | --- a/xen/arch/x86/mm/p2m.c | |
40 | +++ b/xen/arch/x86/mm/p2m.c | |
41 | @@ -1366,15 +1366,14 @@ void p2m_mem_access_resume(struct domain *d) | |
42 | ||
43 | /* Set access type for a region of pfns. | |
44 | * If start_pfn == -1ul, sets the default access type */ | |
45 | -int p2m_set_mem_access(struct domain *d, unsigned long start_pfn, | |
46 | - uint32_t nr, hvmmem_access_t access) | |
47 | +long p2m_set_mem_access(struct domain *d, unsigned long pfn, uint32_t nr, | |
48 | + hvmmem_access_t access) | |
49 | { | |
50 | struct p2m_domain *p2m = p2m_get_hostp2m(d); | |
51 | - unsigned long pfn; | |
52 | p2m_access_t a, _a; | |
53 | p2m_type_t t; | |
54 | mfn_t mfn; | |
55 | - int rc = 0; | |
56 | + long rc; | |
57 | ||
58 | /* N.B. _not_ static: initializer depends on p2m->default_access */ | |
59 | p2m_access_t memaccess[] = { | |
60 | @@ -1397,14 +1396,17 @@ int p2m_set_mem_access(struct domain *d, unsigned long start_pfn, | |
61 | a = memaccess[access]; | |
62 | ||
63 | /* If request to set default access */ | |
64 | - if ( start_pfn == ~0ull ) | |
65 | + if ( pfn == ~0ul ) | |
66 | { | |
67 | p2m->default_access = a; | |
68 | return 0; | |
69 | } | |
70 | ||
71 | + if ( !nr ) | |
72 | + return 0; | |
73 | + | |
74 | p2m_lock(p2m); | |
75 | - for ( pfn = start_pfn; pfn < start_pfn + nr; pfn++ ) | |
76 | + for ( ; ; ++pfn ) | |
77 | { | |
78 | mfn = p2m->get_entry(p2m, pfn, &t, &_a, 0, NULL); | |
79 | if ( p2m->set_entry(p2m, pfn, mfn, PAGE_ORDER_4K, t, a) == 0 ) | |
80 | @@ -1412,6 +1414,13 @@ int p2m_set_mem_access(struct domain *d, unsigned long start_pfn, | |
81 | rc = -ENOMEM; | |
82 | break; | |
83 | } | |
84 | + | |
85 | + /* Check for continuation if it's not the last interation. */ | |
86 | + if ( !--nr || hypercall_preempt_check() ) | |
87 | + { | |
88 | + rc = nr; | |
89 | + break; | |
90 | + } | |
91 | } | |
92 | p2m_unlock(p2m); | |
93 | return rc; | |
94 | diff --git a/xen/include/asm-x86/p2m.h b/xen/include/asm-x86/p2m.h | |
95 | index f4e7253..a2cb1b7 100644 | |
96 | --- a/xen/include/asm-x86/p2m.h | |
97 | +++ b/xen/include/asm-x86/p2m.h | |
98 | @@ -576,8 +576,8 @@ void p2m_mem_access_resume(struct domain *d); | |
99 | ||
100 | /* Set access type for a region of pfns. | |
101 | * If start_pfn == -1ul, sets the default access type */ | |
102 | -int p2m_set_mem_access(struct domain *d, unsigned long start_pfn, | |
103 | - uint32_t nr, hvmmem_access_t access); | |
104 | +long p2m_set_mem_access(struct domain *d, unsigned long start_pfn, | |
105 | + uint32_t nr, hvmmem_access_t access); | |
106 | ||
107 | /* Get access type for a pfn | |
108 | * If pfn == -1ul, gets the default access type */ |