Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sandboxed Mac app exhausting security scoped URL resources

I am developing a Mac application that prompts the user for files using the NSOpenPanel. The application is sandboxed (testing on OSX 10.9.4). I noticed that if I open a large amount of files (~3000), the open panel starts to emit errors to the log. This also happens if I try to open less amount of files in chucks for several times.

After the errors start to appear the first time, every time the NSOpenPanel is used again to open files, no matter for how many files, these errors will be generated again (until the application is closed).

The error message looks like this:

TestPanel[98508:303] __41+[NSSavePanel _consumeSandboxExtensions:]_block_invoke: sandbox_consume_fs_extension failed

One line for each file I try to open.

I managed to reproduce this behavior with a simple app: A sandboxed application with a single button invoking the following code:

NSOpenPanel* panel = [NSOpenPanel openPanel];
[panel setAllowsMultipleSelection:YES];
[panel setCanChooseDirectories:NO];
[panel setCanChooseFiles:YES];
[panel beginSheetModalForWindow:[self window] completionHandler:^(NSInteger result) {
    NSLog(@"%lu", [panel.URLs count]);
}];

The errors appear before the code reaches the completion handler.

It seems that I can still get the URLs from the panel in the completion handler but it really pollutes the system log.

EDIT:

Seems that this problem is not directly related to the NSOpenPanel/NSSavePanel panels. A very similar thing happens when using drap/drop with files. Something like this:

- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender {
    ...
    NSPasteboard *pboard = [sender draggingPasteboard];
    if ([[pboard types] containsObject:NSURLPboardType]) {
        NSArray *urls = [pboard readObjectsForClasses:@[[NSURL class]] options:nil];
    }
    ...
}

This will generate the following log messages when dragging a large amount of files (the "magic" number seems to be somewhere around 2900):

Consume sandbox extension for itemIdentifier (2937) from pasteboard failed!

As with the NSOpenPanel, after the first occurrence of this, every single file dropped will generate the same error in the log.

EDIT 2:

@mahal tertin's reply pointed me to the right direction. The problem is indeed with the number of files and the fact that security scoped URL resources are limited.

However, there seems to be no reasonable solution found. The problem is that when the user clicks "OK" on the NSOpenPanel (or drops the files on a drag&drop aware control), behind the scenes the OS already attempts to create these security scoped URLs and implicitly calls startAccessingSecurityScopedResource for you. So if the user attempts to open more files than the limit, the resources are exhausted and the only option is to close and restart the application.

Calling stopAccessingSecurityScopedResource on the returned URLs seem to free the resources however this solution was discouraged by Apple's representative on the official developers forums (link is behind login).

It seems that the app is at the mercy of the user not to open too many files. And that is not even at once, since there is no approved way to release these resources. You can warn the user in documentation or even with an in-app alert but there is no way to prevent them from messing up the app and forcing a restart.

So if the app runs long enough and the user keeps opening files, the app will eventually become unusable.

Still looking for a reasonable solution for this.

like image 523
danielv Avatar asked Sep 02 '14 15:09

danielv


People also ask

Are Mac apps sandboxed?

The App Sandbox is an access control technology that macOS provides and enforces at the kernel level. The sandbox's primary function is to contain damage to the system and the user's data if the user executes a compromised app.

What is Sandbox in Safari?

Sandboxing. All third-party apps are “sandboxed,” so they are restricted from accessing files stored by other apps or from making changes to the device. Sandboxing is designed to prevent apps from gathering or modifying information stored by other apps.


2 Answers

After searching high and low and asking in various places, I am going to close this question and conclude there is no answer or solution to this. I am posting the known information on this for future reference.

All the solutions suggested are just workarounds that may minimize the problem and try to guide the user toward not trying to open too many files. But there nothing that can be done to actually solve this.

Here are the known facts about this issue:

  • No matter what you do, the user can attempt to open too many files in the NSOpenPanel dialog and exhaust the security scoped URL resources
  • Once these resources are exhausted, it is not possible to open any more files for reading/writing. The application needs to be closed and reopened
  • Even if the user doesn't attempt to open too many files at once, the application may still exhaust these resources if it runs long enough and the user opens enough files over time since startAccessingSecurityScopedResource is called automatically for files opened with NSOpenPanel (or the drag/drop mechanism) and nothing ever closes these resources
  • Calling stopAccessingSecurityScopedResource on all URL retrieved by the open panel will free these resources but this practice is discouraged by Apple, saying it might not be compatible with future solutions
  • When you receive the list of URLs from NSOpenPanel (or drag/drop), there is no way to tell if all URLs were successfully accessed or if there are URLs that are over the limit and therefore invalid.
  • Apple is aware of this and may fix it in the future. It is still not fixed in 10.10 and of course, that will not help current applications running on current/previous OSX version.

It seems Apple has really dropped the ball on this one, the Sandbox implementation seems very sloppy and short sighted.

like image 98
danielv Avatar answered Oct 24 '22 04:10

danielv


The behavior you experience is because the security scoped resources are limited:

NSURL - (BOOL)startAccessingSecurityScopedResource tells

If sufficient kernel resources are leaked, your app loses its ability to add file-system locations to its sandbox...

The current limit is roughly what you experienced. See: What are the current kernel resource limits on security-scoped bookmarks?

To prevent it:

  • only start accessing those SSBs you need at a given time and subsequently stop accessing them
  • start access not files but enclosing folders: ask the user not to choose files but a full folder. This will grant you access to the whole tree beneath that directory
  • on draggingEntered: show a NSOpenPanel with the enclosing directory(ies) to grant access
like image 31
mahal tertin Avatar answered Oct 24 '22 04:10

mahal tertin