[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <ZshYTyNbveD7WMyJ@arm.com>
Date: Fri, 23 Aug 2024 10:37:19 +0100
From: Catalin Marinas <catalin.marinas@....com>
To: Mark Brown <broonie@...nel.org>
Cc: Will Deacon <will@...nel.org>, Jonathan Corbet <corbet@....net>,
Andrew Morton <akpm@...ux-foundation.org>,
Marc Zyngier <maz@...nel.org>,
Oliver Upton <oliver.upton@...ux.dev>,
James Morse <james.morse@....com>,
Suzuki K Poulose <suzuki.poulose@....com>,
Arnd Bergmann <arnd@...db.de>, Oleg Nesterov <oleg@...hat.com>,
Eric Biederman <ebiederm@...ssion.com>,
Shuah Khan <shuah@...nel.org>,
"Rick P. Edgecombe" <rick.p.edgecombe@...el.com>,
Deepak Gupta <debug@...osinc.com>, Ard Biesheuvel <ardb@...nel.org>,
Szabolcs Nagy <Szabolcs.Nagy@....com>, Kees Cook <kees@...nel.org>,
"H.J. Lu" <hjl.tools@...il.com>,
Paul Walmsley <paul.walmsley@...ive.com>,
Palmer Dabbelt <palmer@...belt.com>,
Albert Ou <aou@...s.berkeley.edu>,
Florian Weimer <fweimer@...hat.com>,
Christian Brauner <brauner@...nel.org>,
Thiago Jung Bauermann <thiago.bauermann@...aro.org>,
Ross Burton <ross.burton@....com>,
Yury Khrustalev <yury.khrustalev@....com>,
Wilco Dijkstra <wilco.dijkstra@....com>,
linux-arm-kernel@...ts.infradead.org, linux-doc@...r.kernel.org,
kvmarm@...ts.linux.dev, linux-fsdevel@...r.kernel.org,
linux-arch@...r.kernel.org, linux-mm@...ck.org,
linux-kselftest@...r.kernel.org, linux-kernel@...r.kernel.org,
linux-riscv@...ts.infradead.org
Subject: Re: [PATCH v11 25/39] arm64/signal: Expose GCS state in signal frames
On Thu, Aug 22, 2024 at 02:15:28AM +0100, Mark Brown wrote:
> +static int preserve_gcs_context(struct gcs_context __user *ctx)
> +{
> + int err = 0;
> + u64 gcspr;
> +
> + /*
> + * We will add a cap token to the frame, include it in the
> + * GCSPR_EL0 we report to support stack switching via
> + * sigreturn.
> + */
> + gcs_preserve_current_state();
> + gcspr = current->thread.gcspr_el0 - 8;
> +
> + __put_user_error(GCS_MAGIC, &ctx->head.magic, err);
> + __put_user_error(sizeof(*ctx), &ctx->head.size, err);
> + __put_user_error(gcspr, &ctx->gcspr, err);
> + __put_user_error(0, &ctx->reserved, err);
> + __put_user_error(current->thread.gcs_el0_mode,
> + &ctx->features_enabled, err);
> +
> + return err;
> +}
Do we actually need to store the gcspr value after the cap token has
been pushed or just the value of the interrupted context? If we at some
point get a sigaltshadowstack() syscall, the saved GCS wouldn't point to
the new stack but rather the original one. Unwinders should be able to
get the actual GCSPR_EL0 register, no need for the sigcontext to point
to the new shadow stack.
Also in gcs_signal_entry() in the previous patch, we seem to subtract 16
rather than 8.
I admit I haven't checked the past discussions in this area, so maybe
I'm missing something.
> +static int restore_gcs_context(struct user_ctxs *user)
> +{
> + u64 gcspr, enabled;
> + int err = 0;
> +
> + if (user->gcs_size != sizeof(*user->gcs))
> + return -EINVAL;
> +
> + __get_user_error(gcspr, &user->gcs->gcspr, err);
> + __get_user_error(enabled, &user->gcs->features_enabled, err);
> + if (err)
> + return err;
> +
> + /* Don't allow unknown modes */
> + if (enabled & ~PR_SHADOW_STACK_SUPPORTED_STATUS_MASK)
> + return -EINVAL;
> +
> + err = gcs_check_locked(current, enabled);
> + if (err != 0)
> + return err;
> +
> + /* Don't allow enabling */
> + if (!task_gcs_el0_enabled(current) &&
> + (enabled & PR_SHADOW_STACK_ENABLE))
> + return -EINVAL;
> +
> + /* If we are disabling disable everything */
> + if (!(enabled & PR_SHADOW_STACK_ENABLE))
> + enabled = 0;
> +
> + current->thread.gcs_el0_mode = enabled;
> +
> + /*
> + * We let userspace set GCSPR_EL0 to anything here, we will
> + * validate later in gcs_restore_signal().
> + */
> + current->thread.gcspr_el0 = gcspr;
> + write_sysreg_s(current->thread.gcspr_el0, SYS_GCSPR_EL0);
So in preserve_gcs_context(), we subtract 8 from the gcspr_el0 value.
Where is it added back?
What I find confusing is that both restore_gcs_context() and
gcs_restore_signal() seem to touch current->thread.gcspr_el0 and the
sysreg. Which one takes priority? I should probably check the branch out
to see the end result.
> @@ -977,6 +1079,13 @@ static int setup_sigframe_layout(struct rt_sigframe_user_layout *user,
> return err;
> }
>
> + if (add_all || task_gcs_el0_enabled(current)) {
> + err = sigframe_alloc(user, &user->gcs_offset,
> + sizeof(struct gcs_context));
> + if (err)
> + return err;
> + }
I'm still not entirely convinced of this conditional saving and the
interaction with unwinders. In a previous thread you mentioned that we
need to keep the GCSPR_EL0 sysreg value up to date even after disabling
GCS for a thread as not to confuse the unwinders. We could get a signal
delivered together with a sigreturn without any context switch. Do we
lose any state?
It might help if you describe the scenario, maybe even adding a comment
in the code, otherwise I'm sure we'll forget in a few months time.
--
Catalin
Powered by blists - more mailing lists