Launchpad Entry: topic-security-application-isolation
Created: Jamie Strandboge
Packages affected: apparmor, dbus, linux, mir, signon, etc
Status: In Progress
Ubuntu plans to support an app store model where software is made available that has not gone through the traditional Ubuntu archive process. While this greatly expands the quantity of quality software available to Ubuntu users, it also introduces new security risks. The simplified process used may:
- facilitate the introduction of malware
- prolong the risk exposure window since security maintenance is up to application authors
- allow applications to collect private user data for monetary purposes.
Therefore we must confine applications in a secure way to limit their scope. This is a technique currently being used on phones and tablets, and is becoming more prevalent on desktop systems. The strategy must be usable with Ubuntu's App Ecosystem.
AppArmor is a security module for the Linux kernel that enables mandatory access-control (MAC). This enables a system to limit what applications can do beyond traditional Unix user permissions. AppArmor is very similar to XNU Sandbox1 used by Apple to successfully confine applications downloaded from the App Store on millions of iOS devices, such as the iPhone. Now it is also required that OS X applications available in the Mac App Store run under this sandbox.
AppArmor is mature technology, is root-safe, and has been used to confine applications on every Ubuntu default installation since Ubuntu Gutsy Gibbon (7.10). It is the ideal technology to be used for widespread application confinement in Ubuntu.
The technology selected should be able to work under the converged device strategy: phone, tablet, desktop and TV. It should not require a substantially different API for app developers, and existing apps not developed specifically for Ubuntu should be able to be trivially modified to use the new confinement.
Data and Internet access
An application that is confined should only be allowed to read and write data from locations that have been approved in advance by the App Store owner. It should only be able to access the Internet if permitted.
It should be possible for the device owner to adjust permissions (presenting this graphically is not a requirement).
Additional capabilities may be added to the restrictions, such as the ability to launch the phone dialer (but not initiate calls) if being used on a mobile phone device.
The implemented solution should be secure. A rogue application should not be able to break out of confinement. There are three scenarios where this would be an attack vector:
- Jailbreaking. A device owner may want to obtain privileges on his device to install his own applications, to customize it, or to replace the firmware with a custom built one. This would be a common scenario with locked-down mobile phones and tablets. Even in cases where a special "developer" mode is offered by the manufacturer to unlock the device in a simple way, this often invalidates warranty, imposes DRM restrictions on downloaded media, or is disabled by the service provider. A user may still attempt to jailbreak a device that is unlockable in order to maintain warranty and functionality.
- Malicious applications will attempt to break out of their sandbox in order to access personal data, such as passwords, access the Internet, dial the phone to cause phone billing, etc.
- Security researchers will attempt to circumvent, and will publish deficiencies in any security technology that will be used to isolate applications. Once they have published a recipe for doing so, the recipe will be used to jailbreak devices, and will be used by malicious applications.
The technology that is used to confine applications must be of a design that is sound security wise, and can be fixed in the event that a weakness is discovered. "Good enough" is unacceptable once millions of devices have been deployed, a weakness is found, and a recipe for exploiting it has been published.
Applications should be able to be launched from the user's context without requiring special privileges or root-running helpers.
The technology used should be able to log failure events for debugging and review purposes.
The technology used should be reliable and should not leave the device in an unknown state upon application failure.
The technology used should not have a impact on the startup time of an application. If application startup is delayed for sandbox preparation, devices may feel sluggish.
Application rights should be simple to understand by developers. It should be easy for them to place check boxes next to different rights their application needs before submitting it for review. The App Store reviewers should be able to easily understand the rights the application developer has requested, and should be able to easily understand log entries from failures to comply with those rights.
Most of the technologies that are being used on the traditional desktop today assume that whatever is running under the user's privileges has the same level of security. Desktop application technologies don't confine or restrict what a user's applications can do. AppArmor already capably mediates the following:
- system files and user data
- library loading
- execution of applications
- privileged operations, such as mount
Confining applications on the converged device (phone, tablet, desktop, TV) can present difficulties. Here are a few technologies that can be problematic:
D-Bus is a simple IPC mechanism for applications to communicate. Typically, there are different buses available:
- "system bus" - a D-Bus service running privileged
- "session bus" - a D-Bus service running as the login user (each user has his/her own session bus)
- Optional other buses, such as the accessibility bus (a D-Bus service which runs as the login user)
Although there are access rights associated with communicating with the system bus, the session bus enforces no control between applications. Any application can use the session bus to communicate with another.
Typically, applications communicate with the system bus through a well-known socket in the /var/run/dbus directory. For the session bus, applications use the DBUS_SESSION_BUS_ADDRESS environment variable to determine the name of an abstract unix socket.
Any application gaining access to the abstract unix socket can send D-Bus messages to other applications, and trivially impersonate other applications. This may lead to escaping the application confinement restrictions or obtaining sensitive information.
GConf is a system for storing application configuration settings. Typically, a daemon is run under the user's context and stores settings in the ~/.gconf directory. Applications use a GConf library that communicates with the daemon using CORBA in older versions, and D-Bus in newer versions.
Any application that can communicate with the gconf daemon, or can access the database directly in the ~/.gconf directory is able to modify settings for other applications. This may include adding arbitrary plugins that are executed on application load, or modifying command lines. This can lead to escaping the application confinement restrictions. Even simply obtaining read access to other application's settings may expose sensitive information, and may result in privacy issues.
As of Gnome 3, use of GConf is deprecated and has been replaced by GSettings. Although applications should now all be using GSettings, a number of existing applications have not migrated yet.
GSettings is a system for storing application configuration settings. It has replaced GConf as of Gnome 3. GSettings uses a backend plugin to actually store the configuration settings. In Ubuntu, this is typically dconf, but an application may specify which backend to use via the API, or with the GSETTINGS_BACKEND environment variable.
dconf has two parts: a plugin for GIO which implements reading settings by directly accessing the database files, and a dconf daemon which is communicated with over D-Bus for writing settings.
The default dconf database files can be overridden with a profile file in a system location, or specified with an environment variable.
Any application that can access the database files can read and modify settings for other applications. Any application that can communicate with the dconf daemon may modify settings for other applications. This may include adding arbitrary plugins that are executed on application load, or modifying command lines, and results in being able to escape application confinement restrictions. Even simply obtaining read access to other application's settings may expose sensitive information, and may result in privacy issues.
While Ubuntu will eventually use Mir for the converged experience (phone, tablet, desktop and TV), it is worth noting that the traditional X server has a number of characteristics that make it difficult to confine:
Keyboard and mouse sniffing
Since applications running in the same X server are running in the same security context by default, they can perform certain operations such as capturing key press and mouse events. This allows a confined application to capture passwords and data that is entered into other applications.
The design of Mir should prevent these actions by default (a regular application will not be able to provide a virtual keyboard or sniff events).
In X, Any application can take screenshots of windows on the screen. This allows confined applications to capture sensitive data being displayed in other applications.
The design of Mir should prevent these actions by default (a regular application is only able to screen grab its own window).
With X, any application can obtain access to the display server clipboard. This allows confined applications to capture and modify sensitive data that is being copied and pasted between other applications.
Drag and drop
With X, any application can perform drag and drop operations. This allows confined applications to possibly capture and modify sensitive data that is being dragged between other applications, or to possibly cause other applications to open arbitrary data.
The XSETTINGS protocol provides a mechanism for applications running different toolkits to share common settings, such as double-click timeout, and interface colours. The currently running settings manager maintains an unmapped window on which all settings are stored. Applications that access X can modify XSETTINGS. Some toolkits, such as GTK, permit loading arbitrary modules specified with XSETTINGS. This may lead to escaping the application confinement restrictions.
The design of Mir should not support XSETTINGS.
A lot of libraries allow changing behaviour by setting certain environment variables before starting them. For example, GTK allows specifying arbitrary modules to be loaded by setting the GTK_MODULES environment variable. Environment variables must be inspected and possibly stripped for processes that are spawned by confined applications in order to prevent this being used to escape confinement.
GNOME Keyring is a daemon running in the user's process space designed to store secrets and credentials for applications, such as usernames and passwords. Data that is stored in GNOME Keyring is encrypted and stored in a file in the user's home directory. A pam module takes care of unlocking the default GNOME Keyring database with the user's password upon login.
The GNOME Keyring daemon is accessible over D-Bus and via a unix socket. Any application running as the user can access any secret stored in the keyring database, even if the secret was intended to be used by another application. Any application running as the user has access to the encrypted database file. Although the database is encrypted with the user's login password, an offline attack could possibly result in exposing its contents.
Confined applications should be prevented from accessing other application credentials, and should be prevented from reading the encrypted database file.
Ubuntu Online Accounts
Ubuntu Online Accounts is a central location for storing web account credentials and was originally based on libaccounts and libsignon from Meego. Any application running as the user can access any account information stored in Online Accounts, and can directly access the accounts database file. Ubuntu Online Accounts is accessible over D-Bus. Confined applications should not be granted access to account information that they don't require for proper operation.
Any application running within the user's context can send a signal to any other running application, such as the TERM signal with would cause the process to terminate. A confined application may attempt to send signals to other processes in order to perform a denial of service, to terminate processes that enforce security, or to replace a running process with itself.
/proc information disclosure
A confined application may attempt to read information about other processes directly from the /proc directory. For example, it may attempt to perform data collection on which apps are used by the user, the name of documents and websites that are currently open, etc.
Other platforms support the concept of clicking on a URI to install applications from an app store. Ubuntu should support this model in a safe manner.
Data and file access
One of the challenges in confining an application is giving it access to some of the user's data without the application being able to maliciously access it all. For example, allowing the application to open a picture should not allow it to access the whole pictures directory, and allowing an application to send an email to a contact shouldn't give the application access to the whole address book.
Overcoming challenges with AppArmor and application isolation
This section gives specific information on how we are able to use AppArmor to overcome the challenges presented when attempting to confine applications.
D-Bus will gain AppArmor mediation capabilities. The AppArmor profile for a confined application will define what D-Bus communications are allowed, and only the required access will be authorized. This is already implmented and available in a PPA. Typically an application will be allowed to use the AppMenu and HUD APIs to integrate with Ubuntu Unity and other DBus APIs such as GeoLocation will be available to the application developer.
Access to GConf will be blocked by default. Since GConf is deprecated, no solution is currently being worked on for fine-grained access to GConf for confined applications. If the need to support GConf for confined applications is determined to be a requirement, a private GConf service can be spawned for each confined application which will allow them to read and write their own settings.
Coarse-grained boolean access to GSettings/dconf will be provided and blocked by default. If supporting fine-grained access to GSettings/dconf becomes a requirement, a new dconf agent and dconf backend will be written. The confined application will come with a list of GSettings paths and permissions that are authorized. The confined application will be launched with an appropriate environment variable so the special backend is used. The special backend will then send read and write requests to the new dconf agent over D-Bus. The D-Bus AppArmor mediation will prevent the confined application from directly communicating with the dconf daemon. The dconf agent will read the application's permissions from the config file, will read settings directly from the dconf database in the user's home directory, and will write to the database over D-Bus using the dconf daemon.
Mir will be the supported display manager for Ubuntu and its design should by default address keyboard/mouse sniffing, taking screenshots, accessing the clipboard, drag and drop operations, and XSETTINGS. AppArmor integration with Mir is still desirable to restrict applications with legitimate needs for clipboard access, taking screenshots, drag and drop, etc. Mir will be implemented with security hooks at appropriate places that AppArmor can plugin to. This will allow Mir to, for example, query if an application should have access to the clipboard. Since Mir will also provide an X compatibility layer, AppArmor integration at this level may also be required.
XSETTINGS will not be supported in native Mir, at least at the application level. In other words, the shell may honor settings in some fashion, but apps won't be able to access/modify them or trigger module loading.
The converged strategy may require running some old applications (ie, from the Ubuntu archive) within a shared rootless X session on top of Mir. Any applications running in this shared session will be exposed to the traditional X design flaws, but they will not be accessible by native Mir applications and they will not be able to access native Mir applications. XSETTINGS limiting needs to be investigated in this context, although a workaround for now could be to audit toolkit libraries and limit configuration options to render them useless as a confinement escape mechanism. For example, Qt should be modified to only load arbitrary modules from system directories, or from a specific user directory that can be easily confined with an AppArmor profile.
Creating a fully-functional Xace plugin for X is not within scope for this specification. If it becomes a requirement, we will implement an Xace plugin to address these concerns. We may provide isolation within this rootless X session at some point in the future.
The confined application's AppArmor profile will contain a list of authorized environment variables for processes that are allowed to be spawned. AppArmor will either deny the process from being spawned if the environment contains an unwanted environment variable, or it will scrub the environment before the application is started.
Coarse-grained boolean access to GNOME Keyring will be provided, and blocked by default. GNOME Keyring will not be available to applications directly, but may be used by other services, such as Online Accounts.
If fine-grained access to GNOME Keyring is a requirement, GNOME Keyring will gain AppArmor integration. When an application attempts to store or retrieve a credential, GNOME Keyring will determine if it is confined by an AppArmor profile. If it is, the application will only be allowed to retrieve credentials it stored itself.
In the future, we may extend the AppArmor integration to allow confined applications to access credentials belonging to other applications, either by permitting it in the AppArmor profile, or by prompting the user for confirmation.
Ubuntu Online Accounts
Ubuntu Online Accounts will gain AppArmor integration. Initially, this access will be boolean. Fine-grained access will be added such that when an application attempts to access an online account credential, Ubuntu Online Accounts will determine if the application is confined with an AppArmor profile. If it is, the application will only be able to access credentials for which is has authorization.
An application install helper will be developed that provides a D-Bus API so that AppArmor can mediate access to it. The URI must specify a URL into the app store. When the user clicks on a link to install an app, the browser will give the application install helper the URI and it will launch the app installer so the user can install the app like normal. In this manner, the user then has a contextual prompt (the app installer). The application install helper must not allow applications to be installed without user confirmation.
The AppArmor profile will determine which signals a confined application can send to other processes.
/proc information disclosure
AppArmor will gain support for using a "PID" variable in profile rules, which will allow writing rules that will prevent a confined application from reading information out of /proc that belong to other processes.
Data and file access
The big challenge with confining an application is access to the user's data. Presenting a file chooser to the user to open and save arbitrary files outside of the application's confined directory is desired behaviour in certain circumstances. For example, a game may ask the user for a picture to attach to their online profile. This would require access to a single file in the user's pictures directory, but not access to all of them.
The simple solution to this problem is to offer an API that would present a chooser dialog to the user on behalf of the confined application. When a user specifically selects an item, such as a picture, or a contact, the confined application would gain access to it. Since the chooser dialog is not displayed by the confined application itself, the user is automatically granting permission on the file when selecting it. This allows files and other data to be read and written outside of the application's sandbox without granting access to the complete contents of the user's directories.
A more complex solution allows for applications to provide views on their supported data types such that one application can use another application's view for selecting content. For example, if a user were using an app and choose to upload a photo, the app could ask the gallery app to display available photos to upload.
Allowing the application access to the data is specific to the type of data that is requested. In the case of a contact, for example, it could simply be returned by the helper daemon over D-Bus. Granting access to a file is slightly more complex. Once a file is authorized, it could be dynamically loaded into the AppArmor profile by the daemon. This functionality doesn't currently exist in AppArmor, and a detailed analysis would need to be made to determine if this could be done in a secure fashion. If it is determined that there is no secure way to allow dynamically modifying a profile, an alternative would be to simply use hard links. The helper daemon would simply hard link the file into the confined application directory. A list of hard linked files would be maintained and a helper daemon would remove them upon application clean-up. An API can be made available to applications to allow them to preserve access to authorized data. This will allow applications to maintain a list of recently-used items, and preserve access rights to them without prompting the user once again.
In all cases, the final solution will require a helper daemon that is a separate process from the app(s) to mediate access to the files and this will likely happen over D-Bus. When the application has a need to access data outside of its confinement, it will ask the helper daemon. Ideally, the helper daemon would allow the application to access a large variety of different types of data. The helper daemon can also perform content filtering on the files and data that are read and saved in order to sanitize them from security issues.
Applications developed with the Ubuntu SDK will be mediated by AppArmor in the ways described above. Per-application configuration and keystores shall not be shared between applications. In the future, we may provide methods for applications to share this information. The SDK will allow for developers to specify access rights in the following manner:
- A high-level manifest file will be used to define the security profile for the application (see below for more information). The SDK will allow developers to create and edit this file
- The manifest file will contain (among other things):
- The name of the application and its installation path
- The name of the template profile to use (ie, one for each type of app in the app-ecosystem: QML, HTML5, etc)
Any AppArmor abstractions and policy groups to use (eg, networking, GeoLocation, Online Accounts, etc)
Once the manifest file is created, a tool can be used to generate an installable package that includes an AppArmor profile that was generated from the manifest file
- The developer can install the package and test the application under confinement
App confinement with AppArmor
In order to confine applications with AppArmor, the following are required:
An AppArmor profile for each application
- A method to launch applications in a predictable way that is run with user privileges
This consists of a text file containing a set of rules describing the resources an application is allowed to access. A customized profile ships with each application. This file is similar to Apple's App Sandbox .sb files.
To simplify application development, the AppArmor aa-easyprof tool will be used to support a predetermined list of access rights which can get automatically turned into an AppArmor profile directly via the SDK (via the manifest file). For example, some access rights might include (see AppDevUploadProcess for the actual list):
- Access the Internet
- Access Photos
- Access Documents
- Access Music
- Access Movies
- Access contacts
- Access calendar
- Access GeoIP information
- Access Downloads directory
- Use the webcam
- Launch the phone dialer
- Record audio
The list of access rights required for an application to function normally is submitted by the application developer which allows for easy reviewing. When the package is built, a debhelper plugin wll transform the list of access rights in the manifest file into an appropriate AppArmor profile such that the developer does not need to be aware of the underlying confinement implementation details.
AppArmor policy normally attaches to the executable with the kernel examining the path to the binary. For example, when /usr/bin/foo is executed on the system, the kernel sees if there is policy defined for it, then enforces the policy. AppArmor also provides the aa-exec utility to execute a program under a specific profile and the aa_change_profile() API to change into another profile during prgram execution (typically used prior to exec() after fork()). Many applications in the Ubuntu app-ecosystem are not executables in the traditional sense. They may be a QML script to be run in a QML shell (eg, qmlscene) or and html file to be rendered in a webview. Launching applications must take this into account. The AppArmor policy will also enforcement that files that are executed from the install paths (ie, in /opt/.../!AppName) will inherit the policy of the parent.
By utilizing Upstart to start apps, we can specify the policy attachment in the Upstart job. Each application will have its own upstart job to handle starting the app appropriately, and .desktop files will use 'Exec=start foo' instead specifying a path to the executable.
The upstart job will at a minimum do the following:
- Set up sandbox environment variables:
UBUNTU_APPLICATION_ISOLATION=1 (see [[https://bugs.launchpad.net/ubuntu/+source/glib2.0/+bug/1176127|LP: #1176127 for one reason why)
- set XDG_DATA_HOME, XDG_CONFIG_HOME and XDG_CACHE_HOME to reasonable values (if needed)
- (any other variables that are worthwhile)
If required, specify the AppArmor profile to change to on application launch
- Spawn the application
By using Upstart jobs, there is great flexibility for preparing the environment as well as clean up if it is needed.
A main environment variable should always be set to indicate to the application that it is running in a sandbox. This may allow an application to dynamically adjust its behaviour, and have a single source tree that would work in both a sandboxed environment, and as a regular desktop application.
Appropriate environment variables also need to be set to indicate to the application that it needs to store its data and settings in the special sandbox directory. For backwards compatibility, and to minimize modifications needing to be applied to applications to be sandbox compatible, it is suggested to simply set the XDG_* variables, as defined in the XDG Base Directory Specification. Applications that don't adhere to those variables will need to be modified, but should remain compatible with standard desktop usage.
By setting appropriate environment variables for XDG_DATA_HOME, XDG_CONFIG_HOME and XDG_CACHE_HOME, a well behaved application will work correctly. These will correspond with the paths in the AppArmor profile. Applications will should use the XDG directories. Install paths (ie, read-only) will be in /opt/.../!AppName and their writable data directories will be in ~/.config/!AppName, ~/.cache/!AppName and ~/.local/share/!AppName.
Upstart by default will provide the same environment that was setup upon the user's initial session start. In this manner, the environment is always consistent and cannot be modified by a malicious app to trigger different behavior in another app or the parent environment. The upstart job may optionally clean the environment such that only the environment variables required for execution by the application are present.
Because Upstart is spawning the application it is in a position to monitor it and some portions of the application lifecycle are free by using Upstart. For example, if the application dies, Upstart can restart it and Upstart won't launch the application more than once.
Optionally, before spawning the application, Upstart could validate the signature on the application binary to make sure it is authorized and has not been tampered with, and validate licensing. Upon failure, a message would need to be presented to the user offering to purchase the app, or download it again to fix it, as appropriate.
Controls could also be put in place to control/monitor its CPU usage, memory consumption, AppArmor failure events, disk use, and other parameters. If the application is failing, and consuming more resources than allowed (either static limits, dynamically calculated based on resource availability, based on application usage trends, or determined by a configuration file supplied with the application itself), Upstart can gracefully shutdown, or forcibly terminate the application. A friendly dialog could be presented to the user, log events, submit a crash report, and offer to respawn the application automatically.
Upstart has cgroups support which could be used for this, but it should be noted that while the use of cgroups to perform resource limiting is ideal in certain environments (such as setting resource limits on a predetermined number of virtual machines running in a controlled environment), attempting to use cgroups for limiting confined applications is difficult. Since total memory and number of running applications varies, a userspace helper is most certainly needed to dynamically balance the limits configured for each application. It is also difficult to protect against rogue applications simply by setting hard limits, as applications may need bursts of CPU time or memory to perform certain operations, in which case a hard limit would impact the user experience. Simply limiting resources isn't the solution to handling a rogue application. It should be monitored, and gracefully shutdown with an appropriate message to the user. Also, use of cgroups to confine applications is a privileged operation, which is something that we shouldn't be doing for security reasons.
- Why not use use another MAC system such as SELinux, Smack, or Tomoyo?
While there are other MAC systems available, AppArmor is a mature, proven and established technology within Ubuntu that is easy to use. By choosing AppArmor, we have a jump start on our confinement implementation and we can continue to protect the core OS while at the same time confining app store applications. Its ease of use allows for us to more easily define reusable policy and its flexibility allows for very fine-grained access controls.
- Why not use LXC?
LXC is an interesting technology that is useful for many things. It is great for Juju or providing a lightweight alternative to virtualization. It is not the right choice for application confinement because it doesn't provide significant benefits over AppArmor in its current form, but has several drawbacks: it is a new technology, it requires privileges to start/stop applications, it requires several different bind mounts for each application (which becomes messy when lots of applications are running), does not (easily) provide fine-grained access controls to files, and is generally too heavyweight for application confinement. While LXC could with effort possibly be made to provide a similar level of fine-grained confinement that AppArmor currently has, you would still have to deal with the challenging parts such as D-Bus and Ubuntu Online Accounts and would have difficulties allowing access to things such as the clipboard or individual keys within a keyring. AppArmor is mature and provides a jump start on application confinement (it was specifically designed for this purpose). It is lightweight, provides a simpler implementation that is easy to extend and allows us to unify the application confinement pieces in an elegant manner.
- Why not use seccomp?
seccomp is an interesting and effective technology that restricts which syscalls a process can use. Seccomp is a process/task level technology that is well-suited for when an application is specifically written with internal sandboxing and privilege separation in mind. While it is possible to launch an application in a seccomp enforced jail, it is difficult for seccomp to enforce a system level policy on tasks, applications, and objects (files, sockets) and it doesn't handle interactions between applications. While seccomp support may be integrated into AppArmor as part of its backend policy enforcement, at this time developers are encouraged to use seccomp in their applications to leverage further internal restrictions/separation beyond the system level sandbox. In the future, the Ubuntu SDK may use seccomp and/or make it easier to use when writing an application.
- Why not use virtualization?
- Virtualization provides very strong separation between processes, but it far too heavyweight and inflexible for this purpose (each application would ideally need its own VM which requires significant CPU, disk space and RAM. Sharing VMs to reduce this cost allows for attacks between applications within the shared VM).
- Why not use separate users, like with Android?
- This is effective but does not provide enough flexibility and ultimately doesn't meet our requirements without having to start a new security sandbox from scratch.
AppArmor is the ideal technology to confine applications on all types of Ubuntu devices. It is similar technology to what is being used in competitor's products, and is mature and proven. When completed, Ubuntu will have a modern, lightweight and comprehensive sandboxing solution.
XNU Sandbox (previously called seatbelt) is a MAC system for the TrustedBSD frame work (1)