[PATCH v2 4/4] aarch64: Fix LD_AUDIT with GCS in permissive mode
Yury Khrustalev
yury.khrustalev@arm.com
Thu Jan 8 14:27:34 GMT 2026
On Thu, Jan 08, 2026 at 11:19:35AM -0300, Adhemerval Zanella Netto wrote:
>
> On 08/01/26 09:06, Yury Khrustalev wrote:
> > On Wed, Jan 07, 2026 at 01:52:39PM -0300, Adhemerval Zanella wrote:
> >>
> >> ...
> >>
> >> static bool
> >> -check_gcs (struct link_map *l, const char *program, bool enforced)
> >> +check_gcs (struct link_map *l, const char *program, bool enforced, int mode)
> >> {
> >> #ifdef SHARED
> >> /* Ignore GCS marking on ld.so: its properties are not processed. */
> >> @@ -61,8 +61,10 @@ check_gcs (struct link_map *l, const char *program, bool enforced)
> >> /* Binary is marked, all good. */
> >> if (l->l_mach.gcs)
> >> return true;
> >> - /* Binary is not marked and loaded via dlopen: abort. */
> >> - if (program == NULL)
> >> + /* Binary is not marked and loaded via dlopen: abort. Also, do not
> >> + fail is optional mode is being used with audit modules without
> >> + GCS support. */
> >> + if (program == NULL && (mode & __RTLD_AUDIT) == 0)
> >> fail (l, program);
> >
> > In this case we skip failing when 'program == NULL' (which is identical
> > to "we are inside dlopen()" in this context) when the 'mode' param has
> > the __RTLD_AUDIT bit set. In this case, if we enforce GCS, then the
> > failure will happen at the next step below (as expected).
> >
> > Previously, we always failed in the dlopen() case because we presumed
> > that dlopen() is used only after startup has completed and GCS is
> > already either enabled or not, and if we intended to enforce it, we must
> > prevent dlopen() from opening an unmarked. This assumption was incorrect
> > in the LD_AUDIT use case because in this situation dlopen() is used to
> > load special shared object before all other dependencies. At this point
> > we can honour GCS_POLICY_OPTIONAL if it was selected. The result is that
> > GCS might be disabled if at least one of the shared objects loaded at
> > startup is not GCS-compatible (which includes LD_AUDIT objects).
> >
> > My only concern is that this logic is somewhat fragile. Is it possible
> > to forge the __RTLD_AUDIT in the dlopen() flags and as a result trick
> > dlopen() into loading an unmarked object when GCS is enabled?
>
> Not with current provided dlfcn.h API, where we explicit signal an error for
> invalid/internal flags:
>
> dlfcn/dlopen.c
>
> 46 static void
> 47 dlopen_doit (void *a)
> 48 {
> 49 struct dlopen_args *args = (struct dlopen_args *) a;
> 50
> 51 if (args->mode & ~(RTLD_BINDING_MASK | RTLD_NOLOAD | RTLD_DEEPBIND
> 52 | RTLD_GLOBAL | RTLD_LOCAL | RTLD_NODELETE
> 53 | __RTLD_SPROF))
> 54 _dl_signal_error (0, NULL, NULL, _("invalid mode parameter"));
>
> The __RTLD_AUDIT is only used and supported internally, and audit modules
> are only supposed to be loaded at program statup (either by LD_AUDIT, ld.so
> --audit, or DT_AUDIT/DT_DEPAUDIT).
I see, thanks for clarification, it clears my concern.
Thanks,
Yury
More information about the Libc-alpha
mailing list