A control point for reducing root abuse of file-system privileges

A Control Point for Reducing Root Abuse of File-System PrivilegesGlenn WursterSchool of Computer Science Carleton University, Ottawa, Canada

Paul C. van OorschotS

chool of Computer Science Carleton University, Ottawa, Canada

gwurster@scs.carleton.ca ABSTRACTWe address the problem of restricting root’s ability to change arbitrary ?les on disk, in order to prevent abuse on most current desktop operating systems. The approach ?rst involves recognizing and separating out the ability to con?gure a system from the ability to use the system to perform tasks. The permission to modify con?guration of the system is then further subdivided in order to restrict applications from modifying the ?le-system objects of other applications. We explore the division of root’s current ability to change arbitrary ?les on disk and discuss a prototype that proves out the viability of the approach for designated system-wide ?le-system objects. Our architecture exposes a control point available for use to enforce policies that prevent one application from modifying another’s ?le-system objects. In addition, we review in detail the permissions given to current installers, and alternative approaches for secure software installation.

paulv@scs.carleton.caaccount can perform arbitrary actions on the ?le-system, including creating, modifying, and deleting any ?le-system object (including ?les, directories, and links). This open environment has lead to many problems, both stability and malware related. On most current desktops, malware uses the ability to change arbitrary ?les on disk in order to hide itself. While the principle of least privilege dictates that the privileges assigned to a process should be no more than the privileges required to perform the designed task, the standard exercising of root privilege in order to install applications does not follow the principle. While some progress has been made by encouraging users and daemons not to run as root, the same cannot be said for installers – perhaps the most common use of root privilege in the current computing environment is for system recon?guration (i.e., installing, uninstalling, or upgrading software). In this paper, we pursue reducing the ?le-system privileges of root in order to better protect a system against abuse. The actions performed by any user (including root) on a system can be partitioned into two classes. The ?rst involves actions related to performing day-to-day operations on the system (e.g., writing a paper, browsing, reading email, or playing a game). Such actions typically do not have a lasting impact on the state of the system (modulo data ?le creation and deletion). The second class involves actions related to changing system con?guration. We de?ne the con?guration state of a system as the set of programs installed, as well as the global con?guration related to each program. In order to survive reboot, both the programs installed and all global con?guration state must be saved into the ?le-system, and hence we focus on those con?guration operations having a direct visible e?ect on disk. The common protection long used in practice is to limit write access to application ?le-system objects (e.g., ?les including binaries, directories, symbolic links, and other objects that are part of the ?le-system) to root [14]. This protection mechanism fails to prevent abuse by any application running as root, including during install, upgrade, uninstall, or run-time. In today’s computing environments, it is only realistic to treat any two applications on a system as mutually untrustworthy. Given this updated threat model, we further subdivide con?guration in order to encapsulate applications – by this we mean that while it may be possible for one application to read the binary, data, and con?guration ?les belonging to another application, it is not possible to modify another’s ?les on disk. In contrast, current desktop approaches for software installation do not pre-

Major commodity operating systems have a root or superuser account which has total control over the machine, including the ?le-system. Processes running under the root

Permission to make digital or hard copies of all or part of this work for personal or classroom use is granted without fee provided that copies are not made or distributed for pro?t or commercial advantage and that copies bear this notice and the full citation on the ?rst page. To copy otherwise, to republish, to post on servers or to redistribute to lists, requires prior speci?c permission and/or a fee. CCS’10, October 4–8, 2010, Chicago, Illinois, USA. Copyright 2010 ACM 978-1-4503-0244-9/10/10 ...$10.00.

224

vent an application from modifying or deleting ?le-system objects related to or created by an unrelated application, a problem previously identi?ed in the literature [56, 51]. Our restriction and division of root ?le-system permissions addresses this problem, without requiring any radical change in ?le-system layout (e.g., applications can still install their binaries in a common location such as /bin). As a direct result, applications are better protected from malware and other applications, even those running with root privileges. In our design, which expands on preliminary ideas outlined in a workshop paper [66], the ability to modify arbitrary objects (beyond simply ?les) on the ?le-system is removed from root and reassigned to a process running with a new con?guration privilege. This process in turn can be used to prevent one application from modifying the ?lesystem objects related to another. In creating a distinct con?guration permission, the con?guration tasks currently performed under root privilege are separated from the everyday tasks. Daemons, applications, or installers running as root no longer automatically inherit con?guration privilege. While we focus primarily on installers in this paper (since they perform the vast majority of system con?guration changes), the protection mechanism remains in force past install time, restricting system modi?cations while applications (including Trojans) are running. Our implemented prototype system, using Debian 5.0 as the base environment, consists of a modi?ed Linux kernel which restricts updates to designated ?le-system objects (but not, for example, user-speci?c ?le-system objects), a modi?ed Debian package manager, and a user-space daemon (called configd) which is responsible for protecting an application’s ?le-system objects from being modi?ed by other applications. A control point made available in configd allows each con?guration related ?le-system modi?cation request to be examined, and either authorized or denied. As we explain in detail later, the prototype successfully prevented installation of current rootkit malware while having an imperceptible overhead to the end-user. While our discussion and prototype focus on Linux, we believe the approach can be adapted to Windows, Mac OS X, BSD, and other operating systems. Indeed, configd implemented on Windows could also protect the Windows registry (since it is stored on disk). In Section 2, we give background which motivates our work. Section 3 discusses several currently-deployed alternative approaches for encapsulating an application’s ?lesystem objects on disk. Section 4 discusses design constraints and introduces the two levels which together protect system con?guration and applications. Section 5 discusses our proof of concept prototype. Section 6 discusses related work. We conclude in Section 7.

plication installer. The installer is a binary or script, often written by the same company or individual that developed the application. Its purpose, when run, is to place the various ?le-system objects associated with the application in the correct location and con?gure any system parameters (e.g., in some cases to ensure the program gets run during boot). Application installers are typically given complete control over the system during install, with users encouraged to run them with full permissions as shown in Figure 1. Whenever an application installer is run on a typical system, the entire system is opened up for modi?cation by the installer. If the installer is malicious, or can be compromised [7], the entire system can become easily compromised. This approach does not prevent one application’s installer from modifying the ?le-system objects of another application.

Figure 1: A Windows 7 prompt to run an installer with administrator privileges. Application install scripts, like those executed through the make install command on many open source projects, are a slight variation of the application installer. When told to install to a user’s home directory, they do not require administrator privileges. They still require administrator privileges, however, when attempting to install to a location controlled by the administrator. Using make install does not prevent modi?cation of ?le-system objects belonging to other applications installed by the same user. While Windows encourages following the principle of each application installing into its own directory on the ?le-system, the practice of running application installers as root leaves the principle unenforced.

2.2

Application packages

2.

BACKGROUND ON INSTALLERS

Our approach of limiting abuse of root privilege as it relates to con?guration changes of designated ?le-system objects is most relevant to the case of software installs, upgrades, and uninstalls. For context and to highlight the problem, we review existing approaches to installing software on a desktop.

2.1

Application installers

The most common approach to installing applications on commodity desktops and servers is through the use of an ap-

Package managers are typically provided by an operating system (OS) or OS developer to ease development of an application installer for the platform. Instead of writing an application installer from scratch, the application developer creates a package using the package manager APIs and following the rules set by those who developed the package manager. Typically, the package consists of data used by the package manager, as well as ?les to be installed and scripts to run as part of the install. Common install operations are taken care of by the package manager. While the development of package managers has resulted in installers transitioning from being executables to packages (e.g., various Linux packages [10], Microsoft Installer packages [36],

225

and Apple application packages [50]), most of these package managers still allow for executing arbitrary binary code or scripts contained in the package being installed, resulting in the same level of risk to the system as if an executable was run to perform the install. If root permission is requested by the package (or required by the package manager, as is the case with Linux packages), and the end-user enters an appropriate password when prompted (as users are now well trained to do so upon request), these scripts are run as root. The use of application packages does not prevent an application from modifying arbitrary ?le-system objects. One example of a malicious Debian package was a screensaver posted on http://gnome-look.org. The package, when installed, would also download and install a bot onto the local machine [55, 57].

from page . While we choose to implement the GoboLinux approach in configd (as discussed later in this paper), the alternative approaches discussed in this section are equally viable. We summarize the three approaches in Table 1. Note that although Table 1 indicates that for GoboLinux, application upgrades are not supported, the use of the GoboLinux approach in configd is done in such a way that application upgrades are supported.

3.1

GoboLinux

2.3

Apple bundles and packages

With Mac OS X, Apple introduced a new method for installing commodity applications other than application packages: application bundles. This results in two approaches on Mac OS X for installing software. Application bundles. Application bundles are similar to packages as discussed above with two key di?erences. The ?rst is that all ?le-system objects in the bundle will be installed into the same sub-directory by the OS (akin to the approach used on Android described in Section 3.2). The second is that scripts are not run by the OS during install. Typically, application bundles are installed through a dragand-drop style copy operation. Commonly distributed as disk images, application bundles greatly increase the security of the system against malicious application installers. Unfortunately, Apple still supports a second approach for installing applications and relies on the software developer to choose between them. The malicious developer is unlikely to distribute his software as a bundle when distributing a package (see below) is possible. Legitimate applications are distributed as both bundles (e.g., Mozilla Firefox) and packages (e.g., Adobe Flash). While application bundles remove the ability for many applications to obtain root privileges, they do not mitigate the entire threat. Any application which obtains root privileges (maliciously or otherwise), even if installed as a bundle, can still modify any ?le on the system. Application packages. For more complex applications, additional actions (other than simply copying the ?les into the application directory) may need to be performed by the installer during the install process. For these applications, Apple provides an application package framework as discussed in Section 2.2. The status quo across multiple operating systems is to “restrict” installers by requiring the user authorize an installation by entering an administrator password before the installer can run. Once the installer is given “blind” full permission to the system, the user must trust that the installer does not abuse its privilege (since it is di?cult to tell what the installer actually does with its root privilege – thus we call it blind trust).

3.

APPROACHES FOR ENCAPSULATING APPLICATIONS

In this section, we discuss several approaches for encapsulating applications, using the de?nition of encapsulation

In GoboLinux [38, 39], each application is installed into its own directory (similar to Android). The actual install of a program is done through calling three scripts. PrepareProgram is responsible for creating the base directory where the program will be installed. CompileProgram takes a compressed archive of the program source, con?gures it with the appropriate ?ags so it will be installed into the directory prepared for it by PrepareProgram, compiles the program, and installs it. SymlinkProgram creates symbolic links to the various program binaries, libraries, and settings. For backwards compatibility, the common Unix directories (e.g., /usr/bin, /sbin, and /lib) are also linked to /System/Links, which is in turn populated with symbolic links for each of the applications that have been installed. To prevent an application from escaping its assigned application directory, the make install command is run under a special user ID [37]. This user is only allowed to modify ?les under two directories: the one in which the application is being installed to, and the one it was compiled from [38, 39]. In restricting an application during both compile and install, the other applications on the system remain protected against modi?cation. For those applications which are not complete programs in themselves but instead extensions to other applications which are already on the system (e.g., the PHP module is often installed as an extension to the web server Apache), the base application needs to be made aware of the extension. In GoboLinux, the con?guration of each application is stored in the shared tree /System/Settings/. All ?les in this directory are symbolic links that point back to the settings folder, which is a sub-directory of where the application was installed. The base application provides a directory under /System/Settings where a module can register itself (through SymlinkProgram). Many distributions other than GoboLinux have also adopted this as the method of installing extensions into a base application (although the exact path to the con?guration will change). Another related example involves services which should be started on system boot. On Debian based distributions, the accepted location for a script responsible for starting a service is in the directory /etc/init.d. GoboLinux places scripts responsible for starting the various system services in /System/Links/Tasks. GoboLinux depends heavily on symbolic links being placed into the above mentioned standard directories for extensions to applications. The base GoboLinux executable SymlinkProgram is responsible for updating this directory tree based on the layout of ?les in any particular application directory (GoboLinux does not allow application installers to directly modify the symbolic links in shared directories). A limitation of GoboLinux is that it does not cleanly support upgrades (or security patches) to an application. Each upgrade is treated as an install of a new version of the ap-

Table 1: Characteristics of current systems which encapsulate applications on disk. plication, resulting in each version being installed into its own directory on disk. The job of sorting out which version of an application should be used by default on a system is left to SymlinkProgram (the PATH environment variable is set to point to /System/Links/Executables, a directory maintained by SymlinkProgram). The sharing of con?guration ?les between di?erent versions of an application is left up to the individual application. Indeed, each version of an application has its own copy of the con?guration ?les stored in a Settings sub-directory of the application directory, alongside the various sub-directories for each version of the application which is installed. bundled applications targeting iPhones (up to those released in January 2010) [3]. The biggest change is that each application installed onto the iPhone is limited to making ?lesystem modi?cations only in the directory it was installed into. This includes limiting an application to reading and writing data ?les to an application speci?c area of the ?lesystem (similar to Android). In contrast to Android, Apple application bundles targeted to the iPhone are not signed with the key of the software developer. Instead, each application must be signed by Apple before it can be run on an iPhone (we ignore “jailbroken” iPhones in our discussion). Before signing an iPhone application bundle, Apple examines the application to ensure it meets their criteria [2]. For application bundles designed for Mac OS X, Apple has no such restriction that the bundle be veri?ed and signed by Apple before it can be installed.

3.2

Android

On the Android platform [1, 20], each application package is assigned its own directory and unique user id. While Android uses the Linux kernel as its base, being a single user platform, Android remapped the traditional user accounts to restrict communication between applications. The Android application installer ensures that each application is restricted to making ?le-system modi?cations in the directory it was installed into. Unlike the ?le-system hierarchy standard [43] as used on Linux, there are no shared directories for storing binaries, libraries, con?guration ?les, and other elements. Android bene?ts greatly from the ability to mandate a ?le-system layout which restricts each application to single sub-directory on the ?le-system. The Android platform only allows a new version of an application to be installed over top of the old if all public keys in the new version are also contained in the old version already installed (new keys cannot currently be introduced during an upgrade). During the install of an application, the application itself is not given a chance to run any installer scripts as administrator – greatly restricting the damage a particular application can do to ?les belonging to other applications. The platform does a good job of preventing one application from modifying another’s ?les. With additional work, the Android approach can be adapted to the standard Linux ?le-system hierarchy [43]. Instead of storing all ?les related to an application in a single directory, a database could be maintained which maps each individual ?le to the application it is associated with (the Debian package manager already keeps such information), as well as a list of public keys which are used to verify the next version of the package. The Android approach does not support scripts being run as part of the installation process (similar to Apple bundles not supporting scripts; see Section 2.3). Combining the Android approach with GoboLinux, however, allows the execution of installation scripts which can modify the con?guration of the application being installed while still preventing other applications from being modi?ed.

4.

DESIGN FOR CONTROLLING ROOT PRIVILEGES ON FILE SYSTEMS

3.3

Apple application bundles

While the general application bundle is discussed in Section 2.3, a number of restrictions were made by Apple for

Our main objective is to reduce root privilege so that programs, such as installers, cannot take advantage of overly coarse access controls to abuse the privileges they have been given. The design of our approach is subject to several selfimposed constraints. We believe that, to be viable, any alternate approach for restricting ?le-system privileges on the desktop at a per-application level would need to ful?l the following considerations. 1. Compatibility with current ?le-system layouts. In designing a Linux-based prototype of the proposal, our goal was to avoid requiring redesign of the current ?le-system hierarchy [43] in favour of a solution compatible with the current ?le-system layout. Applications are protected against modi?cation while retaining the current ?le-system layout – installing ?les to directories shared with other applications. In contrast, GoboLinux [39] and Apple (in Mac OS X) did redesign the ?le-system hierarchy. Their motivations were apparently to impose cleanliness in restricting each application to its own directory. While the separation of each application into its own directory may simplify the challenge of restricting con?guration changes on a per-application basis, a backwards compatibility layer is still required to support applications not designed for the new layout. 2. Minimal impact on day-to-day operations. Most of the time, a computer is used to perform day-to-day tasks (run applications) with a constant con?guration of the applications and operating system. Occasionally, its con?guration is modi?ed in order to expand/modify the tasks it can perform (e.g., applications are installed, updated, removed, or recon?gured). Our proposal (and indeed any alternate configd approach) should impose no noticeable impact on such day-to-day operations, with no changes to regular user work ?ow. 3. Backwards compatibility for current installers. We introduce new restrictions on an application’s ability to modify ?le-system objects. These restrictions will typically

227

in?uence the install, upgrade, and removal of applications. It is unrealistic to assume that all application packages will be modi?ed in parallel during deployment of such a solution. Backwards compatibility is therefore critical for incremental deployability. Our prototype did not change the Debian package structure at all, maintaining backwards compatibility with versions of dpkg not designed to work with configd. 4. Usability. Our focus in this paper is on providing a solution which can be used by non-expert users, and to avoid forcing upon users choices which they are ill-equipped to respond to correctly. Our solution achieves this goal, allowing an applications’ ?le-system objects to be protected against modi?cation during install, upgrade, uninstall, and at runtime, without presenting the user with complex choices. While our prototype solution did leave enabled the option of querying the user about ?le-system operations, this feature can be disabled without impacting the ability to install software (as discussed in Section 5.5).

4.1

A control point for division of root privileges

To build a system designed to reduce root abuse of ?lesystem privileges, we ?rst separate con?guration related activities (those con?guration actions a?ecting the applications installed or their global con?guration as stored on disk). We then further subdivide the con?guration privilege to remove the ability of an application installer to modify any ?le-system object other than those which are part of the application being installed (or upgraded/removed). Our prototype design consists of two main elements: a kernel extension and a user-space daemon. The user-space daemon is responsible for the bulk of the work, namely, ensuring that one application cannot modify ?les related to a di?erent application. The kernel is responsible for denying (or forwarding) requests to modify protected ?le-system objects, by which we mean ?les (including binaries), directories, symbolic links, and other objects that are part of the ?le-system. Protected ?le-system objects (which we call c-locked ?le-system objects, short for con?guration locked ) are designated (marked) as such by the user-space daemon (an alternate method of protecting ?le-system objects is by using a union ?le-system to redirect writes [63]). Any application ?le-system object marked as part of the system con?guration (and hence to be protected against modi?cation by other applications) must be so designated. Only a process holding a newly introduced con?guration permission is allowed to modify the system con?guration on disk (and hence c-locked ?le-system objects). The exact distribution of duties within our design has the kernel responsible for: 1. Restricting to programs running with con?guration permission the ability to delete, move, and write to clocked ?le-system objects. By design, “root” is not allowed to make arbitrary changes to c-locked ?le-system objects (including the kernel image) – changes are limited to processes running with con?guration privilege. 2. Restricting the ability to obtain con?guration permission. In our prototype, this is done by allowing only a single process, the con?guration daemon (configd) to have con?guration permission. 3. Restricting the ability to control the process running with con?guration permission (e.g., by not allowing configd to be killed or modi?ed by a debugger).

In restricting con?guration permission to a single daemon, we introduce a chokepoint within which we can further subdivide ?le-system access by application. (While it is possible to use the kernel as the chokepoint, our preliminary exploration in this direction suggested that implementing the functionality required to further subdivide root on a perapplication basis directly in the kernel introduces functionality into the kernel which is already available in user-space.) We perform the actual subdivision in the above-mentioned con?guration daemon configd. It performs the following operations: 1. Respond to requests for con?guration changes from processes running on the system. In our prototype, requests were at the granularity of package installs and uninstalls, but our design could be easily modi?ed to handle other granularities. 2. Designate ?le-system objects as c-locked. It marks a setting in a data structure associated with the object to denote this designation. In our prototype, each ?le installed when upgrading or installing a package is marked as c-locked. 3. Perform authorized changes to the con?guration of the system. We now discuss the threat model, and how the two elements work together to restrict the ability for an application to modify ?le-system objects belonging to another application.

4.2

Threat model

We assume that applications cannot obtain kernel level control of the system,1 although on most current systems, any application running with root access can modify the running kernel. This assumption therefore relies on the proper functioning of a subset of mechanisms designed to protect kernel data and code against compromise by applications running with root access, as proposed in the considerable independent literature [4, 41, 60, 30, 19, 42, 29, 61, 44, 11, 16]). For the prototype implementation, disabling access to /dev/kmem was su?cient to simulate restricting kernel level control of the system. We assume that the user of a computer system can be trusted to not be malicious. The proposal, therefore, does not protect against physical attacks, such as rebooting into a kernel that does not enforce the proposed protection mechanism. Our work avoids declaring the user as the enemy and preventing them from modifying their own system as they wish [58, 31]. We favour using persuasive approaches to encourage users to protect their system against malware while not taking control completely out of their hands. We assume malware can run arbitrary code in userspace (including installing new code while not modifying any clocked ?le-system object), but cannot gain con?guration permission (i.e., the permission delegated to configd, which is required to modify c-locked ?le-system objects). We stop malware from modifying permanent (i.e., on disk) systemwide con?guration beyond those ?les packaged with it. While we leave open the exact set of c-locked ?le-system objects, we view the set to include shared libraries, executables, system1 We de?ne the kernel (and hence kernel level control) to include only those aspects running with elevated CPU privileges (ring 0 privileges on x86); this de?nition does not include core system libraries installed alongside the OS but run in user-space.

228

con?guration ?les, start-up scripts, and other ?le-system objects which do not change as a result of day-to-day system use. In e?ect, the system con?guration on disk includes the set of applications installed as well as each application’s ?les which are required at run time. We do not attempt to prevent malware from running on the system. The system is also not designed to support c-locking of user-speci?c application con?guration ?les. If all system-wide con?guration ?les and applications are c-locked, malware is restricted to modifying user-speci?c data ?les (e.g., embedding a macro in word processing documents) and user-speci?c con?guration settings (e.g., if rlogin is enabled on the system, malware may still be able to propagate by modifying individual user’s .rhosts ?les). The new restrictions on modifying systemwide con?guration prevent many attacks currently used by malware authors, including modifying /sbin/init (e.g., by the mood-nt kernel based rootkit), modifying core system libraries and executables (e.g., by the ARK rootkit), and modifying con?guration ?les (e.g., the hosts ?le, as done by malware). All ?le-system objects used during boot prior to a user logging in (e.g., virus checkers) can be protected by configd. Furthermore, applications’ ?le-system objects cannot be arbitrarily modi?ed by malware. While we do not restrict the running of arbitrary malicious code, we do restrict the ability to have code automatically run at the appropriate time (e.g., during system boot).

Figure 2: File-system data-structure layout including new c-lock ?ag.

4.3

Linux kernel protection of c-locked ?lesystem objects

How a kernel handles ?le-system objects can directly affect the security of c-locking. In the Linux kernel, the key ?le-system data structures directly related to the protection of ?le-system objects by configd are the directory entry (or dentry) and inode [47]. The inode data structure contains most of the information related to the ?le data and meta data (e.g., the traditional Unix ?le-system permissions read, write, and execute) and pointers to the actual blocks on disk which hold the ?le contents. The dentry contains information related to the speci?c instance of a ?le in a particular directory, including the name of the ?le (as it appears in that directory) and a pointer to the inode. For the purposes of c-locking, the dentry inherits the c-locked status of the inode. If the inode is marked as c-locked, then the directory entry can be deleted or moved only by configd. File operations on an inode which is not c-locked are restricted through current access-control restrictions (including traditional Unix ?le permissions). Figure 2 demonstrates the relationship between inodes and dentries. Symbolic Links. Symbolic links are directory entries in Linux pointing to an inode containing a path string. When opening a symbolic link, the kernel retrieves the path name from the symbolic link inode. It then follows the retrieved path name to obtain another dentry and inode (which is either yet another symbolic link or some other element such as a ?le or directory). The proposed system supports either c-locking the symbolic link, the object it points to, or both. Hard Links. A hard link is a directory entry in Linux pointing to the same inode as another directory entry. As with regular ?les, because the inode itself contains the clock ?ag, any hard link pointing to the inode inherits the c-locked attribute associated with the inode. An attacker does not gain modi?cation privilege by creating a hard link to a ?le-system object protected by c-locking. The ability to

create a hard link to a c-locked ?le is restricted, being either allowed or denied by configd. Directories. A directory is an inode which instead of pointing to ?le data, points to a list of dentries. While previous approaches [9, 67] focused on protecting ?les more than directories, there are cases in which a directory should be protected. As an example, during start-up the Debian /etc/rcS.d directory is accessed and every ?le (or ?le pointed to by a symbolic link) in this directory is run. Any malware installed into this directory would be started automatically during system boot. The proposed system can protect directories since they can be c-locked in the same manner as ?les and symbolic links.

4.4

configd

The prototype configd is designed to subdivide root ?lesystem permissions on a per-application basis. In our framework, configd, or its equivalent, becomes a chokepoint which applications must use in order to modify c-locked ?le-system objects (and hence the con?guration of the system). To enforce that configd is the only way that c-locked ?le-system objects can be modi?ed, the kernel grants the new con?guration permission to configd alone. By delegating this privilege to configd, the kernel need not know about every application on the system or what ?le belongs to which application; it need only recognize that a speci?c ?le is c-locked and leave the handling of this ?le to configd. configd must be started early during the boot process (configd itself restricts changes to the boot process). Once configd has started, other programs are prevented by the OS kernel from obtaining con?guration permission. The design of configd takes advantage of the temporal nature of software installs. At the time of installation of application software, it is assumed that the operating system and configd are already installed and running. This assumption is reasonable if configd is made part of the OS or core system.

4.4.1

Example configd rule set

While the core configd approach can use any number of di?erent protection mechanisms for separating ?les on a perapplication basis, we chose to depend on Debian packages (and indeed, the package manager – dpkg) in our solution. During the package install process, we allow the following actions to be performed.

229

1. If A is a c-locked ?le-system object whose contents under a cryptographic hash have the same value as A.dpkg-new, then A.dpkg-new can replace A (i.e., if A and A.dpkg-new contain the same data). We do not mandate any speci?c cryptographic hash algorithm, other than to stipulate that, at minimum, it must have second pre-image resistance [33] (our configd prototype currently supports SHA-1 and can be easily expanded to support others). 2. If A is a c-locked ?le containing one or more public keys and A.dpkg-new is another ?le containing a digital signature veri?ed by using a public key in A, then A.dpkg-new is allowed to replace A. 3. If c-locked ?le A is associated with package PKG and is not associated with any other package installed on the system, then when upgrading package PKG, A may be modi?ed. 4. If c-locked ?le A is associated with package PKG and is not associated with any other package installed on the system, then install scripts associated with package PKG may modify A. 5. All other operations involving a c-locked ?le are considered to be potentially dangerous. They can either be presented to an expert user for additional oversight, or simply denied (as discussed in Section 5.5). Of the above rules, some merit further discussion. Rule 2 adapts concepts used by the Android OS [1], but to the ?le (as discussed by Wurster et al. [65]) as opposed to package level. The rule relies upon the use of public keys and signatures, but does not rely on a PKI. Rule 3 allows the modi?cation of all ?les associated with a package when a new version of the package is installed. The rule requires that configd keep track of packages installed on the system, as well as which ?les are associated with which packages. We discuss the semantics of how our prototype handled packages in Section 5.3. It is important to note, however, that a package cannot modify any ?le on the system simply by asserting ownership of the ?le (through including the ?le in the list of ?les the package is associated with). Any ?le which is listed as belonging to more than one package cannot be arbitrarily modi?ed by any package. The option still exists, however, for a ?le associated with more than one package to be updated through rule 2. Rule 4 restricts, through exclusion, the ?les that an install script can modify. The rule is borrowed from GoboLinux [39] and discussed in more detail in Section 3.1. Our testing con?rmed that the above rule set allows package installs and upgrades to be automatically allowed, while providing encapsulation. While the option of querying the user with remaining operations was left enabled in the prototype, we found in testing that during upgrades, the user is not queried at all – with the exception of updating global con?guration ?les (see Section 5.4), rules 1 through 4 accommodated all install operations.

[45]. In so doing, the underlying ?le-system-speci?c data structures do not need to be modi?ed. The extended attributes are tied to the inode. We used the trusted extended attribute name space because it supported setting extended attributes on symbolic links. We created our c-locking protection mechanism as a Linux Security Module [32, 62]. The kernel implementation was approximately 2200 lines of code, including the backward compatibility layer. A new device node (/dev/configd) was used as the interface between the user-space configd and the modi?ed kernel, allowing communication between the two. The process of opening the device node initiated c-locking protection in the modi?ed kernel. The kernel understands and responds to commands sent by the user-space configd through the new device node, allowing configd to disable raw disk writes (as discussed in Section 5.2), and mark ?les as c-locked (as discussed in Section 4.1). To prevent applications from being able to modify c-locked ?le-system objects through modi?cation of the kernel, access to both /dev/kmem and /dev/mem was restricted (both are options built into the Linux kernel).

5.2

configd implementation

While the primary purpose of configd is to encapsulate applications on disk, during the course of prototype development several additional features were added. These include: 1. A mounting module which can decide whether a request to mount a ?le-system should be performed (it performs the operation, if allowed). To ensure that c-locked ?le-system objects remain accessible by applications they are associated with, we must ensure that a new ?le-system cannot be mounted over top of c-locked ?le-system objects. configd does this by examining the trusted.con?gd.nomount ?le-system extended attribute. For directories which should not be mounted over (e.g. /usr), this extended attribute should be set on the directory inode. The mounting module also informs the kernel through the configd device node that requests to write to the underlying raw hard drive sectors should be denied, since allowing such requests would undermine the security of both c-locking and per-application restrictions enforced by configd. 2. A modprobe module which handles requests for the insertion or removal of kernel modules. In order to ensure that configd remains the chokepoint for restricting ?lesystem objects on a per-application basis, root must not be allowed to install arbitrary code into the running kernel. While the prototype version of this module currently accepts all requests, kernel module loading can be easily restricted based on a number of criteria, including whether the module is signed with a recognizable key [29] (such an approach would not require a complete PKI infrastructure).

5.3

Debian package manager modi?cations

5. 5.1

PROTOTYPE IMPLEMENTATION AND EVALUATION Kernel extensions

To support c-locked ?le-system objects, we used the extended attributes functionality [53] of ?le-systems such as ext3 and XFS. This is the same approach used by SELinux

Because the Debian package manager (dpkg) is responsible for performing most con?guration changes on a system, we integrated dpkg with configd. While other methods of restricting con?guration changes at a per-application level may choose to totally replace dpkg, augmenting dpkg to communicate with configd was suitable for our prototype (configd had the ?nal say as to whether all requests for operations on c-locked ?les are allowed). The modi?ed dpkg informed configd about each package which was being installed or upgraded, and also marked as c-locked each

230

?le installed when upgrading or installing a package, regardless of whether the ?le was previously c-locked. Because it is considered an error on Debian to have a ?le belonging to two unrelated packages [23], Debian’s package approach lends itself nicely to a clean separation between applications. Since packages can contain arbitrary ?les, any ?le which should be c-locked either already is, or can be, distributed in a package. In our prototype, the Debian package manager and surrounding infrastructure was responsible for preventing one application from assuming the name of another (and hence being able to modify the ?les associated with the second package). Such an approach depends on the security of the packaging system in Debian, which although reasonably secure against intrusion, is not perfect [10]. To reduce the dependence on Debian to keep packages from replacing other un-related packages in the archive, an approach similar to that used in Android could be deployed. In Android, a form of digital signature not tied to an identity is used as a way of restricting replacement of packages (see Section 3.2). A package is typically signed with a private key held by the developer. Any new version of that package is allowed to replace the installed one if it is signed with a private key veri?able with the corresponding public key contained in the currently installed package. In this way, application updates are restricted to those software authors holding the private signing key. Unless two applications are written by the same developer, and assuming that private keys are not generally shared between developers, the two applications are unlikely to have any identical keys and hence will not be able to modify each other. In adapting the approach to Debian packages, we can eliminate the risks associated with relying on the Debian packaging team to properly keep packages distinct [10].

4. For each ?le associated with the package PKG, the UID is changed back to the value stored in step 2, unless the user owning the ?le has been changed by the script. 5. The UID allocated in step 1 is freed. The approach allows an (un)install script associated with package PKG to modify any ?le associated with the same package, but does not allow the install script to modify any ?le associated with any other package installed on the system. It achieves the design goal of restricting ?le-system modi?cations such that one application can not modify the ?le-system objects associated with another application installed on the system. Indeed, simply implementing the approach into dpkg without fully implementing configd has bene?ts over the current approach of allowing unrestricted access to the ?le-system by install scripts. While we did not encounter any scripts which were affected by the change from running as root to running as an unprivileged UID, if such a scenario did pose problems, the use of a fake root would allow configd to better emulate the permissions an install script has without configd running. fakeroot is a program commonly used in the Linux environment to make an application believe it has root privileges. The operations performed while running under fakeroot are recorded with the goal of being able to save and replay them later. This approach is most often used when creating a distribution package from a source archive, but can also be used by configd. It is also the approach used in related work to record the actions performed by an installer [56, 51].

5.5

Handling of operations not automatically allowed

5.4

Allowing scripts during package install and uninstall

In Section 4.4.1, rule 4 states that if c-locked ?le A is associated with package PKG and is not associated with any other package installed on the system, then install scripts associated with package PKG may modify A. In order to enforce that an install script contained in a package may only modify ?les on the system associated with that package (and no other package), we implemented an ability to run install scripts within configd. The approach closely parallels the approach used by GoboLinux for installing applications (see Section 3.1). The following procedure was followed for running both install and uninstall scripts: 1. An unused user ID (UID) is allocated by configd. While configd examined /etc/passwd in our prototype, di?erent methods may be required when using alternate approaches for user account control. 2. For each ?le associated with package PKG (and not associated with any other package installed on the system), the owner of the ?le is recorded by configd and then changed to UID. 3. The script is run as user UID by configd. In running the script as a user who only has permission to modify ?les associated with the package, other applications on the system are protected by the standard access controls on the system.

While the prototype left enabled the option of querying the user for operations not allowed by other rules discussed in Section 4.4.1, we believe that this rule can be disabled when deploying configd to non-expert user systems, causing configd to reject of any ?le-system operation not allowed by the other rules. During testing, we were not queried by configd at all about modi?cations to the ?le-system during package install and upgrade. The user continues to be queried by configd about con?guration ?le changes performed manually by root. To prevent malware from interfering with questions configd poses to the user, we extended the kernel, preventing other applications from running while the user is being queried. Because root no longer has permission to modify arbitrary ?les on disk, any con?guration changes performed directly by the root user will be potentially be disallowed by configd or a related per-application encapsulation mechanism (con?guration changes performed during install by the related install script are easily allowed; see Section 3). In the prototype system, con?guration changes performed by the physical user acting as root ended up being approved, since the person modifying the application con?guration and the person approving the change when queried by configd are one and the same. Because any updates to con?guration require an individual acting as root to perform them, we believe the extra step of the same individual verifying the change before it is propagated to disk to be minor (e.g., the user updates the con?guration ?le and then authorizes that the update be written to disk when prompted by configd). Indeed, we can avoid querying the user about con?guration changes if

231

the implementation of configd exports a user interface for performing changes (e.g., by providing a text editor). Such an ability does not detract from the security of the system because applications still do not gain the ability to write to ?le-system objects belonging to other applications.

5.6

Performance evaluation

To test the performance of our kernel modi?cations on ?le-system intensive day-to-day operations, we performed a complete compile of the Linux 2.6.31.5 kernel. We unpacked, con?gured (make allmodconfig), compiled, and removed the directory tree containing the compiled kernel. We chose a kernel unzip, compile, and removal because of the number of required disk operations, heavily exercising the ?le-system as well as our prototype c-locking Linux security module. We ran the test on two di?erent 2.6.28.7 Linux kernels. The ?rst test was with c-locking support not compiled in, and averaged 158 minutes and 52 seconds over three runs. The second timing was performed with c-locking enabled and configd running, and averaged 166 minutes and 34 seconds over three runs. Both tests were run on the same Pentium 4 2.8GHz with 1Gb of RAM. Over the three test runs, the average increased run time for the compile with c-locking enforcement enabled was 4.8%. For day to day operations which do not involve heavy ?le-system activity, we expect the overhead of configd to be well under 4.8%. We also expect alternate implementations of configd functionality would produce comparable results.

We selected six representative Linux rootkits, two that modify the kernel and four that replace system binaries. Both kernel-based rootkits (suckit2 and mood-nt) failed to install because of disabled write access to /dev/kmem in the prototype’s modi?ed kernel. The mood-nt kernel based rootkit which we tested also attempted to replace /bin/init. The attempt was denied by the prototype3 because /bin/init is part of a di?erent application on the system. The four binary replacement rootkits (ARK 1.0.1, cb-r00tkit, dica, and Linux Rootkit 5) all resulted in ?le-system operations which were denied because they attempted to either replace or delete core system binaries (e.g., ls, netstat, top, and ps). The core system binaries installed belong to applications other than the rootkits and hence changes to them by the rootkit installer were disallowed by our prototype.

5.8

Evaluating installation and upgrade of nonmalicious software

5.7

Veri?cation that application encapsulation is enforced

Malware frequently modi?es ?le-system objects not directly associated with the malware itself (e.g., replacing ls). This provides an appropriate test case for the proposed restriction of con?guration changes on a per-application basis during install. Under the new root ?le-system restrictions, the test is to verify that applications (malicious or other) running with root privileges cannot modify other applications ?le-system objects. To test how well the mechanism presented in this paper protect a system when exposed to malware, we became root on a system with configd running and kernel protections enabled. We then attempted to run six di?erent Linux rootkit installers.2 Linux rootkits can be grouped into two categories: those that use some method to gain access to kernel memory, installing themselves in the running kernel and then operating at kernel level, hiding their actions from even root processes; and rootkits that replace core system binaries that are often used by the root user in examining a system. Using the six representative rootkits, we con?rmed that the installer failed to gain access to the kernel because of disabled write access to /dev/kmem (which would otherwise undermine configd), and that configd works as expected (i.e., ?le-system changes possible by malware are restricted to prevent other applications from being modi?ed). That the rootkits failed to gain access to the kernel was veri?ed by examining errors returned by the rootkit installer when attempting the install. The integrity of other applications ?le-system objects was veri?ed through comparing cryptographic hashes using Tripwire [26].2 All Linux rootkits tested were from http:// packetstormsecurity.org/UNIX/penetration/rootkits/

We performed several tests to verify that the prototype system is capable of supporting the install of new packages, as well as the upgrade and re-install of already-installed packages. To test how well configd can be deployed on a pre-existing system, we introduced configd into a Debian desktop installation. We ?rst installed an unmodi?ed Debian Lenny (v5.0) distribution, including the KDE graphical desktop environment, onto a desktop. We then installed the configd daemon and modi?ed kernel, which enforces clocked ?le-system restrictions. At this point, any package updates on the system (including installs, re-installs, and upgrades) would result in the associated ?les being marked c-locked, and hence protected by configd. We then proceeded to re-install all packages that were already present on the system. In performing a re-install, all ?les associated with a package became marked as c-locked and hence protected by the combination of configd and the modi?ed kernel. Using this base system, where all package ?les are marked as c-locked, configd is running, and kernel protections are enabled, we then proceeded to do further testing of the prototype using our desktop install. To test how well the configd prototype accommodates package upgrades, we installed all security updates made available for our desktop install between the days of November 12, 2009 and May 6, 2010 (a total of ? 100 packages). We were not queried by configd at all about modi?cations to the ?le-system, did not see any errors displayed during the upgrade process, and none of the packages appeared to be broken by the upgrades (i.e., the system still ran as expected). To test how well the prototype configd accommodates re-installs, we reinstalled all packages on the desktop system (a total of 897 packages). Again, during the process we were not queried about changes to the system con?guration, we did not see any errors displayed during the process, and the system appeared to be fully functional after the reinstall (i.e., we could still log into KDE, browse the web, read e-mail, and watch videos). As a ?nal test, we installed several (new) desktop applications (each consisting of multiple packages), including Inkscape (http://www.inkscape.org/), Pidgin (http://www.3 In our prototype, the denial was performed by the prototype user, but would be performed automatically if the userinterface is disabled. The rootkit install was not able to put up a fake configd prompt because of protections discussed in Section 5.5.

232

pidgin.im/), and Digikam (http://www.digikam.org/). The new ?les installed during each application install were marked as c-locked, there were no errors displayed by the package installer, and each application ran correctly after install.

con?guration from normal day-to-day activities performed on a system. The approach taken by Butler et al. attempts to further minimize the potential for abuse through the use of multiple USB keys, but does not reach an application level granularity. Indeed, they suggest using di?erent tokens for di?erent roles (e.g., one token associated with all binaries and another associated with all con?guration ?les) [9].

6.1

Secure software installation

6.3

Other related work

Venkatakrishnan et al. [56] proposed RPMShield, a system where actions which will be performed during install of a package are presented to the administrator for veri?cation and then all install actions are logged. RPMShield concentrates on install time, not preventing already-installed applications from modifying the system if they are run as root. While configd focuses on encapsulating an application’s ?lesystem objects, RPMShield focuses on allowing the system administrator to examine and approve the actions which will be performed during install. Kato et al. [24] proposed SoftwarePot, an approach where each application is encapsulated in its own sandbox, with mediated access to the ?le-system and network. Shared ?les are accessed by mapping sandbox-speci?c ?le-names to global ?le-system objects. The mapping between sandboxspeci?c ?les and global ?le-system objects requires additional information not currently distributed with an application package. SoftwarePot encountered a 21% overhead, while configd encountered a 4.8% overhead. Sun et al. [51] proposed grouping applications into two categories, those which are trusted, and those which are not. All untrusted applications are installed inside a common sandbox, while trusted applications are not. The approach relies on malicious applications always being classi?ed as untrusted. It does not prevent trusted applications from modifying ?le-system objects related to other trusted applications (and indeed, untrusted applications can modify ?le-system objects related to other untrusted applications). configd, in contrast, does not distinguish between trusted and untrusted applications, treating all applications equal and restricting the modi?cations which can be performed on ?le-system objects.

6.2

Rootkit resistant disks

Butler et al. [9] proposed a method where regions of disk were marked as requiring a speci?c USB key to be inserted before they could be updated. The approach works at the block level, underneath the ?le-system. Blocks on disk become marked as associated with a USB key when they are updated while the key is installed. In their approach, the user is involved in di?erentiating between when a system should be used to perform day-to-day operations and when the system is being con?gured. This separation, however, does not carry over into isolating day-to-day and con?guration operations. Because the protection mechanism is implemented underneath the operating system at the block level, applications used for performing day-to-day operations continue to run (and even inherit con?guration permission) when the user inserts a USB key indicating they want to change the con?guration of the system. The Butler et al. approach of attempting to restrict con?guration operations closely parallels the ?rst step in our limiting the potential for abuse in root ?le-system privilege – the separation of

The splitting of root privilege is a common technique for limiting abuse in areas other than ?le-system control. Techniques such as capabilities [27, 21] and ?ne-grained access control [32] also split up root, but focus mainly on installed applications, not the installers themselves. configd focuses on environments for non-experts, where there is little uptake of ?ne-grained access control due to its complexity and skill requirement. Solaris di?erentiates between operations and con?guration administrators [8], similar to the di?erentiation between con?guration and day-to-day use. While configd shares this characteristic, it goes one step further by encapsulating each application. On the iPhone platform, each application must be signed by Apple before being loaded onto the device. This approach assumes Apple will be able to properly vet all applications before allowing them to be loaded onto the device. Apple also has a mechanism for disabling malicious applications which happen to slip through [25]. The approach has scalability drawbacks in that it relies on a central authority to certify all software for the platform. Declarative con?guration [18, 15] attempts to fully specify system con?guration using purely functional methods, with the result that system con?guration becomes deterministic and reproducible. A complete system is built using a speci?cation which documents every software component version and its con?guration. Such an approach requires a purely functional package management system [17], hence it is not backwards compatible with current mainstream install methods. While using declarative con?guration prevents modi?cations to the con?guration of a running system, it is not speci?cally concerned with the e?ect that including a malicious piece of software in the speci?cation will have on system state (in contrast to configd). In recent years, virtual machines (VMs) have started to become much more popular in server environments, to allow a single machine to run multiple instances of an operating system [5]. As part of the popularization of virtual environments, the opportunity to introduce additional segregation between applications has arisen. Each VM instance runs its own instance of an operating system and is assigned its own ?le-system and display. A typical setup involving virtual machines still groups many related applications together in a single VM. In this paper, we focus on a method for dividing up root ?le-system privilege to prevent abuse by applications running on the same instance of the operating system, regardless of whether or not that OS happens to be running in a virtual machine. While the practice of an ordinary user installing applications into their home directory avoids root entirely, the application’s ?le-system objects are not protected against modi?cation by other applications the user installs (or indeed, any application the user happens to run).

233

Ioannidis et al. [22] introduced the concept of sub-operating systems, marking each ?le with a label indicating where it came from. These labels restrict what data ?les an application is allowed to access at a ?ner granularity than the user. Sub-OS does not explicitly tackle limiting the abuse of root ?le-system privilege during the process of installing, upgrading, and removing an application. Polaris [48] likewise focuses on application data, restricting what user ?les an application can access based on user interaction with the window manager. Much of the recent practical work related to MAC has been through ?ne-grained access control systems, such as SELinux [32]. SELinux permissions granted to an application are restricted based on the labels assigned to both that application and the resources it wishes to use. SELinux systems have the potential to split up root ?le-system privilege, parallelling the approach used herein. We are not aware, however, of any commodity or widely deployed ?ne-grained access control system built to accommodate the continual updating and recon?guring which goes on in modern computer systems. In Linux, the default SELinux security policy has dpkg being granted write access to almost every ?le on the system [12]. Other systems, such as AppArmor [6], appear to work best when new applications are not being installed or upgraded. configd tracks the c-locking ?ag and which package a ?le-system object belongs to. While using SELinux to track and enforce permissions associated with these attributes may be possible, such an approach was not the focus of our work. While projects such as DTE-enhanced UNIX [59] and XENIX [52] restrict the privileges of root (including root’s ability to con?gure the system), it seems most installs on these systems still happen with full privileges (admin_d privilege in DTE, TSP in XENIX), having full access to all ?lesystem objects on disk. For systems using the OpenBSD schg [28] and ext2 immutable [54] ?ags, any application can be given the ability to change an immutable ?le – the user can simply be asked to run an application after acquiring su?cient con?guration privileges. SVFS [67] protects ?les on disk but is susceptible to the same problem of inadequate control over installation applications. There have been many attempts to detect malicious modi?cations to system con?guration. Windows ?le protection (WFP) [13, 34] maintains a database of speci?c ?les which are protected, along with digital signatures of them. WFP is designed, however, to protect against a non-malicious enduser, preventing only accidental system modi?cation. Pennington et al. [40] proposed implementing an intrusion detection system in the storage device to detect suspicious modi?cations. Strunk et al. [49] proposed logging all ?le modi?cations for a period of time to assist in the recovery after malware infection. Tripwire [26] maintains cryptographic hashes of all ?les in an attempt to detect modi?cations. All these proposals detect modi?cations after the fact. Applications such as registry watchers [46] and clean uninstallers [35] attempt to either detect or revert changes made to a system by an application installer. These systems similarly don’t prevent changes in system con?guration. The separation of con?guration privileges as proposed in this paper prevents installers from making unauthorized changes to system state, leading to a proactive rather than reactive approach to limiting system con?guration changes. Package managers [10] and the Microsoft installer [36] both limit sys-

tem con?guration actions allowed by packages designed for their system, but do not prevent applications from simply providing their own installer (or install script), bypassing the limits enforced by the package manager. This paper includes work from the ?rst author’s PhD thesis [64]. Relative to the preliminary workshop paper [66], this paper expands the work by evaluating current installers, introducing the concept of restricting con?guration changes at a per-application granularity, protecting ?le-system objects (as opposed to just ?les), and discussing a working prototype. The prototype implementation con?rms the feasibility of protecting against abuse of root ?le-system privileges, and is evaluated for both its performance and ability to defend against several rootkits.

7.

SUMMARY

The bene?ts of preventing one application from modifying another’s ?le-system objects are well-recognized in the smart phone environment. On modern desktop computing platforms which are less tightly controlled, and more generic, there has been little progress on architectural designs which support encapsulation of applications throughout frequent install, upgrade, and uninstall processes. Unix (including Linux) provides a challenge in that much of its design is from an era where applications were all installed into common directories. While Windows does slightly better by encouraging each application be installed into its own directory, the way applications are installed leaves the system open to attack. In this paper, we present a framework for restricting con?guration changes, including kernel extensions and an associated user-space daemon. The status quo on end-user operating systems is dangerous – giving every application complete control during install, upgrade, and removal. We provide the foundation of a full solution including concept, architecture, design, and prototype implementation proving out the design. The design provides a control point to reduce root abuse of ?le-system privileges without breaking normal software operation, and has acceptable performance. Our prototype has demonstrated that it is possible to separate out con?guration privileges from root-privileged processes, providing a step forward in tackling the long-standing problem of over-privileged installation and modi?cation permissions.

AcknowledgementWe thank the anonymous reviewers, our CCS shepherd, Vinod Ganapathy, and many individuals who provided feedback on preliminary drafts of this work, including Trent Jaeger. Their comments have signi?cantly improved the presentation and clarity of this work. The second author acknowledges NSERC for an NSERC Discovery Grant and his Canada Research Chair in Internet Authentication and Computer Security. Partial funding from NSERC ISSNet is also acknowledged.