Commit 08925c2f authored by Laura Abbott's avatar Laura Abbott Committed by Russell King

ARM: 8464/1: Update all mm structures with section adjustments

Currently, when updating section permissions to mark areas RO
or NX, the only mm updated is current->mm. This is working off
the assumption that there are no additional mm structures at
the time. This may not always hold true. (Example: calling
modprobe early will trigger a fork/exec). Ensure all mm structres
get updated with the new section information.
Reviewed-by: default avatarKees Cook <keescook@chromium.org>
Signed-off-by: default avatarLaura Abbott <labbott@fedoraproject.org>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 40ee068e
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/memblock.h> #include <linux/memblock.h>
#include <linux/dma-contiguous.h> #include <linux/dma-contiguous.h>
#include <linux/sizes.h> #include <linux/sizes.h>
#include <linux/stop_machine.h>
#include <asm/cp15.h> #include <asm/cp15.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
...@@ -627,12 +628,10 @@ static struct section_perm ro_perms[] = { ...@@ -627,12 +628,10 @@ static struct section_perm ro_perms[] = {
* safe to be called with preemption disabled, as under stop_machine(). * safe to be called with preemption disabled, as under stop_machine().
*/ */
static inline void section_update(unsigned long addr, pmdval_t mask, static inline void section_update(unsigned long addr, pmdval_t mask,
pmdval_t prot) pmdval_t prot, struct mm_struct *mm)
{ {
struct mm_struct *mm;
pmd_t *pmd; pmd_t *pmd;
mm = current->active_mm;
pmd = pmd_offset(pud_offset(pgd_offset(mm, addr), addr), addr); pmd = pmd_offset(pud_offset(pgd_offset(mm, addr), addr), addr);
#ifdef CONFIG_ARM_LPAE #ifdef CONFIG_ARM_LPAE
...@@ -656,49 +655,82 @@ static inline bool arch_has_strict_perms(void) ...@@ -656,49 +655,82 @@ static inline bool arch_has_strict_perms(void)
return !!(get_cr() & CR_XP); return !!(get_cr() & CR_XP);
} }
#define set_section_perms(perms, field) { \ void set_section_perms(struct section_perm *perms, int n, bool set,
size_t i; \ struct mm_struct *mm)
unsigned long addr; \ {
\ size_t i;
if (!arch_has_strict_perms()) \ unsigned long addr;
return; \
\ if (!arch_has_strict_perms())
for (i = 0; i < ARRAY_SIZE(perms); i++) { \ return;
if (!IS_ALIGNED(perms[i].start, SECTION_SIZE) || \
!IS_ALIGNED(perms[i].end, SECTION_SIZE)) { \ for (i = 0; i < n; i++) {
pr_err("BUG: section %lx-%lx not aligned to %lx\n", \ if (!IS_ALIGNED(perms[i].start, SECTION_SIZE) ||
perms[i].start, perms[i].end, \ !IS_ALIGNED(perms[i].end, SECTION_SIZE)) {
SECTION_SIZE); \ pr_err("BUG: section %lx-%lx not aligned to %lx\n",
continue; \ perms[i].start, perms[i].end,
} \ SECTION_SIZE);
\ continue;
for (addr = perms[i].start; \ }
addr < perms[i].end; \
addr += SECTION_SIZE) \ for (addr = perms[i].start;
section_update(addr, perms[i].mask, \ addr < perms[i].end;
perms[i].field); \ addr += SECTION_SIZE)
} \ section_update(addr, perms[i].mask,
set ? perms[i].prot : perms[i].clear, mm);
}
} }
static inline void fix_kernmem_perms(void) static void update_sections_early(struct section_perm perms[], int n)
{ {
set_section_perms(nx_perms, prot); struct task_struct *t, *s;
read_lock(&tasklist_lock);
for_each_process(t) {
if (t->flags & PF_KTHREAD)
continue;
for_each_thread(t, s)
set_section_perms(perms, n, true, s->mm);
}
read_unlock(&tasklist_lock);
set_section_perms(perms, n, true, current->active_mm);
set_section_perms(perms, n, true, &init_mm);
}
int __fix_kernmem_perms(void *unused)
{
update_sections_early(nx_perms, ARRAY_SIZE(nx_perms));
return 0;
}
void fix_kernmem_perms(void)
{
stop_machine(__fix_kernmem_perms, NULL, NULL);
} }
#ifdef CONFIG_DEBUG_RODATA #ifdef CONFIG_DEBUG_RODATA
int __mark_rodata_ro(void *unused)
{
update_sections_early(ro_perms, ARRAY_SIZE(ro_perms));
return 0;
}
void mark_rodata_ro(void) void mark_rodata_ro(void)
{ {
set_section_perms(ro_perms, prot); stop_machine(__mark_rodata_ro, NULL, NULL);
} }
void set_kernel_text_rw(void) void set_kernel_text_rw(void)
{ {
set_section_perms(ro_perms, clear); set_section_perms(ro_perms, ARRAY_SIZE(ro_perms), false,
current->active_mm);
} }
void set_kernel_text_ro(void) void set_kernel_text_ro(void)
{ {
set_section_perms(ro_perms, prot); set_section_perms(ro_perms, ARRAY_SIZE(ro_perms), true,
current->active_mm);
} }
#endif /* CONFIG_DEBUG_RODATA */ #endif /* CONFIG_DEBUG_RODATA */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment