Launchpad Entry: topic-security-application-isolation
Created: Jamie Strandboge
Packages affected: apparmor, dbus, linux, etc
Status: In Progress
Ubuntu plans to support an app store model where software 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.
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 TrustedBSD, the MAC framework 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 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 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 dial the phone 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 though 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.
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.
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.
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.
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
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.
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 and XSETTINGS. AppArmor integration with Mir is still desirable to restrict applications with legitimate needs for clipboard access, taking screenshots, 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.
If XSETTINGS is supported in Mir, XSETTINGS limiting needs to be investigated, 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. Ideally, XSETTINGS would no longer be used by confined applications, and toolkits should read common configuration from a more reasonable location. If that cannot be accomplished, Mir should gain AppArmor integration to prevent confined applications from modifying XSETTINGS.
Creating a fully-functional Xace plugin for X is not within scope for this specification. If it becomes a requirement, in addition to implementing the Xace plugin,
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. 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.
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 a 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 chooser helper daemon will be available to the application via D-Bus. When the application has a need to access data outside of it's 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.
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 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.
The Ubuntu SDK is still under development but applications developed with it will be mediated by AppArmor in the ways described above. That said, we need to ensure that per-application configuration and keystores are not shared between applications (or mediate the access).
App confinement with AppArmor
In order to confine applications with AppArmor, the following are required:
An AppArmor profile for each application
- A helper tool/daemon that is run with user privileges
This consists of a text 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. For example, some access rights that could be added to the developer tool (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
- 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. A debhelper plugin would transform the list of access rights into an appropriate AppArmor profile so that the developer does not need to be aware of the underlying confinement implementation details.
This consists of a tool that is used to launch applications in a confined way, similar to Apple's "sandbox-exec" tool, but would perform all the required setup, monitoring, and cleanup of the application. Here is a list of actions the tool would need to perform, followed by a description of each:
- Prepare the application directory
- Set up sandbox environment variables
Load AppArmor profile for application
- Spawn application
- Monitor application resource usage
- Upon application exit, perform clean up tasks
Prepare the application directory
This step consists of preparing a directory in the user's home directory where the application can store settings and files. For example, "~/.confined/AppName".
If the directory doesn't exist, the helper will create it, create appropriate sub-directories, and possibly copy over some template files. If the directory does exist, it will make sure data files that were placed into it in previous launches have been properly cleaned out.
Set up sandbox environment variables
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.
The application launcher may optionally clean the environment such that only the environment variables required for execution by the application are present.
Load AppArmor profile for application
AppArmor currently loads profiles at system startup. It is possible to load a specific AppArmor profile after the system has booted, but that is a privileged operation. For security reasons, we do not wish to perform privileged operations when launching a confined application. For the initial implementation, profiles will be loaded at system startup, and on application installation. The launcher may want to take advantage of the "aa-exec" tool to launch the confined application under an existing, loaded profile.
It may be desirable in the future for AppArmor to gain functionality for unprivileged users to load a profile for applications they subsequently spawn. In this case, the launcher would ensure the proper AppArmor profile is loaded.
At this point, the launcher spawns the application but stays alive to monitor it. Optionally, before spawning the application, the loader can validate the signature on the application binary to make sure it is authorized and has not been tampered with, and validate licensing. Upon failure, the loader can display a dialog to the user offering to purchase the app, or download it again to fix it, as appropriate.
Monitor application resource usage
While the application is running, the launcher could 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), the loader can gracefully shutdown, or forcibly terminate the application. It can present a friendly dialog to the user, log events, submit a crash report, and offer to respawn the application automatically.
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.
Having the launcher monitor for application malfunction is the ideal solution for this issue.
Upon application exit, perform clean up tasks
The launcher will perform any cleanup tasks including removing hard linked files, possibly unloading the AppArmor profile, and any other clean up task that is necessary.
- 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. It's 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 keryring. 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 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 the 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.