[PATCH 3/3] powerpc/mm/ Add proper pte access check helper

Christophe LEROY christophe.leroy at c-s.fr
Mon Aug 20 16:12:33 AEST 2018



Le 17/08/2018 à 17:12, Christophe LEROY a écrit :
> 
> 
> Le 04/12/2017 à 03:19, Aneesh Kumar K.V a écrit :
>> pte_access_premitted get called in get_user_pages_fast path. If we 
>> have marked
>> the pte PROT_NONE, we should not allow a read access on the address. With
>> the current implementation we are not checking the READ and only check 
>> for
>> WRITE. This is needed on archs like ppc64 that implement PROT_NONE using
>> _PAGE_USER access instead of _PAGE_PRESENT. Also add pte_user check 
>> just to make sure
>> we are not accessing kernel mapping.
>>
>> Even though there is code duplication, keeping the low level pte 
>> accessors
>> different for different platforms helps in code readability.
>>
>> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
>> ---
>>   arch/powerpc/include/asm/book3s/32/pgtable.h | 23 
>> +++++++++++++++++++++++
>>   arch/powerpc/include/asm/nohash/pgtable.h    | 23 
>> +++++++++++++++++++++++
>>   2 files changed, 46 insertions(+)
>>
>> diff --git a/arch/powerpc/include/asm/book3s/32/pgtable.h 
>> b/arch/powerpc/include/asm/book3s/32/pgtable.h
>> index 016579ef16d3..30a155c0a6b0 100644
>> --- a/arch/powerpc/include/asm/book3s/32/pgtable.h
>> +++ b/arch/powerpc/include/asm/book3s/32/pgtable.h
>> @@ -311,6 +311,29 @@ static inline int pte_present(pte_t pte)
>>       return pte_val(pte) & _PAGE_PRESENT;
>>   }
>> +/*
>> + * We only find page table entry in the last level
>> + * Hence no need for other accessors
>> + */
>> +#define pte_access_permitted pte_access_permitted
>> +static inline bool pte_access_permitted(pte_t pte, bool write)
>> +{
>> +    unsigned long pteval = pte_val(pte);
>> +    /*
>> +     * A read-only access is controlled by _PAGE_USER bit.
>> +     * We have _PAGE_READ set for WRITE and EXECUTE
>> +     */
>> +    unsigned long need_pte_bits = _PAGE_PRESENT | _PAGE_USER;
>> +
>> +    if (write)
>> +        need_pte_bits |= _PAGE_WRITE;
>> +
>> +    if ((pteval & need_pte_bits) != need_pte_bits)
>> +        return false;
>> +
>> +    return true;
>> +}
>> +
>>   /* Conversion functions: convert a page and protection to a page entry,
>>    * and a page entry and page directory to the page they refer to.
>>    *
>> diff --git a/arch/powerpc/include/asm/nohash/pgtable.h 
>> b/arch/powerpc/include/asm/nohash/pgtable.h
>> index 5c68f4a59f75..fc4376c8d444 100644
>> --- a/arch/powerpc/include/asm/nohash/pgtable.h
>> +++ b/arch/powerpc/include/asm/nohash/pgtable.h
>> @@ -45,6 +45,29 @@ static inline int pte_present(pte_t pte)
>>       return pte_val(pte) & _PAGE_PRESENT;
>>   }
>> +/*
>> + * We only find page table entry in the last level
>> + * Hence no need for other accessors
>> + */
>> +#define pte_access_permitted pte_access_permitted
>> +static inline bool pte_access_permitted(pte_t pte, bool write)
>> +{
>> +    unsigned long pteval = pte_val(pte);
>> +    /*
>> +     * A read-only access is controlled by _PAGE_USER bit.
>> +     * We have _PAGE_READ set for WRITE and EXECUTE
>> +     */
> 
> Not fully right. asm/pte-common.h defines:
> 
> #define PAGE_NONE    __pgprot(_PAGE_BASE | _PAGE_NA)
> #define PAGE_SHARED    __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW)
> #define PAGE_SHARED_X    __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW | \
>                   _PAGE_EXEC)
> #define PAGE_COPY    __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RO)
> #define PAGE_COPY_X    __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RO | \
>                   _PAGE_EXEC)
> #define PAGE_READONLY    __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RO)
> #define PAGE_READONLY_X    __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RO | \
>                   _PAGE_EXEC)
> 
> On the 8xx, _PAGE_USER = 0
> 
>> +    unsigned long need_pte_bits = _PAGE_PRESENT | _PAGE_USER;

_PAGE_PRIVILEGED should be checked as well.

Indeed, it seems like our patches crossed each other. My patch for 
adding _PAGE_PRIVILEGED is date January 16th while your's was merged on 
the 17th.

I'm wondering if there are other places that are missing _PAGE_RO 
handling and _PAGE_PRIVILEGED handling. Do you remember if you added any 
recently ?

Christophe

>> +
>> +    if (write)
>> +        need_pte_bits |= _PAGE_WRITE;
>> +
>> +    if ((pteval & need_pte_bits) != need_pte_bits)
>> +        return false;
> 
> This test is not fully correct:
> - To check access(read) permission, you also have to check that _PAGE_NA 
> is not set.
> - To check write permission, you also have to check that neither 
> _PAGE_NA nor _PAGE_RO are set.
> 
> On the 8xx, you have:
> _PAGE_RW = _PAGE_WRITE = 0
> _PAGE_NA = 0x0200
> _PAGE_RO = 0x0600
> 
> Christophe
> 
>> +
>> +    return true;
>> +}
>> +
>>   /* Conversion functions: convert a page and protection to a page entry,
>>    * and a page entry and page directory to the page they refer to.
>>    *
>>


More information about the Linuxppc-dev mailing list