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

Christophe LEROY christophe.leroy at c-s.fr
Sat Aug 18 01:12:18 AEST 2018



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;
> +
> +	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