lkml.org 
[lkml]   [2021]   [Nov]   [15]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.15 508/917] s390/mm: validate VMA in PGSTE manipulation functions
    Date
    From: David Hildenbrand <david@redhat.com>

    [ Upstream commit fe3d10024073f06f04c74b9674bd71ccc1d787cf ]

    We should not walk/touch page tables outside of VMA boundaries when
    holding only the mmap sem in read mode. Evil user space can modify the
    VMA layout just before this function runs and e.g., trigger races with
    page table removal code since commit dd2283f2605e ("mm: mmap: zap pages
    with read mmap_sem in munmap"). gfn_to_hva() will only translate using
    KVM memory regions, but won't validate the VMA.

    Further, we should not allocate page tables outside of VMA boundaries: if
    evil user space decides to map hugetlbfs to these ranges, bad things will
    happen because we suddenly have PTE or PMD page tables where we
    shouldn't have them.

    Similarly, we have to check if we suddenly find a hugetlbfs VMA, before
    calling get_locked_pte().

    Fixes: 2d42f9477320 ("s390/kvm: Add PGSTE manipulation functions")
    Signed-off-by: David Hildenbrand <david@redhat.com>
    Reviewed-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
    Acked-by: Heiko Carstens <hca@linux.ibm.com>
    Link: https://lore.kernel.org/r/20210909162248.14969-4-david@redhat.com
    Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    arch/s390/mm/pgtable.c | 13 +++++++++++++
    1 file changed, 13 insertions(+)

    diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c
    index 034721a68d8fd..2717a406edeb3 100644
    --- a/arch/s390/mm/pgtable.c
    +++ b/arch/s390/mm/pgtable.c
    @@ -988,6 +988,7 @@ EXPORT_SYMBOL(get_guest_storage_key);
    int pgste_perform_essa(struct mm_struct *mm, unsigned long hva, int orc,
    unsigned long *oldpte, unsigned long *oldpgste)
    {
    + struct vm_area_struct *vma;
    unsigned long pgstev;
    spinlock_t *ptl;
    pgste_t pgste;
    @@ -997,6 +998,10 @@ int pgste_perform_essa(struct mm_struct *mm, unsigned long hva, int orc,
    WARN_ON_ONCE(orc > ESSA_MAX);
    if (unlikely(orc > ESSA_MAX))
    return -EINVAL;
    +
    + vma = vma_lookup(mm, hva);
    + if (!vma || is_vm_hugetlb_page(vma))
    + return -EFAULT;
    ptep = get_locked_pte(mm, hva, &ptl);
    if (unlikely(!ptep))
    return -EFAULT;
    @@ -1089,10 +1094,14 @@ EXPORT_SYMBOL(pgste_perform_essa);
    int set_pgste_bits(struct mm_struct *mm, unsigned long hva,
    unsigned long bits, unsigned long value)
    {
    + struct vm_area_struct *vma;
    spinlock_t *ptl;
    pgste_t new;
    pte_t *ptep;

    + vma = vma_lookup(mm, hva);
    + if (!vma || is_vm_hugetlb_page(vma))
    + return -EFAULT;
    ptep = get_locked_pte(mm, hva, &ptl);
    if (unlikely(!ptep))
    return -EFAULT;
    @@ -1117,9 +1126,13 @@ EXPORT_SYMBOL(set_pgste_bits);
    */
    int get_pgste(struct mm_struct *mm, unsigned long hva, unsigned long *pgstep)
    {
    + struct vm_area_struct *vma;
    spinlock_t *ptl;
    pte_t *ptep;

    + vma = vma_lookup(mm, hva);
    + if (!vma || is_vm_hugetlb_page(vma))
    + return -EFAULT;
    ptep = get_locked_pte(mm, hva, &ptl);
    if (unlikely(!ptep))
    return -EFAULT;
    --
    2.33.0


    \
     
     \ /
      Last update: 2021-11-16 01:34    [W:4.064 / U:0.016 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site