[S390] Write protect module text and RO data

Implement write protection for kernel modules text and read-only
data sections by implementing set_memory_[ro|rw] on s390.
Since s390 has no execute bit in the pte's NX is not supported.

set_memory_[ro|rw] will only work on normal pages and not on
large pages, so in case a large page should be modified bail
out with a warning.

Signed-off-by: Jan Glauber <jang@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
Jan Glauber 2011-03-15 17:08:22 +01:00 committed by Martin Schwidefsky
parent d54cddb620
commit 305b152325
4 changed files with 63 additions and 0 deletions

View file

@ -31,4 +31,7 @@ config DEBUG_STRICT_USER_COPY_CHECKS
If unsure, or if you run an older (pre 4.4) gcc, say N. If unsure, or if you run an older (pre 4.4) gcc, say N.
config DEBUG_SET_MODULE_RONX
def_bool y
depends on MODULES
endmenu endmenu

View file

@ -8,4 +8,8 @@
void kernel_map_pages(struct page *page, int numpages, int enable); void kernel_map_pages(struct page *page, int numpages, int enable);
#endif #endif
int set_memory_ro(unsigned long addr, int numpages);
int set_memory_rw(unsigned long addr, int numpages);
int set_memory_nx(unsigned long addr, int numpages);
#endif /* _S390_CACHEFLUSH_H */ #endif /* _S390_CACHEFLUSH_H */

View file

@ -6,3 +6,4 @@ obj-y := init.o fault.o extmem.o mmap.o vmem.o pgtable.o maccess.o \
page-states.o gup.o page-states.o gup.o
obj-$(CONFIG_CMM) += cmm.o obj-$(CONFIG_CMM) += cmm.o
obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
obj-$(CONFIG_DEBUG_SET_MODULE_RONX) += pageattr.o

55
arch/s390/mm/pageattr.c Normal file
View file

@ -0,0 +1,55 @@
/*
* Copyright IBM Corp. 2011
* Author(s): Jan Glauber <jang@linux.vnet.ibm.com>
*/
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/hugetlb.h>
#include <asm/pgtable.h>
static void change_page_attr(unsigned long addr, int numpages,
pte_t (*set) (pte_t))
{
pte_t *ptep, pte;
pmd_t *pmdp;
pud_t *pudp;
pgd_t *pgdp;
int i;
for (i = 0; i < numpages; i++) {
pgdp = pgd_offset(&init_mm, addr);
pudp = pud_offset(pgdp, addr);
pmdp = pmd_offset(pudp, addr);
if (pmd_huge(*pmdp)) {
WARN_ON_ONCE(1);
continue;
}
ptep = pte_offset_kernel(pmdp, addr + i * PAGE_SIZE);
pte = *ptep;
pte = set(pte);
ptep_invalidate(&init_mm, addr + i * PAGE_SIZE, ptep);
*ptep = pte;
}
}
int set_memory_ro(unsigned long addr, int numpages)
{
change_page_attr(addr, numpages, pte_wrprotect);
return 0;
}
EXPORT_SYMBOL_GPL(set_memory_ro);
int set_memory_rw(unsigned long addr, int numpages)
{
change_page_attr(addr, numpages, pte_mkwrite);
return 0;
}
EXPORT_SYMBOL_GPL(set_memory_rw);
/* not possible */
int set_memory_nx(unsigned long addr, int numpages)
{
return 0;
}
EXPORT_SYMBOL_GPL(set_memory_nx);