[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