Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+62 −30
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
#include <linux/memblock.h>
#include <linux/dma-contiguous.h>
#include <linux/sizes.h>
#include <linux/stop_machine.h>

#include <asm/cp15.h>
#include <asm/mach-types.h>
@@ -627,12 +628,10 @@ static struct section_perm ro_perms[] = {
 * safe to be called with preemption disabled, as under stop_machine().
 */
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;

	mm = current->active_mm;
	pmd = pmd_offset(pud_offset(pgd_offset(mm, addr), addr), addr);

#ifdef CONFIG_ARM_LPAE
@@ -656,49 +655,82 @@ static inline bool arch_has_strict_perms(void)
	return !!(get_cr() & CR_XP);
}

#define set_section_perms(perms, field)	{				\
	size_t i;							\
	unsigned long addr;						\
									\
	if (!arch_has_strict_perms())					\
		return;							\
									\
	for (i = 0; i < ARRAY_SIZE(perms); i++) {			\
		if (!IS_ALIGNED(perms[i].start, SECTION_SIZE) ||	\
		    !IS_ALIGNED(perms[i].end, SECTION_SIZE)) {		\
			pr_err("BUG: section %lx-%lx not aligned to %lx\n", \
				perms[i].start, perms[i].end,		\
				SECTION_SIZE);				\
			continue;					\
		}							\
									\
		for (addr = perms[i].start;				\
		     addr < perms[i].end;				\
		     addr += SECTION_SIZE)				\
			section_update(addr, perms[i].mask,		\
				       perms[i].field);			\
	}								\
void set_section_perms(struct section_perm *perms, int n, bool set,
			struct mm_struct *mm)
{
	size_t i;
	unsigned long addr;

	if (!arch_has_strict_perms())
		return;

	for (i = 0; i < n; i++) {
		if (!IS_ALIGNED(perms[i].start, SECTION_SIZE) ||
		    !IS_ALIGNED(perms[i].end, SECTION_SIZE)) {
			pr_err("BUG: section %lx-%lx not aligned to %lx\n",
				perms[i].start, perms[i].end,
				SECTION_SIZE);
			continue;
		}

		for (addr = perms[i].start;
		     addr < perms[i].end;
		     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
int __mark_rodata_ro(void *unused)
{
	update_sections_early(ro_perms, ARRAY_SIZE(ro_perms));
	return 0;
}

void mark_rodata_ro(void)
{
	set_section_perms(ro_perms, prot);
	stop_machine(__mark_rodata_ro, NULL, NULL);
}

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)
{
	set_section_perms(ro_perms, prot);
	set_section_perms(ro_perms, ARRAY_SIZE(ro_perms), true,
				current->active_mm);
}
#endif /* CONFIG_DEBUG_RODATA */