[PATCH 2/2] aarch64: Accept string values for glibc.cpu.aarch64_gcs tunable
Adhemerval Zanella
adhemerval.zanella@linaro.org
Fri Mar 27 17:44:24 GMT 2026
This patch updates the glibc.cpu.aarch64_gcs tunable to accept
human-readable strings in addition to its standard numerical values.
The tunable now accepts the strings 'disabled', 'enforced', 'optional',
and 'override', mapping them to their corresponding 0, 1, 2, and 3 internal
enum states.
To support custom parsing in architecture-specific code, the
'tunable_parse_num' function is moved to the generic dl-tunables-parse.h
as an inline function.
The '__tunable_print_error' function is exposed globally so that invalid
string inputs caught in the newly added 'aarch64_gcs' callback can trigger
standard tunable warnings.
Checked on aarch64-linux-gnu.
---
elf/dl-tunables.c | 29 +++++++++----------
elf/dl-tunables.h | 3 ++
manual/tunables.texi | 8 ++---
sysdeps/aarch64/dl-tunables.list | 5 +---
sysdeps/generic/dl-tunables-parse.h | 13 +++++++++
.../unix/sysv/linux/aarch64/cpu-features.c | 28 +++++++++++++++++-
6 files changed, 61 insertions(+), 25 deletions(-)
diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c
index bdb1de4ceb..7fd6894ec9 100644
--- a/elf/dl-tunables.c
+++ b/elf/dl-tunables.c
@@ -36,6 +36,7 @@
#define TUNABLES_INTERNAL 1
#include "dl-tunables.h"
+#include <dl-tunables-parse.h>
static char **
get_next_env (char **envp, char **name, char **val, char ***prev_envp)
@@ -119,17 +120,6 @@ do_tunable_update_val (tunable_t *cur, const tunable_val_t *valp,
cur->initialized = true;
}
-static bool
-tunable_parse_num (const char *strval, size_t len, tunable_num_t *val)
-{
- char *endptr = NULL;
- uint64_t numval = _dl_strtoul (strval, &endptr);
- if (endptr != strval + len)
- return false;
- *val = (tunable_num_t) numval;
- return true;
-}
-
/* Validate range of the input value and initialize the tunable CUR if it looks
good. */
static bool
@@ -239,14 +229,21 @@ parse_tunables_string (const char *valstring, struct tunable_toset_t *tunables)
return ntunables;
}
-static void
-parse_tunable_print_error (const struct tunable_toset_t *toset)
+
+void
+__tunable_print_error (const char *value, size_t len, const char *name)
{
_dl_error_printf ("WARNING: ld.so: invalid GLIBC_TUNABLES value `%.*s' "
"for option `%s': ignored.\n",
- (int) toset->len,
- toset->value,
- toset->t->name);
+ (int) len,
+ value,
+ name);
+}
+
+static inline void
+parse_tunable_print_error (const struct tunable_toset_t *toset)
+{
+ __tunable_print_error (toset->value, toset->len, toset->t->name);
}
static void
diff --git a/elf/dl-tunables.h b/elf/dl-tunables.h
index 45aeed47bc..9a1d12922e 100644
--- a/elf/dl-tunables.h
+++ b/elf/dl-tunables.h
@@ -61,6 +61,9 @@ rtld_hidden_proto (__tunable_get_val)
rtld_hidden_proto (__tunable_set_val)
rtld_hidden_proto (__tunable_get_default)
+extern void __tunable_print_error (const char *, size_t, const char *)
+ attribute_hidden;
+
/* Define TUNABLE_GET and TUNABLE_SET in short form if TOP_NAMESPACE and
TUNABLE_NAMESPACE are defined. This is useful shorthand to get and set
tunables within a module. */
diff --git a/manual/tunables.texi b/manual/tunables.texi
index 72769428e8..b8befde341 100644
--- a/manual/tunables.texi
+++ b/manual/tunables.texi
@@ -605,12 +605,12 @@ This tunable controls Guarded Control Stack (GCS) for the process.
Accepted values are:
@itemize @bullet
-@item @code{0} = disabled: do not enable GCS.
-@item @code{1} = enforced: check markings and abort if any binary is not
+@item @code{0} or @code{disabled}: do not enable GCS.
+@item @code{1} or @code{enforced}: check markings and abort if any binary is not
marked, otherwise enable GCS and lock all GCS features.
-@item @code{2} = optional: check markings but keep GCS off if any binary
+@item @code{2} or @code{optional}: check markings but keep GCS off if any binary
is unmarked, otherwise enable GCS but do not lock any GCS features.
-@item @code{3} = override: enable GCS and lock all GCS features, markings
+@item @code{3} or @code{override}: enable GCS and lock all GCS features, markings
are ignored.
@end itemize
diff --git a/sysdeps/aarch64/dl-tunables.list b/sysdeps/aarch64/dl-tunables.list
index a2ccba0b29..302cbac437 100644
--- a/sysdeps/aarch64/dl-tunables.list
+++ b/sysdeps/aarch64/dl-tunables.list
@@ -28,10 +28,7 @@ glibc {
default: 0
}
aarch64_gcs {
- type: UINT_64
- minval: 0
- maxval: 3
- default: 0
+ type: STRING
}
}
}
diff --git a/sysdeps/generic/dl-tunables-parse.h b/sysdeps/generic/dl-tunables-parse.h
index 8ac49bff0b..f021036bbd 100644
--- a/sysdeps/generic/dl-tunables-parse.h
+++ b/sysdeps/generic/dl-tunables-parse.h
@@ -131,4 +131,17 @@ tunable_str_comma_strcmp (const struct tunable_str_comma_t *t, const char *str,
#define tunable_str_comma_strcmp_cte(__t, __str) \
tunable_str_comma_strcmp (__t, __str, sizeof (__str) - 1)
+static inline bool
+tunable_parse_num (const char *strval, size_t len, tunable_num_t *val)
+{
+ char *endptr = NULL;
+ uint64_t numval = _dl_strtoul (strval, &endptr);
+ if (endptr != strval + len)
+ return false;
+ *val = (tunable_num_t) numval;
+ return true;
+}
+#define tunable_parse_num_tun(__tunable, __ret) \
+ tunable_parse_num (__tunable->strval.str, __tunable->strval.len, __ret)
+
#endif
diff --git a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
index 1e4f8a86b1..fe634cbded 100644
--- a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
+++ b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
@@ -65,6 +65,31 @@ get_midr_from_mcpu (const struct tunable_str_t *mcpu)
return UINT64_MAX;
}
+static void
+TUNABLE_CALLBACK (aarch64_gcs) (tunable_val_t *valp)
+{
+ tunable_num_t val;
+ if (tunable_parse_num_tun (valp, &val))
+ {
+ if (tunable_val_lt (val, AARCH64_GCS_POLICY_DISABLED, true))
+ val = AARCH64_GCS_POLICY_DISABLED;
+ if (tunable_val_gt (val, AARCH64_GCS_POLICY_OVERRIDE, true))
+ val = AARCH64_GCS_POLICY_OVERRIDE;
+ GL(dl_aarch64_gcs) = val;
+ }
+ else if (tunable_strcmp_cte (valp, "disabled"))
+ GL(dl_aarch64_gcs) = AARCH64_GCS_POLICY_DISABLED;
+ else if (tunable_strcmp_cte (valp, "enforced"))
+ GL(dl_aarch64_gcs) = AARCH64_GCS_POLICY_ENFORCED;
+ else if (tunable_strcmp_cte (valp, "optional"))
+ GL(dl_aarch64_gcs) = AARCH64_GCS_POLICY_OPTIONAL;
+ else if (tunable_strcmp_cte (valp, "override"))
+ GL(dl_aarch64_gcs) = AARCH64_GCS_POLICY_OVERRIDE;
+ else
+ __tunable_print_error (valp->strval.str, valp->strval.len,
+ "glibc.cpu.aarch64_gcs");
+}
+
static inline void
init_cpu_features (struct cpu_features *cpu_features)
{
@@ -136,5 +161,6 @@ init_cpu_features (struct cpu_features *cpu_features)
if (GLRO (dl_hwcap) & HWCAP_GCS)
/* GCS status may be updated later by binary compatibility checks. */
- GL (dl_aarch64_gcs) = TUNABLE_GET (glibc, cpu, aarch64_gcs, uint64_t, 0);
+ TUNABLE_GET (glibc, cpu, aarch64_gcs, tunable_val_t *,
+ TUNABLE_CALLBACK (aarch64_gcs));
}
--
2.43.0
More information about the Libc-alpha
mailing list