Mark Brown <broo...@kernel.org> writes:

> When a new thread is created by a thread with GCS enabled the GCS needs
> to be specified along with the regular stack.  clone3() has been
> extended to support this case, allowing userspace to explicitly specify
> the size and location of the GCS.  The specified GCS must have a valid
> GCS token at the top of the stack, as though userspace were pivoting to
> the new GCS.  This will be consumed on use.  At present we do not
> atomically consume the token, this will be addressed in a future
> revision.
>
> Unfortunately plain clone() is not extensible and existing clone3()
> users will not specify a stack so all existing code would be broken if
> we mandated specifying the stack explicitly.  For compatibility with
> these cases and also x86 (which did not initially implement clone3()
> support for shadow stacks) if no GCS is specified we will allocate one
> thread so when a thread is created which has GCS enabled allocate one
  ~~~~~~

This "thread" seems extraneous in the sentence. Remove it?

> for it.  We follow the extensively discussed x86 implementation and
> allocate min(RLIMIT_STACK, 4G).  Since the GCS only stores the call

Isn't it min(RLIMIT_STACK/2, 2G), as seen in gcs_size()? If true, this
size should also be fixed in Documentation/arch/arm64/gcs.rst.

> stack and not any variables this should be more than sufficient for most
> applications.
>
> GCSs allocated via this mechanism then it will be freed when the thread
> exits, those explicitly configured by the user will not.

I'm not sure I parsed this sentence correctly. Is it missing an "If" at
the beginning?

> +unsigned long gcs_alloc_thread_stack(struct task_struct *tsk,
> +                                  const struct kernel_clone_args *args)
> +{
> +     unsigned long addr, size, gcspr_el0;
> +
> +     /* If the user specified a GCS use it. */
> +     if (args->shadow_stack_size) {
> +             if (!system_supports_gcs())
> +                     return (unsigned long)ERR_PTR(-EINVAL);
> +
> +             addr = args->shadow_stack;
> +             size = args->shadow_stack_size;
> +
> +             /*
> +              * There should be a token, there might be an end of
> +              * stack marker.
> +              */
> +             gcspr_el0 = addr + size - (2 * sizeof(u64));
> +             if (!gcs_consume_token(tsk, gcspr_el0)) {

Should this code validate the end of stack marker? Or doesn't it matter
whether the marker is correct or not?

> +                     gcspr_el0 += sizeof(u64);
> +                     if (!gcs_consume_token(tsk, gcspr_el0))
> +                             return (unsigned long)ERR_PTR(-EINVAL);
> +             }
> +
> +             /* Userspace is responsible for unmapping */
> +             tsk->thread.gcspr_el0 = gcspr_el0 + sizeof(u64);
> +     } else {

-- 
Thiago

Reply via email to