Код: Выделить всё
sudo touch /System/testРазберём четыре слоя: ядро XNU, структуру дисков и томов APFS, механику запечатанной системы (SSV), и песочницу приложений. Пойдём вглубь - не "что нажать", а как и почему это работает.
Слои системы и ядро macOS: что такое XNU
macOS - это не монолит, а стопка слоёв. Сверху - графические приложения и фреймворки (Cocoa, SwiftUI, AppKit). Ниже - системные службы и демоны, которыми дирижирует launchd (про него отдельный урок). Ещё ниже - userspace-библиотеки и BSD-окружение, которое ты видишь в терминале: zsh, ls, ps, утилиты. А в самом низу - ядро macOS под названием XNU.
XNU расшифровывается шутливо как "X is Not Unix", и это гибридное ядро. Гибридное - значит склеено из двух разных движков:
- Mach - микроядро родом из университета Карнеги-Меллона. Отвечает за самое нутро: управление задачами и потоками, виртуальную память, межпроцессное взаимодействие через порты и сообщения (IPC), планировщик. Когда ты слышишь "Mach port" или видишь в выводе - это вот этот слой.
Код: Выделить всё
mach_msg - BSD - слой поверх Mach, дающий привычный Unix-интерфейс: процессы с PID, пользователи и группы, права POSIX, сетевой стек, файловые системы, системные вызовы (open, read, fork). Команда покажет Darwin - это и есть открытая основа macOS, ядро XNU плюс BSD-userland.
Код: Выделить всё
uname -a - IOKit / драйверы - объектно-ориентированный фреймворк драйверов на C++. Исторически именно сюда грузились kext-ы (kernel extensions).
Код: Выделить всё
$ uname -a
Darwin MacBook-Pro.local 25.0.0 Darwin Kernel Version 25.0.0: ... arm64
$ sysctl kern.osversion kern.bootargs
kern.osversion: 25A123
kern.bootargs:
Код: Выделить всё
Darwin Kernel Version 25.0.0Код: Выделить всё
arm64Код: Выделить всё
x86_64
Kext-ы против System Extensions: код уходит из ядра
Раньше всё, что лезло глубоко в систему - антивирусы, VPN, драйверы железа, файловые фильтры - писалось как kext, kernel extension, и грузилось прямо внутрь XNU. Проблема очевидна: код в ядре имеет полный доступ ко всему. Один кривой указатель в kext-е - и паника ядра, синий, простите, серый экран и ребут. Один зловредный kext - и привет, у тебя руткит уровня ядра.
Apple это похоронила. Начиная с macOS 10.15 код выносят из ядра в userspace в виде System Extensions. Ключевая разница в принципе наименьших привилегий: kext имел доступ ко всей системе, а system extension работает в пользовательском пространстве и получает только те привилегии, что нужны для его функции. Упал такой extension - перезапустился сам, ядро живо.
System extensions реализуются через несколько фреймворков:
- DriverKit - драйверы устройств (USB, HID, сеть, аудио) в формате . В отличие от kext-ов, где можно было только C/C++, тут можно писать хоть на Swift.
Код: Выделить всё
.dext - EndpointSecurity (ES) - для антивирусов, EDR и DLP. Даёт API для наблюдения и контроля: процессы, события файловой системы, сеть, операции ядра. Авторизационные события можно блокировать в реальном времени.
- NetworkExtension - VPN, контент-фильтры, прокси.
Код: Выделить всё
$ systemextensionsctl list
1 extension(s)
--- com.apple.system_extension.endpoint_security
enabled active teamID bundleID (version) name [state]
* * ABCDE12345 com.vendor.edr.es (3.2/3.2) edr-agent [activated enabled]
Код: Выделить всё
activated enabledКод: Выделить всё
Recovery -> Startup Security UtilityСтруктура диска: System volume, Data volume и firmlinks
Теперь к диску. Физически у тебя один SSD, на нём один раздел GUID с одним APFS-контейнером. APFS-контейнер - это как пул: внутри него живёт несколько томов (volumes), и они делят свободное место динамически, без жёстких границ разделов. Запусти и смотри:
Код: Выделить всё
$ diskutil apfs list
+-- Container disk3 ...
APFS Container Reference: disk3
|
+-> Volume disk3s1 Macintosh HD (Role: System, Read-Only)
+-> Volume disk3s2 Macintosh HD - Data (Role: Data, Read-Write)
+-> Volume disk3s3 Preboot
+-> Volume disk3s4 Recovery
+-> Volume disk3s5 VM
- System volume (Macintosh HD) - только чтение. Тут лежит сама ОС: /System, системные бинари, /usr (кроме /usr/local), штатные приложения. Ты сюда писать не можешь.
- Data volume (Macintosh HD - Data) - чтение-запись. Тут всё твоё: домашние папки /Users, сторонние приложения, /usr/local, изменяемые системные данные, которые физически не могут жить на read-only томе.
Код: Выделить всё
$ cat /usr/share/firmlinks
/AppleInternal AppleInternal
/Applications Applications
/Library Library
/Users Users
/Volumes Volumes
/private private
/usr/local usr/local
...
Код: Выделить всё
/Users/khovanskiyКод: Выделить всё
/System/ApplicationsКод: Выделить всё
/opt/homebrewSigned System Volume: почему систему нельзя изменить
Read-only - это полдела. Самое интересное - Signed System Volume (SSV), он же sealed system volume. System volume не просто примонтирован только на чтение - он криптографически запечатан, и проверяется на каждой загрузке.
Механика такая. У каждого файла на системном томе посчитан SHA-256 хеш, и он лежит прямо в метаданных файловой системы. Хеши не разрозненные - они собраны в дерево Меркла: хеш каждого узла рекурсивно покрывает хеши его детей, и так до самого корня. Хеш корня называется seal (печать) - одно значение, которое математически покрывает каждый байт системного тома. Изменишь один байт в одном файле - корневой seal перестанет сходиться.
При установке и обновлении macOS установщик строит это дерево Меркла, вычисляет seal и делает APFS-снапшот системного тома. И вот тонкость: загружается Mac не с самого System volume, а с этого подписанного снапшота, доступного только на чтение. Печать сверяется с подписью Apple - сначала на устройстве при установке, потом на каждом старте. До загрузки ядра загрузчик проверяет seal; не сошлось - Mac не загрузится с этого тома.
Что это даёт на практике:
- Записать в /System нельзя даже руту - том запечатан, а не просто "защищён правами". Это другой уровень.
- Малварь не может незаметно подменить системный бинарь - подмена ломает seal, и система это заметит при загрузке.
- Откат безопасен: снапшоты APFS дешёвые, и если обновление пошло не так, старую версию системы можно вернуть без переустановки.
Код: Выделить всё
$ diskutil apfs listSnapshots /
Snapshot for disk3s1 ...
+-- com.apple.os.update-<хеш>
Name: com.apple.os.update-<хеш>
Sealed: Broken / Yes
Код: Выделить всё
SealedКод: Выделить всё
YesКод: Выделить всё
BrokenТри Library и песочница приложений
Раз уж система отделена от данных, надо чётко держать в голове три директории Library - их вечно путают:
- - системные компоненты Apple. Read-only, запечатано в SSV. Руками не трогаешь.
Код: Выделить всё
/System/Library - - общесистемное для всех пользователей: сторонние launch-демоны, конфиги, шрифты, профили конфигурации MDM. Сюда ставят корпоративный софт и системные настройки. Это на Data volume, писать можно (с правами).
Код: Выделить всё
/Library - - всё пользовательское: настройки приложений (Preferences/*.plist), кеши, контейнеры песочницы, ключи. По умолчанию скрыта в Finder.
Код: Выделить всё
~/Library
Код: Выделить всё
~/Library/Containers/<bundle-id>/Код: Выделить всё
~/Library/Group Containers/Соберём картину целиком: гибридное ядро XNU (Mach + BSD) внизу, драйверы и код безопасности вынесены из ядра в userspace-расширения, система живёт на запечатанном read-only томе SSV и сшита firmlinks с read-write томом данных, а приложения сверху сидят по песочницам. Каждый слой ограничивает соседа. Вот почему
Код: Выделить всё
sudo touch /System/testТипичные грабли
- "Диск раздвоился, в системе два Macintosh HD". Это не баг. System и Data - штатная Volume Group, Finder сливает их в один. Удалять "лишний" Data нельзя - там все твои данные.
- Пытаешься писать в /usr/bin или /System и злишься на root. Том запечатан SSV - рут тут не всесилен. Свои бинари клади в /usr/local/bin или /opt/homebrew/bin.
- Старый гайд советует отключить SIP и смонтировать систему на запись ради "кастомизации". Это ломает seal, отключает защиту и в 2026 почти всегда не нужно. Сначала ищи штатный путь через /Library, профили или defaults.
- Ждёшь, что VPN или антивирус заработает kext-ом. На Apple Silicon это требует понижения Secure Boot и одобрения. Современный софт идёт через System Extensions - проверяй , а не
Код: Выделить всё
systemextensionsctl list.Код: Выделить всё
kextstat - Путаешь /Library и ~/Library. Конфиг "для всех" - в /Library, "для меня" - в ~/Library. Положишь не туда - либо не подхватится, либо повлияет не на того пользователя.
Открой Терминал и пройди по шагам, разбирая вывод:
- Узнай ядро и архитектуру: и
Код: Выделить всё
uname -a. Запиши версию Darwin и arm64/x86_64.Код: Выделить всё
sysctl kern.osversion - Посмотри тома контейнера: . Найди роли System (Read-Only) и Data (Read-Write).
Код: Выделить всё
diskutil apfs list - Проверь печать: - убедись, что
Код: Выделить всё
diskutil apfs listSnapshots /.Код: Выделить всё
Sealed: Yes - Прочитай список сшивок: . Сопоставь левую и правую колонки.
Код: Выделить всё
cat /usr/share/firmlinks - Попробуй (и получи отлуп) запись в систему: . Прочитай "Read-only file system" - теперь ты знаешь, почему.
Код: Выделить всё
sudo touch /System/proba - Глянь расширения и статус SIP: и
Код: Выделить всё
systemextensionsctl list.Код: Выделить всё
csrutil status
- Из каких двух движков склеено гибридное ядро XNU и за что отвечает каждый?
- Чем Signed System Volume отличается от простого "тома только для чтения" и что такое seal?
- Зачем нужны firmlinks и почему /Users доступна на запись, хотя формально стартует с read-only тома?
- Почему современный VPN или антивирус ставится как System Extension, а не как kext, и в чём выигрыш по безопасности?
macOS - это слоёная система с гибридным ядром XNU (Mach плюс BSD), где код безопасности вынесен из ядра в userspace-расширения, ОС живёт на криптографически запечатанном read-only томе (Signed System Volume) и сшита firmlinks с томом данных, а приложения сверху изолированы песочницами. Запись в систему закрыта не правами, а печатью - и это фундамент устойчивости и безопасности. Дальше в курсе всё ложится на этот каркас: defaults пишет в plist на Data, launchd крутит демоны из /Library, Homebrew ставит в /opt - каждый инструмент знает своё место в архитектуре. Держи эту карту в голове - и macOS перестанет сопротивляться.