diff mbox series

[V4,1/4] x86/mm: Add array_index_nospec to guest provided index values

Message ID 20191217151144.9781-1-aisaila@bitdefender.com (mailing list archive)
State Superseded
Headers show
Series [V4,1/4] x86/mm: Add array_index_nospec to guest provided index values | expand

Commit Message

Alexandru Stefan ISAILA Dec. 17, 2019, 3:12 p.m. UTC
This patch aims to sanitize indexes, potentially guest provided
values, for altp2m_eptp[] and altp2m_p2m[] arrays.

Signed-off-by: Alexandru Isaila <aisaila@bitdefender.com>
---
CC: Razvan Cojocaru <rcojocaru@bitdefender.com>
CC: Tamas K Lengyel <tamas@tklengyel.com>
CC: Petre Pircalabu <ppircalabu@bitdefender.com>
CC: George Dunlap <george.dunlap@eu.citrix.com>
CC: Jan Beulich <jbeulich@suse.com>
CC: Andrew Cooper <andrew.cooper3@citrix.com>
CC: Wei Liu <wl@xen.org>
CC: "Roger Pau Monné" <roger.pau@citrix.com>
CC: Jun Nakajima <jun.nakajima@intel.com>
CC: Kevin Tian <kevin.tian@intel.com>
---
 xen/arch/x86/mm/mem_access.c | 15 +++++++++------
 xen/arch/x86/mm/p2m-ept.c    |  5 +++--
 xen/arch/x86/mm/p2m.c        | 27 +++++++++++++++++----------
 3 files changed, 29 insertions(+), 18 deletions(-)

Comments

Tamas K Lengyel Dec. 17, 2019, 3:21 p.m. UTC | #1
On Tue, Dec 17, 2019 at 8:12 AM Alexandru Stefan ISAILA
<aisaila@bitdefender.com> wrote:
>
> This patch aims to sanitize indexes, potentially guest provided
> values, for altp2m_eptp[] and altp2m_p2m[] arrays.
>
> Signed-off-by: Alexandru Isaila <aisaila@bitdefender.com>

LGTM, thanks!

Acked-by: Tamas K Lengyel <tamas@tklengyel.com>
Jan Beulich Dec. 17, 2019, 4:50 p.m. UTC | #2
On 17.12.2019 16:12, Alexandru Stefan ISAILA wrote:
> --- a/xen/arch/x86/mm/mem_access.c
> +++ b/xen/arch/x86/mm/mem_access.c
> @@ -367,10 +367,11 @@ long p2m_set_mem_access(struct domain *d, gfn_t gfn, uint32_t nr,
>      if ( altp2m_idx )
>      {
>          if ( altp2m_idx >= MAX_ALTP2M ||
> -             d->arch.altp2m_eptp[altp2m_idx] == mfn_x(INVALID_MFN) )
> +             d->arch.altp2m_eptp[array_index_nospec(altp2m_idx, MAX_EPTP)] ==

The bounds check is against MAX_ALTP2M. Both MAX_ values look to be
independent, which means bounds check and value passed to the
helper need to match up (not just here).

> --- a/xen/arch/x86/mm/p2m-ept.c
> +++ b/xen/arch/x86/mm/p2m-ept.c
> @@ -1353,7 +1353,8 @@ void setup_ept_dump(void)
>  
>  void p2m_init_altp2m_ept(struct domain *d, unsigned int i)
>  {
> -    struct p2m_domain *p2m = d->arch.altp2m_p2m[i];
> +    struct p2m_domain *p2m =
> +           d->arch.altp2m_p2m[array_index_nospec(i, MAX_ALTP2M)];
>      struct p2m_domain *hostp2m = p2m_get_hostp2m(d);
>      struct ept_data *ept;
>  
> @@ -1366,7 +1367,7 @@ void p2m_init_altp2m_ept(struct domain *d, unsigned int i)
>      p2m->max_mapped_pfn = p2m->max_remapped_gfn = 0;
>      ept = &p2m->ept;
>      ept->mfn = pagetable_get_pfn(p2m_get_pagetable(p2m));
> -    d->arch.altp2m_eptp[i] = ept->eptp;
> +    d->arch.altp2m_eptp[array_index_nospec(i, MAX_EPTP)] = ept->eptp;
>  }
>  
>  unsigned int p2m_find_altp2m_by_eptp(struct domain *d, uint64_t eptp)
> --- a/xen/arch/x86/mm/p2m.c
> +++ b/xen/arch/x86/mm/p2m.c
> @@ -2499,7 +2499,7 @@ static void p2m_reset_altp2m(struct domain *d, unsigned int idx,
>      struct p2m_domain *p2m;
>  
>      ASSERT(idx < MAX_ALTP2M);
> -    p2m = d->arch.altp2m_p2m[idx];
> +    p2m = d->arch.altp2m_p2m[array_index_nospec(idx, MAX_ALTP2M)];
>  
>      p2m_lock(p2m);
>  
> @@ -2540,7 +2540,7 @@ static int p2m_activate_altp2m(struct domain *d, unsigned int idx)
>  
>      ASSERT(idx < MAX_ALTP2M);
>  
> -    p2m = d->arch.altp2m_p2m[idx];
> +    p2m = d->arch.altp2m_p2m[array_index_nospec(idx, MAX_ALTP2M)];

All of the above have a more or less significant disconnect between
the bounds check and the use as array index. I think it would be
quite helpful if these could live close to one another, so one can
(see further up) easily prove that both specified bounds actually
match up.

Jan
Alexandru Stefan ISAILA Dec. 18, 2019, 8:06 a.m. UTC | #3
On 17.12.2019 18:50, Jan Beulich wrote:
> On 17.12.2019 16:12, Alexandru Stefan ISAILA wrote:
>> --- a/xen/arch/x86/mm/mem_access.c
>> +++ b/xen/arch/x86/mm/mem_access.c
>> @@ -367,10 +367,11 @@ long p2m_set_mem_access(struct domain *d, gfn_t gfn, uint32_t nr,
>>       if ( altp2m_idx )
>>       {
>>           if ( altp2m_idx >= MAX_ALTP2M ||
>> -             d->arch.altp2m_eptp[altp2m_idx] == mfn_x(INVALID_MFN) )
>> +             d->arch.altp2m_eptp[array_index_nospec(altp2m_idx, MAX_EPTP)] ==
> 
> The bounds check is against MAX_ALTP2M. Both MAX_ values look to be
> independent, which means bounds check and value passed to the
> helper need to match up (not just here).

I will have both checks against MAX_ALTP2M.

> 
>> --- a/xen/arch/x86/mm/p2m-ept.c
>> +++ b/xen/arch/x86/mm/p2m-ept.c
>> @@ -1353,7 +1353,8 @@ void setup_ept_dump(void)
>>   
>>   void p2m_init_altp2m_ept(struct domain *d, unsigned int i)
>>   {
>> -    struct p2m_domain *p2m = d->arch.altp2m_p2m[i];
>> +    struct p2m_domain *p2m =
>> +           d->arch.altp2m_p2m[array_index_nospec(i, MAX_ALTP2M)];
>>       struct p2m_domain *hostp2m = p2m_get_hostp2m(d);
>>       struct ept_data *ept;
>>   
>> @@ -1366,7 +1367,7 @@ void p2m_init_altp2m_ept(struct domain *d, unsigned int i)
>>       p2m->max_mapped_pfn = p2m->max_remapped_gfn = 0;
>>       ept = &p2m->ept;
>>       ept->mfn = pagetable_get_pfn(p2m_get_pagetable(p2m));
>> -    d->arch.altp2m_eptp[i] = ept->eptp;
>> +    d->arch.altp2m_eptp[array_index_nospec(i, MAX_EPTP)] = ept->eptp;
>>   }
>>   
>>   unsigned int p2m_find_altp2m_by_eptp(struct domain *d, uint64_t eptp)
>> --- a/xen/arch/x86/mm/p2m.c
>> +++ b/xen/arch/x86/mm/p2m.c
>> @@ -2499,7 +2499,7 @@ static void p2m_reset_altp2m(struct domain *d, unsigned int idx,
>>       struct p2m_domain *p2m;
>>   
>>       ASSERT(idx < MAX_ALTP2M);
>> -    p2m = d->arch.altp2m_p2m[idx];
>> +    p2m = d->arch.altp2m_p2m[array_index_nospec(idx, MAX_ALTP2M)];
>>   
>>       p2m_lock(p2m);
>>   
>> @@ -2540,7 +2540,7 @@ static int p2m_activate_altp2m(struct domain *d, unsigned int idx)
>>   
>>       ASSERT(idx < MAX_ALTP2M);
>>   
>> -    p2m = d->arch.altp2m_p2m[idx];
>> +    p2m = d->arch.altp2m_p2m[array_index_nospec(idx, MAX_ALTP2M)];
> 
> All of the above have a more or less significant disconnect between
> the bounds check and the use as array index. I think it would be
> quite helpful if these could live close to one another, so one can
> (see further up) easily prove that both specified bounds actually
> match up.
> 

Sure, I can move the array use closer together.

Alex
Alexandru Stefan ISAILA Dec. 18, 2019, 9:57 a.m. UTC | #4
On 18.12.2019 10:06, Alexandru Stefan ISAILA wrote:
> 
> 
> On 17.12.2019 18:50, Jan Beulich wrote:
>> On 17.12.2019 16:12, Alexandru Stefan ISAILA wrote:
>>> --- a/xen/arch/x86/mm/mem_access.c
>>> +++ b/xen/arch/x86/mm/mem_access.c
>>> @@ -367,10 +367,11 @@ long p2m_set_mem_access(struct domain *d, gfn_t gfn, uint32_t nr,
>>>        if ( altp2m_idx )
>>>        {
>>>            if ( altp2m_idx >= MAX_ALTP2M ||
>>> -             d->arch.altp2m_eptp[altp2m_idx] == mfn_x(INVALID_MFN) )
>>> +             d->arch.altp2m_eptp[array_index_nospec(altp2m_idx, MAX_EPTP)] ==
>>
>> The bounds check is against MAX_ALTP2M. Both MAX_ values look to be
>> independent, which means bounds check and value passed to the
>> helper need to match up (not just here).
> 
> I will have both checks against MAX_ALTP2M.
> 
>>
>>> --- a/xen/arch/x86/mm/p2m-ept.c
>>> +++ b/xen/arch/x86/mm/p2m-ept.c
>>> @@ -1353,7 +1353,8 @@ void setup_ept_dump(void)
>>>    
>>>    void p2m_init_altp2m_ept(struct domain *d, unsigned int i)
>>>    {
>>> -    struct p2m_domain *p2m = d->arch.altp2m_p2m[i];
>>> +    struct p2m_domain *p2m =
>>> +           d->arch.altp2m_p2m[array_index_nospec(i, MAX_ALTP2M)];
>>>        struct p2m_domain *hostp2m = p2m_get_hostp2m(d);
>>>        struct ept_data *ept;
>>>    
>>> @@ -1366,7 +1367,7 @@ void p2m_init_altp2m_ept(struct domain *d, unsigned int i)
>>>        p2m->max_mapped_pfn = p2m->max_remapped_gfn = 0;
>>>        ept = &p2m->ept;
>>>        ept->mfn = pagetable_get_pfn(p2m_get_pagetable(p2m));
>>> -    d->arch.altp2m_eptp[i] = ept->eptp;
>>> +    d->arch.altp2m_eptp[array_index_nospec(i, MAX_EPTP)] = ept->eptp;
>>>    }
>>>    
>>>    unsigned int p2m_find_altp2m_by_eptp(struct domain *d, uint64_t eptp)
>>> --- a/xen/arch/x86/mm/p2m.c
>>> +++ b/xen/arch/x86/mm/p2m.c
>>> @@ -2499,7 +2499,7 @@ static void p2m_reset_altp2m(struct domain *d, unsigned int idx,
>>>        struct p2m_domain *p2m;
>>>    
>>>        ASSERT(idx < MAX_ALTP2M);
>>> -    p2m = d->arch.altp2m_p2m[idx];
>>> +    p2m = d->arch.altp2m_p2m[array_index_nospec(idx, MAX_ALTP2M)];
>>>    
>>>        p2m_lock(p2m);
>>>    
>>> @@ -2540,7 +2540,7 @@ static int p2m_activate_altp2m(struct domain *d, unsigned int idx)
>>>    
>>>        ASSERT(idx < MAX_ALTP2M);
>>>    
>>> -    p2m = d->arch.altp2m_p2m[idx];
>>> +    p2m = d->arch.altp2m_p2m[array_index_nospec(idx, MAX_ALTP2M)];
>>
>> All of the above have a more or less significant disconnect between
>> the bounds check and the use as array index. I think it would be
>> quite helpful if these could live close to one another, so one can
>> (see further up) easily prove that both specified bounds actually
>> match up.
>>
> 
> Sure, I can move the array use closer together.
> 

Sorry to come back on this but I was looking in the code and I am not 
sure I follow where is the disconnect. If you are talking about 
p2m_init_altp2m_ept() the eptp code will move up in patch 3/4.

Can you please clarify?

Thanks,
Alex
Jan Beulich Dec. 18, 2019, 9:59 a.m. UTC | #5
On 18.12.2019 09:06, Alexandru Stefan ISAILA wrote:
> On 17.12.2019 18:50, Jan Beulich wrote:
>> On 17.12.2019 16:12, Alexandru Stefan ISAILA wrote:
>>> --- a/xen/arch/x86/mm/mem_access.c
>>> +++ b/xen/arch/x86/mm/mem_access.c
>>> @@ -367,10 +367,11 @@ long p2m_set_mem_access(struct domain *d, gfn_t gfn, uint32_t nr,
>>>       if ( altp2m_idx )
>>>       {
>>>           if ( altp2m_idx >= MAX_ALTP2M ||
>>> -             d->arch.altp2m_eptp[altp2m_idx] == mfn_x(INVALID_MFN) )
>>> +             d->arch.altp2m_eptp[array_index_nospec(altp2m_idx, MAX_EPTP)] ==
>>
>> The bounds check is against MAX_ALTP2M. Both MAX_ values look to be
>> independent, which means bounds check and value passed to the
>> helper need to match up (not just here).
> 
> I will have both checks against MAX_ALTP2M.

An alternative would be something along the lines of

           if ( altp2m_idx >= min(MAX_ALTP2M, MAX_EPTP) ||

Jan
Jan Beulich Dec. 18, 2019, 10:06 a.m. UTC | #6
On 18.12.2019 10:57, Alexandru Stefan ISAILA wrote:
> On 18.12.2019 10:06, Alexandru Stefan ISAILA wrote:
>> On 17.12.2019 18:50, Jan Beulich wrote:
>>> On 17.12.2019 16:12, Alexandru Stefan ISAILA wrote:
>>>> --- a/xen/arch/x86/mm/p2m-ept.c
>>>> +++ b/xen/arch/x86/mm/p2m-ept.c
>>>> @@ -1353,7 +1353,8 @@ void setup_ept_dump(void)
>>>>    
>>>>    void p2m_init_altp2m_ept(struct domain *d, unsigned int i)
>>>>    {
>>>> -    struct p2m_domain *p2m = d->arch.altp2m_p2m[i];
>>>> +    struct p2m_domain *p2m =
>>>> +           d->arch.altp2m_p2m[array_index_nospec(i, MAX_ALTP2M)];
>>>>        struct p2m_domain *hostp2m = p2m_get_hostp2m(d);
>>>>        struct ept_data *ept;
>>>>    
>>>> @@ -1366,7 +1367,7 @@ void p2m_init_altp2m_ept(struct domain *d, unsigned int i)
>>>>        p2m->max_mapped_pfn = p2m->max_remapped_gfn = 0;
>>>>        ept = &p2m->ept;
>>>>        ept->mfn = pagetable_get_pfn(p2m_get_pagetable(p2m));
>>>> -    d->arch.altp2m_eptp[i] = ept->eptp;
>>>> +    d->arch.altp2m_eptp[array_index_nospec(i, MAX_EPTP)] = ept->eptp;
>>>>    }
>>>>    
>>>>    unsigned int p2m_find_altp2m_by_eptp(struct domain *d, uint64_t eptp)
>>>> --- a/xen/arch/x86/mm/p2m.c
>>>> +++ b/xen/arch/x86/mm/p2m.c
>>>> @@ -2499,7 +2499,7 @@ static void p2m_reset_altp2m(struct domain *d, unsigned int idx,
>>>>        struct p2m_domain *p2m;
>>>>    
>>>>        ASSERT(idx < MAX_ALTP2M);
>>>> -    p2m = d->arch.altp2m_p2m[idx];
>>>> +    p2m = d->arch.altp2m_p2m[array_index_nospec(idx, MAX_ALTP2M)];
>>>>    
>>>>        p2m_lock(p2m);
>>>>    
>>>> @@ -2540,7 +2540,7 @@ static int p2m_activate_altp2m(struct domain *d, unsigned int idx)
>>>>    
>>>>        ASSERT(idx < MAX_ALTP2M);
>>>>    
>>>> -    p2m = d->arch.altp2m_p2m[idx];
>>>> +    p2m = d->arch.altp2m_p2m[array_index_nospec(idx, MAX_ALTP2M)];
>>>
>>> All of the above have a more or less significant disconnect between
>>> the bounds check and the use as array index. I think it would be
>>> quite helpful if these could live close to one another, so one can
>>> (see further up) easily prove that both specified bounds actually
>>> match up.
>>>
>>
>> Sure, I can move the array use closer together.
>>
> 
> Sorry to come back on this but I was looking in the code and I am not 
> sure I follow where is the disconnect. If you are talking about 
> p2m_init_altp2m_ept() the eptp code will move up in patch 3/4.

My remark was about all four hunks left in context (and then still
possibly extending to other ones). Let's take the last one above:
p2m_activate_altp2m() has two callers, one of which loops over
altp2m-s (and hence doesn't need the guard). The other one is
p2m_init_altp2m_by_id() which does the range check I'm talking
about (ASSERT() doesn't count), and which therefore is the place
to use array_index_nospec(). Once you look there you'll notice
that the function also has an array access itself which you've
left untouched.

Jan
Alexandru Stefan ISAILA Dec. 18, 2019, 10:26 a.m. UTC | #7
On 18.12.2019 12:06, Jan Beulich wrote:
> On 18.12.2019 10:57, Alexandru Stefan ISAILA wrote:
>> On 18.12.2019 10:06, Alexandru Stefan ISAILA wrote:
>>> On 17.12.2019 18:50, Jan Beulich wrote:
>>>> On 17.12.2019 16:12, Alexandru Stefan ISAILA wrote:
>>>>> --- a/xen/arch/x86/mm/p2m-ept.c
>>>>> +++ b/xen/arch/x86/mm/p2m-ept.c
>>>>> @@ -1353,7 +1353,8 @@ void setup_ept_dump(void)
>>>>>     
>>>>>     void p2m_init_altp2m_ept(struct domain *d, unsigned int i)
>>>>>     {
>>>>> -    struct p2m_domain *p2m = d->arch.altp2m_p2m[i];
>>>>> +    struct p2m_domain *p2m =
>>>>> +           d->arch.altp2m_p2m[array_index_nospec(i, MAX_ALTP2M)];
>>>>>         struct p2m_domain *hostp2m = p2m_get_hostp2m(d);
>>>>>         struct ept_data *ept;
>>>>>     
>>>>> @@ -1366,7 +1367,7 @@ void p2m_init_altp2m_ept(struct domain *d, unsigned int i)
>>>>>         p2m->max_mapped_pfn = p2m->max_remapped_gfn = 0;
>>>>>         ept = &p2m->ept;
>>>>>         ept->mfn = pagetable_get_pfn(p2m_get_pagetable(p2m));
>>>>> -    d->arch.altp2m_eptp[i] = ept->eptp;
>>>>> +    d->arch.altp2m_eptp[array_index_nospec(i, MAX_EPTP)] = ept->eptp;
>>>>>     }
>>>>>     
>>>>>     unsigned int p2m_find_altp2m_by_eptp(struct domain *d, uint64_t eptp)
>>>>> --- a/xen/arch/x86/mm/p2m.c
>>>>> +++ b/xen/arch/x86/mm/p2m.c
>>>>> @@ -2499,7 +2499,7 @@ static void p2m_reset_altp2m(struct domain *d, unsigned int idx,
>>>>>         struct p2m_domain *p2m;
>>>>>     
>>>>>         ASSERT(idx < MAX_ALTP2M);
>>>>> -    p2m = d->arch.altp2m_p2m[idx];
>>>>> +    p2m = d->arch.altp2m_p2m[array_index_nospec(idx, MAX_ALTP2M)];
>>>>>     
>>>>>         p2m_lock(p2m);
>>>>>     
>>>>> @@ -2540,7 +2540,7 @@ static int p2m_activate_altp2m(struct domain *d, unsigned int idx)
>>>>>     
>>>>>         ASSERT(idx < MAX_ALTP2M);
>>>>>     
>>>>> -    p2m = d->arch.altp2m_p2m[idx];
>>>>> +    p2m = d->arch.altp2m_p2m[array_index_nospec(idx, MAX_ALTP2M)];
>>>>
>>>> All of the above have a more or less significant disconnect between
>>>> the bounds check and the use as array index. I think it would be
>>>> quite helpful if these could live close to one another, so one can
>>>> (see further up) easily prove that both specified bounds actually
>>>> match up.
>>>>
>>>
>>> Sure, I can move the array use closer together.
>>>
>>
>> Sorry to come back on this but I was looking in the code and I am not
>> sure I follow where is the disconnect. If you are talking about
>> p2m_init_altp2m_ept() the eptp code will move up in patch 3/4.
> 
> My remark was about all four hunks left in context (and then still
> possibly extending to other ones). Let's take the last one above:
> p2m_activate_altp2m() has two callers, one of which loops over
> altp2m-s (and hence doesn't need the guard). The other one is
> p2m_init_altp2m_by_id() which does the range check I'm talking
> about (ASSERT() doesn't count), and which therefore is the place
> to use array_index_nospec(). Once you look there you'll notice
> that the function also has an array access itself which you've
> left untouched.
> 

So add a "idx = array_index_nospec(idx, MAX_ALTP2M)" in the callers 
where there is a need for this and drop checks in the lower functions.


Alex
diff mbox series

Patch

diff --git a/xen/arch/x86/mm/mem_access.c b/xen/arch/x86/mm/mem_access.c
index 320b9fe621..70f3528bb1 100644
--- a/xen/arch/x86/mm/mem_access.c
+++ b/xen/arch/x86/mm/mem_access.c
@@ -367,10 +367,11 @@  long p2m_set_mem_access(struct domain *d, gfn_t gfn, uint32_t nr,
     if ( altp2m_idx )
     {
         if ( altp2m_idx >= MAX_ALTP2M ||
-             d->arch.altp2m_eptp[altp2m_idx] == mfn_x(INVALID_MFN) )
+             d->arch.altp2m_eptp[array_index_nospec(altp2m_idx, MAX_EPTP)] ==
+             mfn_x(INVALID_MFN) )
             return -EINVAL;
 
-        ap2m = d->arch.altp2m_p2m[altp2m_idx];
+        ap2m = d->arch.altp2m_p2m[array_index_nospec(altp2m_idx, MAX_ALTP2M)];
     }
 #else
     ASSERT(!altp2m_idx);
@@ -426,10 +427,11 @@  long p2m_set_mem_access_multi(struct domain *d,
     if ( altp2m_idx )
     {
         if ( altp2m_idx >= MAX_ALTP2M ||
-             d->arch.altp2m_eptp[altp2m_idx] == mfn_x(INVALID_MFN) )
+             d->arch.altp2m_eptp[array_index_nospec(altp2m_idx, MAX_EPTP)] ==
+             mfn_x(INVALID_MFN) )
             return -EINVAL;
 
-        ap2m = d->arch.altp2m_p2m[altp2m_idx];
+        ap2m = d->arch.altp2m_p2m[array_index_nospec(altp2m_idx, MAX_ALTP2M)];
     }
 #else
     ASSERT(!altp2m_idx);
@@ -492,10 +494,11 @@  int p2m_get_mem_access(struct domain *d, gfn_t gfn, xenmem_access_t *access,
     else if ( altp2m_idx ) /* altp2m view 0 is treated as the hostp2m */
     {
         if ( altp2m_idx >= MAX_ALTP2M ||
-             d->arch.altp2m_eptp[altp2m_idx] == mfn_x(INVALID_MFN) )
+             d->arch.altp2m_eptp[array_index_nospec(altp2m_idx, MAX_EPTP)] ==
+             mfn_x(INVALID_MFN) )
             return -EINVAL;
 
-        p2m = d->arch.altp2m_p2m[altp2m_idx];
+        p2m = d->arch.altp2m_p2m[array_index_nospec(altp2m_idx, MAX_ALTP2M)];
     }
 #else
     ASSERT(!altp2m_idx);
diff --git a/xen/arch/x86/mm/p2m-ept.c b/xen/arch/x86/mm/p2m-ept.c
index b5517769c9..e088a63f56 100644
--- a/xen/arch/x86/mm/p2m-ept.c
+++ b/xen/arch/x86/mm/p2m-ept.c
@@ -1353,7 +1353,8 @@  void setup_ept_dump(void)
 
 void p2m_init_altp2m_ept(struct domain *d, unsigned int i)
 {
-    struct p2m_domain *p2m = d->arch.altp2m_p2m[i];
+    struct p2m_domain *p2m =
+           d->arch.altp2m_p2m[array_index_nospec(i, MAX_ALTP2M)];
     struct p2m_domain *hostp2m = p2m_get_hostp2m(d);
     struct ept_data *ept;
 
@@ -1366,7 +1367,7 @@  void p2m_init_altp2m_ept(struct domain *d, unsigned int i)
     p2m->max_mapped_pfn = p2m->max_remapped_gfn = 0;
     ept = &p2m->ept;
     ept->mfn = pagetable_get_pfn(p2m_get_pagetable(p2m));
-    d->arch.altp2m_eptp[i] = ept->eptp;
+    d->arch.altp2m_eptp[array_index_nospec(i, MAX_EPTP)] = ept->eptp;
 }
 
 unsigned int p2m_find_altp2m_by_eptp(struct domain *d, uint64_t eptp)
diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c
index ba126f790a..7e7f4f1a7c 100644
--- a/xen/arch/x86/mm/p2m.c
+++ b/xen/arch/x86/mm/p2m.c
@@ -2499,7 +2499,7 @@  static void p2m_reset_altp2m(struct domain *d, unsigned int idx,
     struct p2m_domain *p2m;
 
     ASSERT(idx < MAX_ALTP2M);
-    p2m = d->arch.altp2m_p2m[idx];
+    p2m = d->arch.altp2m_p2m[array_index_nospec(idx, MAX_ALTP2M)];
 
     p2m_lock(p2m);
 
@@ -2540,7 +2540,7 @@  static int p2m_activate_altp2m(struct domain *d, unsigned int idx)
 
     ASSERT(idx < MAX_ALTP2M);
 
-    p2m = d->arch.altp2m_p2m[idx];
+    p2m = d->arch.altp2m_p2m[array_index_nospec(idx, MAX_ALTP2M)];
     hostp2m = p2m_get_hostp2m(d);
 
     p2m_lock(p2m);
@@ -2622,9 +2622,10 @@  int p2m_destroy_altp2m_by_id(struct domain *d, unsigned int idx)
     rc = -EBUSY;
     altp2m_list_lock(d);
 
-    if ( d->arch.altp2m_eptp[idx] != mfn_x(INVALID_MFN) )
+    if ( d->arch.altp2m_eptp[array_index_nospec(idx, MAX_EPTP)] !=
+         mfn_x(INVALID_MFN) )
     {
-        p2m = d->arch.altp2m_p2m[idx];
+        p2m = d->arch.altp2m_p2m[array_index_nospec(idx, MAX_ALTP2M)];
 
         if ( !_atomic_read(p2m->active_vcpus) )
         {
@@ -2686,11 +2687,13 @@  int p2m_change_altp2m_gfn(struct domain *d, unsigned int idx,
     mfn_t mfn;
     int rc = -EINVAL;
 
-    if ( idx >= MAX_ALTP2M || d->arch.altp2m_eptp[idx] == mfn_x(INVALID_MFN) )
+    if ( idx >= MAX_ALTP2M ||
+         d->arch.altp2m_eptp[array_index_nospec(idx, MAX_EPTP)] ==
+         mfn_x(INVALID_MFN) )
         return rc;
 
     hp2m = p2m_get_hostp2m(d);
-    ap2m = d->arch.altp2m_p2m[idx];
+    ap2m = d->arch.altp2m_p2m[array_index_nospec(idx, MAX_ALTP2M)];
 
     p2m_lock(hp2m);
     p2m_lock(ap2m);
@@ -3030,10 +3033,12 @@  int p2m_set_suppress_ve(struct domain *d, gfn_t gfn, bool suppress_ve,
     if ( altp2m_idx > 0 )
     {
         if ( altp2m_idx >= MAX_ALTP2M ||
-             d->arch.altp2m_eptp[altp2m_idx] == mfn_x(INVALID_MFN) )
+             d->arch.altp2m_eptp[array_index_nospec(altp2m_idx, MAX_EPTP)] ==
+             mfn_x(INVALID_MFN) )
             return -EINVAL;
 
-        p2m = ap2m = d->arch.altp2m_p2m[altp2m_idx];
+        p2m = ap2m = d->arch.altp2m_p2m[array_index_nospec(altp2m_idx,
+                                                           MAX_ALTP2M)];
     }
     else
         p2m = host_p2m;
@@ -3073,10 +3078,12 @@  int p2m_get_suppress_ve(struct domain *d, gfn_t gfn, bool *suppress_ve,
     if ( altp2m_idx > 0 )
     {
         if ( altp2m_idx >= MAX_ALTP2M ||
-             d->arch.altp2m_eptp[altp2m_idx] == mfn_x(INVALID_MFN) )
+             d->arch.altp2m_eptp[array_index_nospec(altp2m_idx, MAX_EPTP)] ==
+             mfn_x(INVALID_MFN) )
             return -EINVAL;
 
-        p2m = ap2m = d->arch.altp2m_p2m[altp2m_idx];
+        p2m = ap2m = d->arch.altp2m_p2m[array_index_nospec(altp2m_idx,
+                                                           MAX_ALTP2M)];
     }
     else
         p2m = host_p2m;