public inbox for linux-arm-kernel@lists.infradead.org
 help / color / mirror / Atom feed
From: Mark Rutland <mark.rutland@arm.com>
To: Will Deacon <will@kernel.org>
Cc: linux-arm-kernel@lists.infradead.org, broonie@kernel.org,
	catalin.marinas@arm.com, daniel.kiss@arm.com,
	david.spickett@arm.com, luis.machado@arm.com, maz@kernel.org,
	richard.sandiford@arm.com, sander.desmalen@arm.com,
	tabba@google.com, tamas.petz@arm.com, tkjos@google.com,
	yury.khrustalev@arm.com
Subject: Re: [PATCH 15/20] arm64/fpsimd: ptrace/prctl: Ensure VL changes leave task in a valid state
Date: Wed, 7 May 2025 18:10:07 +0100	[thread overview]
Message-ID: <aBuT7yS1CYsqOJNM@J2N7QTR9R3> (raw)
In-Reply-To: <20250507161246.GB2580@willie-the-truck>

On Wed, May 07, 2025 at 05:12:47PM +0100, Will Deacon wrote:
> On Tue, May 06, 2025 at 04:25:18PM +0100, Mark Rutland wrote:
> > Currently, vec_set_vector_length() can manipulate a task into an invalid
> > state as a result of a prctl/ptrace syscall which changes the SVE/SME
> > vector length, resulting in several problems:
> > 
> > (1) When changing the SVE vector length, if the task initially has
> >     PSTATE.ZA==1, and sve_alloc() fails to allocate memory, the task
> >     will be left with PSTATE.ZA==1 and sve_state==NULL. This is not a
> >     legitimate state, and could result in a subsequent null pointer
> >     dereference.
> > 
> > (2) When changing the SVE vector length, if the task initially has
> >     PSTATE.SM==1, the task will be left with PSTATE.SM==1 and
> >     fp_type==FP_STATE_FPSIMD. Streaming mode state always needs to be
> >     saved in SVE format, so this is not a legitimate state.
> > 
> >     Attempting to restore this state may cause a task to erroneously
> >     inherit stale streaming mode predicate registers and FFR contents,
> >     behaving non-deterministically and potentially leaving information
> >     from another task.
> > 
> >     While in this state, reads of the NT_ARM_SSVE regset will indicate
> >     that the registers are not stored in SVE format. For the NT_ARM_SSVE
> >     regset specifically, debuggers interpret this as meaning that
> >     PSTATE.SM==0.
> > 
> > (3) When changing the SME vector length, if the task initially has
> >     PSTATE.SM==1, the lower 128 bits of task's streaming mode vector
> >     state will be migrated to non-streaming mode, rather than these bits
> >     being zeroed as is usually the case for changes to PSTATE.SM.
> > 
> > To fix the first issue, we can eagerly allocate the new sve_state and
> > sme_state before modifying the task. This makes it possible to handle
> > memory allocation failure without modifying the task state at all, and
> > removes the need to clear TIF_SVE and TIF_SME.
> > 
> > To fix the second issue, we either need to clear PSTATE.SM or not change
> > the saved fp_type. Given we're going to eagerly allocate sve_state and
> > sme_state, the simplest option is to preserve PSTATE.SM and the saves
> > fp_type, and consistently truncate the SVE state. This ensures that the
> > task always stays in a valid state.
> > 
> > I believe these changes should not be problematic for realistic usage:
> > 
> > * When the SVE/SME vector length is changed via prctl(), syscall entry
> >   will have cleared PSTATE.SM. Unless the task's state has been
> >   manipulated via ptrace after entry, the task will have PSTATE.SM==0.
> > 
> > * When the SVE/SME vector length is changed via a write to the
> >   NT_ARM_SVE or NT_ARM_SSVE regsets, PSTATE.SM will be forced
> >   immediately after the length change, and new vector state will be
> >   copied from userspace.
> > 
> > * When the SME vector length is changed via a write to the NT_ARM_ZA
> >   regset, the (S)SVE state is clobbered today, so anyone who cares about
> >   the specific state would need to install this after writing to the
> >   NT_ARM_ZA regset.

[...]

> > +static int change_live_vector_length(struct task_struct *task,
> > +				     enum vec_type type,
> > +				     unsigned long vl)
> > +{
> > +	unsigned int sve_vl = task_get_sve_vl(task);
> > +	unsigned int sme_vl = task_get_sme_vl(task);
> > +	void *sve_state = NULL, *sme_state = NULL;
> > +
> > +	if (type == ARM64_VEC_SME)
> > +		sme_vl = vl;
> > +	else
> > +		sve_vl = vl;
> > +
> > +	/*
> > +	 * Allocate the new sve_state and sme_state before freeing the old
> > +	 * copies so that allocation failure can be handled without needing to
> > +	 * mutate the task's state in any way.
> > +	 *
> > +	 * Changes to the SVE vector length must not discard live ZA state or
> > +	 * clear PSTATE.ZA, as userspace code which is unaware of the AAPCS64
> > +	 * ZA lazy saving scheme may attempt to change the SVE vector length
> > +	 * while unsaved/dormant ZA state exists.
> > +	 */
> > +	sve_state = kzalloc(__sve_state_size(sve_vl, sme_vl), GFP_KERNEL);
> > +	if (!sve_state)
> > +		goto out_mem;
> > +
> > +	if (type == ARM64_VEC_SME) {
> > +		sme_state = kzalloc(__sme_state_size(sme_vl), GFP_KERNEL);
> > +		if (!sve_state)
> 
> This should be '!sme_state'.

Ugh, yes. Fixed now, thanks.

[...]

> > +	/*
> > +	 * Always preserve PSTATE.SM and the effective FPSIMD state, zeroing
> > +	 * other SVE state.
> > +	 */
> > +	fpsimd_sync_from_effective_state(task);
> > +	task_set_vl(task, type, vl);
> > +	kfree(task->thread.sve_state);
> > +	task->thread.sve_state = sve_state;
> > +	fpsimd_sync_to_effective_state_zeropad(task);
> > +
> > +	if (type == ARM64_VEC_SME) {
> > +		task->thread.svcr &= ~SVCR_ZA_MASK;
> > +		kfree(task->thread.sme_state);
> > +		task->thread.sme_state = sme_state;
> > +	}
> 
> I'm probably just missing something here, but how does this address
> problem three from the commit message where exiting streaming mode
> should zero the bottom bits of the vector registers?

The idea is that we no longer exit streaming mode, so we don't need to zero the
bottom bits.

Instead, when either the SVE or SME vector length changes, we
consitently truncate the (streaming or non-streaming) SVE registers to
128-bits, but preserve the existing value of PSTATE.SM and the saved
fp_type.

That all happens in:

	fpsimd_sync_from_effective_state(task);
	task_set_vl(task, type, vl);
	kfree(task->thread.sve_state);
	task->thread.sve_state = sve_state;
	fpsimd_sync_to_effective_state_zeropad(task);

... where:

* If the task's state was initially stored in FPSIMD format, the
  fpsimd_sync_from_effective_state() and
  fpsimd_sync_to_effective_state_zeropad() functions do not touch the
  saved FPSIMD state, leaving the low 128 bits intact.

* If the task's state was initially stored in SVE format, whether
  streaming or non-streaming, the fpsimd_sync_from_effective_state() and
  fpsimd_sync_to_effective_state_zeropad() functions copy the low 128
  bits into the FPSIMD storage, then copy that back into the new zeroed
  SVE storage.

That's what I was trying to describe in the commit message where I said:

| To fix the second issue, we either need to clear PSTATE.SM or not change
| the saved fp_type. Given we're going to eagerly allocate sve_state and
| sme_state, the simplest option is to preserve PSTATE.SM and the saves
| fp_type, and consistently truncate the SVE state. This ensures that the
| task always stays in a valid state.

... but I appreciate that mentioned the second issue and not the third.

I can add a note there, if it'd help?

Mark.


  reply	other threads:[~2025-05-07 17:38 UTC|newest]

Thread overview: 44+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-05-06 15:25 [PATCH 00/20] arm64: FPSIMD/SVE/SME fixes + re-eanble SME Mark Rutland
2025-05-06 15:25 ` [PATCH 01/20] kselftest/arm64: fp-ptrace: Fix expected FPMR value when PSTATE.SM is changed Mark Rutland
2025-05-06 15:25 ` [PATCH 02/20] arm64/fpsimd: Do not discard modified SVE state Mark Rutland
2025-05-06 15:25 ` [PATCH 03/20] arm64/fpsimd: signal: Clear PSTATE.SM when restoring FPSIMD frame only Mark Rutland
2025-05-07 12:46   ` Will Deacon
2025-05-07 14:01     ` Mark Rutland
2025-05-07 14:39       ` Will Deacon
2025-05-06 15:25 ` [PATCH 04/20] arm64/fpsimd: signal: Mandate SVE payload for streaming-mode state Mark Rutland
2025-05-07  0:59   ` Mark Brown
2025-05-07 12:59   ` Will Deacon
2025-05-07 14:21     ` Mark Rutland
2025-05-07 14:29       ` Will Deacon
2025-05-07 15:02         ` Mark Rutland
2025-05-07 16:14           ` Will Deacon
2025-05-06 15:25 ` [PATCH 05/20] arm64/fpsimd: ptrace: Consistently handle partial writes to NT_ARM_(S)SVE Mark Rutland
2025-05-06 15:25 ` [PATCH 06/20] arm64/fpsimd: Clarify sve_sync_*() functions Mark Rutland
2025-05-06 15:25 ` [PATCH 07/20] arm64/fpsimd: Factor out {sve,sme}_state_size() helpers Mark Rutland
2025-05-06 15:25 ` [PATCH 08/20] arm64/fpsimd: Add task_smstop_sm() Mark Rutland
2025-05-06 15:25 ` [PATCH 09/20] arm64/fpsimd: signal: Use SMSTOP behaviour in setup_return() Mark Rutland
2025-05-06 15:25 ` [PATCH 10/20] arm64/fpsimd: Remove redundant task->mm check Mark Rutland
2025-05-06 15:25 ` [PATCH 11/20] arm64/fpsimd: Consistently preserve FPSIMD state during clone() Mark Rutland
2025-05-06 15:25 ` [PATCH 12/20] arm64/fpsimd: Clear PSTATE.SM " Mark Rutland
2025-05-06 15:25 ` [PATCH 13/20] arm64/fpsimd: Make clone() compatible with ZA lazy saving Mark Rutland
2025-05-07 14:58   ` Will Deacon
2025-05-07 15:22     ` Mark Rutland
2025-05-07 16:11       ` Will Deacon
2025-05-07 17:21         ` Mark Rutland
2025-05-07 15:57   ` Yury Khrustalev
2025-05-06 15:25 ` [PATCH 14/20] arm64/fpsimd: ptrace/prctl: Ensure VL changes do not resurrect stale data Mark Rutland
2025-05-06 15:25 ` [PATCH 15/20] arm64/fpsimd: ptrace/prctl: Ensure VL changes leave task in a valid state Mark Rutland
2025-05-07 16:12   ` Will Deacon
2025-05-07 17:10     ` Mark Rutland [this message]
2025-05-08 10:31       ` Will Deacon
2025-05-06 15:25 ` [PATCH 16/20] arm64/fpsimd: ptrace: Save task state before generating SVE header Mark Rutland
2025-05-06 15:25 ` [PATCH 17/20] arm64/fpsimd: ptrace: Do not present register data for inactive mode Mark Rutland
2025-05-06 15:25 ` [PATCH 18/20] arm64/fpsimd: ptrace: Mandate SVE payload for streaming-mode state Mark Rutland
2025-05-07  1:09   ` Mark Brown
2025-05-06 15:25 ` [PATCH 19/20] arm64/fpsimd: ptrace: Gracefully handle errors Mark Rutland
2025-05-07 16:32   ` Will Deacon
2025-05-08 12:12     ` Mark Rutland
2025-05-06 15:25 ` [PATCH 20/20] arm64/fpsimd: Allow CONFIG_ARM64_SME to be selected Mark Rutland
2025-05-07  1:48 ` [PATCH 00/20] arm64: FPSIMD/SVE/SME fixes + re-eanble SME Mark Brown
2025-05-07  9:56   ` Mark Rutland
2025-05-07 11:26     ` Mark Brown

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=aBuT7yS1CYsqOJNM@J2N7QTR9R3 \
    --to=mark.rutland@arm.com \
    --cc=broonie@kernel.org \
    --cc=catalin.marinas@arm.com \
    --cc=daniel.kiss@arm.com \
    --cc=david.spickett@arm.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=luis.machado@arm.com \
    --cc=maz@kernel.org \
    --cc=richard.sandiford@arm.com \
    --cc=sander.desmalen@arm.com \
    --cc=tabba@google.com \
    --cc=tamas.petz@arm.com \
    --cc=tkjos@google.com \
    --cc=will@kernel.org \
    --cc=yury.khrustalev@arm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox