Phân tích chuyên sâu Darwin OS và nhân XNU của Apple
(tansanrao.com)- Darwin của Apple là nền tảng kiểu Unix cho macOS, iOS và các hệ điều hành Apple hiện đại, còn XNU là nhân lai kết hợp Mach và BSD trong cùng một nhân
- XNU giữ lại task, thread, bộ nhớ ảo và IPC dựa trên cổng của Mach, đồng thời đặt các dịch vụ BSD trong cùng không gian địa chỉ nhân để giảm chi phí truyền thông điệp của mô hình vi nhân thuần túy
- Dòng dõi Mach 2.5+4.3BSD của NeXTSTEP đã tiếp nối thành Mac OS X và Darwin sau khi Apple mua lại NeXT vào năm 1996, rồi dần được bổ sung mã FreeBSD, I/O Kit, 64-bit, ARM và hỗ trợ Apple Silicon
- macOS và iOS đã mở rộng các tính năng như sandbox, ký mã, SIP, APFS, DriverKit, lập lịch QoS, Jetsam và bộ nhớ nén thông qua sự phối hợp giữa nhân và không gian người dùng
- Sự tiến hóa của XNU gần với cách giữ nguyên nền tảng Mach/BSD thay vì viết lại nhân, tích hợp vào trong nhân những phần cần hiệu năng và tách những phần cần cô lập sang IPC cùng không gian người dùng
Điểm khởi đầu của Darwin và XNU
- Darwin là hệ điều hành lõi kiểu Unix nâng đỡ macOS, iOS và các nền tảng OS hiện đại của Apple
- Ở trung tâm là nhân XNU, viết tắt của “X is Not Unix”, kết hợp lõi vi nhân Mach với các thành phần Unix BSD
- Cấu trúc này tận dụng đồng thời thiết kế dựa trên truyền thông điệp của Mach và tính ổn định cùng khả năng tương thích POSIX của BSD, nhằm cân bằng giữa tính mô-đun và hiệu năng
Lịch sử từ Mach qua NeXTSTEP đến Mac OS X
- Mach bắt đầu là một dự án do Richard Rashid và Avie Tevanian dẫn dắt tại Carnegie Mellon University vào năm 1985
- Đây là thiết kế vi nhân với mục tiêu chỉ giữ các chức năng mức thấp như quản lý bộ nhớ, lập lịch CPU và IPC trong nhân, còn hệ thống tệp, mạng và driver sẽ đặt ở các server không gian người dùng
- Các khái niệm như task, thread, Mach port, copy-on-write và memory object trở thành các đối tượng cốt lõi của nhân
- NeXTSTEP được phát hành năm 1989 bằng cách đặt subsystem Unix 4.3BSD lên trên nhân Mach 2.5
- NeXT ưu tiên hiệu năng bằng cách tích hợp mã BSD vào không gian địa chỉ nhân thay vì theo đuổi mô hình vi nhân thuần túy
- Nó cũng bao gồm DriverKit dựa trên Objective-C, và sau đó nối tiếp thành dòng dõi XNU của Apple
- Apple mua lại NeXT vào năm 1996 và chọn NeXTSTEP làm nền tảng cho Mac OS X mới
- Dự án Rhapsody được khởi động, đưa nhân lai Mach/BSD của NeXT vào Apple
- Sau đó XNU tiếp nhận mã Mach 3.0 dựa trên OSFMK 7.3 cùng mã 4.4BSD và FreeBSD
Giai đoạn phát triển ban đầu của Darwin và Mac OS X
- Apple phát hành bản developer preview của Mac OS X vào năm 1999, rồi công bố Darwin 1.0 vào năm 2000 để mở nhân XNU cùng không gian người dùng Unix cơ bản cho giới phát triển
- Mac OS X 10.0 Cheetah được phát hành thương mại năm 2001 dựa trên Darwin 1.3.1
- Trọng tâm thay đổi thời kỳ đầu là tăng cường lớp BSD, mạng, hệ thống tệp và hiệu năng thread
- Mac OS X 10.1 Puma cải thiện hiệu năng quản lý thread và hỗ trợ thread thời gian thực
- Mac OS X 10.2 Jaguar bao gồm IPv6, IPSec,
mDNSRespondervà journaling cho HFS+ - Mac OS X 10.3 Panther tích hợp các cải tiến nhân FreeBSD 5 và khóa nhân tinh hạt hơn để tăng khả năng tận dụng đa bộ xử lý
- Mac OS X 10.4 Tiger đạt chứng nhận UNIX 03, đưa vào
kqueue/keventtừ FreeBSD và duy trì nền tảng đa nền tảng cho quá trình chuyển sang Intel Mac
64-bit và iPhone OS mang đến yêu cầu di động
- Mac OS X 10.5 Leopard dựa trên Darwin 9, đưa vào khả năng chạy nhân 64-bit, driver 64-bit, ASLR, sandbox và DTrace
- iPhone OS đầu tiên năm 2007 cũng phát hành trên nền Darwin 9, mở rộng XNU tới thiết bị di động ARM
- iPhone đời đầu có RAM hạn chế và không thể dùng swap, nên sử dụng cơ chế Jetsam để chấm dứt ứng dụng nền khi bộ nhớ thấp
- iPhone OS chạy ứng dụng bên thứ ba trong sandbox và yêu cầu ký mã rất nghiêm ngặt với binary
- Mac OS X 10.6 Snow Leopard chấm dứt hỗ trợ PowerPC và tăng cường tối ưu 64-bit cùng đa lõi tập trung vào Intel
- Grand Central Dispatch và
libdispatchlà thư viện không gian người dùng, nhưng tận dụng thread pool và hỗ trợ lập lịch của nhân - OpenCL cũng cần tích hợp chặt chẽ giữa framework không gian người dùng và driver trong nhân cho tính toán GPU
- Grand Central Dispatch và
- iOS 4 điều chỉnh scheduler để phù hợp với việc phân biệt mức ưu tiên ứng dụng nền và hỗ trợ ARM SoC đa lõi
Mở rộng tính năng nhân trong macOS và iOS hiện đại
- OS X 10.9 Mavericks bổ sung bộ nhớ nén và timer coalescing
- Bộ nhớ nén nén các trang không hoạt động ngay trong RAM để giảm swap ra đĩa
- Timer coalescing căn chỉnh thời điểm CPU thức dậy để giảm điện năng tiêu thụ
- OS X 10.11 El Capitan giới thiệu System Integrity Protection, tức SIP
- SIP được nhân thực thi thông qua framework Mandatory Access Control của lớp BSD, khiến ngay cả tiến trình root cũng không thể sửa đổi các tệp và tiến trình hệ thống quan trọng
- macOS 10.13 High Sierra đưa APFS thành hệ thống tệp mặc định
- Lớp VFS của XNU được mở rộng để hỗ trợ snapshot, cloning và mã hóa ở cấp container của APFS
- Cùng thời điểm đó, việc nạp kext bên thứ ba bắt đầu yêu cầu người dùng chấp thuận
- macOS 10.15 Catalina giới thiệu DriverKit hiện đại
- DriverKit chuyển nhiều driver ra ngoài nhân thành Driver Extension trong không gian người dùng
- Nhân cung cấp quyền truy cập phần cứng có giới hạn cho driver không gian người dùng thông qua IPC và shared memory
- Catalina cũng đưa vào system volume chỉ đọc để tăng cường bảo vệ của SIP
XNU trong kỷ nguyên Apple Silicon
- macOS 11 Big Sur và Darwin 20 năm 2020 là bản phát hành đầu tiên hỗ trợ máy Mac Apple Silicon
- XNU vốn đã hỗ trợ ARM thông qua iOS, nhưng với Mac Apple Silicon nó còn phải tính đến cả kiến trúc CPU big.LITTLE không đồng nhất
- Scheduler nhận biết lõi không đồng nhất để có thể đặt thread ưu tiên cao và tải nặng lên performance core, còn thread QoS thấp hoặc nền lên efficiency core
- Các lớp QoS cũng có thể được dùng như gợi ý lập lịch ảnh hưởng đến việc chọn loại lõi trên Apple Silicon
- Trong kiến trúc bộ nhớ hợp nhất của Apple Silicon, bộ quản lý bộ nhớ của nhân và driver GPU cùng quản lý việc chia sẻ buffer
- Trừu tượng Mach VM phù hợp để chia sẻ memory object giữa không gian người dùng và GPU bằng VM remapping thay vì sao chép
- Backend ARM64 hỗ trợ Pointer Authentication, dùng khóa PAC cho exception frame và system pointer, góp phần giảm thiểu tấn công ROP
- XNU vẫn là nền tảng chung cho nhiều nền tảng Apple như macOS, iOS, watchOS, tvOS, bridgeOS và visionOS
Kiến trúc nhân lai của XNU
- Các thành phần Mach và BSD của XNU được liên kết thành một binary nhân duy nhất và chia sẻ cùng không gian địa chỉ
- Không có ranh giới bảo vệ giữa Mach và BSD, và bên trong nhân chúng tương tác bằng lời gọi hàm thông thường thay vì thông điệp IPC
- Lời gọi hệ thống Unix như
read()không gửi thông điệp tới một BSD server riêng mà đi thẳng vào mã hệ thống tệp BSD bên trong nhân
- Mach đảm nhiệm hạ tầng nhân cốt lõi
- Nó quản lý việc tạo và kết thúc task, thread, chuyển ngữ cảnh, lập lịch mức thấp, lock, timer và hàng đợi lập lịch
- Mỗi tiến trình BSD tương ứng với một Mach task, và mỗi thread tương ứng với một Mach thread
- Mach VM cung cấp virtual address map, memory object, copy-on-write và chia sẻ bộ nhớ dựa trên IPC
- BSD cung cấp tính chất và dịch vụ kiểu Unix
- Nó quản lý PID, user ID, signal, POSIX thread, hệ thống tệp, mạng, Unix IPC, device I/O, cùng framework quyền hạn và bảo mật
- VFS xử lý các hệ thống tệp như HFS+, APFS và NFS, còn với tệp ánh xạ bộ nhớ thì kết nối qua Mach VM và vnode pager
- Sandbox và SIP hoạt động nhờ sự phối hợp giữa các mô-đun bảo mật BSD và giới hạn Mach task port
- I/O Kit là trụ cột thứ ba của XNU, một framework driver hướng đối tượng viết bằng biến thể C++ bị giới hạn
- Nó biểu diễn thiết bị và driver dưới dạng phân cấp lớp, còn driver chạy như đối tượng C++ trong nhân
- Với không gian người dùng, nó cung cấp quyền truy cập có giới hạn thông qua thuộc tính I/O Registry và giao diện user client
- Trước DriverKit của macOS hiện đại, phần lớn driver hoạt động dưới dạng kext trong nhân
Mach IPC và các dịch vụ hệ thống
- XNU không dùng thông điệp Mach cho đường đi của system call Unix, nhưng tận dụng Mach IPC rất rộng rãi cho giao tiếp giữa dịch vụ không gian người dùng với nhân và giữa các tiến trình
- Mach port được dùng làm handle không gian người dùng cho nhiều đối tượng nhân
- Mỗi task có một task port, và tiến trình có đặc quyền có thể dùng nó để kiểm tra hoặc điều khiển task khác
- Sự kiện và thông báo cũng được truyền bằng thông điệp Mach
- WindowServer nhận sự kiện đầu vào người dùng từ nhân dưới dạng thông điệp Mach
- Grand Central Dispatch nội bộ dùng Mach port để đưa thread chờ sự kiện vào trạng thái ngủ
kqueue/keventcó thể chờ đồng thời cả thông điệp Mach port và file descriptor
- Framework XPC của Apple được xây dựng trên thông điệp Mach
- Kết nối XPC nội bộ dựa trên Mach port
- Mô hình quyền hạn của Mach port được dùng trong các dịch vụ như
securitydcủa Keychain để xác minh quyền của bên gọi - Thông điệp Mach có thể truyền out-of-line memory và quyền truy cập port, nên được dùng để xây dựng RPC mức cao
- MIG, tức Mach Interface Generator, được dùng để sinh định nghĩa giao diện và mã gửi nhận thông điệp giữa nhân với không gian người dùng
Scheduler và quản lý thread
- Scheduler của XNU bắt đầu từ scheduler round-robin dựa trên ưu tiên của Mach, nhưng đã được sửa đổi mạnh để phù hợp với nhu cầu desktop và di động
- Trong lịch sử, Mach định nghĩa mức ưu tiên thread trong khoảng 0~127, còn XNU dùng các giá trị như
sched_privàbase_pri- Thread chia sẻ thời gian có thể thay đổi ưu tiên theo mức sử dụng
- Thread thời gian thực dùng ưu tiên cố định
- XNU xử lý hiệu quả và cân bằng tải bằng hàng đợi chạy theo từng CPU và scheduler interrupt
- Sandbox ứng dụng và thực thi nền trên iOS phản ánh các khái niệm vai trò công việc hoặc nhóm ưu tiên vào scheduler
- Các lớp QoS được tích hợp vào lập lịch từ iOS 8 và OS X 10.10 trở đi
- Các lớp như user-interactive, user-initiated, default, utility và background ảnh hưởng đến dải ưu tiên và cách lập lịch
- Thread được tạo bằng Grand Central Dispatch hoặc NSThread sẽ kế thừa QoS
- Trên Apple Silicon, thread QoS nền có thể được đặt lên efficiency core
- Hệ thống cũng hỗ trợ hàng đợi thời gian thực và lập lịch dựa trên deadline cho âm thanh thời gian thực và các tác vụ quan trọng
Quản lý bộ nhớ và Mach VM
- Quản lý bộ nhớ của XNU lấy subsystem Mach VM làm trung tâm
- Mỗi Mach task có một không gian địa chỉ ảo được biểu diễn bằng VM map và VM region
fork()dùng copy-on-write thay vì sao chép toàn bộ bộ nhớ ngay lập tức- Tiến trình cha và con chia sẻ cùng trang cho đến khi có ghi
- Mach dùng khái niệm memory object và pager
- Với bộ nhớ ẩn danh, default pager do daemon không gian người dùng
dynamic_pagerđảm nhiệm để quản lý swap file khi cần - Với bộ nhớ tệp, vnode pager trong lớp BSD của nhân tương tác với mã hệ thống tệp
- Với bộ nhớ ẩn danh, default pager do daemon không gian người dùng
- Bộ nhớ nén của Mavericks được triển khai bằng cách thêm compression pager trong nhân
- Khi áp lực bộ nhớ cao, các trang không hoạt động không bị đẩy ngay ra đĩa mà được nén và lưu trong compressor pool trong RAM
- Chỉ khi nén vẫn không đủ thì mới dùng swap ra đĩa
- Quản lý bộ nhớ vật lý do lớp phụ thuộc kiến trúc pmap đảm nhiệm
- pmap quản lý page table hoặc cấu trúc tương ứng của kiến trúc đó
- Trên ARM64, các tính năng bảo mật và vấn đề liên quan cache cũng gắn với pmap
- Shared cache của
dyldsử dụng hiệu quả bằng cách ánh xạ cùng một trang vật lý dưới dạng chỉ đọc cho nhiều tiến trình
Hỗ trợ ảo hóa
- Trên Intel Mac, Hypervisor.framework được cung cấp từ OS X 10.10 để hỗ trợ ảo hóa trong không gian người dùng
- Nó dùng Intel VT-x để cho phép tiến trình không gian người dùng hoạt động như virtual machine monitor
- Các công cụ như
xhyvevà một số ứng dụng ảo hóa đã tận dụng khả năng này
- Trên Apple Silicon, Virtualization.framework của macOS 11 hoạt động trên hypervisor trong nhân dành cho ARM64
- Lập trình viên có thể chạy VM Linux hoặc macOS từ không gian người dùng
- Thay vì cho phép hypervisor bên thứ ba tùy ý vào trong nhân, Apple dùng cách tiếp cận truy cập thông qua framework và quyền hạn của mình
- Ở góc nhìn của nhân, các chức năng hypervisor bao gồm quản lý bộ nhớ vật lý của khách, trap-and-emulate cho lệnh nhạy cảm và phơi bày giao diện vCPU
- Scheduler của Mach lập lịch các vCPU vốn là thread dưới góc nhìn của host, còn subsystem bộ nhớ được dùng cho ánh xạ bộ nhớ khách
- Trên iOS, khả năng ảo hóa cũng có thể thực hiện trong một số điều kiện và quyền hạn nhất định; từng có trường hợp kích hoạt hypervisor trên thiết bị A14 đã jailbreak để chạy Linux VM
Secure Enclave và Exclaves
- macOS dùng hai cơ chế cô lập là Secure Enclave và exclaves để bảo vệ các tác vụ và dữ liệu nhạy cảm
- Secure Enclave là một subsystem tăng cường bảo mật chuyên dụng được tích hợp trong Apple SoC
- Nó có mặt trên iPhone, iPad, T2 hoặc máy Mac Apple Silicon
- Nó chạy hệ điều hành riêng dựa trên vi nhân và quản lý thông tin nhạy cảm như khóa mật mã và dữ liệu sinh trắc học
- Mục tiêu là tách biệt dữ liệu quan trọng ngay cả khi bộ xử lý ứng dụng chính hoặc nhân bị xâm phạm
- Exclaves là cấu trúc bảo mật mới hơn xuất hiện trong macOS 14.4 và iOS 17
- Thay vì đặt các tác vụ nhạy cảm trong cùng miền đặc quyền với nhân XNU chính, một số tài nguyên cốt lõi được tách sang miền “externally located” riêng biệt
- Các tài nguyên như dịch vụ Apple ID, audio buffer, dữ liệu cảm biến và thành phần quản lý đèn báo là đối tượng của mô hình này
- Các kext chuyên biệt và private framework như ExclaveKextClient.kext, ExclaveSEPManagerProxy.kext và ExclavesAudioKext.kext tham gia quản lý
- Sự tách biệt này cung cấp thêm một lớp phòng vệ bằng cách cô lập tác vụ trong exclave ngay cả khi nhân chính bị xâm phạm
Định hướng thiết kế dài hạn
- Darwin và XNU là thiết kế lai, không phải vi nhân hoàn toàn cũng không phải nhân nguyên khối hoàn toàn
- Lõi dựa trên Mach giúp thích ứng với kiến trúc mới và tính năng hệ thống mới, còn lớp BSD cung cấp môi trường tương thích POSIX cùng công cụ và API Unix
- Apple đã dùng nền tảng XNU để tiếp nhận các lần chuyển CPU từ PowerPC sang Intel rồi ARM, cũng như các danh mục thiết bị mới như iPhone, Apple Watch và Apple Vision Pro
- Thay đổi trong nhân chủ yếu diễn ra theo ba hướng
- Mở rộng tính năng mới trên nhân hiện có
- Tích hợp vào trong nhân các thành phần quan trọng về hiệu năng
- Tách biệt các thành phần cần cô lập thông qua Mach IPC và không gian người dùng
- Các bản phát hành mã nguồn mở của Darwin mang lại cho giới nghiên cứu một cửa sổ để quan sát nhân lai thương mại này, dù phạm vi công khai vẫn có giới hạn
1 bình luận
Các ý kiến trên Hacker News
Hệ thống bộ nhớ ảo của Mach đã được đưa vào không chỉ 4.4BSD và FreeBSD mà cả NetBSD[0], OpenBSD[1], nhưng có vẻ không phải 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...
Đến thời FreeBSD 4, trong codebase kernel đã không còn mã Mach gốc; việc này đã hoàn tất từ cuối thập niên 1990, nên thứ có thể liên hệ FreeBSD với Mach chỉ là giai đoạn phân nhánh/nền tảng rất sơ khai
NetBSD và OpenBSD cũng tiếp tục một thời gian, nhưng vấp phải các giới hạn về hiệu năng, SMP/khả năng mở rộng và networking của thiết kế Mach, nên đã viết lại hoàn toàn thành UVM (Unified Virtual Memory) do Chuck Cranor thiết kế và dẫn dắt; OpenBSD sau đó mượn triển khai này và vẫn dùng đến nay
Trong số các BSD còn sống[1], XNU/Darwin là bên duy nhất còn tiếp tục dùng Mach, mà cũng không phải Mach 2.5 mà là Mach 3. Từng có Mach 2.5, 3, 4 (GNU/Hurd là Mach 4), nhưng mức tương thích thấp và chủ yếu chỉ chia sẻ ảnh hưởng ở cấp kiến trúc tổng thể, nên nên xem chúng là các thiết kế riêng biệt chịu ảnh hưởng chung
[0] Ngay từ đầu những dấu vết đó cũng không nhiều
[1] Tôi cũng không rõ DragonBSD hiện đã chết hay còn sống
Điều thú vị ở Darwin là tốc độ thay đổi triệt để của các thành phần cốt lõi. Từ việc từ bỏ tương thích ngược system call, bắt buộc code signing, cho đến dyld_shared_cache loại bỏ các file thư viện hệ thống riêng lẻ để tăng tốc tải executable động — đây là cách thiết kế hướng kết quả, không có hoài niệm hay “vùng thánh”
Có vẻ đây là cách tiếp cận chỉ một hãng phần cứng lớn như Apple mới làm được
[1] https://www.theregister.com/2025/03/08/kernel_sanders_apple_...
Bài viết nói pager daemon quản lý swap file chạy trong user space, và cả bộ nhớ kernel cũng có thể bị swap, nhưng không giải thích daemon user space swap bộ nhớ kernel như thế nào
Tôi thắc mắc liệu có ngoại lệ hard-code cho daemon đặc biệt đó, hay nó dùng system call đặc biệt. Có thể xem thêm chi tiết về quản lý bộ nhớ trong user space ở đâu?
https://web.mit.edu/darwin/src/modules/xnu/osfmk/man/memory_...
Tuy vậy không chắc Darwin từng thực sự dùng tính năng này hay chưa, và ít nhất trong khoảng 20 năm qua thì không dùng. dynamic_pager chưa từng dùng interface này; khi XNU báo thiếu swap, nó tạo swap file rồi chuyển cho kernel qua các system call
macx_swapon,macx_swapoff, dùng một interface Mach hạn chế hơn nhiều. Việc swapping thực tế do kernel thực hiện, còn mã dynamic_pager cũ ở đây:https://github.com/apple-oss-distributions/system_cmds/blob/...
Tính năng đó nay cũng đã được đưa vào kernel, nên dynamic_pager hiện tại về cơ bản gần như không làm gì:
https://github.com/apple-oss-distributions/system_cmds/blob/...
Phần lớn bộ nhớ kernel được cố định (wired) nên không thể paging, nhưng kernel có thể yêu cầu rõ ràng bộ nhớ có thể paging bằng các cách như
IOMallocPageable, và bộ nhớ đó có thể swap ra đĩa. Tuy nhiên nó hầu như không được dùng, và loại mã này phải cẩn thận để tránh deadlock. Ngay cả khi user space không còn tham gia trực tiếp vào bản thân “paging”, vẫn thường có trường hợp user space can thiệp ở một hoặc hai tầng bên dưới, như các file system user space dựa trên FSKit hoặc FUSE, file system trên disk image, hay NFS/SMB đi qua extension networking trong user space. Tuy nhiên phần cuối có thể sai. File system bị chặn bởi user space chắc chắn là có thể, nhưng đặt swap trên file system như vậy có thể không được hỗ trợMỗi khi đọc về câu chuyện kernel Darwin, tôi lại tự hỏi mọi thứ sẽ khác đến mức nào nếu Apple chỉ fork Linux rồi xây các dịch vụ OS lên trên đó
Đặc biệt khi nhìn vào mức độ Apple bám chặt lấy Darwin, tôi có ấn tượng không tốt vì những gì mã nguồn mở đã mất đi và lợi ích Apple thu được so với thời gian, chi phí họ phải bỏ ra có vẻ mất cân đối
Linux cuối thập niên 1990 rõ ràng cũng không phải lựa chọn tốt hơn, và sau khi OS X trải qua vài phiên bản rồi trở thành hệ điều hành họ UNIX thành công nhất trên PC tiêu dùng, việc chuyển sang nền tảng Linux gần như không có lợi ích ngắn hạn nào mà chỉ có chi phí và rủi ro lớn
Nếu Apple kéo dài MacOS cổ điển thêm 5 năm nữa, hoặc Linux trưởng thành sớm hơn 5 năm, quá trình chuyển đổi sang OS X có thể đã rất khác. Nhưng bỏ XNU để dùng kernel Linux trước 2.6 thì không hợp lý
Nhìn theo hiện tại, FreeBSD có khá nhiều ưu điểm của Darwin cùng tính chất mã nguồn mở kiểu Linux. Nếu muốn một môi trường an toàn hơn mà không bị lệ thuộc ngày càng nặng vào Apple, FreeBSD và các BSD khác cũng đáng được cân nhắc làm mục tiêu phân phối
https://en.m.wikipedia.org/wiki/MkLinux
Có vẻ như không có nỗ lực nào đưa GUI Macintosh và hệ sinh thái ứng dụng sang Linux. Tuy vậy, ngay cả trước khi mua NeXT, Apple đã chạy môi trường Macintosh trên Unix thông qua A/UX cho Mac 68k, rồi sau đó là Macintosh Application Environment cho Solaris và HP-UX; cái sau chạy Mac OS như một tiến trình Unix. Nếu tôi nhớ không nhầm, công việc trên Macintosh Application Environment đã trở thành nền tảng cho Blue Box của Rhapsody, rồi sau này là môi trường Classic của Mac OS X. Về lý thuyết, cũng có thể tưởng tượng việc port Macintosh Application Environment sang MkLinux. Năm 1996 cũng là sau thỏa thuận dàn xếp các vụ kiện liên quan đến BSD, nên các BSD mã nguồn mở tự do hiện đại cũng đã tồn tại
Tất nhiên, vào giữa thập niên 1990, việc chạy Mac OS cổ điển như một tiến trình trên một OS hiện đại như Linux, FreeBSD, BeOS hay Windows NT không thực tế với chiến lược desktop tiêu dùng. Nó cần tài nguyên cấp workstation, trong khi Apple vẫn còn hỗ trợ Mac 68k, và Mac OS 8 cũng chạy trên một số máy 68030/68040. Đến thời G3/G4 thì điều đó thực tế hơn, và vào thập niên 2000 thậm chí có thể chạy từng chương trình Macintosh cổ điển như các tiến trình Mac OS riêng biệt trên OS hiện đại, nhưng nếu Jobs không quay lại thì Apple có lẽ đã không sống qua năm 1998. Hơn nữa, thương vụ mua NeXT cũng đưa Cocoa, IOKit, Quartz — hậu duệ của Display PostScript — và nhiều công nghệ cốt lõi hiện nay khác lên Mac
Nhìn theo cách khác, cảm giác cũng giống đề xuất Apple nên chuyển Safari sang nền Chromium
Nếu họ fork Linux, về mặt pháp lý có thể họ đã phải mở mã nguồn tất cả các module kernel. Điều đó rất có thể là tích cực cho nhân loại, nhưng hẳn không phải hướng Apple mong muốn
Bài viết này chứa rất nhiều tâm huyết và công sức. Với tư cách một người đã trải qua phần lớn lịch sử này, từng port mã NeXTSTEP sang Windows, đào sâu vào nỗ lực tái hiện của GNUStep, còn nhớ YellowBox và OpenStep, đã đọc các sách về cấu trúc nội bộ và đều đặn xem nội dung WWDC, nó gần như khớp với ký ức của tôi về cách các hệ thống khác nhau đã tiến hóa
Jobs từng cố tuyển Torvalds vào làm Mac OS X, và Linus đã từ chối: https://www.macrumors.com/2012/03/22/steve-jobs-tried-to-hir...
Tôi không chắc I/O Kit được viết bằng tập con C++ này chỉ vì tốc độ. Khi đó từng có tranh cãi. Vì khi Apple công bố MacOS X, họ nói nó không tương thích với phần mềm hiện có và mọi đối tác phải viết lại bằng Objective-C
Khi phản ứng không tốt, Apple lùi lại và giới thiệu Carbon, một tầng API cho ứng dụng C++, cùng Core Foundation, nền tảng bên dưới Foundation dựa trên Objective-C. Đây cũng là lý do Obj-C++ tồn tại. Điểm thú vị là họ làm cho quản lý bộ nhớ có thể bridge miễn phí (toll-free). Tức là các đối tượng được cấp phát trong thế giới C/C++ có thể được chuyển sang Obj-C mà không có overhead bổ sung
Apple lẽ ra nên nuôi dưỡng một cộng đồng mã nguồn mở tự do tốt hơn quanh XNU. Ngay cả khi hiện đã chuyển sang ARM, đáng lẽ vẫn nên có một bản phân phối có thể chạy trên x64
Tôi đã muốn hiểu Darwin sâu đến mức này, và đây là một bài viết hay
Nó cũng được trích dẫn ở cuối bài viết này. Đây là tư liệu sẽ còn được lưu lại lâu dài trong lịch sử macOS
NT kernel bên dưới đủ linh hoạt để cho phép tuân thủ POSIX, nên nếu viết về những nội dung như vậy thì sẽ rất thú vị
Tóm tắt lịch sử hay, nhưng đã bỏ qua khá nhiều công việc bảo mật xuất sắc giúp phân biệt hệ điều hành của Apple với Linux hay Windows. Có vẻ Apple chưa được đánh giá đúng mức về việc hiện họ đi trước xa đến đâu về mặt bảo mật. Biết đâu một ngày nào đó nhận thức này sẽ lan rộng đến mức những người làm việc trong môi trường nhạy cảm sẽ bị CISO yêu cầu dùng Mac
Cốt lõi là hệ thống ký mã. Nó có thể cấp quyền cho ứng dụng hoặc nhốt ứng dụng trong sandbox, đồng thời giúp việc cưỡng chế đó thực sự được duy trì. Apple không dùng ELF như hầu hết UNIX, mà dùng định dạng gọi là Mach-O. Phần lớn khác biệt giữa ELF và Mach-O không quan trọng, nhưng điểm quan trọng là Mach-O hỗ trợ một section bổ sung chứa thư mục mã đã ký. Thư mục mã chứa các hash của những trang mã; kernel hiểu cấu trúc dữ liệu này ở một mức độ nhất định, còn dyld có thể liên kết nó khi binary hoặc thư viện được tải. XNU kiểm tra chữ ký của thư mục mã, và tiểu hệ thống VMM khi cần các trang mã sẽ tải chúng lên, tính hash rồi xác minh xem có khớp với hash đã ký trong thư mục hay không. Vì vậy hash của thư mục mã có thể hoạt động như một định danh duy nhất cho bất kỳ chương trình nào trong hệ sinh thái Apple. Ở đây có một lỗi: liên kết này được treo vào cấu trúc Mach vnode, nên nếu ghi đè một binary đã ký rồi chạy nó, dù chữ ký của tệp mới hợp lệ, kernel vẫn nổi giận và giết tiến trình. Để kernel nhận ra tình huống mới, phải thực sự thay thế toàn bộ tệp
Trên nền tảng này, Apple đặt thêm các yêu cầu mã. Đây là các chương trình được viết bằng một ngôn ngữ biểu thức nhỏ, dùng để mô tả ràng buộc trên nhiều thuộc tính của chữ ký mã. Có thể viết các yêu cầu kiểu “binary này phải được Apple ký”, “cho phép bất kỳ phiên bản nào của binary do chủ thể có danh tính X theo tổ chức chứng thực Y ký”, “binary này phải có cdhash Z”, tức là phải đúng chính binary đó. Binary cũng có thể công bố yêu cầu được chỉ định, cho biết nó muốn được các chủ thể khác nhận diện bằng yêu cầu nào. Ban đầu nghe có vẻ quá mức, nhưng điều này giúp chương trình duy trì một danh tính ổn định và không thể giả mạo ngay cả khi nó tiến hóa
Kernel công bố danh tính chữ ký của một tác vụ cho các tác vụ khác thông qua port. Thư viện ở user space có thể diễn giải ngôn ngữ ràng buộc và áp yêu cầu lên port đó. Ví dụ, khi một chương trình lưu khóa vào system keychain, daemon keychain được triển khai trong user space sẽ kiểm tra yêu cầu được chỉ định của chương trình gửi RPC, rồi đối chiếu với các yêu cầu sử dụng khóa về sau
Hệ thống này được trừu tượng hóa thành quyền (entitlements). Quyền là các cặp key=value biểu diễn giấy phép. Vì đây là hệ thống mở nên ứng dụng cũng có thể tự định nghĩa quyền của riêng mình, nhưng phần lớn do Apple định nghĩa. Một số hoàn toàn là dạng opt-in: chỉ cần yêu cầu thì OS sẽ tự động và âm thầm cho phép. Thoạt đầu trông có vẻ vô dụng, nhưng nó cho phép App Store mô tả trước ứng dụng sẽ làm gì, và nói rộng hơn là tạo ra thái độ đặc quyền tối thiểu, ngăn ứng dụng truy cập những thứ nó không cần. Một số quyền cần bằng chứng bổ sung như provisioning profile. Đây là cấu trúc dữ liệu CMS đã ký do Apple cung cấp, đại khái có nghĩa “ứng dụng có yêu cầu được chỉ định X có thể dùng quyền bị hạn chế Y”, nên muốn dùng thì phải được Apple cho phép. Ngoài ra, một số quyền thực tế bị lạm dụng như một hệ thống cờ ký chung và không liên quan đến bảo mật
Hệ thống còn được mở rộng hơn nhờ sự phối hợp giữa user space và XNU. Có thể ký binary mới chỉ là điểm khởi đầu, vì nhiều chương trình còn có tệp dữ liệu. Ở đây hệ thống bảo mật của Apple trông hơi giống chắp vá. Kernel không tham gia kiểm tra tính toàn vẹn của tệp dữ liệu. Thay vào đó, một plist được đặt ở một vị trí đặc biệt trong cấu trúc thư mục bundle khá tùy ý; plist đó chứa hash theo từng tệp của mọi tệp dữ liệu trong bundle; hash của plist được đưa vào chữ ký mã; và cuối cùng Gatekeeper kiểm tra toàn bộ khi chạy lần đầu. Kernel hỏi Gatekeeper có cho phép chạy chương trình hay không, và Gatekeeper quyết định dựa trên sự tồn tại của extended attribute gắn vào tệp, được các công cụ GUI như trình duyệt web hoặc công cụ giải nén truyền tiếp. Mã OS ở user space như Finder sẽ gọi Gatekeeper để kiểm tra khi chương trình được tải xuống lần đầu, còn Gatekeeper sẽ hash mọi tệp trong bundle để kiểm tra xem có khớp với nội dung đã được ký trong binary hay không. Vì vậy trên macOS khi chạy lần đầu sẽ xuất hiện hộp thoại “Verifying app” chậm chạp. Có vẻ đây là cách để tránh làm các ứng dụng mở tệp dữ liệu lớn mà không dùng mmap bị treo, nhưng đáng tiếc là trên mạng nhanh, bước xác minh Gatekeeper chưa được tối ưu có thể còn chậm hơn cả việc tải xuống. Có vẻ Apple không mấy bận tâm vì họ xem phân phối ngoài store là công nghệ legacy
Cuối cùng là Seatbelt. Đây là một ngôn ngữ lập trình dựa trên Lisp để biểu diễn quy tắc sandbox. Các tệp này được biên dịch trong user space thành một dạng bytecode nào đó để kernel đánh giá. Ngôn ngữ này khá tinh vi, có thể biểu diễn bằng các quy tắc tùy ý cách nhiều thành phần hệ thống tương tác và được phép làm gì, tất cả đều dựa trên danh tính chữ ký mã
Cơ chế trên từng có một lỗ hổng rõ ràng chỉ mới được vá trong các bản phát hành gần đây. Đó là tệp dữ liệu có thể chứa mã nhưng chỉ được kiểm tra một lần. Các ứng dụng Electron hoặc JVM thực sự như vậy, vì chúng chứa mã ở định dạng di động. Do đó một ứng dụng từng có thể sửa tệp dữ liệu để chèn mã vào ứng dụng khác và vượt qua ký mã. Trên macOS mới, Seatbelt sandbox mọi ứng dụng đang chạy để chặn việc này. Theo tôi biết, trên macOS hiện đại không có mã nào nằm ngoài sandbox. Một trong các chính sách sandbox là không cho ứng dụng sửa tệp dữ liệu của ứng dụng khác khi chưa được phép. Chính sách này khá tinh vi: các ứng dụng do cùng một pháp nhân đã được Apple xác minh ký có thể sửa lẫn nhau; ứng dụng cũng có thể cho phép ứng dụng khác đáp ứng yêu cầu mã sửa đổi mình; và người dùng cũng có thể cấp quyền khi cần. Để kiểm tra, hãy vào Settings -> Privacy & Security -> App Management, tắt quyền của Terminal.app rồi khởi động lại, sau đó chạy một lệnh như
vim /Applications/Google Chrome.app/Contents/Info.plist. Dù quyền tệp là rw, vim vẫn thấy nó ở chế độ chỉ đọcTừ đây trở đi thì tôi không làm ở Apple nên hiểu biết của tôi cũng dừng lại. Theo tôi biết, kernel không hiểu app bundle, và tôi cũng không chắc nó quyết định thế nào để biến system call
open()thành chỉ đọc. Tôi đoán chính sách Seatbelt mặc định khiến kernel thực hiện upcall tới một daemon bảo mật biết đọc định dạng bundle và cơ sở dữ liệu quyền SQLite; daemon đó so sánh yêu cầu được chỉ định của bên mở với bundle và chính sách do sandbox biểu diễn để đưa ra quyết địnhTôi không nghĩ gọi những tính năng như vậy là bảo mật là phù hợp
Theo tôi, bảo mật luôn phải chỉ sự an toàn của chủ sở hữu hoặc người dùng máy tính
Những tính năng này của Apple có thể được dùng để tăng cường bảo mật, nhưng mục đích thiết kế chính là để nhà cung cấp đã bán máy tính kiểm soát chặt chẽ hơn cách mà, về lý thuyết, chủ sở hữu sử dụng một thiết bị lẽ ra không còn thuộc về họ nữa. Nói cách khác, đó là hướng cho phép Apple quyết định người dùng cuối được chạy chương trình nào