Anyway, I was expecting a few shitstorms to start happening over macOS 11. Apple not announcing any major deprecations (edit: or removals) for this transition - even OpenGL/CL is still there, depecrated - was suspicious.
Anyway, I was expecting a few shitstorms to start happening over macOS 11. Apple not announcing any major deprecations (edit: or removals) for this transition - even OpenGL/CL is still there, depecrated - was suspicious.
dlopen() will look for the dylib first (as today), and if the file doesn't exist, it'll look in the shared cache.
So the only people this actually impacts are those who stat() system-provided dylibs before calling dlopen(). They should just skip the stat(), and go straight to calling dlopen().
Certainly not worthy of the end-of-the-world vibes in the twitter thread...
@dang - I flagged this for the editorialized title, in my view it's worth updating this to something like "Restrictions on reading dynamic libraries in macOS 11".
But `stat`ing it used to be fine on a Mac. And `stat`ing it is fine on other OSs. Why force software to change for no apparent reason just to appease the arbitrary whims of Apple? (And if it's not an arbitrary whim, you'd think they'd at least hint at the upsides of this, no?)
My guess as to the reason: I would guess the new way is faster, more secure, or takes less memory. Leaving an unused copy of binaries around would be wasting disk space (and yes, disks are enormous nowadays, but SSDs aren’t)
It may cache data from Apple’s servers, but calling it a cache sounds incorrect, though.
Why assume there's no reason?
Note that the dyld shared cache itself has existed for a long time; the only change here is removing the original copy of the dylibs to save disk space.
Like all race condition bugs it is probabilistic, but it can be won. By contrast dlopen either succeeds or does not, and once you have the handle to the library you are good.
Actually windows also works this way, and has done since wow I think vista if not XP? There's a knowndlls registry key. Large parts of the windows api are contained in a few DLLs; these are loaded on system startup. When resolving shared libraries if one of these names is requested the normal DLL loading procedure of checking paths isn't even followed - it just links in the already loaded DLL from the cache.
It actually wasn't designed as a security feature, but for speed. No matter what the OS does there's little need to continually load these DLLs from disk when we know they are already loaded to even display the desktop.
Of course on windows you can still do the windows equivalent of stat'ing these DLLs but nobody ever does.
FWIW, this optimization is unnecessary on modern Unix systems with a unified buffer cache because libraries loaded from disk are already CoW'd into the user process, without the need for special semantics. It's a pertinent point, nonetheless, but I'm guessing Apple made the switch in macOS for other reasons, perhaps related to disk space, its less than ideal ASLR scheme for Mach-O, or something related to code signing and sandboxing.
I second the TOCTOU concern. It's a bad code smell and a poor habit to stat and then open a file, period. (Likewise for the more general pattern.) There are reasons to do it (some better than others), but they're exceptional. You should never be eager to do it, and when you do you should rule out all possible security exploits or bugs, which is usually more work than abstaining from the superfluous hack. Breaking such code patterns is worth the cost in backward compatibility, IMO, for all the exploits and usability headaches this coding pattern leads to.
Linkers just need to somehow find the binary dependencies across the link path/staging.
Performance.
It wouldn’t surprise me if there’s no way to get your dynamic library there anymore, as this explicitly says it’s of the system provided ones.
Say a 'release' turns out to have a discrepancy between documentation and reality, that's when the problems start to mount.