5 ms·
You're correct. For 3rd-party provided dylibs, it also isn't necessary to get them into the system cache. dlopen() will look for the dylib first (as today), an
by frogblast 6y ago
You're correct. For 3rd-party provided dylibs, it also isn't necessary to get them into the system cache.
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...
- DCKing 6y agoThanks for the clarification. I'm guessing people are just looking for the inevitable pitchfork worthy big bad breaking change, but we haven't found one yet (although I'm slightly annoyed my Macbook will be out of official support with this release). @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".
- gspr 6y ago> They should just skip the stat(), and go straight to calling dlopen(). 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?)
- Someone 6y agoEven ignoring the race condition, has stating shared libraries ever been documented as a method to ascertain existence of a shared library? 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.
- barrkel 6y agoI wouldn't think it's any of those reasons. I'd rather think it's to transparently serve up different libraries based on the caller, even if the name is the same, in the name of compatibility or something like it.
- coldtea 6y ago>Why force software to change for no apparent reason just to appease the arbitrary whims of Apple Why assume there's no reason?
- tspike 6y agoTo be fair, the reason is certainly not apparent.
- plorkyeran 6y agoThe reason is immediately apparent. They're eliminating a redundant copy of the libraries to save disk space.
- majewsky 6y agoThat's definitely not the reason, given that symlinks are still a thing.
- plorkyeran 6y agoYou can't symlink into a byte range of a file. All of the system dylibs are stored in a single file.
- comex 6y agoAlso, the dyld shared cache isn’t just some archive containing exact copies of the dylib files. Among other things, the cache builder pre-resolves references between different dylibs in the cache. This saves time on process startup, and also allows pages to be shared between multiple processes even if they contain relocations, saving memory. But it means that even if you could symlink to a byte range, you couldn’t just have the original dylib paths be symlinks to parts of the cache. (It might be possible to make this work with enough effort, but it would be very nontrivial.) 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.
- zahllos 6y agoStat then dlopen is a toctou (time of check/time of use) bug. There's a race condition between the check succeeding and the dlopen being called in which that library might be replaced by a malicious one. 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.
- wahern 6y ago> 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. 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.
- loeg 6y agoClassic linking uses a path to a library at link time. I suppose Apple may have patched ld to work around this choice, but it still begs the question — why change this? Who was it hurting?
- pjmlp 6y agoNot in every OS or programming language, it doesn't. Linkers just need to somehow find the binary dependencies across the link path/staging.
- saagarjha 6y ago> why change this? Who was it hurting? Performance.
- oneplane 6y agoAnd security. If you sign a single cache across millions of systems you know that that is the one true non-tampered cache.
- loeg 6y agoCan you elaborate beyond a single word? It is certainly not immediately obvious to me how this benefits performance, or I wouldn't have asked.
- saagarjha 6y agoHere's one optimization: http://sealiesoftware.com/blog/archive/2009/09/01/objc_explain_Selector_uniquing_in_the_dyld_shared_cache.html http://sealiesoftware.com/blog/archive/2009/09/01/objc_expla...
- saurik 6y agohttp://www.cydiasubstrate.com/id/727f62ed-69d3-4956-86b2-bc0ffea110c1/ http://www.cydiasubstrate.com/id/727f62ed-69d3-4956-86b2-bc0...
- bdash 6y agoThe Apple linker has used `tbd` files, a textual description of a dynamic library's interface, rather than actual dynamic libraries at link time for iOS for several years now. Prior to that it was using stub dylibs, which were essentially symbol-table-only dylib files.