Environment variables aren't really objects, they're almost like a second argument array that can be passed to exec(). LSMs such as AppArmor can filter environment variables inherited across exec, though with AppArmor I'm not sure if it could be done globally (it's available per profile).
Another mitigation would be to maintain your own builds of glibc with the LD_PRELOAD functionality patched out of ld.so
entirely.
glibc's ld.so already has checks to ignore LD_PRELOAD when loading a 'setuid' executable, so any such environment variables would be ineffective against 'sudo' or 'su' tools. This can also be used to guard 'ssh' to some extent – give it a harmless capability such as 'cap_net_broadcast=p' or make it setgid to a harmless group and it'll become immune to LD_PRELOAD.
The library has to be loaded from somewhere, so making all writable locations be mounted noexec
should help, as it prevents ld.so from creating executable mappings of files in those filesystems and therefore not just running executables but also loading libraries from a noexec filesystem.
It's unclear how the malware causes the environment variables to be set originally, that is, do they affect init
itself or do they only affect user shell processes. If they don't affect init, it can be asked to start a new process in a clean environment – e.g. with systemd, nothing leaks from the systemctl caller to the service.