0

This question is really about transferring file permissions from a parent macOS application that is not sandboxed, to a child XPC service that is sandboxed.

This question, App sandbox: how to allow XPC service to read file that user opened in parent app?, is almost identical in purpose, but differs in implementation. (An accepted answer on that question involves sending a security-scoped bookmark across, which works, but is really slow.)

The lower-level implementation that Apple seems to recommend is to send a file descriptor over to the XPC service. Apple's Secure Coding Guide talks about this very issue under "Inheriting File Descriptors".

Using the C-based XPC framework, I can successfully send a file descriptor from the main application to the XPC service and read data using that file descriptor:

In the main app:

NSFileHandle *handle = [NSFileHandle fileHandleForReadingAtPath:@"..."];
xpc_dictionary_set_fd(dict, "fd", handle.fileDescriptor);

In the XPC service:

 int fd = xpc_dictionary_dup_fd(dict, "fd");
 NSFileHandle *handle = [[NSFileHandle alloc] initWithFileDescriptor:fd 
                                                   closeOnDealloc:YES];

 NSData *data = [handle readDataOfLength:1000];
 NSLog(@"Read data of length: %@", @(data.length));

The XPC service is able to read that data. However, any attempts to now create an NSURL using a file path (NSString) that points to the same file will fail. This is problematic because the APIs that I want to use in the XPC service all require an NSURL.

I can't see anyway to create an NSURL from a file descriptor nor convert a file descriptor into an NSURL, but perhaps I've overlooked something.

Is there a way to create an NSURL from a file descriptor, or have a newly created NSURL inherit the read-only permissions of the file descriptor?

Alternatively, is there another way to transfer file permissions from a parent process to a child XPC process that doesn't involve having to create an security scoped bookmark, archiving it and then unarchiving it on the other end?

macOS 10.12/10.13

Edit 1

Apple's SandboxedFetch sample code uses the file descriptor technique perfectly, but the functions it uses in the XPC service are able to take file descriptors. Namely, it just uses read(), fdopen() and curl.

kennyc
  • 5,490
  • 5
  • 34
  • 57
  • What are the APIs that you want to use in the service that take URLs? Perhaps there are alternatives that can work with a file descriptor. – Ken Thomases Oct 12 '17 at 19:57
  • Just about every API :) Specifically, APIs for reading images with Image IO and Core Image, reading and decoding media using AVFoundation and using QuickLook to generate thumbnail previews of files. I can get the NSFileHandle across and read using it, but I can't create a new NSURL that is readable. (I tried passing over a file descriptor for the parent directory, but that didn't seem to work either, or I did it wrong.) I assumed that App Sandbox would see I have an open file descriptor and allow subsequent file descriptors via NSURL to the same file but that doesn't appear to be the case. – kennyc Oct 12 '17 at 20:04
  • You could read in data using the file handle, and create your image source/CIImage/whatever using that data, maybe. – Wevah Oct 13 '17 at 01:04
  • Also, you could probably send the path/URL string over the XPC connection as well. – Wevah Oct 13 '17 at 01:06
  • Even with the path, I don't appear able to create a new NSURL that is readable. In the C interface for XPC, there's no way to send an NSURL, though I'd be surprised if that mattered since I *assume* the Objective-C interface is built on the C interface. Reading in image data and using a data provider could work for images, but that would involve reading in all the data when you might only need a little bit. (Like extracting the JPEG thumbnail from a RAW file.) For generating video thumbnails, reading all the data isn't really practical. – kennyc Oct 13 '17 at 10:08

0 Answers0