Commit 183ac2b2 authored by Marc Zyngier's avatar Marc Zyngier
Browse files

Merge branch kvm-arm64/pkvm-no-mte into kvmarm-master/next



* kvm-arm64/pkvm-no-mte:
  : .
  : pKVM updates preventing the host from using MTE-related system
  : sysrem registers when the feature is disabled from the kernel
  : command-line (arm64.nomte), courtesy of Fuad Taba.
  :
  : From the cover letter:
  :
  : "If MTE is supported by the hardware (and is enabled at EL3), it remains
  : available to lower exception levels by default. Disabling it in the host
  : kernel (e.g., via 'arm64.nomte') only stops the kernel from advertising
  : the feature; it does not physically disable MTE in the hardware.
  :
  : The ability to disable MTE in the host kernel is used by some systems,
  : such as Android, so that the physical memory otherwise used as tag
  : storage can be used for other things (i.e. treated just like the rest of
  : memory). In this scenario, a malicious host could still access tags in
  : pages donated to a guest using MTE instructions (e.g., STG and LDG),
  : bypassing the kernel's configuration."
  : .
  KVM: arm64: Use kvm_has_mte() in pKVM trap initialization
  KVM: arm64: Inject UNDEF when accessing MTE sysregs with MTE disabled
  KVM: arm64: Trap MTE access and discovery when MTE is disabled
  KVM: arm64: Remove dead code resetting HCR_EL2 for pKVM

Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
parents c983b3e2 230b0806
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -101,7 +101,7 @@
			 HCR_BSU_IS | HCR_FB | HCR_TACR | \
			 HCR_AMO | HCR_SWIO | HCR_TIDCP | HCR_RW | HCR_TLOR | \
			 HCR_FMO | HCR_IMO | HCR_PTW | HCR_TID3 | HCR_TID1)
#define HCR_HOST_NVHE_FLAGS (HCR_RW | HCR_API | HCR_APK | HCR_ATA)
#define HCR_HOST_NVHE_FLAGS (HCR_RW | HCR_API | HCR_APK)
#define HCR_HOST_NVHE_PROTECTED_FLAGS (HCR_HOST_NVHE_FLAGS | HCR_TSC)
#define HCR_HOST_VHE_FLAGS (HCR_RW | HCR_TGE | HCR_E2H | HCR_AMO | HCR_IMO | HCR_FMO)

+1 −1
Original line number Diff line number Diff line
@@ -299,7 +299,7 @@ SYM_INNER_LABEL(init_el2, SYM_L_LOCAL)
	isb
0:

	init_el2_hcr	HCR_HOST_NVHE_FLAGS
	init_el2_hcr	HCR_HOST_NVHE_FLAGS | HCR_ATA
	init_el2_state

	/* Hypervisor stub */
+6 −0
Original line number Diff line number Diff line
@@ -2093,6 +2093,12 @@ static void __init cpu_prepare_hyp_mode(int cpu, u32 hyp_va_bits)
		params->hcr_el2 = HCR_HOST_NVHE_PROTECTED_FLAGS;
	else
		params->hcr_el2 = HCR_HOST_NVHE_FLAGS;

	if (system_supports_mte())
		params->hcr_el2 |= HCR_ATA;
	else
		params->hcr_el2 |= HCR_TID5;

	if (cpus_have_final_cap(ARM64_KVM_HVHE))
		params->hcr_el2 |= HCR_E2H;
	params->vttbr = params->vtcr = 0;
+0 −5
Original line number Diff line number Diff line
@@ -260,11 +260,6 @@ reset:
	msr	sctlr_el2, x5
	isb

alternative_if ARM64_KVM_PROTECTED_MODE
	mov_q	x5, HCR_HOST_NVHE_FLAGS
	msr_hcr_el2 x5
alternative_else_nop_endif

	/* Install stub vectors */
	adr_l	x5, __hyp_stub_vectors
	msr	vbar_el2, x5
+67 −0
Original line number Diff line number Diff line
@@ -690,6 +690,69 @@ static void handle_host_smc(struct kvm_cpu_context *host_ctxt)
	kvm_skip_host_instr();
}

/*
 * Inject an Undefined Instruction exception into the host.
 *
 * This is open-coded to allow control over PSTATE construction without
 * complicating the generic exception entry helpers.
 */
static void inject_undef64(void)
{
	u64 spsr_mask, vbar, sctlr, old_spsr, new_spsr, esr, offset;

	spsr_mask = PSR_N_BIT | PSR_Z_BIT | PSR_C_BIT | PSR_V_BIT | PSR_DIT_BIT | PSR_PAN_BIT;

	vbar = read_sysreg_el1(SYS_VBAR);
	sctlr = read_sysreg_el1(SYS_SCTLR);
	old_spsr = read_sysreg_el2(SYS_SPSR);

	new_spsr = old_spsr & spsr_mask;
	new_spsr |= PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT;
	new_spsr |= PSR_MODE_EL1h;

	if (!(sctlr & SCTLR_EL1_SPAN))
		new_spsr |= PSR_PAN_BIT;

	if (sctlr & SCTLR_ELx_DSSBS)
		new_spsr |= PSR_SSBS_BIT;

	if (system_supports_mte())
		new_spsr |= PSR_TCO_BIT;

	esr = (ESR_ELx_EC_UNKNOWN << ESR_ELx_EC_SHIFT) | ESR_ELx_IL;
	offset = CURRENT_EL_SP_ELx_VECTOR + except_type_sync;

	write_sysreg_el1(esr, SYS_ESR);
	write_sysreg_el1(read_sysreg_el2(SYS_ELR), SYS_ELR);
	write_sysreg_el1(old_spsr, SYS_SPSR);
	write_sysreg_el2(vbar + offset, SYS_ELR);
	write_sysreg_el2(new_spsr, SYS_SPSR);
}

static bool handle_host_mte(u64 esr)
{
	switch (esr_sys64_to_sysreg(esr)) {
	case SYS_RGSR_EL1:
	case SYS_GCR_EL1:
	case SYS_TFSR_EL1:
	case SYS_TFSRE0_EL1:
		/* If we're here for any reason other than MTE, it's a bug. */
		if (read_sysreg(HCR_EL2) & HCR_ATA)
			return false;
		break;
	case SYS_GMID_EL1:
		/* If we're here for any reason other than MTE, it's a bug. */
		if (!(read_sysreg(HCR_EL2) & HCR_TID5))
			return false;
		break;
	default:
		return false;
	}

	inject_undef64();
	return true;
}

void handle_trap(struct kvm_cpu_context *host_ctxt)
{
	u64 esr = read_sysreg_el2(SYS_ESR);
@@ -705,6 +768,10 @@ void handle_trap(struct kvm_cpu_context *host_ctxt)
	case ESR_ELx_EC_DABT_LOW:
		handle_host_mem_abort(host_ctxt);
		break;
	case ESR_ELx_EC_SYS64:
		if (handle_host_mte(esr))
			break;
		fallthrough;
	default:
		BUG();
	}
Loading