Mark Brown <broonie@xxxxxxxxxx> 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