All of lore.kernel.org
 help / color / mirror / Atom feed
From: Christophe Leroy <christophe.leroy@csgroup.eu>
To: Michael Ellerman <mpe@ellerman.id.au>
Cc: "linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	"linuxppc-dev@lists.ozlabs.org" <linuxppc-dev@lists.ozlabs.org>,
	Maxime Bizon <mbizon@freebox.fr>,
	"stable@vger.kernel.org" <stable@vger.kernel.org>,
	Russell Currey <ruscur@russell.cc>,
	Paul Mackerras <paulus@samba.org>,
	Benjamin Herrenschmidt <benh@kernel.crashing.org>
Subject: Re: [PATCH v3 2/2] powerpc: Add set_memory_{p/np}() and remove set_memory_attr()
Date: Wed, 19 Jan 2022 12:28:09 +0000	[thread overview]
Message-ID: <02b15e82-5da8-468b-f51a-195594746839@csgroup.eu> (raw)
In-Reply-To: <cda2b44b55c96f9ac69fa92e68c01084ec9495c5.1640344012.git.christophe.leroy@csgroup.eu>

Hi Michael,

Can we get this series in fixes as well ?

Thanks
Christophe

Le 24/12/2021 à 12:07, Christophe Leroy a écrit :
> set_memory_attr() was implemented by commit 4d1755b6a762 ("powerpc/mm:
> implement set_memory_attr()") because the set_memory_xx() couldn't
> be used at that time to modify memory "on the fly" as explained it
> the commit.
> 
> But set_memory_attr() uses set_pte_at() which leads to warnings when
> CONFIG_DEBUG_VM is selected, because set_pte_at() is unexpected for
> updating existing page table entries.
> 
> The check could be bypassed by using __set_pte_at() instead,
> as it was the case before commit c988cfd38e48 ("powerpc/32:
> use set_memory_attr()") but since commit 9f7853d7609d ("powerpc/mm:
> Fix set_memory_*() against concurrent accesses") it is now possible
> to use set_memory_xx() functions to update page table entries
> "on the fly" because the update is now atomic.
> 
> For DEBUG_PAGEALLOC we need to clear and set back _PAGE_PRESENT.
> Add set_memory_np() and set_memory_p() for that.
> 
> Replace all uses of set_memory_attr() by the relevant set_memory_xx()
> and remove set_memory_attr().
> 
> Reported-by: Maxime Bizon <mbizon@freebox.fr>
> Fixes: c988cfd38e48 ("powerpc/32: use set_memory_attr()")
> Cc: stable@vger.kernel.org
> Depends-on: 9f7853d7609d ("powerpc/mm: Fix set_memory_*() against concurrent accesses")
> Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
> Reviewed-by: Russell Currey <ruscur@russell.cc>
> Tested-by: Maxime Bizon <mbizon@freebox.fr>
> ---
> v3: Use _PAGE_PRESENT directly as all platforms have the bit
> 
> v2: Add comment to SET_MEMORY_P and SET_MEMORY_NP
> ---
>   arch/powerpc/include/asm/set_memory.h | 12 ++++++++-
>   arch/powerpc/mm/pageattr.c            | 39 +++++----------------------
>   arch/powerpc/mm/pgtable_32.c          | 24 ++++++++---------
>   3 files changed, 28 insertions(+), 47 deletions(-)
> 
> diff --git a/arch/powerpc/include/asm/set_memory.h b/arch/powerpc/include/asm/set_memory.h
> index b040094f7920..7ebc807aa8cc 100644
> --- a/arch/powerpc/include/asm/set_memory.h
> +++ b/arch/powerpc/include/asm/set_memory.h
> @@ -6,6 +6,8 @@
>   #define SET_MEMORY_RW	1
>   #define SET_MEMORY_NX	2
>   #define SET_MEMORY_X	3
> +#define SET_MEMORY_NP	4	/* Set memory non present */
> +#define SET_MEMORY_P	5	/* Set memory present */
>   
>   int change_memory_attr(unsigned long addr, int numpages, long action);
>   
> @@ -29,6 +31,14 @@ static inline int set_memory_x(unsigned long addr, int numpages)
>   	return change_memory_attr(addr, numpages, SET_MEMORY_X);
>   }
>   
> -int set_memory_attr(unsigned long addr, int numpages, pgprot_t prot);
> +static inline int set_memory_np(unsigned long addr, int numpages)
> +{
> +	return change_memory_attr(addr, numpages, SET_MEMORY_NP);
> +}
> +
> +static inline int set_memory_p(unsigned long addr, int numpages)
> +{
> +	return change_memory_attr(addr, numpages, SET_MEMORY_P);
> +}
>   
>   #endif
> diff --git a/arch/powerpc/mm/pageattr.c b/arch/powerpc/mm/pageattr.c
> index 8812454e70ff..85753e32a4de 100644
> --- a/arch/powerpc/mm/pageattr.c
> +++ b/arch/powerpc/mm/pageattr.c
> @@ -46,6 +46,12 @@ static int change_page_attr(pte_t *ptep, unsigned long addr, void *data)
>   	case SET_MEMORY_X:
>   		pte_update_delta(ptep, addr, _PAGE_KERNEL_RO, _PAGE_KERNEL_ROX);
>   		break;
> +	case SET_MEMORY_NP:
> +		pte_update(&init_mm, addr, ptep, _PAGE_PRESENT, 0, 0);
> +		break;
> +	case SET_MEMORY_P:
> +		pte_update(&init_mm, addr, ptep, 0, _PAGE_PRESENT, 0);
> +		break;
>   	default:
>   		WARN_ON_ONCE(1);
>   		break;
> @@ -90,36 +96,3 @@ int change_memory_attr(unsigned long addr, int numpages, long action)
>   	return apply_to_existing_page_range(&init_mm, start, size,
>   					    change_page_attr, (void *)action);
>   }
> -
> -/*
> - * Set the attributes of a page:
> - *
> - * This function is used by PPC32 at the end of init to set final kernel memory
> - * protection. It includes changing the maping of the page it is executing from
> - * and data pages it is using.
> - */
> -static int set_page_attr(pte_t *ptep, unsigned long addr, void *data)
> -{
> -	pgprot_t prot = __pgprot((unsigned long)data);
> -
> -	spin_lock(&init_mm.page_table_lock);
> -
> -	set_pte_at(&init_mm, addr, ptep, pte_modify(*ptep, prot));
> -	flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
> -
> -	spin_unlock(&init_mm.page_table_lock);
> -
> -	return 0;
> -}
> -
> -int set_memory_attr(unsigned long addr, int numpages, pgprot_t prot)
> -{
> -	unsigned long start = ALIGN_DOWN(addr, PAGE_SIZE);
> -	unsigned long sz = numpages * PAGE_SIZE;
> -
> -	if (numpages <= 0)
> -		return 0;
> -
> -	return apply_to_existing_page_range(&init_mm, start, sz, set_page_attr,
> -					    (void *)pgprot_val(prot));
> -}
> diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c
> index 906e4e4328b2..f71ededdc02a 100644
> --- a/arch/powerpc/mm/pgtable_32.c
> +++ b/arch/powerpc/mm/pgtable_32.c
> @@ -135,10 +135,12 @@ void mark_initmem_nx(void)
>   	unsigned long numpages = PFN_UP((unsigned long)_einittext) -
>   				 PFN_DOWN((unsigned long)_sinittext);
>   
> -	if (v_block_mapped((unsigned long)_sinittext))
> +	if (v_block_mapped((unsigned long)_sinittext)) {
>   		mmu_mark_initmem_nx();
> -	else
> -		set_memory_attr((unsigned long)_sinittext, numpages, PAGE_KERNEL);
> +	} else {
> +		set_memory_nx((unsigned long)_sinittext, numpages);
> +		set_memory_rw((unsigned long)_sinittext, numpages);
> +	}
>   }
>   
>   #ifdef CONFIG_STRICT_KERNEL_RWX
> @@ -152,18 +154,14 @@ void mark_rodata_ro(void)
>   		return;
>   	}
>   
> -	numpages = PFN_UP((unsigned long)_etext) -
> -		   PFN_DOWN((unsigned long)_stext);
> -
> -	set_memory_attr((unsigned long)_stext, numpages, PAGE_KERNEL_ROX);
>   	/*
> -	 * mark .rodata as read only. Use __init_begin rather than __end_rodata
> -	 * to cover NOTES and EXCEPTION_TABLE.
> +	 * mark .text and .rodata as read only. Use __init_begin rather than
> +	 * __end_rodata to cover NOTES and EXCEPTION_TABLE.
>   	 */
>   	numpages = PFN_UP((unsigned long)__init_begin) -
> -		   PFN_DOWN((unsigned long)__start_rodata);
> +		   PFN_DOWN((unsigned long)_stext);
>   
> -	set_memory_attr((unsigned long)__start_rodata, numpages, PAGE_KERNEL_RO);
> +	set_memory_ro((unsigned long)_stext, numpages);
>   
>   	// mark_initmem_nx() should have already run by now
>   	ptdump_check_wx();
> @@ -179,8 +177,8 @@ void __kernel_map_pages(struct page *page, int numpages, int enable)
>   		return;
>   
>   	if (enable)
> -		set_memory_attr(addr, numpages, PAGE_KERNEL);
> +		set_memory_p(addr, numpages);
>   	else
> -		set_memory_attr(addr, numpages, __pgprot(0));
> +		set_memory_np(addr, numpages);
>   }
>   #endif /* CONFIG_DEBUG_PAGEALLOC */

WARNING: multiple messages have this Message-ID (diff)
From: Christophe Leroy <christophe.leroy@csgroup.eu>
To: Michael Ellerman <mpe@ellerman.id.au>
Cc: "linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	"stable@vger.kernel.org" <stable@vger.kernel.org>,
	Paul Mackerras <paulus@samba.org>,
	Maxime Bizon <mbizon@freebox.fr>,
	"linuxppc-dev@lists.ozlabs.org" <linuxppc-dev@lists.ozlabs.org>
Subject: Re: [PATCH v3 2/2] powerpc: Add set_memory_{p/np}() and remove set_memory_attr()
Date: Wed, 19 Jan 2022 12:28:09 +0000	[thread overview]
Message-ID: <02b15e82-5da8-468b-f51a-195594746839@csgroup.eu> (raw)
In-Reply-To: <cda2b44b55c96f9ac69fa92e68c01084ec9495c5.1640344012.git.christophe.leroy@csgroup.eu>

Hi Michael,

Can we get this series in fixes as well ?

Thanks
Christophe

Le 24/12/2021 à 12:07, Christophe Leroy a écrit :
> set_memory_attr() was implemented by commit 4d1755b6a762 ("powerpc/mm:
> implement set_memory_attr()") because the set_memory_xx() couldn't
> be used at that time to modify memory "on the fly" as explained it
> the commit.
> 
> But set_memory_attr() uses set_pte_at() which leads to warnings when
> CONFIG_DEBUG_VM is selected, because set_pte_at() is unexpected for
> updating existing page table entries.
> 
> The check could be bypassed by using __set_pte_at() instead,
> as it was the case before commit c988cfd38e48 ("powerpc/32:
> use set_memory_attr()") but since commit 9f7853d7609d ("powerpc/mm:
> Fix set_memory_*() against concurrent accesses") it is now possible
> to use set_memory_xx() functions to update page table entries
> "on the fly" because the update is now atomic.
> 
> For DEBUG_PAGEALLOC we need to clear and set back _PAGE_PRESENT.
> Add set_memory_np() and set_memory_p() for that.
> 
> Replace all uses of set_memory_attr() by the relevant set_memory_xx()
> and remove set_memory_attr().
> 
> Reported-by: Maxime Bizon <mbizon@freebox.fr>
> Fixes: c988cfd38e48 ("powerpc/32: use set_memory_attr()")
> Cc: stable@vger.kernel.org
> Depends-on: 9f7853d7609d ("powerpc/mm: Fix set_memory_*() against concurrent accesses")
> Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
> Reviewed-by: Russell Currey <ruscur@russell.cc>
> Tested-by: Maxime Bizon <mbizon@freebox.fr>
> ---
> v3: Use _PAGE_PRESENT directly as all platforms have the bit
> 
> v2: Add comment to SET_MEMORY_P and SET_MEMORY_NP
> ---
>   arch/powerpc/include/asm/set_memory.h | 12 ++++++++-
>   arch/powerpc/mm/pageattr.c            | 39 +++++----------------------
>   arch/powerpc/mm/pgtable_32.c          | 24 ++++++++---------
>   3 files changed, 28 insertions(+), 47 deletions(-)
> 
> diff --git a/arch/powerpc/include/asm/set_memory.h b/arch/powerpc/include/asm/set_memory.h
> index b040094f7920..7ebc807aa8cc 100644
> --- a/arch/powerpc/include/asm/set_memory.h
> +++ b/arch/powerpc/include/asm/set_memory.h
> @@ -6,6 +6,8 @@
>   #define SET_MEMORY_RW	1
>   #define SET_MEMORY_NX	2
>   #define SET_MEMORY_X	3
> +#define SET_MEMORY_NP	4	/* Set memory non present */
> +#define SET_MEMORY_P	5	/* Set memory present */
>   
>   int change_memory_attr(unsigned long addr, int numpages, long action);
>   
> @@ -29,6 +31,14 @@ static inline int set_memory_x(unsigned long addr, int numpages)
>   	return change_memory_attr(addr, numpages, SET_MEMORY_X);
>   }
>   
> -int set_memory_attr(unsigned long addr, int numpages, pgprot_t prot);
> +static inline int set_memory_np(unsigned long addr, int numpages)
> +{
> +	return change_memory_attr(addr, numpages, SET_MEMORY_NP);
> +}
> +
> +static inline int set_memory_p(unsigned long addr, int numpages)
> +{
> +	return change_memory_attr(addr, numpages, SET_MEMORY_P);
> +}
>   
>   #endif
> diff --git a/arch/powerpc/mm/pageattr.c b/arch/powerpc/mm/pageattr.c
> index 8812454e70ff..85753e32a4de 100644
> --- a/arch/powerpc/mm/pageattr.c
> +++ b/arch/powerpc/mm/pageattr.c
> @@ -46,6 +46,12 @@ static int change_page_attr(pte_t *ptep, unsigned long addr, void *data)
>   	case SET_MEMORY_X:
>   		pte_update_delta(ptep, addr, _PAGE_KERNEL_RO, _PAGE_KERNEL_ROX);
>   		break;
> +	case SET_MEMORY_NP:
> +		pte_update(&init_mm, addr, ptep, _PAGE_PRESENT, 0, 0);
> +		break;
> +	case SET_MEMORY_P:
> +		pte_update(&init_mm, addr, ptep, 0, _PAGE_PRESENT, 0);
> +		break;
>   	default:
>   		WARN_ON_ONCE(1);
>   		break;
> @@ -90,36 +96,3 @@ int change_memory_attr(unsigned long addr, int numpages, long action)
>   	return apply_to_existing_page_range(&init_mm, start, size,
>   					    change_page_attr, (void *)action);
>   }
> -
> -/*
> - * Set the attributes of a page:
> - *
> - * This function is used by PPC32 at the end of init to set final kernel memory
> - * protection. It includes changing the maping of the page it is executing from
> - * and data pages it is using.
> - */
> -static int set_page_attr(pte_t *ptep, unsigned long addr, void *data)
> -{
> -	pgprot_t prot = __pgprot((unsigned long)data);
> -
> -	spin_lock(&init_mm.page_table_lock);
> -
> -	set_pte_at(&init_mm, addr, ptep, pte_modify(*ptep, prot));
> -	flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
> -
> -	spin_unlock(&init_mm.page_table_lock);
> -
> -	return 0;
> -}
> -
> -int set_memory_attr(unsigned long addr, int numpages, pgprot_t prot)
> -{
> -	unsigned long start = ALIGN_DOWN(addr, PAGE_SIZE);
> -	unsigned long sz = numpages * PAGE_SIZE;
> -
> -	if (numpages <= 0)
> -		return 0;
> -
> -	return apply_to_existing_page_range(&init_mm, start, sz, set_page_attr,
> -					    (void *)pgprot_val(prot));
> -}
> diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c
> index 906e4e4328b2..f71ededdc02a 100644
> --- a/arch/powerpc/mm/pgtable_32.c
> +++ b/arch/powerpc/mm/pgtable_32.c
> @@ -135,10 +135,12 @@ void mark_initmem_nx(void)
>   	unsigned long numpages = PFN_UP((unsigned long)_einittext) -
>   				 PFN_DOWN((unsigned long)_sinittext);
>   
> -	if (v_block_mapped((unsigned long)_sinittext))
> +	if (v_block_mapped((unsigned long)_sinittext)) {
>   		mmu_mark_initmem_nx();
> -	else
> -		set_memory_attr((unsigned long)_sinittext, numpages, PAGE_KERNEL);
> +	} else {
> +		set_memory_nx((unsigned long)_sinittext, numpages);
> +		set_memory_rw((unsigned long)_sinittext, numpages);
> +	}
>   }
>   
>   #ifdef CONFIG_STRICT_KERNEL_RWX
> @@ -152,18 +154,14 @@ void mark_rodata_ro(void)
>   		return;
>   	}
>   
> -	numpages = PFN_UP((unsigned long)_etext) -
> -		   PFN_DOWN((unsigned long)_stext);
> -
> -	set_memory_attr((unsigned long)_stext, numpages, PAGE_KERNEL_ROX);
>   	/*
> -	 * mark .rodata as read only. Use __init_begin rather than __end_rodata
> -	 * to cover NOTES and EXCEPTION_TABLE.
> +	 * mark .text and .rodata as read only. Use __init_begin rather than
> +	 * __end_rodata to cover NOTES and EXCEPTION_TABLE.
>   	 */
>   	numpages = PFN_UP((unsigned long)__init_begin) -
> -		   PFN_DOWN((unsigned long)__start_rodata);
> +		   PFN_DOWN((unsigned long)_stext);
>   
> -	set_memory_attr((unsigned long)__start_rodata, numpages, PAGE_KERNEL_RO);
> +	set_memory_ro((unsigned long)_stext, numpages);
>   
>   	// mark_initmem_nx() should have already run by now
>   	ptdump_check_wx();
> @@ -179,8 +177,8 @@ void __kernel_map_pages(struct page *page, int numpages, int enable)
>   		return;
>   
>   	if (enable)
> -		set_memory_attr(addr, numpages, PAGE_KERNEL);
> +		set_memory_p(addr, numpages);
>   	else
> -		set_memory_attr(addr, numpages, __pgprot(0));
> +		set_memory_np(addr, numpages);
>   }
>   #endif /* CONFIG_DEBUG_PAGEALLOC */

  reply	other threads:[~2022-01-19 12:28 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-12-24 11:07 [PATCH v3 1/2] powerpc/set_memory: Avoid spinlock recursion in change_page_attr() Christophe Leroy
2021-12-24 11:07 ` Christophe Leroy
2021-12-24 11:07 ` [PATCH v3 2/2] powerpc: Add set_memory_{p/np}() and remove set_memory_attr() Christophe Leroy
2021-12-24 11:07   ` Christophe Leroy
2022-01-19 12:28   ` Christophe Leroy [this message]
2022-01-19 12:28     ` Christophe Leroy
2022-02-16 12:25 ` [PATCH v3 1/2] powerpc/set_memory: Avoid spinlock recursion in change_page_attr() Michael Ellerman
2022-02-16 12:25   ` Michael Ellerman

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=02b15e82-5da8-468b-f51a-195594746839@csgroup.eu \
    --to=christophe.leroy@csgroup.eu \
    --cc=benh@kernel.crashing.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linuxppc-dev@lists.ozlabs.org \
    --cc=mbizon@freebox.fr \
    --cc=mpe@ellerman.id.au \
    --cc=paulus@samba.org \
    --cc=ruscur@russell.cc \
    --cc=stable@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.