[v2,1/1] Add system-wide tunables: implement overridability
Checks
| Context |
Check |
Description |
| redhat-pt-bot/TryBot-apply_patch |
success
|
Patch applied to master at the time it was sent
|
| redhat-pt-bot/TryBot-32bit |
success
|
Build for i686
|
| linaro-tcwg-bot/tcwg_glibc_build--master-arm |
success
|
Build passed
|
| linaro-tcwg-bot/tcwg_glibc_build--master-aarch64 |
success
|
Build passed
|
| linaro-tcwg-bot/tcwg_glibc_check--master-aarch64 |
success
|
Test passed
|
Commit Message
Andreas Schwab <schwab@suse.de> writes:
> That proves to be pretty fragile.
How about this?
Add system-wide tunables: implement overridability
Implement the overridability/nonoverridability flags
for tunables.
Comments
On Jul 02 2026, DJ Delorie wrote:
> diff --git a/elf/tunconf.c b/elf/tunconf.c
> index a5ca755abd..c27b50b1de 100644
> --- a/elf/tunconf.c
> +++ b/elf/tunconf.c
> @@ -194,34 +194,40 @@ add_tunable (char *line, const char *filename, int lineno)
> /* Parse modifiers. */
> while (*line)
> {
> - if (strncmp (line, "overridable ", 13) == 0)
> + int prefix_len;
> +
> +#define TUN_PREFIX(s) \
> + prefix_len = sizeof(s) - 1, \
> + strncmp (line, s " ", prefix_len + 1) == 0
> +
> + if (TUN_PREFIX("overridable"))
> {
> top = TOP_ALLOW;
> /* The line++ below skips the space. */
> - line += 12;
> + line += prefix_len;
> }
> - else if (strncmp (line, "nonoverridable ", 16) == 0)
> + else if (TUN_PREFIX ("nonoverridable"))
> {
> top = TOP_DENY;
> - line += 15;
> + line += prefix_len;
> }
> - else if (strncmp (line, "onlysecure ", 11) == 0)
> + else if (TUN_PREFIX ("onlysecure"))
> {
> exclude_nonsecure = 1;
> exclude_secure = 0;
> - line += 10;
> + line += prefix_len;
> }
> - else if (strncmp (line, "nonsecure ", 10) == 0)
> + else if (TUN_PREFIX ("nonsecure"))
> {
> exclude_secure = 1;
> exclude_nonsecure = 0;
> - line += 9;
> + line += prefix_len;
> }
> - else if (strncmp (line, "anysecure ", 10) == 0)
> + else if (TUN_PREFIX ("anysecure"))
> {
> exclude_secure = 0;
> exclude_nonsecure = 0;
> - line += 9;
> + line += prefix_len;
> }
> else switch (*line)
> {
This looks good.
On 02/07/26 12:19, DJ Delorie wrote:
>
> Andreas Schwab <schwab@suse.de> writes:
>> That proves to be pretty fragile.
>
> How about this?
>
> Add system-wide tunables: implement overridability
>
> Implement the overridability/nonoverridability flags
> for tunables.
>
> diff --git a/elf/Makefile b/elf/Makefile
> index 789c504da9..7b00a0b931 100644
> --- a/elf/Makefile
> +++ b/elf/Makefile
> @@ -347,7 +347,11 @@ tests-static += \
> tst-tls9-static \
> # tests-static
>
> -tst-tunconf1-TUNABLES-only = glibc.malloc.tcache_count=5
> +tst-tunconf1-TUNABLES-only = \
> + glibc.malloc.tcache_count=5 \
> + :glibc.malloc.perturb=41 \
> + :glibc.malloc.mmap_threshold=10002 \
> + :glibc.malloc.trim_threshold=10002
No need to add ':' for each tunable, the TUNABLES rule already handles it.
The rest looks ok.
>
> static-dlopen-environment = \
> LD_LIBRARY_PATH=$(ld-library-path):$(common-objpfx)dlfcn
> diff --git a/elf/dl-tunable-types.h b/elf/dl-tunable-types.h
> index f421c01c26..3506eee512 100644
> --- a/elf/dl-tunable-types.h
> +++ b/elf/dl-tunable-types.h
> @@ -65,6 +65,8 @@ struct _tunable
> tunable_val_t val; /* The value. */
> bool initialized; /* Flag to indicate that the tunable is
> initialized. */
> + bool locked; /* If set, modifications are not
> + allowed. */
> /* Compatibility elements. */
> const char env_alias[TUNABLE_ALIAS_MAX]; /* The compatibility environment
> variable name. */
> diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c
> index 197d940d38..d19c2358c1 100644
> --- a/elf/dl-tunables.c
> +++ b/elf/dl-tunables.c
> @@ -72,6 +72,9 @@ do_tunable_update_val (tunable_t *cur, const tunable_val_t *valp,
> {
> tunable_num_t val, min, max;
>
> + if (cur->locked)
> + return;
> +
> switch (cur->type.type_code)
> {
> case TUNABLE_TYPE_STRING:
> @@ -409,6 +412,12 @@ __tunables_init (char **envp, char **argv)
> goto skip_due_to_filter;
> }
>
> + /* If the tunable is set here, any previously set
> + overridability flag is discarded. We need to reset the
> + overridability flag here so we can change the tunable,
> + and may set it later if this tunable also locks it. */
> + tunable_list[tid].locked = false;
> +
> /* See if the parsed type matches the desired type. */
> if (tunable_list[tid].type.type_code == TUNABLE_TYPE_STRING)
> {
> @@ -435,6 +444,12 @@ __tunables_init (char **envp, char **argv)
> }
> }
>
> + /* The overriability flag only applies to tunables
> + which aren't filtered out. */
> + if ((tec->flags & TUNCONF_FLAG_OVERRIDABLE)
> + == TUNCONF_OVERRIDE_DENY)
> + tunable_list[tid].locked = true;
> +
> skip_due_to_filter:;
> }
> }
> diff --git a/elf/tst-tunconf1.c b/elf/tst-tunconf1.c
> index c95a7cb8ba..74f596d913 100644
> --- a/elf/tst-tunconf1.c
> +++ b/elf/tst-tunconf1.c
> @@ -26,10 +26,30 @@ do_test (void)
> {
> size_t tcache_count = TUNABLE_GET_FULL (glibc, malloc, tcache_count, size_t, NULL);
> size_t tcache_max = TUNABLE_GET_FULL (glibc, malloc, tcache_max, size_t, NULL);
> + size_t perturb = TUNABLE_GET_FULL (glibc, malloc, perturb, size_t, NULL);
> + size_t mmap_threshold = TUNABLE_GET_FULL (glibc, malloc, mmap_threshold, size_t, NULL);
> + size_t trim_threshold = TUNABLE_GET_FULL (glibc, malloc, trim_threshold, size_t, NULL);
> +
> printf("tcache count is %ld (should be 5, from env)\n", (long)tcache_count);
> TEST_COMPARE ((long)tcache_count, 5);
> printf("tcache max is %ld (should be 4, from /etc)\n", (long)tcache_max);
> TEST_COMPARE ((long)tcache_max, 4);
> +
> + /* This is set by the environment but blocked by the config. */
> + printf("perturb is %ld (should be 42, from /etc)\n",
> + (long)perturb);
> + TEST_COMPARE ((long)perturb, 42);
> +
> + /* This is blocked by the general config, enabled by filter, set in env. */
> + printf("mmap_threshold is %ld (should be 10002, from env)\n",
> + (long)mmap_threshold);
> + TEST_COMPARE ((long)mmap_threshold, 10002);
> +
> + /* This is allowed by the general config, blocked by filter, set in env. */
> + printf("trim_threshold is %ld (should be 10001, from filter)\n",
> + (long)trim_threshold);
> + TEST_COMPARE ((long)trim_threshold, 10001);
> +
> return 0;
> }
>
> diff --git a/elf/tst-tunconf1.root/etc/tunables.conf b/elf/tst-tunconf1.root/etc/tunables.conf
> index f373a67902..f708a8fce4 100644
> --- a/elf/tst-tunconf1.root/etc/tunables.conf
> +++ b/elf/tst-tunconf1.root/etc/tunables.conf
> @@ -8,7 +8,15 @@ $glibc.test_unsecure=1
> # These are checked inside the test case
> glibc.malloc.tcache_max=6
> $glibc.malloc.tcache_count=3
> +
> +-glibc.malloc.perturb=42
> +-glibc.malloc.mmap_threshold=10000
> +overridable glibc.malloc.trim_threshold=10000
> +
> [proc:/bin/ls]
> glibc.malloc.tcache_max=7
> +
> [proc:tst-tunconf1]
> glibc.malloc.tcache_max=4
> ++glibc.malloc.mmap_threshold=10001
> +nonoverridable glibc.malloc.trim_threshold=10001
> diff --git a/elf/tunconf.c b/elf/tunconf.c
> index a5ca755abd..c27b50b1de 100644
> --- a/elf/tunconf.c
> +++ b/elf/tunconf.c
> @@ -194,34 +194,40 @@ add_tunable (char *line, const char *filename, int lineno)
> /* Parse modifiers. */
> while (*line)
> {
> - if (strncmp (line, "overridable ", 13) == 0)
> + int prefix_len;
> +
> +#define TUN_PREFIX(s) \
> + prefix_len = sizeof(s) - 1, \
> + strncmp (line, s " ", prefix_len + 1) == 0
> +
> + if (TUN_PREFIX("overridable"))
> {
> top = TOP_ALLOW;
> /* The line++ below skips the space. */
> - line += 12;
> + line += prefix_len;
> }
> - else if (strncmp (line, "nonoverridable ", 16) == 0)
> + else if (TUN_PREFIX ("nonoverridable"))
> {
> top = TOP_DENY;
> - line += 15;
> + line += prefix_len;
> }
> - else if (strncmp (line, "onlysecure ", 11) == 0)
> + else if (TUN_PREFIX ("onlysecure"))
> {
> exclude_nonsecure = 1;
> exclude_secure = 0;
> - line += 10;
> + line += prefix_len;
> }
> - else if (strncmp (line, "nonsecure ", 10) == 0)
> + else if (TUN_PREFIX ("nonsecure"))
> {
> exclude_secure = 1;
> exclude_nonsecure = 0;
> - line += 9;
> + line += prefix_len;
> }
> - else if (strncmp (line, "anysecure ", 10) == 0)
> + else if (TUN_PREFIX ("anysecure"))
> {
> exclude_secure = 0;
> exclude_nonsecure = 0;
> - line += 9;
> + line += prefix_len;
> }
> else switch (*line)
> {
> diff --git a/scripts/gen-tunables.awk b/scripts/gen-tunables.awk
> index 5d34075c16..7c832303db 100644
> --- a/scripts/gen-tunables.awk
> +++ b/scripts/gen-tunables.awk
> @@ -169,7 +169,7 @@ END {
> n = indices[2];
> m = indices[3];
> printf (" {TUNABLE_NAME_S(%s, %s, %s)", t, n, m)
> - printf (", {TUNABLE_TYPE_%s, %s, %s}, {%s}, {%s}, false, %s},\n",
> + printf (", {TUNABLE_TYPE_%s, %s, %s}, {%s}, {%s}, false, false, %s},\n",
> types[t,n,m], minvals[t,n,m], maxvals[t,n,m], default_val[t,n,m],
> default_val[t,n,m], env_alias[t,n,m]);
> }
>
Adhemerval Zanella Netto <adhemerval.zanella@linaro.org> writes:
> No need to add ':' for each tunable, the TUNABLES rule already handles it.
Removed. I didn't know it did that...
> The rest looks ok.
Is this a reviewed-by or just commentary?
On 07/07/26 00:27, DJ Delorie wrote:
> Adhemerval Zanella Netto <adhemerval.zanella@linaro.org> writes:
>> No need to add ':' for each tunable, the TUNABLES rule already handles it.
>
> Removed. I didn't know it did that...
>
>> The rest looks ok.
>
> Is this a reviewed-by or just commentary?
>
It is R-B, sorry for missing it:
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
@@ -347,7 +347,11 @@ tests-static += \
tst-tls9-static \
# tests-static
-tst-tunconf1-TUNABLES-only = glibc.malloc.tcache_count=5
+tst-tunconf1-TUNABLES-only = \
+ glibc.malloc.tcache_count=5 \
+ :glibc.malloc.perturb=41 \
+ :glibc.malloc.mmap_threshold=10002 \
+ :glibc.malloc.trim_threshold=10002
static-dlopen-environment = \
LD_LIBRARY_PATH=$(ld-library-path):$(common-objpfx)dlfcn
@@ -65,6 +65,8 @@ struct _tunable
tunable_val_t val; /* The value. */
bool initialized; /* Flag to indicate that the tunable is
initialized. */
+ bool locked; /* If set, modifications are not
+ allowed. */
/* Compatibility elements. */
const char env_alias[TUNABLE_ALIAS_MAX]; /* The compatibility environment
variable name. */
@@ -72,6 +72,9 @@ do_tunable_update_val (tunable_t *cur, const tunable_val_t *valp,
{
tunable_num_t val, min, max;
+ if (cur->locked)
+ return;
+
switch (cur->type.type_code)
{
case TUNABLE_TYPE_STRING:
@@ -409,6 +412,12 @@ __tunables_init (char **envp, char **argv)
goto skip_due_to_filter;
}
+ /* If the tunable is set here, any previously set
+ overridability flag is discarded. We need to reset the
+ overridability flag here so we can change the tunable,
+ and may set it later if this tunable also locks it. */
+ tunable_list[tid].locked = false;
+
/* See if the parsed type matches the desired type. */
if (tunable_list[tid].type.type_code == TUNABLE_TYPE_STRING)
{
@@ -435,6 +444,12 @@ __tunables_init (char **envp, char **argv)
}
}
+ /* The overriability flag only applies to tunables
+ which aren't filtered out. */
+ if ((tec->flags & TUNCONF_FLAG_OVERRIDABLE)
+ == TUNCONF_OVERRIDE_DENY)
+ tunable_list[tid].locked = true;
+
skip_due_to_filter:;
}
}
@@ -26,10 +26,30 @@ do_test (void)
{
size_t tcache_count = TUNABLE_GET_FULL (glibc, malloc, tcache_count, size_t, NULL);
size_t tcache_max = TUNABLE_GET_FULL (glibc, malloc, tcache_max, size_t, NULL);
+ size_t perturb = TUNABLE_GET_FULL (glibc, malloc, perturb, size_t, NULL);
+ size_t mmap_threshold = TUNABLE_GET_FULL (glibc, malloc, mmap_threshold, size_t, NULL);
+ size_t trim_threshold = TUNABLE_GET_FULL (glibc, malloc, trim_threshold, size_t, NULL);
+
printf("tcache count is %ld (should be 5, from env)\n", (long)tcache_count);
TEST_COMPARE ((long)tcache_count, 5);
printf("tcache max is %ld (should be 4, from /etc)\n", (long)tcache_max);
TEST_COMPARE ((long)tcache_max, 4);
+
+ /* This is set by the environment but blocked by the config. */
+ printf("perturb is %ld (should be 42, from /etc)\n",
+ (long)perturb);
+ TEST_COMPARE ((long)perturb, 42);
+
+ /* This is blocked by the general config, enabled by filter, set in env. */
+ printf("mmap_threshold is %ld (should be 10002, from env)\n",
+ (long)mmap_threshold);
+ TEST_COMPARE ((long)mmap_threshold, 10002);
+
+ /* This is allowed by the general config, blocked by filter, set in env. */
+ printf("trim_threshold is %ld (should be 10001, from filter)\n",
+ (long)trim_threshold);
+ TEST_COMPARE ((long)trim_threshold, 10001);
+
return 0;
}
@@ -8,7 +8,15 @@ $glibc.test_unsecure=1
# These are checked inside the test case
glibc.malloc.tcache_max=6
$glibc.malloc.tcache_count=3
+
+-glibc.malloc.perturb=42
+-glibc.malloc.mmap_threshold=10000
+overridable glibc.malloc.trim_threshold=10000
+
[proc:/bin/ls]
glibc.malloc.tcache_max=7
+
[proc:tst-tunconf1]
glibc.malloc.tcache_max=4
++glibc.malloc.mmap_threshold=10001
+nonoverridable glibc.malloc.trim_threshold=10001
@@ -194,34 +194,40 @@ add_tunable (char *line, const char *filename, int lineno)
/* Parse modifiers. */
while (*line)
{
- if (strncmp (line, "overridable ", 13) == 0)
+ int prefix_len;
+
+#define TUN_PREFIX(s) \
+ prefix_len = sizeof(s) - 1, \
+ strncmp (line, s " ", prefix_len + 1) == 0
+
+ if (TUN_PREFIX("overridable"))
{
top = TOP_ALLOW;
/* The line++ below skips the space. */
- line += 12;
+ line += prefix_len;
}
- else if (strncmp (line, "nonoverridable ", 16) == 0)
+ else if (TUN_PREFIX ("nonoverridable"))
{
top = TOP_DENY;
- line += 15;
+ line += prefix_len;
}
- else if (strncmp (line, "onlysecure ", 11) == 0)
+ else if (TUN_PREFIX ("onlysecure"))
{
exclude_nonsecure = 1;
exclude_secure = 0;
- line += 10;
+ line += prefix_len;
}
- else if (strncmp (line, "nonsecure ", 10) == 0)
+ else if (TUN_PREFIX ("nonsecure"))
{
exclude_secure = 1;
exclude_nonsecure = 0;
- line += 9;
+ line += prefix_len;
}
- else if (strncmp (line, "anysecure ", 10) == 0)
+ else if (TUN_PREFIX ("anysecure"))
{
exclude_secure = 0;
exclude_nonsecure = 0;
- line += 9;
+ line += prefix_len;
}
else switch (*line)
{
@@ -169,7 +169,7 @@ END {
n = indices[2];
m = indices[3];
printf (" {TUNABLE_NAME_S(%s, %s, %s)", t, n, m)
- printf (", {TUNABLE_TYPE_%s, %s, %s}, {%s}, {%s}, false, %s},\n",
+ printf (", {TUNABLE_TYPE_%s, %s, %s}, {%s}, {%s}, false, false, %s},\n",
types[t,n,m], minvals[t,n,m], maxvals[t,n,m], default_val[t,n,m],
default_val[t,n,m], env_alias[t,n,m]);
}