[PATCH v3 1/2] aarch64: Lock GCS status at startup
Yury Khrustalev
yury.khrustalev@arm.com
Mon Feb 16 13:26:31 GMT 2026
On Thu, Feb 12, 2026 at 11:36:45AM -0300, Adhemerval Zanella Netto wrote:
>
> On 09/02/26 08:58, Yury Khrustalev wrote:
> > If GCS is enabled (see tunable glibc.cpu.aarch64_gcs), we lock all GCS
> > operations (including status, write on shadow stack, and push to shadow
> > stack) unless OPTIONAL policy is used.
> >
> > ...
> >
> > -
> > +@item
> > @code{aarch64_gcs == 1}: GCS markings will be checked for all binaries loaded
> > -at startup and, only if all binaries are GCS-marked, GCS will be enabled. If
> > -any of the binaries are not GCS-marked, the process will abort. Subsequent call
> > -to @code{dlopen} for an unmarked binary will also result in abort.
> > -
> > +at startup and, only if all binaries are GCS-marked, GCS will be enabled and
> > +all GCS features will be locked. If any of the binaries are not GCS-marked,
> > +the process will abort. Subsequent call to @code{dlopen} for an unmarked binary
> > +will also result in abort.
>
> I think 'abort' is not the correct description for dlopen, it might confusing
> with the previous description of process abort. Maybe state that dlopen will
> not load a module without GCS markings in such case.
Correct. I will fix the wording around dlopen to make it clear that
dlopen returns an error in this case.
> > ...
> >
> > + /* If the aarch64_gcs tunable is either 0 or 2 do not lock GCS. */
> > + tst x22, #-3
> > + beq L(skip_gcs_enable)
> > + mov x0, PR_LOCK_SHADOW_STACK_STATUS
> > + /* Lock everything including future operations. */
> > + mov x1, ~0
> > + mov x2, 0
> > + mov x3, 0
> > + mov x4, 0
> > + mov x8, #SYS_ify(prctl)
> > + svc 0x0
> > + cbnz w0, L(failed_gcs_enable)
> > L(skip_gcs_enable):
> >
> > .globl _dl_start_user
>
> These will issue 2 prctl syscalls, where if locking is required it can just
> issue one with PR_SHADOW_STACK_ENABLE | PR_LOCK_SHADOW_STACK_STATUS.
STACK_ENABLE and STACK_STATUS have different params (passed via x1 reg)
so I'm not sure how one call may work here.
> Also, I think maybe we should make _dl_gcs_enable_failed print the command
> that was issue instead of a generic message for both enablement and locking.
Do you mean saying what exactly failed (enable or lock)? I can do that.
> > diff --git a/sysdeps/unix/sysv/linux/aarch64/libc-start.h b/sysdeps/unix/sysv/linux/aarch64/libc-start.h
> > index 9eecc557fd..24eb5ce967 100644
> >
> > ...
> >
> > +# ifndef GCS_POLICY_DISABLED
> > +/* GCS is disabled. */
> > +# define GCS_POLICY_DISABLED 0
> > +/* Optionally enable GCS if all startup dependencies are marked. */
> > +# define GCS_POLICY_OPTIONAL 2
> > +# endif
> > +
>
> These are define by glibc, instead of importing from kernel. I think
> it should define in a common header instead of redefine them on both
> sysdeps/aarch64/dl-gcs.c and sysdeps/unix/sysv/linux/aarch64/libc-start.h
I don't think it makes much difference since these are internal macros.
What common header would you use? A new one?
Thanks,
Yury
More information about the Libc-alpha
mailing list