Using IFUNC to patch sshd was kind of elegant, it achieved rootkit like behaviour with a pre-existing mechanism. And sure, it might be possible for a secure daemon like sshd to drop enough privileges that it could protect itself from a malicious dynamically linked library.
But IFUNC was not required, neither was systemd. The game was lost as soon as the attacker had arbitrary code installed in a semi-common library. It doesn't have to get linked directly with sshd, it only needed to be linked into any program running as root, at least one time.
Most programs make zero effort to sandbox themselves, and as soon as one of those links with the malicious library, it could do anything. Like indirectly targeting sshd by patching its binary on disk (optionally hiding it with a rootkit), or using debug APIs to patch sshd in memory.
IFUNC, systemd, and the patched openssh are all irrelevant to the issue, that was simply the route this attacker took to leverage their foothold in libxz. There are thousands of potential routes the attacker could have taken, and we simply can't defend from all of them.
I do not understand how you even expected sshd to sandbox itself. Its entire purposes is to (a) daemonize , (b) allow incoming connections in and then (c) forward (possibly-root) shell statements. All 3 things are 100% required for sshd and would have already allowed an attack like this. Any talk about sandboxing here (or dropping privileges) is wishful thinking.
If you wanted to do something really new in operating systems, you might think "POSIX is insecure" or "POSIX is bloated", etc. If you have a fundamentally different API though you have to write a whole new userspace. You're going to put in a POSIX personality so you can run bash and vim and nethack but once you do that you have the insecurity, bloat, etc.
That is not quite true! You still have to get the code to be executed. I can call dlopen on a malicious library, load it into my address space, and still not necessarily invoke any dangerous functions. What ifunc did in this case is allow the attacker to manipulate symbols so that calls to real, well-behaved xz routines were instead redirected to the attack payload.
2) The alternative they present is arguably less secure because the function pointer will remain writable for the life of the process, whereas with IFUNC the GOT will eventually be made immutable (or can be... not sure if that's the default behavior). In general function pointers aren't great for security unless you explicitly make the memory backing the pointer(s) unwritable, which at least is easier to do for a global table than it is for things like C++ vtables (because there's the extra indirection through data pointers involved to get to the table).
The interesting thing is obviously not that you can get code to run at high privilege level by modifying a system component. I mean, duh, as it were.
The interesting thing is that the attackers (almost) got downstream Linux distros to suck down and deploy that malicious component for them. And that's not down to an oddball glibc feature, it happened because they got some human beings to trust a malicious actor. GNU glibc can't patch that!
[1] Incorrectly, as you point out.
They also suggest an alternative to storing the function pointer, store the bit flags that decide which function to call. That restricts the call targets to only the legitimate ones intended.
The article mentions this, and also points to mprotect which you can use to protect the pointer.
Why people jump to criticize without reading first? BTW, you can ask an LLM to check your critique, before posting, if you don't want to read the text.
Some solaris engineer got a little too clever and decided that the modular part of the the auth system needed to be dynamic libs. Now it's all in one process space, hard to understand, hard to debug and fragile.
I really like openbsd's bsdauth, I don't know if it is actually any better than pam but because it is moduler at the process level it is possible for mere mortals to debug and make custom auth plugins. Sadly only obsd actually uses it. https://man.openbsd.org/login.conf.5#AUTHENTICATION
It also fails to mention glibc-hwcaps, which would've been a cleaner solution in the context.
The title is just clickbait.
As I know C++ allows running arbitrary code before main too - for constructors of global variables. Does it bring security risks too?
And I am again going to mention the book Linkers and Loaders by John R. Levine from 1999, I'm not sure if there's anything comparable to it. How else does anyone know anything about this stuff?
Curses, thwarted again!
> The short answer is that they have to. OpenSSH is developed by the OpenBSD community, for the OpenBSD community, and they do not give a flying Fedora about Linux.
What complete horseshit. I stopped reading there.
The OpenSSH Portable branch is maintained by OpenBSD developers and SystemD is a completely optional add-on so why on earth would they make it a dependency? If they didn't care about the Linux community they wouldn't develop this software *for free* for them. They can go write their own GNU SSH then.
It certainly doesn't help that there are 165+ definitions of what constitutes a "complete GNU+Linux system" some of which use SystemD and some which vow never to.
It's not the OpenBSD developers' fault some Linux distros use overly complex plumbing and can't agree on one standard for their OS unlike every other OS out there, including Windows.
The xz backdoor was a Debian and Red Hat issue because they maintained patches to fix problems of their own creation. No one else was affected. Why should the OpenBSD people care? It's not their problem.
> These patches never went into Portable OpenSSH, because the Portable OpenSSH folks were ["not interested in taking a dependency on libsystemd"](link). And they never went into upstream OpenSSH, because OpenBSD doesn't have any need to support SystemD.
The language may have been harsher than it needed to and therefore could be more easily misunderstood, but I believe you are actually in agreement with them
It reeks of trashing your benefactor, who gave you well-written free software, which you then made insecure with your own patches.
If you remove the roof of your car with a chainsaw and are inevitably injured later, is it the car manufacturer's fault they didn't offer that model as a convertible from the factory?
The better question is why are people still trying to assign blame all these years later? The IT world dodged a bullet but has moved on (and likely didn't learn from their mistakes as supply chain attacks are steadily increasing).
I do not know why you were down-voted, maybe you deserved no up-votes, but down-votes to me were a bit extreme :) But that quote tends to indicate to me the author put a little blame on OpenSSH Developers. Maybe the author did not intend it to be read in the way I read it.
OpenSSH developers should not need to know what or why systemd distros apply patches to OpenSSH, the distro I use, Slackware, did not have this vulnerability because the Slackware team, AFAIK, only adds patches if the package does not compile. If other distros did that this issue would not have occurred.
To me the issue was patching OpenSSH for some systemd thing. Maybe IFUNC was part of the issue, but the real issue was patching OpenSSH.
But I know one thing, I never heard of IFUNC and after reading about it, I will avoid that as much as I can. So at least I was educated :)
(In practice _start calls __libc_start_main, a libc function that handles all of that).
> No one person or team really made a mistake here, but with the benefit of hindsight it's clear the attackers perceived that the left hand of Debian/Fedora SSH did not know what the right hand of xz-utils was doing.
with OpenBSD not even being mentioned here
1. It impiles some function pointers to be writable temporarily, not all of them.
2. It doesn't hide writable pointers from a cursory glance not familiar with IFUNC.
(A1) In a POSIX constructor function in liblzma, set an alarm(2) for a few seconds later (once sshd has fully loaded).
(A2) In the alarm callback locate the original function that was patched using dlfcn, and mmap a page of modified code over the top that calls the exploit.
Or:
(B1) POSIX constructor function, call clone(2) to start a background thread.
(B2) In the background thread, sleep for a little, then patch the code as in A2 above.
Or:
(C1) POSIX constructor function that completely replaces the sshd process with a workalike that contains the exploit.
In A & B, for OSes (not Linux) that deny mmap, you'll need to find a struct or stack frame used by the function and work out how to adjust the data it uses or find a function pointer and exploit that.
So it's clever to use ifunc, but not necessary for an attack to work.
Likely the existing toolkit they seem to have been using had primitives for this already, but as I said in the Veritasium video I appreciate that this was a very sophisticated attack executed by a smart team.
Even in your own talk you basically admit this, so what are you doing here? If you think there's something here that everyone is missing but you don't, why not actually explain what it is?