That this was dynamically linked is the least interesting thing about it IMO. It was a long term I filtration where they got legitimate commit access to a well used library.
If xz was statically linked in some way, or just used as an executa Le to compress something (like the kernel), the same problems exist and no dynamic linking would need to be involved.
> If xz was statically linked in some way, or just used as an executa Le to compress something (like the kernel), the same problems exist and no dynamic linking would need to be involved.
even more so: all binaries dynamically linking xz can be updated by installing a fixed library version. For statically linked binaries: not so much, each individual binary would have to be relinked, good luck with that.
In exchange, each binary can be audited as a final product on its own merits, rather than leaving the final symbols-in-memory open to all kinds of dubious manipulation.
Not true, it would be much harder to hook into openssl functions if the final executable was static [1], the only way is that if the openssl function this attack targeted, actually called a function from libxz.
Dynamic loading is relic of the past and cause of many headaches in linux ecosystem, in this case it also just obfuscates the execution path of the code more so you can't really rely on the code you are reading. Unfortunately I don't think it's possible to completely get rid of dynamic loading as some components such as GPU drivers require it, but it should be reduced to minimum.
This particular approach of hooking would be much harder; but a malicious xz has other options as well.
It's already in the code path used by dpkg when unpacking packages for security updates, so it could just modify the sshd binary, or maybe add a rootkit to the next kernel security update.
It seems foolish to change our systems to stop one of the steps the attacker used after their code was already running as root; the attacker can just pick something else; as root they have essentially unlimited options.
True, but such code changes in xz would be much easier to audit than all the dynamic loading shenanigans, even if obfuscated in the build system. The GNU's dynamic loader specially has grown to be very complicated (having all these OOP-like polymorphism features on linker / loader level ...) and I think we should tone down the usage of dynamic linking as I see it as low hanging fruit for attacks in general.
There are other reasons to change, though. The main thing to consider here is that static linking is the "OG" way of doing things, and also the simplest and the most easily understandable one. There are also obvious perf benefits to it when it comes to optimizing compilers.
On the other hand, dynamic linking was originally more or less just a hack to deal with memory-restricted environments in the face of growing amounts of code. It was necessary at the time because we simply wouldn't have things like X or Windows without it way back when.
But RAM is nowhere near as sparse these days, and it could be even less so if there was a concerted push on hardware vendors to stop skimping on it. So why don't we remove the hack and get back to a simple model that is much easier to understand, implement, and audit?
agree, it’s difficult to believe that people believe in dynamic linking so strongly that they are unwilling to consider abandoning it even in the face of obvious problems like this xz situation
Looking at IFUNC, there never seems to be a reason to allow function loading from a different library than the one the call is in, right? Maybe a restriction like that could be built in. Or just explicitly enumerate the possible substitutions per site.
IFUNC isn't used directly to patch the functions of another library here, it's just the entry point for the exploit code. IFUNC is used as opposed to other ways to execute code on library load because it runs very early (before linking tables are remapped read-only).
Yes, the dynamic linker (/lib/ld-linux.so.2), which is one relatively short program as opposed to thousands of big ones. :)
The point is, there's simply no usecase to require or even allow the program to do IFUNC substitution freely on its own. A programming framework should not opt the developer in to capabilities they don't want or need. Much of C-likes' complexity arises from unnecessary, mandated capabilities.
I mean dynamic loader is part of the base system and you generally trust the compiler and linker you build the program with. If any of those are malicious, you've already lost the game.
Asking a programmer to trust his own compiler and libraries which he can personally analyze and vouch for (static linking) is much different than asking the programmer to vouch for the dynamic libraries present on some given user’s machine.
If xz was statically linked in some way, or just used as an executa Le to compress something (like the kernel), the same problems exist and no dynamic linking would need to be involved.