Strip the read-only attribute from the selected memory range when restoring the linear map after an execmem cache clean. An execmem cache clean is performed when a cache block becomes empty after unloading a module. When making the memory valid again, the linear memory alias must also have its read-only attribute cleared. Without this change, the linear memory alias remains read-only even after the execmem cache block itself is freed, which prevents subsequent allocations from writing to that memory. Signed-off-by: Adrian Barnaƛ --- arch/arm64/mm/pageattr.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/arch/arm64/mm/pageattr.c b/arch/arm64/mm/pageattr.c index 88720bbba892..eaefdf90b0d5 100644 --- a/arch/arm64/mm/pageattr.c +++ b/arch/arm64/mm/pageattr.c @@ -239,6 +239,13 @@ int set_memory_x(unsigned long addr, int numpages) __pgprot(PTE_PXN)); } +static int set_memory_default(unsigned long addr, int numpages) +{ + return __change_memory_common(addr, PAGE_SIZE * numpages, + __pgprot(PTE_VALID), + __pgprot(PTE_RDONLY)); +} + int set_memory_valid(unsigned long addr, int numpages, int enable) { if (enable) @@ -362,7 +369,15 @@ int set_direct_map_valid_noflush(struct page *page, unsigned nr, bool valid) if (!can_set_direct_map()) return 0; - return set_memory_valid(addr, nr, valid); + /* + * Execmem cache uses this function to reset permissions on linear mapping + * when freeing unused cache block. On x86 it makes memory RW which is + * desirable. On ARM64 set_memory_valid() just change valid bit which + * leave direct mapping read-only so use set_memory_default instead. + */ + + return valid ? set_memory_default(addr, nr) : + set_memory_valid(addr, nr, false); } #ifdef CONFIG_DEBUG_PAGEALLOC -- 2.54.0.1136.gdb2ca164c4-goog