Fix terminal “operation not permitted” error in macos mojave
Содержание:
How to Fix “Operation not permitted” Error in Terminal for Mac OS
- Pull down the Apple menu and choose ‘System Preferences’
- Choose “Security & Privacy” control panel
- Now select the “Privacy” tab, then from the left-side menu select “Full Disk Access”
- Click the lock icon in the lower left corner of the preference panel and authenticate with an admin level login
- Now click the plus button to add an application with full disk access
Navigate to the /Applications/Utilities/ folder and choose “Terminal” to grant Terminal with Full Disk Access privileges
Relaunch Terminal, the “Operation not permitted” error messages will be gone
If you have not encountered the “Operation not permitted” error message in the Terminal of MacOS (Mojave 10.14 or later) yet, then it’s likely because you haven’t wandered into a directory or file path that has the additional access restrictions (or that you don’t use Terminal, in which case this entire article is not for you).
While many of the various core System and root directories will throw error messages in macOS Terminal too, you can also find the error message even when trying to work in the users own Home directory, including in many of the user ~/Library/ folders, like ~/Library/Messages (where iMessage attachments and chat logs are stored in Mac OS) and ~/Library/Mail/ (where user-level mail plugins, mailbox data, and other Mail app data is stored), and many others.
You can test this yourself, before and after making the settings adjustment outlined above with a simple command like using ls on one of the protected folders:
If Terminal does not have Full Disk Access granted, you will see the “Operation not permitted” error message.
If Terminal does have Full Disk Access granted, or if SIP is disabled, you will not see that error message in the MacOS Terminal.
In case you were wondering, yes that does mean there are actually two ways to fix the “Operation not permitted” errors you may encounter in MacOS Terminal; the first which we detail here is rather simple that grants additional access privileges to Terminal app, and the other is a bit more dramatic which involves disabling System Integrity Protection on the Mac which is generally not recommended and we won’t specifically cover here, though simply disabling SIP and rebooting is typically enough to make the error go away if you’d rather go that route.
The “Operation not permitted” message is one of a variety of command line errors you may encounter in Mac OS Terminal. Another frequently seen command line error is the the “command not found” error message which can also be encountered in the Terminal for MacOS for a variety of different reasons as well.
If you have any other tips, tricks, suggestions, or thoughts about the command line in MacOS or this particular error message, share with us in the comments below.
Как разрешаются ID
Мы только что увидели процесс, запущенный от обычного пользователя внезапно переключился на . Не волнуйтесь, никакой эскалации привилегий не было. Помните, что это просто маппинг ID: пока наш процесс думает, что он является пользователем в системе, Linux знает, что — в его случае — означает обычный UID (благодаря нашему маппингу). Так что в то время, когда пространства имён, принадлежащие его новому user namespace (подобно network namespace в C), признают его права в качестве , другие (как например, network namespace в P) — нет. Поэтому процесс не может делать ничего, что пользователь не смог бы.
Всякий раз, когда процесс во вложенном user namespace выполняет операцию, требующую проверки разрешений — например, создание файла — его UID в этом user namespace сравнивается с эквивалентным ID пользователя в корневом user namespace путём обхода маппингов в дереве пространств имён до корня. В обратном направлении происходит движение, например, когда он читает ID пользователей, как мы это делаем с помощью . UID владельца маппится из корневого user namespace до текущего и окончательный соответствующий ID (или nobody, если маппинг отсутствовал где-либо вдоль всего дерева) отдаётся читающему процессу.
Map-файлы
Map-файлы — особенные файлы в системе. Чем особенные? Ну, тем, что возвращают разное содержимое всякий раз, когда вы читаете из них, в зависимости от того, какой ваш процесс читает. Например, map-файл возвращает маппинг от UID’ов из user namespace, которому принадлежит процесс , UID’ам в user namespace читающего процесса. И, как следствие, содержимое, возвращаемое в процесс X, может отличаться от того, что вернулось в процесс Y, даже если они читают один и тот же map файл одновременно.
В частности, процесс X, считывающий UID map-файл , получает набор строк. Каждая строка отображает непрерывный диапазон UID’ов в user namespace C процесса , соответствующий диапазону UID в другом namespace.
Каждая строка имеет формат , где:
- является стартовым UID диапазона для user namespace процесса
- — это длина диапазона.
- Трансляция зависит от читающего процесса X. Если X принадлежит другому user namespace U, то — это стартовый UID диапазона в U, который мапится с . В противном случае — это стартовый UID диапазона в P — родительского user namespace процесса C.
Например, если процесс читает файл и среди полученных строк видно , то UID’ы с 15 по 19 в user namespace процесса маппятся в UID’ы 22-26 отдельного user namespace читающего процесса.
С другой стороны, если процесс читает из файла (или map-файла любого процесса, принадлежащего тому же user namespace, что и читающий процесс) и получает , то UID’ы c 15 по 19 в user namespace C маппятся в UID’ы c 22 по 26 родительского для C user namespace.
Давайте это попробуем:
Хорошо, это было не очень захватывающе, так как это были два крайних случая, но это говорит там о нескольких вещах:
- Вновь созданный user namespace будет фактически иметь пустые map-файлы.
- UID 4294967295 не маппится и непригоден для использования даже в user namespace. Linux использует этот UID специально, чтобы показать отсутствие user ID.
Маппинги User ID
User namespace, по сути, содержит набор идентификаторов и некоторую информацию, связывающую эти ID с набором ID других user namespace — этот дуэт определяет полное представление о ID процессов, доступных в системе. Давайте посмотрим, как это может выглядеть:
В другом окне терминала давайте запустим шелл с помощью (флаг создаёт процесс в новом user namespace):
Погодите, кто? Теперь, когда мы находимся во вложенном шелле в C, текущий пользователь становится nobody? Мы могли бы догадаться, что поскольку C является новым user namespace, процесс может иметь иной вид ID. Поэтому мы, возможно, и не ждали, что он останется , но — это не смешно. С другой стороны, это здорово, потому что мы получили изолирование, которое и хотели. Наш процесс теперь имеет другую (хоть и поломанную) подстановку ID в системе — в настоящее время он видит всех, как и каждую группу как .
Информация, связывающая UID из одного user namespace с другим, называется маппингом user ID. Он представляет из себя таблицы поиска соответствия ID в текущем user namespace для ID в других namespace и каждый user namespace связан ровно одним маппингом UID (в дополнение еще к одному маппингу GID для group ID).
Этот маппинг и есть то, что сломано в нашем шелле. Оказывается, что новые user namespaces начинаются с пустого маппинга, и в результате Linux по умолчанию использует ужасного пользователя . Нам нужно исправить это, прежде чем мы сможем сделать какую-либо полезную работу в нашем новом пространстве имён. Например, в настоящее время системные вызовы (например, ), которые пытаются работать с UID, потерпят неудачу. Но не бойтесь! Верный традиции всё-есть-файл, Linux представляет этот маппинг с помощью файловой системы в (в для GID), где — ID процесса. Мы будем называть эти два файла map-файлами
Владелец пространств имён и привилегии
В предыдущем посте мы упомянули, что при создании новых пространств имён требуется доступ с уровнем суперпользователя. User namespaces не налагают этого требования. На самом деле, еще одной их особенностью является то, что они могут владеть другими пространствами имён.
Всякий раз, когда создаётся не user namespace N, Linux назначает текущий user namespace P процесса, создающего N, владельцем namespace N. Если P создан наряду с другими пространствами имён в одном и том же системном вызове , Linux гарантирует, что P будет создан первым и назначен владельцем других пространств имён.
Владелец пространств имён важен потому, что процесс, запрашивающий выполнения привилегированного действия над ресурсом, задействованным не user namespace, будет иметь свои UID привилегии, проверенные в отношении владельца этого user namespace, а не корневого user namespace. Например, скажем, что P является родительским user namespace дочернего C, а P и C владеют собственными network namespace M и N соответственно. Процесс может не иметь привилегий для создания сетевых устройств, включенных в M, но может быть в состоянии это делать для N.
Следствием наличия владельца пространств имён для нас является то, что мы можем отбросить требование при выполнении команд с помощью или , если если мы запрашиваем также создание и user namespace. Например, потребует , но — уже нет: