···5566 parentWrapperDir = dirOf wrapperDir;
7788- securityWrapper = sourceProg : pkgs.callPackage ./wrapper.nix {
88+ # This is security-sensitive code, and glibc vulns happen from time to time.
99+ # musl is security-focused and generally more minimal, so it's a better choice here.
1010+ # The dynamic linker is still a fairly complex piece of code, and the wrappers are
1111+ # quite small, so linking it statically is more appropriate.
1212+ securityWrapper = sourceProg : pkgs.pkgsStatic.callPackage ./wrapper.nix {
913 inherit sourceProg;
1414+1515+ # glibc definitions of insecure environment variables
1616+ #
1717+ # We extract the single header file we need into its own derivation,
1818+ # so that we don't have to pull full glibc sources to build wrappers.
1919+ #
2020+ # They're taken from pkgs.glibc so that we don't have to keep as close
2121+ # an eye on glibc changes. Not every relevant variable is in this header,
2222+ # so we maintain a slightly stricter list in wrapper.c itself as well.
2323+ unsecvars = lib.overrideDerivation (pkgs.srcOnly pkgs.glibc)
2424+ ({ name, ... }: {
2525+ name = "${name}-unsecvars";
2626+ installPhase = ''
2727+ mkdir $out
2828+ cp sysdeps/generic/unsecvars.h $out
2929+ '';
3030+ });
1031 };
11321233 fileModeType =
+49
nixos/modules/security/wrappers/wrapper.c
···1717#include <syscall.h>
1818#include <byteswap.h>
19192020+// imported from glibc
2121+#include "unsecvars.h"
2222+2023#ifndef SOURCE_PROG
2124#error SOURCE_PROG should be defined via preprocessor commandline
2225#endif
···151154 return 0;
152155}
153156157157+// These are environment variable aliases for glibc tunables.
158158+// This list shouldn't grow further, since this is a legacy mechanism.
159159+// Any future tunables are expected to only be accessible through GLIBC_TUNABLES.
160160+//
161161+// They are not included in the glibc-provided UNSECURE_ENVVARS list,
162162+// since any SUID executable ignores them. This wrapper also serves
163163+// executables that are merely granted ambient capabilities, rather than
164164+// being SUID, and hence don't run in secure mode. We'd like them to
165165+// defend those in depth as well, so we clear these explicitly.
166166+//
167167+// Except for MALLOC_CHECK_ (which is marked SXID_ERASE), these are all
168168+// marked SXID_IGNORE (ignored in secure mode), so even the glibc version
169169+// of this wrapper would leave them intact.
170170+#define UNSECURE_ENVVARS_TUNABLES \
171171+ "MALLOC_CHECK_\0" \
172172+ "MALLOC_TOP_PAD_\0" \
173173+ "MALLOC_PERTURB_\0" \
174174+ "MALLOC_MMAP_THRESHOLD_\0" \
175175+ "MALLOC_TRIM_THRESHOLD_\0" \
176176+ "MALLOC_MMAP_MAX_\0" \
177177+ "MALLOC_ARENA_MAX\0" \
178178+ "MALLOC_ARENA_TEST\0"
179179+154180int main(int argc, char **argv) {
155181 ASSERT(argc >= 1);
182182+183183+ int debug = getenv(wrapper_debug) != NULL;
184184+185185+ // Drop insecure environment variables explicitly
186186+ //
187187+ // glibc does this automatically in SUID binaries, but we'd like to cover this:
188188+ //
189189+ // a) before it gets to glibc
190190+ // b) in binaries that are only granted ambient capabilities by the wrapper,
191191+ // but don't run with an altered effective UID/GID, nor directly gain
192192+ // capabilities themselves, and thus don't run in secure mode.
193193+ //
194194+ // We're using musl, which doesn't drop environment variables in secure mode,
195195+ // and we'd also like glibc-specific variables to be covered.
196196+ //
197197+ // If we don't explicitly unset them, it's quite easy to just set LD_PRELOAD,
198198+ // have it passed through to the wrapped program, and gain privileges.
199199+ for (char *unsec = UNSECURE_ENVVARS_TUNABLES UNSECURE_ENVVARS; *unsec; unsec = strchr(unsec, 0) + 1) {
200200+ if (debug) {
201201+ fprintf(stderr, "unsetting %s\n", unsec);
202202+ }
203203+ unsetenv(unsec);
204204+ }
156205157206 // Read the capabilities set on the wrapper and raise them in to
158207 // the ambient set so the program we're wrapping receives the