Swift file reading permission error on macOS sandbox

I'm trying to read the contents of a file on the filesystem in a macOS Swift app (Xcode 9 / Swift 4).

I'm using the following snippet for it:


let path = "/my/path/string.txt"
let s = try! String(contentsOfFile: path)
print(s)


My problem is the following:


1. This works in a Playground

2. This works when I use the Command Line Tool macOS app template

3. This terminates in a permission error when I use the Cocoa App macOS app template


The permission error is the following:

Fatal error: 'try!' expression unexpectedly raised an error:
Error Domain=NSCocoaErrorDomain Code=257 "The file "data.txt" couldn't be opened because you don't have permission to view it."
UserInfo={NSFilePath=/my/path/data.txt, NSUnderlyingError=0x60c0000449b0 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}


I guess it's related to sandboxing but I found no information about it.


1. How can I read from the filesystem in a sandboxed app? I mean there are so many GUI apps which need an Open File dialog, it cannot be a realistic restriction of sandboxed apps to not read files from outside the sandbox.

2. Alternatively, how can I switch off sandboxing in Build Settings?

3. Finally, I tried to compare the project.pbxproj files between the default Cocoa Apps and Command Line Tool template and I didn't see any meaningful difference, like something about security or sandbox. If not here, where are those settings stored?

Accepted Reply

You are correct that this is a sandboxing restriction.


>> there are so many GUI apps which need an Open File dialog, it cannot be a realistic restriction of sandboxed apps to not read files from outside the sandbox


Sandboxed apps cannot read files from outside the sandbox, except where explicitly given permission by the user via an Open File dialog, which returns a "security scoped URL".


You can turn off sandboxing by selecting the project item in the navigator pane, and choosing the Entitlements tab of the project editor. This is OK to do, but it means you can't distribute the app through the Mac App Store. (It should still be code-signed, though, for ad-hoc distribution, to avoid being blocked by GateKeeper.)


Or, you can let your app be sandboxed, and use NSOpenPanel to get permission from the user. In this case, you can save a security scoped bookmark from the URL that can be re-consistituted the next time the app launches, so you only need to get permission once.


Or, if the file you're trying to read, you can arrange to place it inside the sandbox somewhere (such as the Application Support folder, if not you app bundle), so permissions are not an issue.


Finally, all modern Mac apps should not use path-based APIs except in extremely unusual circumstances. URL-based APIs are always preserved. (One reason: there are no security-scoped paths, only URLs.)

Replies

You are correct that this is a sandboxing restriction.


>> there are so many GUI apps which need an Open File dialog, it cannot be a realistic restriction of sandboxed apps to not read files from outside the sandbox


Sandboxed apps cannot read files from outside the sandbox, except where explicitly given permission by the user via an Open File dialog, which returns a "security scoped URL".


You can turn off sandboxing by selecting the project item in the navigator pane, and choosing the Entitlements tab of the project editor. This is OK to do, but it means you can't distribute the app through the Mac App Store. (It should still be code-signed, though, for ad-hoc distribution, to avoid being blocked by GateKeeper.)


Or, you can let your app be sandboxed, and use NSOpenPanel to get permission from the user. In this case, you can save a security scoped bookmark from the URL that can be re-consistituted the next time the app launches, so you only need to get permission once.


Or, if the file you're trying to read, you can arrange to place it inside the sandbox somewhere (such as the Application Support folder, if not you app bundle), so permissions are not an issue.


Finally, all modern Mac apps should not use path-based APIs except in extremely unusual circumstances. URL-based APIs are always preserved. (One reason: there are no security-scoped paths, only URLs.)

Thanks a lot, the keyword was Entitlements! I was able to Google the Apple docs using this as well as I finally see where are those settings stored in the project.

I know this is old, but it helped me a lot, so thank you. Interesting to note that in Xcode 12.3 the menus and wording to get to the Sandbox setting are different and to me they don't seem to match what's shown in the Xcode help, either. But from what I read here and a little educated guessing / poking around I got there.

I'm still searching for the location of the settings, bc. there is no "Entitlements" tab. Do you have a screenshot, where to find?

On modern versions of Xcode you configure the App Sandbox via the App Sandbox capability in the Signing & Capabilities editor.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Does this apply to Xcode iOS projects too?

Does this apply to Xcode iOS projects too?

Yes and no. On macOS, sandboxing is optional [1]. On iOS, all apps are sandboxed all the time. Thus, there’s no App Sandbox capability in the Signing & Capabilities editor.

The iOS sandbox are similar to the App Sandbox on macOS but it’s not exactly the same. In some cases it’s stricter and in some cases it’s more relaxed. For example, a sandboxed macOS app must declare its use of the network whereas an iOS app can always use the network.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] Except for Mac App Store apps, where App Review requires it.

  • What do I have to do to give my iOS access to the files on the device? I ask because I can't find where it allows me to select what my app is allowed access to like that screenshot above shows at the very right-bottom, where it says "File Access", then "Type" and "Permission & Access" above the two columns after it says "File Access".

  • I did find documentation from Apple saying I have to do the following:

    Before accessing the URL, call startAccessingSecurityScopedResource().Use a file coordinator to perform read or write operations on the URL’s contents.After you access the URL, call stopAccessingSecurityScopedResource().
  • Hi eskimo, Same problem for my macOS app(distributing outside the MAC App Store through Notarizing)Removed AppSandbox capability, still not allow me to readwrite to the Resource folder.

    Error : error: Error Domain=NSCocoaErrorDomain Code=513 "You don’t have permission to save the file “SupportTextFiles” in the folder “Resources”." UserInfo={NSFilePath=/x.app/Contents/Resources/SupportTextFiles, NSUnderlyingError=0x6000030e3c00 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}

Add a Comment