It's usually possible to see if sandbox entitlements exist for an application with the codesign command line call. For example, calling this
codesign --display --entitlements :- /Applications/Notes.app/ | grep sandbox
Will result in this output
Executable=/Applications/Notes.app/Contents/MacOS/Notes
<key>com.apple.security.app-sandbox</key>
Where the key com.apple.security.app-sandbox denotes that the app runs in a sandbox.
On Mavericks, some XPC helper apps show in Activity Monitor to be running in a sandbox, but calling codesign on them doesn't reveal anything. An example for one of Safari's XPC helper applications: -
codesign -display --entitlements :- /System/Library/PrivateFrameworks/WebKit2.framework/Versions/A/XPCServices/com.apple.WebKit.WebContent.xpc/Contents/MacOS/com.apple.WebKit.WebContent | grep sandbox
Just returns this: -
Executable=/System/Library/PrivateFrameworks/WebKit2.framework/Versions/A/XPCServices/com.apple.WebKit.WebContent.xpc/Contents/MacOS/com.apple.WebKit.WebContent
I've also tried checking programatically if the bundle is sandboxed, with the code described in this article, but again, returns as not sandboxed, even though Activity Monitor clearly states that it is.
Is it possible to check such an xpc bundle, to see if will be executed in a sandbox and uses sandbox entitlements?
Looking for the com.apple.security.app-sandbox entitlement as you're doing is the way to check if an XPC service uses App Sandbox. The reason that the Safari Web Content process shows up as sandboxed despite not having this entitlement is that it does not use App Sandbox, but rather lower level interfaces to the underlying sandbox facility in OS X. Early on the web content process calls WebKit's initializeSandbox() method, which uses a system private interface to apply a sandbox policy at runtime. So finding out whether a given XPC service will create a sandboxed process is as difficult as finding out whether that service will call a function. However, if you're curious about the restrictions placed on such processes the sandbox policy is usually stored in a .sb file somewhere on the system. In this case it's at /System/Library/PrivateFrameworks/WebKit2.framework/Versions/A/Resources/com.apple.WebProcess.sb.
Related
I'm building a virtual HID device in Driver Kit.
I was wanting to communicate with the virtual device driver from a daemon, as the daemon is necessary for generating the HID events that would be sent from the driver.
I'm matching on my driver service fine via the daemon, however when I attempt to open the service I get -536870174 which from what I see here means kIOReturnNotPermitted.
From what I've read about this, the device driver user client can only be opened via an application that has been granted the com.apple.developer.driverkit.userclient-access entitlement by Apple.
So, my question:
Is opening the user client of a device driver in Driver Kit with a daemon completely out of the question?
Is my only option here to have a intermediate application with the com.apple.developer.driverkit.userclient-access entitlement, which can act as a broker between the daemon and the driver?
So it would be something like:
Daemon <---xpc connection--> Intermediate App <--- user client ---> Virtual HID device
Edit:
To add to Phil's answer below regarding running an app as a daemon, there's some Apple written guidance here.
The short of it: there's no need to go to such lengths. Daemons can have entitlements.
The official solution is to make your daemon an application, from the OS's point of view. Essentially, build your daemon as an application bundle, just don't call it .app. Your launchd plist can point at the embedded executable and it will inherit the surrounding package's entitlements.
Unofficially, I've also had success with directly embedding the Info.plist in the daemon's binary, without a surrounding bundle directory. This is commonly done for privileged helper tools for use with SMJobBless() and is described in a bunch of places including here. Essentially, enable the "Create Info.plist Section in Binary" build setting in Xcode, or add -sectcreate __TEXT __info_plist path/to/Info.plist to your linker flags when using another build system. However, I didn't end up shipping this (didn't need it in the end) so I only ever tested it with SIP disabled. So I currently can't say for certain if it will work when signed with an appropriate provisioning profile.
Both methods allow you to give the binary an application bundle ID by specifying it in the Info.plist, which then also enables you to include an entitlements file during code signing. As com.apple.developer.driverkit.userclient-access is not one of the "open" entitlements from the com.apple.security.* namespace, you'll also need a provisioning profile that includes it, or the OS won't accept it with SIP enabled.
If you take the path of running an app as a daemon as in the apple resource stated above, the following code is a swift variation of the objective-c that Eskimo has posted.
import Foundation
import Security
import OSLog;
var me:SecCode? = nil;
let kSecCSDefaultFlags:SecCSFlags = SecCSFlags(rawValue: SecCSFlags.RawValue(0))
var err = SecCodeCopySelf(kSecCSDefaultFlags, &me);
assert(err == errSecSuccess)
var infoCF:CFDictionary? = nil;
var staticMe:SecStaticCode? = nil;
err = SecCodeCopyStaticCode(me!, kSecCSDefaultFlags, &staticMe)
assert(err == errSecSuccess);
err = SecCodeCopySigningInformation(staticMe!, kSecCSDefaultFlags, &infoCF);
assert(err == errSecSuccess);
print(infoCF);
os_log("%{public}s", infoCF.debugDescription);
It may be because I'm not developing a traditional Swift app, instead I'm using the https://github.com/zserge/webview library to develop a cross platform app.
My app has 2 parts, divided into 2 different threads: one thread launches the window and displays a JS app. The second thread contains a background server bound to an ephemeral port and serves a json api, written in Rust. The Rust side is also the one talking with the File System and making all requests. On Linux I don't have any problem, but on Mac it works only when requesting resources from root and home directories but not from Documents/Desktop etc
The first problem I had when running it on Mac has been allowing access to the server from the window: I had to add a new entry to the info.plist file, according to this answer in stackoverflow: The resource could not be loaded because the App Transport Security policy requires the use of a secure connection
This resolved the issue I had talking to the server bound to the ephemeral port. Truth be said I have to also say that now it requests me to allow access to external resources every time I launch the app.
But, when trying to execute a function which requires access from the Rust side to the Desktop (for example), it doesn't work and it does not show any popup and never did
Btw, if you want to have a look at the final product, maybe to help you understand better the app, have a look here: http://getdevspace.com/
Check the ch mode file system
Even had the same problem so i checked the ch mode so it worked
Thanks
I'm implementing API which allows to launch other apps (using NSTask) inside VFS (FUSE on macOS). After VFS is mounted a bunch of processes start accessing launched VFS in which my app works, and I'd like to implement some kind of filtering mechnism which will allow to detect whether process which is accessing the VFS is created by system (and potentially safe) or not, and if so it'll be granted an access to the file system where my app runs.
So far I'm able to get basic information of the process by it's pid. For example: process path, uid, ppid, code signature of the process etc (using Security framework, libproc etc)
I've done a couple of tests and see that there are process with uid != 0 and still critical for my app to run (if I deny access to them app which is started in VFS crashes) (e.g. /usr/libexec/secinitd, /System/Library/CoreServices/Dock.app/Contents/MacOS/Dock), so looks like approach with filtering processes by pids, uids, ppids might not work.
So the question is: is it possible to distinguish whether process which is accessing my app was created by system and is potentially safe? I also don't want to do too much work by denying accees to critical system processes which will allow the app to successfully start and run in VFS.
Judging from the comment thread, your threat model is data theft via malware etc.
In this case, you can trust almost nothing, so the best way is probably to maintain an explicit whitelist of processes which are allowed to access your mount point, and block access to everything else by default. Log any processes to which access is denied, and allow the user to reverse that decision and add them to the whitelist. In other words, let the user decide what applications they consider safe.
Your said that according to your inspection, there were several processes which were mandatory for the process to run, so why won't use try-and-error approach.
You deploy you FUSE drive on clean environment and record all processes that attempt to access your files - try to prevent each process and keep only those which crash your apps, and add them to a white-list.
Of course that this list is subject to change in different macOS versions, but it can give you the general idea.
Alternatively, you can break your app into couple of parts. for example, put the sensitive logic inside separated dylib file, and prevent access to this file only.. since dylib is not the main executable in your app, I believe fewer processes require mandatory access it.
How would you use a LaunchAgent inside the sandbox? I want to distribute a UI-less LaunchAgent app bundle inside my main application that I can launch on demand. The reason I want this instead of an XPC service is for the KeepAlive option, which will prevent launchd from automatically killing my process when its idle. This option doesn't exist on XPC services.
The documentation says that there's a plist that needs to be copied into ~/Library/LaunchAgents, and this is obviously not possible inside the sandbox. Is there some sort of system API that would handle copy the plist for me? I've seen Apple's SMJobBless sample code, but it seems like that's for registering a privileged LaunchDaemon rather than an unprivileged LaunchAgent.
The API you're looking for is SMLoginItemSetEnabled(). You'll have to package your long-running agent as a regular .app bundle and put it into your main app's bundle at Content/Library/LoginItems.
Then at runtime in the main application you can use the SMLoginItemSetEnabled() call with the agent's bundle identifier to enable and disable your agent. If your main application quits, the agent stays alive. If the user logs out and back in or reboots, the OS will relaunch your agent when the user logs back in.
Update: As Dmitry notes, the documentation no longer comes with the sample I originally mentioned, but another Apple sample code project, for App Sandbox, demonstrates the same API (see the file NSXPCConnection+LoginItem.m).
Documentation page now doesn't contain a sample project, so here it is: http://rhult.github.io/articles/sandboxed-launch-on-login/
I'm writing a framework for OS X that may be used by applications with or without a connection to the OS X WindowServer (i.e. both GUI apps and command-line apps run via, e.g. an ssh session). One class in the framework is for tracking files in the user's home folder across netework and mobile home directories (on OS X, users can have their home directory served via AFP from a server--a "network home directory"--or have the same home folder syncrhonized for offline access--a "mobile home directory").
Because I need to track files across filesystems, we've chosen to use relative paths, rather than OS X aliases (or the 10.6 NSURL bookmarks). When a file can't be found, I need to ask the user for input to relocate that file (like how the Alias Manager prompts the user to reconnect a broken alias). If the application has (or can make) a connection to the WindowServer, this is as simple as using an NSOpenPanel. However, when the app can't make a connection to the WindowServer I need to use an alternative method to get the user input.
So, how can I tell which method to use from within the famework code? Is there a way to programatically determine if a WindowServer connection is available (or possible)?
I recognize that an alternative architecture, where the framework client provides a callback mechanism to prompt the user would let the input-gathering strategy be provided by the calling application. I'd like to make things as simple as possible for the calling application, however, so my first choice would be to encapsulate these details in the framework if I can.
There's an environment variable named SECURITYSESSIONID that is set by loginwindow.app and get's passed to the user's applications. The variable is not set if you login via ssh. It serves as kind of a handle to talk to the window server.
Problem: The existence of this variable does not mean that this user currently controls the window manager (think fast user switching).
There's a function called CGSessionCopyCurrentDictionary in the ApplicationServices framework which looks promising:
Return Value: A window server session dictionary, or NULL if the caller is not running within a Quartz GUI session or the window server is disabled. You should release the dictionary when you are finished using it. For information about the key-value pairs in this dictionary, see "Window Server Session Properties."