Message ID | 20200310010338.21205-7-ruscur@russell.cc (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | set_memory() routines and STRICT_MODULE_RWX | expand |
Russell Currey <ruscur@russell.cc> writes: > From: Christophe Leroy <christophe.leroy@c-s.fr> > > In addition to the set_memory_xx() functions which allows to change > the memory attributes of not (yet) used memory regions, implement a > set_memory_attr() function to: > - set the final memory protection after init on currently used > kernel regions. > - enable/disable kernel memory regions in the scope of DEBUG_PAGEALLOC. > > Unlike the set_memory_xx() which can act in three step as the regions > are unused, this function must modify 'on the fly' as the kernel is > executing from them. At the moment only PPC32 will use it and changing > page attributes on the fly is not an issue. > > Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr> > Reported-by: kbuild test robot <lkp@intel.com> > [ruscur: cast "data" to unsigned long instead of int] > Signed-off-by: Russell Currey <ruscur@russell.cc> > --- > arch/powerpc/include/asm/set_memory.h | 2 ++ > arch/powerpc/mm/pageattr.c | 33 +++++++++++++++++++++++++++ > 2 files changed, 35 insertions(+) > > diff --git a/arch/powerpc/include/asm/set_memory.h b/arch/powerpc/include/asm/set_memory.h > index 64011ea444b4..b040094f7920 100644 > --- a/arch/powerpc/include/asm/set_memory.h > +++ b/arch/powerpc/include/asm/set_memory.h > @@ -29,4 +29,6 @@ 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); > + > #endif > diff --git a/arch/powerpc/mm/pageattr.c b/arch/powerpc/mm/pageattr.c > index 748fa56d9db0..60139fedc6cc 100644 > --- a/arch/powerpc/mm/pageattr.c > +++ b/arch/powerpc/mm/pageattr.c > @@ -77,3 +77,36 @@ int change_memory_attr(unsigned long addr, int numpages, long action) > > return apply_to_page_range(&init_mm, start, sz, 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) > + return 0; > + > + return apply_to_page_range(&init_mm, start, sz, set_page_attr, > + (void *)pgprot_val(prot)); This should probably use apply_to_existing_page_range as well. Regards, Daniel > +} > -- > 2.25.1
diff --git a/arch/powerpc/include/asm/set_memory.h b/arch/powerpc/include/asm/set_memory.h index 64011ea444b4..b040094f7920 100644 --- a/arch/powerpc/include/asm/set_memory.h +++ b/arch/powerpc/include/asm/set_memory.h @@ -29,4 +29,6 @@ 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); + #endif diff --git a/arch/powerpc/mm/pageattr.c b/arch/powerpc/mm/pageattr.c index 748fa56d9db0..60139fedc6cc 100644 --- a/arch/powerpc/mm/pageattr.c +++ b/arch/powerpc/mm/pageattr.c @@ -77,3 +77,36 @@ int change_memory_attr(unsigned long addr, int numpages, long action) return apply_to_page_range(&init_mm, start, sz, 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) + return 0; + + return apply_to_page_range(&init_mm, start, sz, set_page_attr, + (void *)pgprot_val(prot)); +}