Apple Darwin OS और XNU कर्नेल का गहन विश्लेषण
(tansanrao.com)- Apple का Darwin, macOS, iOS और आधुनिक Apple OS का Unix-परिवार आधारित आधार है, और XNU एक hybrid kernel है जो Mach और BSD को एक ही kernel में जोड़ता है
- XNU, Mach के task, thread, virtual memory और port-आधारित IPC को बनाए रखते हुए BSD services को उसी kernel address space में रखता है, जिससे शुद्ध microkernel-शैली message passing की लागत घटती है
- NeXTSTEP की Mach 2.5+4.3BSD वंशावली 1996 में Apple द्वारा NeXT के अधिग्रहण के बाद Mac OS X और Darwin तक पहुँची, और बाद में FreeBSD code, I/O Kit, 64-bit, ARM और Apple Silicon support चरणबद्ध तरीके से जोड़े गए
- macOS और iOS ने sandbox, code signing, SIP, APFS, DriverKit, QoS scheduling, Jetsam और compressed memory जैसी सुविधाओं को kernel और user space के सहयोग से विस्तारित किया है
- XNU का विकास kernel को नए सिरे से लिखने के बजाय Mach/BSD आधार को बनाए रखते हुए, प्रदर्शन-जरूरी हिस्सों को kernel के भीतर integrate करने और isolation-जरूरी हिस्सों को IPC और user space में अलग करने के तरीके के करीब है
Darwin और XNU की शुरुआत
- Darwin macOS, iOS और Apple के आधुनिक OS platforms को सहारा देने वाला Unix-परिवार का core operating system है
- इसके केंद्र में “X is Not Unix” का संक्षेप XNU kernel है, जो Mach microkernel core और BSD Unix components को जोड़ता है
- यह संरचना Mach के message passing-आधारित design और BSD की स्थिरता व POSIX compatibility, दोनों का उपयोग करके modularity और performance के बीच संतुलन साधने का लक्ष्य रखती है
Mach, NeXTSTEP और Mac OS X तक पहुँचा इतिहास
- Mach 1985 में Carnegie Mellon University में Richard Rashid और Avie Tevanian के नेतृत्व वाले project के रूप में शुरू हुआ
- इसका microkernel design memory management, CPU scheduling और IPC जैसी low-level सुविधाओं को ही kernel में रखकर file system, networking और drivers को user-space servers में रखने का था
- task, thread, Mach port, copy-on-write और memory object जैसी अवधारणाएँ kernel के core objects बन गईं
- NeXTSTEP 1989 में Mach 2.5 kernel के ऊपर 4.3BSD Unix subsystem के साथ जारी हुआ
- NeXT ने शुद्ध microkernel तरीके की बजाय BSD code को kernel address space में integrate करने का रास्ता चुना, ताकि performance को प्राथमिकता दी जा सके
- इसमें Objective-C आधारित DriverKit भी शामिल था, और बाद में यह Apple की XNU वंशावली तक पहुँचा
- Apple ने 1996 में NeXT का अधिग्रहण किया और NeXTSTEP को नए Mac OS X के आधार के रूप में चुना
- Rhapsody project शुरू हुआ और NeXT का Mach/BSD hybrid kernel Apple में आया
- इसके बाद XNU ने OSFMK 7.3 आधारित Mach 3.0 वंश के code और 4.4BSD व FreeBSD code को अपनाया
Darwin और Mac OS X का शुरुआती विकास
- Apple ने 1999 में Mac OS X developer preview जारी किया, और 2000 में Darwin 1.0 को सार्वजनिक कर XNU kernel और basic Unix user space को developers के लिए खोला
- Mac OS X 10.0 Cheetah 2001 में Darwin 1.3.1 आधारित commercial release के रूप में आया
- शुरुआती बदलावों का focus BSD layer, networking, file system और threading performance को मजबूत करने पर था
- Mac OS X 10.1 Puma ने thread management performance और real-time thread support में सुधार किया
- Mac OS X 10.2 Jaguar में IPv6, IPSec,
mDNSResponderऔर HFS+ journaling शामिल थे - Mac OS X 10.3 Panther ने FreeBSD 5 kernel improvements और fine-grained kernel locks को integrate कर multiprocessor उपयोग को मजबूत किया
- Mac OS X 10.4 Tiger को UNIX 03 certification मिला, इसने FreeBSD का
kqueue/keventअपनाया, और Intel Mac transition के लिए cross-platform आधार बनाए रखा
64-bit और iPhone OS से आई mobile जरूरतें
- Mac OS X 10.5 Leopard ने Darwin 9 के आधार पर 64-bit kernel execution, 64-bit drivers, ASLR, sandbox और DTrace को पेश किया
- 2007 में पहला iPhone OS भी Darwin 9 के आधार पर release हुआ, जिससे XNU ARM mobile devices तक विस्तारित हुआ
- शुरुआती iPhone में RAM सीमित थी और swap इस्तेमाल नहीं किया जा सकता था, इसलिए low-memory स्थिति में background apps को terminate करने वाला Jetsam mechanism इस्तेमाल हुआ
- iPhone OS third-party apps को sandbox के भीतर चलाता था और binaries के लिए सख्त code signing की मांग करता था
- Mac OS X 10.6 Snow Leopard ने PowerPC support बंद कर Intel-केंद्रित 64-bit और multicore optimization को मजबूत किया
- Grand Central Dispatch और
libdispatchuser-space libraries हैं, लेकिन kernel के thread pool और scheduling support का उपयोग करती हैं - OpenCL को भी GPU computing के लिए user frameworks और kernel drivers के गहरे integration की जरूरत थी
- Grand Central Dispatch और
- iOS 4 ने background apps की priority separation और multicore ARM SoC support के अनुरूप scheduler को adjust किया
आधुनिक macOS और iOS में kernel features का विस्तार
- OS X 10.9 Mavericks ने compressed memory और timer coalescing जोड़ा
- compressed memory inactive pages को RAM के भीतर compress कर disk swap घटाती है
- timer coalescing CPU wake-up timings को align कर power usage कम करने का तरीका है
- OS X 10.11 El Capitan ने System Integrity Protection, यानी SIP, पेश किया
- SIP को kernel BSD layer के Mandatory Access Control framework के जरिए enforce करता है, और root processes को भी important system files और processes बदलने से रोकता है
- macOS 10.13 High Sierra ने APFS को default file system के रूप में पेश किया
- XNU की VFS layer को APFS snapshots, cloning और container-level encryption support करने के लिए expand किया गया
- इसी समय third-party kext loading के लिए user approval जरूरी हो गया
- macOS 10.15 Catalina ने modern DriverKit पेश किया
- DriverKit कई drivers को kernel से बाहर user-space Driver Extension में ले जाता है
- kernel IPC और shared memory के जरिए user-space drivers को सीमित hardware access देता है
- Catalina ने read-only system volume भी पेश किया, जिससे SIP protection मजबूत हुआ
Apple Silicon युग में XNU
- 2020 में macOS 11 Big Sur और Darwin 20, Apple Silicon Mac support करने वाला पहला release था
- XNU iOS के जरिए पहले से ARM support करता था, लेकिन Apple Silicon Mac में heterogeneous big.LITTLE CPU architecture तक को ध्यान में रखना पड़ा
- scheduler high-priority और heavy threads को performance cores पर, और low-QoS या background threads को efficiency cores पर रख सके, इसके लिए heterogeneous cores को पहचानता है
- QoS classes Apple Silicon में core type selection को भी प्रभावित कर सकने वाले scheduling hints के रूप में इस्तेमाल होती हैं
- Apple Silicon की unified memory architecture में kernel memory manager और GPU drivers buffer sharing manage करते हैं
- Mach VM abstraction user space और GPU के बीच copies की जगह VM remapping द्वारा memory objects share करने के लिए उपयुक्त है
- ARM64 backend Pointer Authentication support करता है, exception frames और system pointers के लिए PAC keys का उपयोग करता है और ROP attacks को mitigate करने में मदद करता है
- XNU, macOS, iOS, watchOS, tvOS, bridgeOS और visionOS जैसे कई Apple platforms का common foundation बना हुआ है
XNU की hybrid kernel structure
- XNU के Mach और BSD components एक single kernel binary में link होते हैं और वही address space share करते हैं
- Mach और BSD के बीच कोई protection boundary नहीं है, और kernel के भीतर वे IPC messages के बजाय सामान्य function calls से interact करते हैं
read()जैसी Unix system call किसी अलग BSD server को message नहीं भेजती, बल्कि सीधे kernel के भीतर BSD file system code में जाती है
- Mach core kernel infrastructure संभालता है
- task और thread creation/termination, context switching, low-level scheduling, locks, timers और scheduling queues manage करता है
- हर BSD process एक Mach task से, और हर thread एक Mach thread से map होता है
- Mach VM virtual address maps, memory objects, copy-on-write और IPC-based memory sharing देता है
- BSD Unix nature और services प्रदान करता है
- PID, user ID, signals, POSIX threads, file systems, networking, Unix IPC, device I/O, permissions और security framework manage करता है
- VFS, HFS+, APFS और NFS जैसे file systems संभालता है, और memory-mapped files में Mach VM और vnode pager के जरिए जुड़ता है
- sandbox और SIP, BSD security modules और Mach task port restrictions के सहयोग से काम करते हैं
- I/O Kit XNU का तीसरा pillar है, जो restricted C++ form में लिखा गया object-oriented driver framework है
- devices और drivers को class hierarchy के रूप में represent करता है, और drivers kernel के भीतर C++ objects के रूप में चलते हैं
- user space को I/O Registry properties और user client interfaces के जरिए सीमित access देता है
- modern macOS के DriverKit से पहले तक अधिकांश drivers kernel के भीतर kext के रूप में चलते थे
Mach IPC और system services
- XNU, Unix system call path में Mach messages का उपयोग नहीं करता, लेकिन user-space services और kernel/process communication में Mach IPC का व्यापक उपयोग करता है
- Mach ports कई kernel objects के user-space handles के रूप में इस्तेमाल होते हैं
- हर task के पास task port होता है, और privileged processes इसके जरिए दूसरे tasks को inspect या control कर सकते हैं
- events और notifications भी Mach messages से deliver होते हैं
- WindowServer user input events को kernel से Mach messages के रूप में प्राप्त करता है
- Grand Central Dispatch internally Mach ports का उपयोग कर event-waiting threads को sleep कराता है
kqueue/keventMach port messages और file descriptors का साथ में wait कर सकता है
- Apple का XPC framework Mach messages के ऊपर बना है
- XPC connections internally Mach ports पर आधारित होते हैं
- Mach port का permission model Keychain के
securitydजैसी services में caller permissions verify करने के लिए इस्तेमाल होता है - Mach messages out-of-line memory और port rights pass कर सकते हैं, इसलिए high-level RPC बनाने में इस्तेमाल होते हैं
- MIG, यानी Mach Interface Generator, kernel और user space के बीच interface definitions और message send/receive code generate करने के लिए इस्तेमाल होता है
Scheduler और thread management
- XNU scheduler Mach के priority-based round-robin scheduler से शुरू हुआ था, लेकिन desktop और mobile जरूरतों के अनुसार काफी बदला गया
- Mach ने ऐतिहासिक रूप से 0~127 range की thread priorities define कीं, और XNU
sched_priवbase_priजैसे values का उपयोग करता है- time-sharing threads की priority usage के आधार पर बदल सकती है
- real-time threads fixed priority इस्तेमाल करते हैं
- XNU प्रति-CPU run queues और scheduler interrupts के जरिए efficiency और load balancing संभालता है
- iOS का app sandbox और background execution, work role या priority group जैसे concepts को scheduler में reflect करता है
- QoS classes iOS 8 और OS X 10.10 के बाद scheduling में integrate हुईं
- user-interactive, user-initiated, default, utility और background जैसी classes priority bands और scheduling को प्रभावित करती हैं
- Grand Central Dispatch या NSThread से बने threads QoS inherit करते हैं
- Apple Silicon में background QoS threads efficiency cores पर रखे जा सकते हैं
- real-time audio और critical tasks के लिए real-time queues और deadline-based scheduling भी support होती है
Memory management और Mach VM
- XNU का memory management Mach VM subsystem पर केंद्रित है
- हर Mach task के पास VM map और VM regions से दर्शाया गया virtual address space होता है
fork()पूरी memory तुरंत copy नहीं करता, बल्कि copy-on-write इस्तेमाल करता है- parent और child write होने तक वही pages share करते हैं
- Mach memory objects और pager concepts का उपयोग करता है
- anonymous memory का default pager user-space
dynamic_pagerdaemon संभालता है, और जरूरत पड़ने पर swap files manage करता है - file memory kernel के भीतर BSD layer में मौजूद vnode pager के जरिए file system code से interact करती है
- anonymous memory का default pager user-space
- Mavericks की compressed memory kernel के भीतर compression pager जोड़कर implement हुई
- memory pressure ज्यादा होने पर inactive pages को सीधे disk पर भेजने के बजाय RAM में compressor pool में compress कर store किया जाता है
- compression से भी कमी पूरी न हो तो disk swap इस्तेमाल होता है
- physical memory management architecture-dependent layer pmap संभालती है
- pmap page tables या उस architecture की corresponding structures manage करता है
- ARM64 में security features और cache-related issues भी pmap से जुड़े होते हैं
dyldका shared cache कई processes में वही physical pages read-only रूप में map कर efficient उपयोग करता है
Virtualization support
- Intel Mac में OS X 10.10 से Hypervisor.framework उपलब्ध है, जो user-space virtualization support करता है
- Intel VT-x का उपयोग कर user-space process को virtual machine monitor की तरह काम करने देता है
xhyveजैसे tools और कुछ virtualization apps इस feature का उपयोग करते हैं
- Apple Silicon में macOS 11 का Virtualization.framework ARM64 के लिए in-kernel hypervisor पर चलता है
- developers user space में Linux या macOS VM चला सकते हैं
- kernel के भीतर arbitrary third-party hypervisors की अनुमति देने के बजाय Apple frameworks और entitlements के जरिए access देने का तरीका अपनाया जाता है
- kernel perspective से hypervisor features में guest physical memory management, sensitive instructions का trap-and-emulate और vCPU interface exposure शामिल हैं
- Mach scheduler host के नजरिए से threads होने वाले vCPU को schedule करता है, और memory subsystem guest memory mapping में इस्तेमाल होता है
- iOS में भी कुछ conditions और permissions के तहत virtualization features संभव हैं, और jailbroken A14 devices में hypervisor enable कर Linux VM चलाने के उदाहरण हैं
Secure Enclave और Exclaves
- macOS sensitive operations और data की सुरक्षा के लिए Secure Enclave और exclaves नाम की दो isolation mechanisms का उपयोग करता है
- Secure Enclave, Apple SoC में integrated dedicated hardened subsystem है
- यह iPhone, iPad, T2 या Apple Silicon Mac आदि में मौजूद होता है
- यह अपना microkernel-based operating system चलाता है और encryption keys व biometric data जैसी sensitive जानकारी manage करता है
- इसका उद्देश्य main application processor या kernel compromise होने पर भी महत्वपूर्ण data को अलग रखना है
- Exclaves macOS 14.4 और iOS 17 में आई नई security architecture है
- sensitive work को main XNU kernel के समान privilege domain में रखने के बजाय, कुछ core resources को अलग “externally located” domain में isolate करती है
- Apple ID services, audio buffers, sensor data और indicator management components जैसे resources इसके target हैं
- ExclaveKextClient.kext, ExclaveSEPManagerProxy.kext, ExclavesAudioKext.kext जैसे special kext और private framework management में शामिल हैं
- यह separation main kernel compromise होने पर भी exclave के भीतर के work को isolate कर additional defense layer देता है
Long-term design direction
- Darwin और XNU न तो पूरी तरह microkernel हैं, न पूरी तरह monolithic kernel, बल्कि mixed design हैं
- Mach-based core नए architectures और system features के अनुकूल होने में मददगार रहा, और BSD layer ने POSIX-compatible environment व Unix tools/API दिए
- Apple ने PowerPC से Intel और ARM तक CPU transitions, और iPhone, Apple Watch व Apple Vision Pro जैसी नई device categories को XNU आधार पर अपनाया
- kernel changes मुख्य रूप से तीन तरीकों से आगे बढ़ते हैं
- नई features को मौजूदा kernel के ऊपर extend किया जाता है
- performance-critical components को kernel के भीतर integrate किया जाता है
- isolation-जरूरी components को Mach IPC और user space के जरिए separate किया जाता है
- Darwin के public source releases researchers को commercial hybrid kernel को देखने की एक window देते हैं, लेकिन public scope में limitations हैं
1 टिप्पणियां
Hacker News टिप्पणियाँ
Mach की virtual memory system सिर्फ 4.4BSD और FreeBSD ही नहीं, बल्कि NetBSD[0] और OpenBSD[1] में भी गई थी, लेकिन लगता है DragonFly BSD[2] में नहीं
[0] https://netbsd.org/docs/kernel/uvm.html
[1] https://man.openbsd.org/OpenBSD-3.0/uvm.9
[2] https://www.dragonflybsd.org/mailarchive/kernel/2011-04/msg0...
FreeBSD 4 तक आते-आते kernel codebase में मूल Mach code बचा ही नहीं था, और यह काम 1990 के दशक के आखिर में ही पूरा हो चुका था, इसलिए FreeBSD को Mach से जोड़ना हो तो वह सिर्फ बहुत शुरुआती branch/base चरण तक ही सीमित रहेगा
NetBSD और OpenBSD ने भी इसे कुछ समय तक जारी रखा, लेकिन Mach design की performance, SMP/scalability और networking सीमाओं से टकराने के बाद Chuck Cranor द्वारा design और lead किए गए UVM (Unified Virtual Memory) के रूप में पूरा rewrite किया, और OpenBSD ने बाद में यह implementation उधार लेकर आज तक इस्तेमाल किया है
अभी जीवित BSDs[1] में Mach का उपयोग जारी रखने वाला सिर्फ XNU/Darwin है, और वह भी Mach 2.5 नहीं बल्कि Mach 3 है। Mach 2.5, 3 और 4 (GNU/Hurd, Mach 4 का उपयोग करता है) मौजूद थे, लेकिन compatibility कम थी और वे मुख्यतः पूरे architecture स्तर के प्रभाव ही साझा करते थे, इसलिए उन्हें एक ही lineage के बजाय समान प्रभाव से निकले अलग designs के रूप में देखना बेहतर है
[0] वैसे शुरू से ही ऐसे निशान बहुत ज्यादा नहीं थे
[1] DragonBSD अब मरा हुआ है या अभी भी जीवित है, यह भी पक्का नहीं पता
Darwin में यह दिलचस्प है कि उसके core components कितनी तेजी से radical बदलाव झेलते हैं। System call backward compatibility छोड़ना, mandatory code signing, और dynamic executable loading को तेज करने के लिए individual system library files को हटाकर dyld_shared_cache तक—यह nostalgia या किसी पवित्र परंपरा के बिना, पूरी तरह results-oriented design जैसा लगता है
यह ऐसा approach लगता है जिसे Apple जैसी बड़ी hardware company ही निभा सकती है
[1] https://www.theregister.com/2025/03/08/kernel_sanders_apple_...
लेख में कहा गया था कि swap files को manage करने वाला pager daemon user space में चलता है, और kernel memory भी swap हो सकती है, लेकिन यह नहीं बताया गया कि user-space daemon kernel memory को swap कैसे करता है
जिज्ञासा है कि क्या special daemons के लिए कोई hardcoded exception है, या फिर यह special system calls का उपयोग करता है। User-space memory management के ठोस विवरण कहाँ देखे जा सकते हैं?
https://web.mit.edu/darwin/src/modules/xnu/osfmk/man/memory_...
लेकिन यह स्पष्ट नहीं है कि Darwin ने इस सुविधा का कभी वास्तव में उपयोग किया भी था या नहीं, और कम-से-कम पिछले लगभग 20 वर्षों से तो इसका उपयोग नहीं हुआ है। dynamic_pager ने कभी इस interface का उपयोग नहीं किया; XNU जब swap की कमी की सूचना देता था, तब यह swap files बनाकर
macx_swaponऔरmacx_swapoffsystem calls के जरिए उन्हें kernel को सौंपता था—यह कहीं अधिक सीमित Mach interface था। असली swapping kernel ही करता था, और पुराना dynamic_pager code यहाँ है:https://github.com/apple-oss-distributions/system_cmds/blob/...
अब वह functionality भी kernel में चली गई है, इसलिए मौजूदा dynamic_pager व्यावहारिक रूप से लगभग कुछ नहीं करता:
https://github.com/apple-oss-distributions/system_cmds/blob/...
Kernel memory का अधिकांश हिस्सा wired होता है, इसलिए उसे page out नहीं किया जा सकता, लेकिन kernel
IOMallocPageableजैसी विधियों से स्पष्ट रूप से pageable memory माँग सकता है, और ऐसी memory को disk पर swap किया जा सकता है। हालांकि इसका उपयोग लगभग नहीं के बराबर है, और ऐसे code को deadlock से बचाने के लिए बहुत सावधानी रखनी पड़ती है। भले ही user space अब सीधे “paging” में शामिल न हो, FSKit या FUSE-आधारित user-space file systems, disk image के ऊपर file systems, या NFS/SMB जैसे मामले जहाँ user-space networking extensions एक-दो स्तर नीचे शामिल होते हैं, अब भी आम हैं। हालांकि आखिरी हिस्सा गलत भी हो सकता है। ऐसे file systems जहाँ user space बीच में आता है, वे निश्चित रूप से संभव हैं, लेकिन ऐसे file system के ऊपर swap रखना शायद supported न होजब भी Darwin kernel की कहानी देखता हूँ, यह सोचकर जिज्ञासा होती है कि अगर Apple ने बस Linux को fork करके उसके ऊपर OS services बनाई होतीं, तो कितना अलग होता
खासकर यह देखकर कि Apple Darwin को लेकर कितना जुनूनी है, लगता है कि open source ने जो खोया और Apple को जो समय·लागत लगानी पड़ती है, उसके मुकाबले मिलने वाला लाभ असंतुलित है, इसलिए इसका प्रभाव अच्छा नहीं लगता
1990 के दशक के आखिर का Linux भी साफ तौर पर बेहतर विकल्प नहीं था, और OS X के कुछ versions के बाद जब वह consumer PC पर सबसे सफल UNIX-परिवार का OS बन गया, तब Linux-based में बदलना ऐसा फैसला होता जिसमें short-term फायदा लगभग नहीं और सिर्फ लागत व जोखिम ज्यादा होता
अगर Apple ने classic MacOS को 5 साल और खींचा होता, या Linux 5 साल पहले mature हुआ होता, तो OS X transition बहुत अलग हो सकता था। लेकिन pre-2.6 Linux kernel के लिए XNU को छोड़ना तर्कसंगत नहीं था
आज के नज़रिए से FreeBSD में Darwin के फायदे और Linux-शैली के open source स्वभाव, दोनों काफी हद तक साथ मिलते हैं। अगर आप Apple की लगातार बढ़ती dependency के बिना ज्यादा सुरक्षित environment चाहते हैं, तो FreeBSD और दूसरे BSDs को deployment target के रूप में सोचा जा सकता है
https://en.m.wikipedia.org/wiki/MkLinux
ऐसा नहीं लगता कि Macintosh GUI और application ecosystem को Linux पर लाने का काम हुआ था। लेकिन NeXT acquisition से पहले भी Apple, 68k Mac के लिए A/UX और बाद में Solaris तथा HP-UX के लिए Macintosh Application Environment के ज़रिए Unix पर Macintosh environment चला रहा था, और दूसरे वाले में Mac OS एक Unix process के रूप में चलता था। अगर मुझे सही याद है, तो Macintosh Application Environment पर हुआ काम ही Rhapsody के Blue Box और बाद के Mac OS X Classic environment की नींव बना। सिद्धांत रूप से Macintosh Application Environment को MkLinux पर port करने की कल्पना की जा सकती है। 1996 तक BSD से जुड़े मुकदमे का settlement हो चुका था, इसलिए आधुनिक free open source BSDs भी पहले से मौजूद थे
बेशक, 1990 के दशक के मध्य में classic Mac OS को Linux, FreeBSD, BeOS, Windows NT जैसे modern OS के ऊपर एक process के रूप में चलाना consumer desktop strategy के हिसाब से व्यावहारिक नहीं था। इसके लिए workstation-स्तर के resources चाहिए थे, जबकि Apple तब भी 68k Mac को support कर रहा था, और Mac OS 8 कुछ 68030/68040 machines पर भी चलता था। G3/G4 दौर में यह ज्यादा यथार्थवादी होता, और 2000 के दशक में हर classic Macintosh program को modern OS के ऊपर अलग Mac OS process के रूप में चलाना भी संभव हो सकता था, लेकिन Jobs की वापसी के बिना Apple शायद 1998 के आगे नहीं निकल पाता। इसके अलावा, NeXT acquisition ने Cocoa, IOKit, Quartz (Display PostScript का successor) और दूसरी आज की core technologies भी Mac तक पहुँचाईं
दूसरे नज़रिए से देखें तो यह कुछ वैसा लगता है जैसे कोई कहे कि Apple को Safari को Chromium पर ले जाना चाहिए
अगर Apple ने Linux को fork किया होता, तो कानूनी रूप से उसे शायद सारे kernel modules को open source के रूप में जारी करना पड़ता। मानवता के लिए यह शायद अच्छा होता, लेकिन Apple यही नहीं चाहता
इस लेख में काफी लगाव और मेहनत गई है। मैंने इस इतिहास का बड़ा हिस्सा खुद देखा है, NeXTSTEP code को Windows पर port करने की कोशिश की है, GNUStep के recreation प्रयासों को खंगाला है, YellowBox और OpenStep को याद करता हूँ, internal architecture की किताबें पढ़ी हैं, और लगातार WWDC content देखता रहा हूँ; उस नज़रिए से देखें तो अलग-अलग systems कैसे evolve हुए, इस बारे में मेरी यादों से यह लगभग पूरी तरह मेल खाता है
Jobs ने Torvalds को Mac OS X पर काम करने के लिए लाने की कोशिश की थी, और Linus ने मना कर दिया: https://www.macrumors.com/2012/03/22/steve-jobs-tried-to-hir...
मुझे पक्का नहीं कि I/O Kit को C++ के इस subset में लिखने की वजह सिर्फ performance थी। उस समय इस पर विवाद था। Apple ने जब MacOS X की घोषणा की, तब कहा गया कि यह पुराने software के साथ compatible नहीं होगा और सभी partners को सब कुछ Objective-C में फिर से लिखना होगा
प्रतिक्रिया अच्छी नहीं रही, तो Apple पीछे हटा और C++ applications के लिए API layer Carbon तथा Objective-C आधारित Foundation की बुनियाद Core Foundation लेकर आया। Obj-C++ के होने की एक वजह यह भी है। दिलचस्प हिस्सा यह है कि memory management को toll-free bridging बनाया गया। यानी C/C++ दुनिया में allocated object को बिना अतिरिक्त overhead के Obj-C में pass किया जा सकता है
Apple को XNU के आसपास एक बेहतर free open source community बनानी चाहिए थी। ARM पर जाने के बाद भी x64 पर चलने वाली distributions होनी चाहिए थीं
मैं Darwin को इतनी गहराई से समझना चाहता था, यह एक अच्छा लेख था
लेख के अंत में इसका उद्धरण भी है। यह macOS के इतिहास में लंबे समय तक याद रखे जाने लायक सामग्री है
आधारभूत NT kernel इतना flexible है कि POSIX compliance की अनुमति दे सके, इसलिए अगर इस तरह की बातें कवर की जाएँ तो यह एक दिलचस्प लेख होगा
इतिहास का अच्छा सार है, लेकिन Apple के operating system को Linux या Windows से अलग करने वाले बेहतरीन security work का बड़ा हिस्सा छोड़ दिया गया है। लगता है कि security के मामले में Apple आज कितना आगे है, इसका सही आकलन नहीं हो रहा। कभी न कभी यह समझ बढ़ेगी और शायद sensitive environments में काम करने वाले लोगों के लिए CISO Mac इस्तेमाल करना अनिवार्य कर देंगे
इसका मूल code signing system है। यह apps को permissions देने या उन्हें sandbox में बंद करने की सुविधा देता है, और यह भी सुनिश्चित करता है कि वह enforcement वास्तव में लागू रहे। Apple ज़्यादातर UNIX systems की तरह ELF का इस्तेमाल नहीं करता, बल्कि Mach-O नाम का format इस्तेमाल करता है। ELF और Mach-O के बीच ज़्यादातर फर्क महत्वपूर्ण नहीं हैं, लेकिन यह बात महत्वपूर्ण है कि Mach-O signed code directory रखने के लिए एक अतिरिक्त section को support करता है। code directory में code pages के hashes होते हैं, kernel इस data structure को कुछ हद तक समझता है, और dyld binary या library लोड होने पर इसे जोड़ सकता है। XNU code directory signature की जांच करता है, और VMM subsystem code pages की ज़रूरत पड़ने पर उन्हें लोड करते समय hash निकालकर यह verify करता है कि वे directory के signed hashes से मेल खाते हैं या नहीं। इसलिए code directory hash, Apple ecosystem के भीतर किसी भी program के लिए एक unique identifier की तरह काम कर सकता है। इसमें एक bug है: यह linkage Mach vnode structure से जुड़ा होता है, इसलिए अगर आप signed binary को overwrite करके चलाते हैं, तो नई file signature valid होने पर भी kernel नाराज़ होकर process को मार देता है। नई स्थिति को पहचानने के लिए पूरी file को वास्तव में replace करना पड़ता है
इसी आधार पर Apple code requirements बनाता है। यह एक छोटा expression language में लिखा गया program होता है जो code signature की कई properties पर constraints व्यक्त करता है। आप ऐसी requirements लिख सकते हैं जैसे “यह binary Apple द्वारा signed होनी चाहिए”, “certificate authority Y के अनुसार identity X वाले principal द्वारा signed इस binary का कोई भी version स्वीकार्य है”, या “इस binary का cdhash Z होना चाहिए”, यानी बिल्कुल वही binary होनी चाहिए। binary दूसरे parties को यह बताने के लिए designated requirements भी expose कर सकती है कि वह किस requirement के आधार पर अपनी पहचान चाहती है। शुरू में यह overkill लग सकता है, लेकिन इससे program evolve होने पर भी एक stable और unforgeable identity बनाए रख सकता है
kernel किसी task की signed identity को ports के माध्यम से दूसरे tasks के सामने expose करता है। user-space libraries constraint language को interpret कर सकती हैं और उन ports पर requirements लागू कर सकती हैं। उदाहरण के लिए, अगर कोई program system keychain में key store करता है, तो user space में implemented keychain daemon RPC भेजने वाले program की designated requirement की जांच करता है और बाद में key इस्तेमाल करने के अनुरोधों से उसका मिलान करता है
इस system को entitlements के रूप में abstract किया गया है। entitlements, permissions को व्यक्त करने वाले key=value pairs होते हैं। system खुला है, इसलिए apps अपने खुद के entitlements भी define कर सकते हैं, लेकिन ज़्यादातर Apple define करता है। कुछ पूरी तरह optional होते हैं, इसलिए सिर्फ request करने पर OS उन्हें automatically और silently allow कर देता है। पहली नज़र में यह बेकार लग सकता है, लेकिन इससे App Store को पहले से यह बताने में मदद मिलती है कि app क्या करेगा, और अधिक सामान्य रूप से यह least-privilege approach को सक्षम बनाता है, जिसमें app उन चीज़ों तक access नहीं कर सकता जिनकी उसे ज़रूरत नहीं है। कुछ के लिए provisioning profile जैसे अतिरिक्त proof की ज़रूरत होती है। यह Apple द्वारा दिया गया signed CMS data structure होता है, जिसका लगभग मतलब होता है “designated requirement X वाला app restricted entitlement Y का इस्तेमाल कर सकता है”, इसलिए इसे इस्तेमाल करने के लिए Apple की अनुमति चाहिए। और कुछ को वास्तव में एक general-purpose signing flag system की तरह misuse किया जाता है और उनका security से कोई संबंध नहीं होता
यह system user space और XNU के सहयोग से और आगे बढ़ता है। binaries को sign कर पाना तो सिर्फ शुरुआत है; कई programs के पास data files भी होती हैं। यहाँ Apple का security system थोड़ा patchwork जैसा लगता है। kernel data file integrity checking में शामिल नहीं होता। इसके बजाय, कुछ हद तक मनमाने bundle directory structure में एक खास जगह plist रखा जाता है, उस plist में bundle के भीतर की सभी data files के per-file hashes होते हैं, plist का hash code signature में शामिल होता है, और अंत में Gatekeeper पहली run के समय पूरे bundle की जांच करता है। kernel Gatekeeper से पूछता है कि program execution की अनुमति दी जाए या नहीं, और Gatekeeper यह निर्णय file पर लगे extended attributes की मौजूदगी के आधार पर करता है, जिन्हें web browser या archive extraction tools जैसे GUI tools propagate करते हैं। Finder जैसे user-space OS code, program के पहली बार download होने पर Gatekeeper को बुलाकर verification कराते हैं, और Gatekeeper bundle की हर file का hash निकालकर जांचता है कि वह binary में signed सामग्री से मेल खाती है या नहीं। इसलिए macOS में पहली बार launch पर धीमा “Verifying app” dialog दिखाई देता है। लगता है कि यह इस तरह डिजाइन किया गया है कि जो apps
mmapका इस्तेमाल नहीं करते और बड़ी data files खोलते हैं, वे अटकें नहीं, लेकिन अफ़सोस यह है कि तेज़ network पर unoptimized Gatekeeper verification खुद download से भी धीमा हो सकता है। Apple शायद store के बाहर distribution को legacy technology मानता है, इसलिए इस पर ज़्यादा ध्यान नहीं देताअंत में Seatbelt है। यह sandbox rules को व्यक्त करने वाली Lisp-आधारित programming language है। इन files को user space में किसी bytecode में compile किया जाता है, जिसे kernel evaluate करता है। यह language काफ़ी sophisticated है, इसलिए पूरी तरह code signing identity के आधार पर अलग-अलग system components कैसे interact करते हैं और क्या कर सकते हैं, इसके लिए मनचाहे rules व्यक्त किए जा सकते हैं
इस व्यवस्था में एक साफ़ छेद था, जिसे हाल की releases में जाकर बंद किया गया। data files code रख सकती हैं, लेकिन उनकी जांच सिर्फ एक बार होती थी। Electron या JVM apps में वास्तव में ऐसा ही होता है, क्योंकि code एक portable format में मौजूद होता है। इसलिए एक app data files को modify करके दूसरे app में code inject कर सकता था और code signing को bypass कर सकता था। नवीनतम macOS में इसे रोकने के लिए Seatbelt सभी running apps को sandbox करता है। जहाँ तक मुझे पता है, आधुनिक macOS में sandbox के बाहर कोई code नहीं है। sandbox policies में से एक यह है कि कोई app बिना अनुमति दूसरे app की data files modify नहीं कर सकता। policies काफ़ी sophisticated हैं: Apple द्वारा verify किए गए एक ही legal entity से signed apps एक-दूसरे को modify कर सकते हैं, कोई app code requirements से मेल खाने वाले दूसरे apps द्वारा modification की अनुमति दे सकता है, और ज़रूरत पड़ने पर user भी permission दे सकता है। इसे जांचने के लिए Settings -> Privacy & Security -> App Management में Terminal.app की permission बंद करें, उसे restart करें, फिर
vim /Applications/Google Chrome.app/Contents/Info.plistजैसा command चलाएँ। file permissions rw होने के बावजूद vim उसे read-only मानेगायहाँ से आगे, क्योंकि मैं Apple में काम नहीं करता, मेरी समझ भी यहीं तक है। मेरी जानकारी में kernel app bundles को नहीं समझता, और यह भी स्पष्ट नहीं है कि वह
open()system call को read-only में बदलने का निर्णय कैसे लेता है। मेरा अनुमान है कि default Seatbelt policy, kernel को इस तरह बनाती है कि वह किसी security daemon को upcall करे जो bundle format और SQLite permission database पढ़ना जानता हो, और वह daemon opener की designated requirement की तुलना bundle और sandbox द्वारा व्यक्त policy से करके फैसला करता होमुझे नहीं लगता कि ऐसे फीचर्स को सुरक्षा कहना उचित है
मेरे विचार में सुरक्षा का मतलब हमेशा कंप्यूटर के मालिक या उपयोगकर्ता की सुरक्षा होना चाहिए
Apple के ऐसे फीचर्स का इस्तेमाल सुरक्षा बढ़ाने के लिए किया जा सकता है, लेकिन उनका मुख्य डिज़ाइन उद्देश्य यह है कि कंप्यूटर बेचने वाला vendor उस डिवाइस पर, जो अब सैद्धांतिक रूप से उसका नहीं रहना चाहिए, मालिक उसे कैसे इस्तेमाल करता है इस पर और कड़ा नियंत्रण रख सके। यानी दिशा यह है कि Apple तय कर सके कि अंतिम उपयोगकर्ता कौन-से प्रोग्राम चला सकता है