Re: [PATCH v10 25/40] arm64/ptrace: Expose GCS via ptrace and core files

Catalin Marinas
2024-08-21T17:57:23Z

On Thu, Aug 01, 2024 at 01:06:52PM +0100, Mark Brown wrote:
> @@ -1440,6 +1441,51 @@ static int tagged_addr_ctrl_set(struct task_struct *target, const struct
> }
> #endif
>
> +#ifdef CONFIG_ARM64_GCS
> +static int gcs_get(struct task_struct *target,
> + const struct user_regset *regset,
> + struct membuf to)
> +{
> + struct user_gcs user_gcs;
> +
> + if (target == current)
> + gcs_preserve_current_state();
> +
> + user_gcs.features_enabled = target->thread.gcs_el0_mode;
> + user_gcs.features_locked = target->thread.gcs_el0_locked;
> + user_gcs.gcspr_el0 = target->thread.gcspr_el0;

If it's not the current thread, I guess the task was interrupted,
scheduled out (potentially on another CPU) and its GCSPR_EL0 saved.

> +
> + return membuf_write(&to, &user_gcs, sizeof(user_gcs));
> +}
> +
> +static int gcs_set(struct task_struct *target, const struct
> + user_regset *regset, unsigned int pos,
> + unsigned int count, const void *kbuf, const
> + void __user *ubuf)
> +{
> + int ret;
> + struct user_gcs user_gcs;
> +
> + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &user_gcs, 0, -1);
> + if (ret)
> + return ret;
> +
> + if (user_gcs.features_enabled & ~PR_SHADOW_STACK_SUPPORTED_STATUS_MASK)
> + return -EINVAL;
> +
> + /* Do not allow enable via ptrace */
> + if ((user_gcs.features_enabled & PR_SHADOW_STACK_ENABLE) &&
> + !(target->thread.gcs_el0_mode & PR_SHADOW_STACK_ENABLE))
> + return -EBUSY;
> +
> + target->thread.gcs_el0_mode = user_gcs.features_enabled;
> + target->thread.gcs_el0_locked = user_gcs.features_locked;
> + target->thread.gcspr_el0 = user_gcs.gcspr_el0;

As in the previous thread, I thought we need to restore GCSPR_EL0
unconditionally.

I don't particularly like that this register becomes some scrap one that
threads can use regardless of GCS. Not sure we have a simple solution.
We could track three states: GCS never enabled, GCS enabled and GCS
disabled after being enabled. It's probably not worth it.

On ptrace() access to the shadow stack, we rely on the barrier in the
context switch code if stopping a thread. If other threads are running
on other CPUs, it's racy anyway even for normal accesses, so I don't
think we need to do anything more for ptrace.

--
Catalin