macOS Containers and defaults
This is a follow-up to the article Enabling the Debug menu in Safari 14 on Big Sur and Catalina by Dan Moren. In the past, you could enable the hidden Debug menu in Safari by using the command defaults write com.apple.Safari IncludeInternalDebugMenu -bool true
in Terminal app. However, Dan discovered that this no longer worked for him, and he was forced to manually edit a plist file in order to enable the Debug menu. So what happened here? This is the question my blog post will answer.
Dan correctly notes that Safari's preferences file has moved from ~/Library/Preferences/com.apple.Safari.plist
to ~/Library/Containers/com.apple.Safari/Data/Library/Preferences/com.apple.Safari.plist
, which is inside Safari's "container". What Dan didn't realize is that this has nothing to do with Safari 14. It actually happened quite some time ago, I believe last year with Safari 13. For the first time, Safari 13 was sandboxed. If you do codesign --display --entitlements - /Applications/Safari.app
in Terminal, you'll see the indicator of a sandboxed app:
<key>com.apple.security.app-sandbox</key>
<true/>
Safari 12 and earlier were not sandboxed, and Safari preferences were always stored in the traditional location for preferences files, the ~/Library/Preferences
folder. However, a sandboxed app has only limited access to the file system on your Mac. For example, a sandboxed app can't read or write to the ~/Library/Preferences
folder. This is why each sandboxed app has its own special container to store the files it needs. In the case of Safari, that's the ~/Library/Containers/com.apple.Safari
folder. Thus, the Safari preferences file location had to move in Safari 13. The catch is that if you ever ran Safari 12 or earlier on your Mac, the old ~/Library/Preferences/com.apple.Safari.plist
file was left behind!
Besides sandboxing, there's another factor at work in this scenario: System Integrity Protection, AKA SIP. Certain files and folders on your Mac are protected by the system, and cannot be accessed without special permission, even by non-sandboxed apps. It turns out that Safari's container is one of those protected folders. By default, Finder has special permission to access the whole file system, but Terminal app does not have special permission by default. So if you try to list the contents of Safari's container, you can't.
$ cd Library/Containers/com.apple.Safari
$ ls
ls: .: Operation not permitted
If you want to give special permission to Terminal, you have to open System Preferences, Security & Privacy pane, Privacy tab, select Full Disk Access in the list, unlock with your administrator password, add Terminal, and relaunch Terminal if it was already running. (The last step is crucial.) Now you have access to Safari's container.
$ cd Library/Containers/com.apple.Safari
$ ls
Container.plist Data
How does this affect the defaults
command-line tool? If Terminal app has Full Disk Access, then defaults write com.apple.Safari
is smart enough to use the preferences file in Safari's container. But if Terminal does not have Full Disk Access, then defaults
falls back to the preferences in the ~/Library/Preferences
folder! So if you do defaults write com.apple.Safari IncludeInternalDebugMenu -bool true
without Full Disk Access, it'll write to ~/Library/Preferences/com.apple.Safari.plist
, but that has no effect, because Safari is sandboxed and only reads preferences from its own container. Note that this happens even if there's no old file at ~/Library/Preferences/com.apple.Safari.plist
, because defaults
will create a new file when necessary.
$ defaults read com.apple.Safari
2020-09-22 08:17:23.053 defaults[1782:31894]
Domain com.apple.Safari does not exist
$ defaults write com.apple.Safari IncludeInternalDebugMenu -bool true
$ defaults read com.apple.Safari
{
IncludeInternalDebugMenu = 1;
}
There are three morals to the story, First, if you want defaults write
to work right for Safari, you need to give Full Disk Access to Terminal. Second, if you want to avoid confusion, make sure to delete the old ~/Library/Preferences/com.apple.Safari.plist
file, because it's no longer used by Safari, but it may be used by defaults
, resulting in much hilarity. For example, defaults read com.apple.Safari IncludeInternalDebugMenu
could show the wrong value. If you want to see how this could happen, compare the result of defaults read com.apple.Safari NewestLaunchedSafariVersion
with and without Full Disk Access. They're different!
The third and final moral to the story is that SIP and sandboxing are terrible and ought to be abolished.
from Hacker News https://ift.tt/32VdZig
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.