Commit 08cd8f41 authored by Will Deacon's avatar Will Deacon Committed by Peter Zijlstra
Browse files

arm64: exec: Adjust affinity for compat tasks with mismatched 32-bit EL0



When exec'ing a 32-bit task on a system with mismatched support for
32-bit EL0, try to ensure that it starts life on a CPU that can actually
run it.

Similarly, when exec'ing a 64-bit task on such a system, try to restore
the old affinity mask if it was previously restricted.

Signed-off-by: default avatarWill Deacon <will@kernel.org>
Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: default avatarDaniel Bristot de Oliveira <bristot@redhat.com>
Reviewed-by: default avatarQuentin Perret <qperret@google.com>
Link: https://lore.kernel.org/r/20210730112443.23245-12-will@kernel.org
parent d82158fa
Loading
Loading
Loading
Loading
+2 −4
Original line number Diff line number Diff line
@@ -213,10 +213,8 @@ typedef compat_elf_greg_t compat_elf_gregset_t[COMPAT_ELF_NGREG];

/* AArch32 EABI. */
#define EF_ARM_EABI_MASK		0xff000000
#define compat_elf_check_arch(x)	(system_supports_32bit_el0() && \
					 ((x)->e_machine == EM_ARM) && \
					 ((x)->e_flags & EF_ARM_EABI_MASK))

int compat_elf_check_arch(const struct elf32_hdr *);
#define compat_elf_check_arch		compat_elf_check_arch
#define compat_start_thread		compat_start_thread
/*
 * Unlike the native SET_PERSONALITY macro, the compat version maintains
+38 −1
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include <linux/mman.h>
#include <linux/mm.h>
#include <linux/nospec.h>
#include <linux/sched.h>
#include <linux/stddef.h>
#include <linux/sysctl.h>
#include <linux/unistd.h>
@@ -579,6 +580,28 @@ unsigned long arch_align_stack(unsigned long sp)
	return sp & ~0xf;
}

#ifdef CONFIG_COMPAT
int compat_elf_check_arch(const struct elf32_hdr *hdr)
{
	if (!system_supports_32bit_el0())
		return false;

	if ((hdr)->e_machine != EM_ARM)
		return false;

	if (!((hdr)->e_flags & EF_ARM_EABI_MASK))
		return false;

	/*
	 * Prevent execve() of a 32-bit program from a deadline task
	 * if the restricted affinity mask would be inadmissible on an
	 * asymmetric system.
	 */
	return !static_branch_unlikely(&arm64_mismatched_32bit_el0) ||
	       !dl_task_check_affinity(current, system_32bit_el0_cpumask());
}
#endif

/*
 * Called from setup_new_exec() after (COMPAT_)SET_PERSONALITY.
 */
@@ -588,9 +611,23 @@ void arch_setup_new_exec(void)

	if (is_compat_task()) {
		mmflags = MMCF_AARCH32;
		if (static_branch_unlikely(&arm64_mismatched_32bit_el0))

		/*
		 * Restrict the CPU affinity mask for a 32-bit task so that
		 * it contains only 32-bit-capable CPUs.
		 *
		 * From the perspective of the task, this looks similar to
		 * what would happen if the 64-bit-only CPUs were hot-unplugged
		 * at the point of execve(), although we try a bit harder to
		 * honour the cpuset hierarchy.
		 */
		if (static_branch_unlikely(&arm64_mismatched_32bit_el0)) {
			force_compatible_cpus_allowed_ptr(current);
			set_tsk_thread_flag(current, TIF_NOTIFY_RESUME);
		}
	} else if (static_branch_unlikely(&arm64_mismatched_32bit_el0)) {
		relax_compatible_cpus_allowed_ptr(current);
	}

	current->mm->context.flags = mmflags;
	ptrauth_thread_init_user();