Skip to content

Commit 2ed18c5

Browse files
committed
Fix SXID_ERASE behavior in setuid programs (BZ #27471)
When parse_tunables tries to erase a tunable marked as SXID_ERASE for setuid programs, it ends up setting the envvar string iterator incorrectly, because of which it may parse the next tunable incorrectly. Given that currently the implementation allows malformed and unrecognized tunables pass through, it may even allow SXID_ERASE tunables to go through. This change revamps the SXID_ERASE implementation so that: - Only valid tunables are written back to the tunestr string, because of which children of SXID programs will only inherit a clean list of identified tunables that are not SXID_ERASE. - Unrecognized tunables get scrubbed off from the environment and subsequently from the child environment. - This has the side-effect that a tunable that is not identified by the setxid binary, will not be passed on to a non-setxid child even if the child could have identified that tunable. This may break applications that expect this behaviour but expecting such tunables to cross the SXID boundary is wrong. Reviewed-by: Carlos O'Donell <carlos@redhat.com>
1 parent 061fe3f commit 2ed18c5

File tree

2 files changed

+52
-30
lines changed

2 files changed

+52
-30
lines changed

elf/dl-tunables.c

Lines changed: 26 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ parse_tunables (char *tunestr, char *valstring)
174174
return;
175175

176176
char *p = tunestr;
177+
size_t off = 0;
177178

178179
while (true)
179180
{
@@ -187,7 +188,11 @@ parse_tunables (char *tunestr, char *valstring)
187188
/* If we reach the end of the string before getting a valid name-value
188189
pair, bail out. */
189190
if (p[len] == '\0')
190-
return;
191+
{
192+
if (__libc_enable_secure)
193+
tunestr[off] = '\0';
194+
return;
195+
}
191196

192197
/* We did not find a valid name-value pair before encountering the
193198
colon. */
@@ -213,35 +218,28 @@ parse_tunables (char *tunestr, char *valstring)
213218

214219
if (tunable_is_name (cur->name, name))
215220
{
216-
/* If we are in a secure context (AT_SECURE) then ignore the tunable
217-
unless it is explicitly marked as secure. Tunable values take
218-
precedence over their envvar aliases. */
221+
/* If we are in a secure context (AT_SECURE) then ignore the
222+
tunable unless it is explicitly marked as secure. Tunable
223+
values take precedence over their envvar aliases. We write
224+
the tunables that are not SXID_ERASE back to TUNESTR, thus
225+
dropping all SXID_ERASE tunables and any invalid or
226+
unrecognized tunables. */
219227
if (__libc_enable_secure)
220228
{
221-
if (cur->security_level == TUNABLE_SECLEVEL_SXID_ERASE)
229+
if (cur->security_level != TUNABLE_SECLEVEL_SXID_ERASE)
222230
{
223-
if (p[len] == '\0')
224-
{
225-
/* Last tunable in the valstring. Null-terminate and
226-
return. */
227-
*name = '\0';
228-
return;
229-
}
230-
else
231-
{
232-
/* Remove the current tunable from the string. We do
233-
this by overwriting the string starting from NAME
234-
(which is where the current tunable begins) with
235-
the remainder of the string. We then have P point
236-
to NAME so that we continue in the correct
237-
position in the valstring. */
238-
char *q = &p[len + 1];
239-
p = name;
240-
while (*q != '\0')
241-
*name++ = *q++;
242-
name[0] = '\0';
243-
len = 0;
244-
}
231+
if (off > 0)
232+
tunestr[off++] = ':';
233+
234+
const char *n = cur->name;
235+
236+
while (*n != '\0')
237+
tunestr[off++] = *n++;
238+
239+
tunestr[off++] = '=';
240+
241+
for (size_t j = 0; j < len; j++)
242+
tunestr[off++] = value[j];
245243
}
246244

247245
if (cur->security_level != TUNABLE_SECLEVEL_NONE)
@@ -254,9 +252,7 @@ parse_tunables (char *tunestr, char *valstring)
254252
}
255253
}
256254

257-
if (p[len] == '\0')
258-
return;
259-
else
255+
if (p[len] != '\0')
260256
p += len + 1;
261257
}
262258
}

elf/tst-env-setuid-tunables.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,37 @@
4545
const char *teststrings[] =
4646
{
4747
"glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096",
48+
"glibc.malloc.check=2:glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096",
49+
"glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096:glibc.malloc.check=2",
50+
"glibc.malloc.perturb=0x800",
51+
"glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096",
52+
"glibc.malloc.perturb=0x800:not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096",
53+
"glibc.not_valid.check=2:glibc.malloc.mmap_threshold=4096",
54+
"not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096",
55+
"glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096:glibc.malloc.check=2",
56+
"glibc.malloc.check=4:glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096",
57+
":glibc.malloc.garbage=2:glibc.malloc.check=1",
58+
"glibc.malloc.check=1:glibc.malloc.check=2",
59+
"not_valid.malloc.check=2",
60+
"glibc.not_valid.check=2",
4861
};
4962

5063
const char *resultstrings[] =
5164
{
5265
"glibc.malloc.mmap_threshold=4096",
66+
"glibc.malloc.mmap_threshold=4096",
67+
"glibc.malloc.mmap_threshold=4096",
68+
"glibc.malloc.perturb=0x800",
69+
"glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096",
70+
"glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096",
71+
"glibc.malloc.mmap_threshold=4096",
72+
"glibc.malloc.mmap_threshold=4096",
73+
"",
74+
"",
75+
"",
76+
"",
77+
"",
78+
"",
5379
};
5480

5581
static int

0 commit comments

Comments
 (0)