Toward safer GNU C Library tunable handling
The tunables mechanism allows various aspects of the library's behavior to be adjusted at run time. Many of the provided knobs relate to memory-management algorithms hidden behind malloc(), but there are others as well. The list of available tunables on any given system can be seen by running:
/lib64/ld-linux-x86-64.so.2 --list-tunables
The library provides no public functions for setting or querying tunable values; instead, users can set them, before running a program, by setting GLIBC_TUNABLES. This variable is processed early in the startup routine, well before a program's main() function is called. So a program has little control over which tunables are applied to it; in a sense, glibc tunables allow the library's behavior to be tweaked behind a program's back.
The ability to do such tweaking raises some obvious red flags when the program involved has the setuid or setgid permissions set. Those programs constitute a security boundary within the system, so allowing users on the unprivileged side of the boundary to adjust behavior on the privileged side is going to be fraught. Glibc has long recognized that some tunables should cease to be tunable when a program is setuid or setgid; to enforce that restriction, each tunable is marked, within glibc, with a "security level". If a tunable is marked SXID_ERASE, it will be ignored in privileged programs and erased from GLIBC_TUNABLES entirely, with the result that it will not be present in any child processes created by that program. SXID_IGNORE, instead, causes the tunable to be ignored but left in place. Without one of those settings, the tunable will be honored in privileged programs.
Even with this mechanism in place, the intersection of tunables and privileged programs has proved to be a reliable source of security bugs. So the glibc developers are looking at ways of eliminating that intersection entirely. Siddhesh Poyarekar posted a patch set setting all tunables to SXID_ERASE, essentially disabling the tunables mechanism for privileged programs entirely, shortly after the latest vulnerability disclosure. Some discussion followed and, one week later, Adhemerval Zanella proposed a deeper set of changes aimed at eliminating this class of problems.
Step one in Zanella's series is to eliminate support for the special /etc/suid-debug file. If that file exists (it can be empty), then the glibc.malloc.check tunable can turn on malloc() checking, even in privileged programs. Normally this feature is disabled in such programs because it can generate output to the standard error stream, which could be abused by an attacker. This debugging can be useful, so the check for this file was added as a way of giving the system administrator a way to make it available for privileged programs. It turns out, though, that the /etc/suid-debug check hasn't worked since the 2.34 release, when memory allocation was pushed out into a separate library; rather than fix this feature, this series just removes that support.
The next step is to ignore all tunables in privileged programs, essentially setting them all to SXID_IGNORE. A later patch then adds GLIBC_TUNABLES to the list of environment variables that are not passed through to child processes, effectively changing that setting to SXID_ERASE via a different means. There is another set of environment variables that can change many of the malloc() tunables as well; for example, MALLOC_MMAP_THRESHOLD can be used to change glibc.malloc.mmap_threshold. All of those variables are added to the "insecure variables" list as well.
That eliminates the handling of tunables from privileged programs, but the patch set makes another set of changes as well. Current glibc versions are relatively forgiving about invalid GLIBC_TUNABLES settings; a number of patches in this series put an end to that, aborting tunable parsing and emitting a warning when badly formatted tunable settings are found. Finally, there is a patch that causes GLIBC_TUNABLES to be parsed in place rather than copied to a separate string. That change is intended to avoid any problems that might come about as the result of memory-allocation failures; this processing happens before glibc's memory management is initialized, so allocation is trickier at this stage.
The end result should be a distinct reduction in tunable-related bugs and
vulnerabilities in future glibc releases — if the series is accepted, of
course. This change could come at a cost for users who have a reason to
set these tunables for privileged programs, should any such users exist.
But the glibc documentation is explicit in its statement that tunables are
not considered part of the ABI and can change at any time. In this case,
most users may well conclude that these changes are overdue and the cost is
well worth paying if it results in fewer vulnerabilities in the future.
Posted Oct 19, 2023 16:45 UTC (Thu)
by sroracle (subscriber, #124960)
[Link] (2 responses)
Posted Oct 19, 2023 20:29 UTC (Thu)
by itsmycpu (guest, #139639)
[Link] (1 responses)
Posted Oct 19, 2023 21:06 UTC (Thu)
by itsmycpu (guest, #139639)
[Link]
Posted Oct 19, 2023 22:36 UTC (Thu)
by joib (subscriber, #8541)
[Link]
Posted Oct 20, 2023 0:43 UTC (Fri)
by tilt12345678 (subscriber, #126336)
[Link] (12 responses)
Posted Oct 20, 2023 7:45 UTC (Fri)
by taladar (subscriber, #68407)
[Link] (5 responses)
However I agree, the environment variable system seems the wrong place for this, especially considering the low level nature of these settings and the issues around setting and getting environment variables from different threads of the same process without crashes.
Posted Oct 20, 2023 17:14 UTC (Fri)
by raven667 (subscriber, #5198)
[Link] (2 responses)
The main takeaway for me is that a lot of tunable env vars like this may not be well documented on systems in a way that the millions and millions of people who admin and develop on Linux are generally aware they even exist, let alone could list the various settings and describe what they do. glibc is probably not the only library which has optional behavior which can be set by environment variables that could break a program, which the developers and users aren't taking sufficient precaution against because they aren't aware of the risk.
Posted Oct 22, 2023 16:03 UTC (Sun)
by dezgeg (subscriber, #92243)
[Link] (1 responses)
Command line would be much preferable, for example for Haskell code compiled with GHC you can pass 'tunables' to the GHC runtime by passing something like '+RTS -M128m -RTS' on the command line. Of course that GHC solution has the problem of in-band signalling.
At least for dynamically linked programs one neat way would be to explicitly invoke the dynamic linker and pass the tunables there, just like it already supports flags like --preload (ie. instead of 'LD_PRELOAD=foo.so /bin/ls' one can do '/lib64/ld-linux-x86-64.so.2 --preload foo.so /bin/ls').
Posted Nov 2, 2023 14:20 UTC (Thu)
by roblucid (guest, #48964)
[Link]
If your program system breaks it is written badly. Just sanitise the environment when you start your fragile application. Set things like PATH, adjust variables if required. Users are allowed to break their session.
Requiring every program anyone ever writes to pass through by CLI argument something like terminal type, printing width or display device is ridiculous.
Posted Oct 22, 2023 17:17 UTC (Sun)
by tilt12345678 (subscriber, #126336)
[Link]
Problem 1: The method of applying tunables via environment is intrusive on a systems design/management level.
Problem 2: Being able to apply tunables via every process's environment makes a system's behavior less clear.
Problem 3: The current design of the tunables configuration interface offers a questionable mixup of debugging and performance settings.
I am aware that my ramblings do not include even a hint of an idea of how to actually accomplish such improvements, because frankly i have none!
Posted Nov 2, 2023 13:39 UTC (Thu)
by roblucid (guest, #48964)
[Link]
It's hard to think of a valid use of environment passed in. For instance even dynamic linking with a local directory, you would optionally at build time insert a fixed directory to the default runtime .so search path. You could not rely on users not breaking environment.
This sounds like GNU lost the plot on this, when ld.so has an altered [ui]d it is simply asking for trouble to worry about a user's POSIXLY_CORRECT setting or other options that might introduce unanticipated behaviour.
Posted Oct 20, 2023 16:48 UTC (Fri)
by matthias (subscriber, #94967)
[Link] (2 responses)
And seeing that there are actually security holes in the parsing code for a pre-allocated very simple key-value store (environment variables), I can only imagine how hand crafted low level file parsing code without access to malloc would look like. Existing high level libraries will not be of much help in this restricted environment.
And while I do not really like environment variables, the problems are really not in the interface, but the language used to access the information. There will not be less buffer overflows in the checking code just because we switch from environment variables to files. The only real solution is to switch to a language that enforces bound checking.
And the problem that this kind of tunables crosses a security boundary for SUID files will also not go away if we switch the interface. We really should get rid of SUID. There is way too much state that crosses the boundary during fork+exec, not only the environment variables.
Posted Nov 2, 2023 13:24 UTC (Thu)
by sammythesnake (guest, #17693)
[Link]
Posted Nov 2, 2023 14:43 UTC (Thu)
by roblucid (guest, #48964)
[Link]
Such programs are supposed to be small, carefully written and sanitise all input including the environment. Glibc tunables broke that contract.
Things worked before these GNU tunables, it's unclear why ld.so is EVEN looking at them when exec changes the effective [ug]id.
It's not environment that's broken it's a badly thought out feature created by glibc.
Posted Oct 24, 2023 15:00 UTC (Tue)
by rwmj (subscriber, #5474)
[Link]
Posted Oct 28, 2023 1:27 UTC (Sat)
by siddhesh (guest, #64914)
[Link]
Posted Nov 2, 2023 13:52 UTC (Thu)
by roblucid (guest, #48964)
[Link]
The whole point of environment was to allow users to alter their preferences and also have things like their terminal type and X-server work.
BUT privileged programs with an effective [ug]id should not be affected by environmental whims of the misguided or malicious.
Toward safer GNU C Library tunable handling
Toward safer GNU C Library tunable handling
Toward safer GNU C Library tunable handling
Toward safer GNU C Library tunable handling
Toward safer GNU C Library tunable handling
Shouldn't all this configuration go into a configuration file in /etc that has an expressive, descriptive language stating how a system behaves totally instead of offering the possibility to inject settings all over the place via environment?
Toward safer GNU C Library tunable handling
Toward safer GNU C Library tunable handling
Toward safer GNU C Library tunable handling
Toward safer GNU C Library tunable handling
When running with effective UID privilege the environment should not be trusted just as any user input needs careful verification.
Similarly you don't want low level routines continually opening config files to simulate the process environment.
Toward safer GNU C Library tunable handling
Being able to tune via environment is convenient, but - to state the obvious - it actually requires modifying the environment. Therefore, to be able to tune/trace every process, every potential process start has to be wrapped individually. A central policy mechanism could relieve system engineering from re-implementing this for every process that can be run in a system and that should be tuned/traced, making the tunables accessible where they right now are not (think containerized workloads etc.)
Given the current tuning configuration mechanism, it is a non-trivial task to state how a system currently actually behaves. Many corner cases have to be considered. Just some examples: Can a process apply tunables to itself by modifying its own environment? Is it safe to state that, if a process's environment contains a tunable setting X, then X is actually effective? Is it safe to state that X applies to all threads of X or only future threads? Also consider the special rules that apply to SUID/SGID binaries. Etc, etc. Much like discretionary access control, it's another semantical nightmare in audit situations.
The current set of tunables mixes settings for tuning (e.g. hugeTLB) with settings for tracing (e.g. malloc check). A central policy syntax maybe could allow for a splitting of these substantially different activities into separate mechanisms, or maybe just a "sounder" design in general.
Toward safer GNU C Library tunable handling
Toward safer GNU C Library tunable handling
Toward safer GNU C Library tunable handling
Toward safer GNU C Library tunable handling
It's self inflicted because it's providing features that are highly dubious in programs with setuid/setgid bit set.
Toward safer GNU C Library tunable handling
Toward safer GNU C Library tunable handling
Toward safer GNU C Library tunable handling
Personal choices in ~/. profile are desirable, users are free to break their session settings.