ISTR0701.qxd
4/9/02
2:28 PM
Page 37
Information Security Technical Report, Vol. 7, No. 1 (2002) 37-56
Design of Secure Unix C.I.Dalton, T.H.Choo and A.P.Norman, HewlettPackard Laboratories
Introduction Strong networking support and freely and readily available software has helped Unixbased systems become incredibly popular for hosting Internet-based applications and services. However, as the range and value of services offered over the Internet evolves, the security of those services become more of a key issue. Unix-based systems can be configured and run securely if expertly administered and managed. However, security was not a primary design goal of the Unix originators. The standard model of Unix access control centres around facilitating the sharing of resources, not restricting access to resources. Equally relevant, the administration model of Unix is based on the concept of an all-powerful root account. These two factors often lead to system compromises being relatively trivial to accomplish. It has become clear that the standard Unix security model is not sufficient when security concerns are paramount.
that are generally useful outside the military arena and go some way to addressing the concerns over standard Unix security. However, whilst having desirable security properties we also see that Unix-based trusted operating systems in conventional form are typically not practical or useable in the general sense. The major part of this article takes Trusted Linux as a case study of a modern secure Unix. Trusted Linux is a version of Linux that we have evolved from traditional trusted operating system technology but with practicality and usability in mind. It has been extended with the strong security property of containment and is explicitly designed for the hosting of Internet applications and services. We discuss our design goals and go into some detail over the architecture, implementation and deployment models of Trusted Linux. Finally, we briefly discuss a couple of experimental frameworks (RSBAC and SELinux) that provide more general means of getting new security models into Linux.
Standard Unix security model This article looks at the way stronger security models can be fitted into the Unix systems, specifically we look at the design of Trusted Linux, a secure Linux-based Unix system. We first look at the standard Unix security model and highlight some of the inherent weaknesses that a secure Unix would need to address. We then look at early attempts at adding stronger security to Unix centred around the needs of military classified information processing. We see how these types of systems (referred to as Trusted Operating systems) have several properties
Information Security Technical Report, Vol. 7, No. 1
For our purposes the standard Unix security model can be separated into two aspects. Firstly, the access control model that applies to system resources. Secondly, the administration model for system resources. Unix access control model
Unix is a file-orientated operating system. In general, access to resources on the system is via the Unix file abstraction. The model adopted for controlling accesses to files is one that makes it easy to share files amongst
37
ISTR0701.qxd
4/9/02
2:28 PM
Page 38
Design of Secure Unix
different users without administrator intervention. In formal terms, standard Unix is based on a Discretionary Access Control (DAC) model. With this model, if a user owns a resource then they can decide who gets access to that resource. Unix administration model
Unix employs a simple administrative model. There is a firm distinction (at the kernel level) between user-permitted actions and administrator-permitted actions. As far as the kernel is concerned, an administrator on Unix is simply a process with its UID equal to 0. In user space this is equivalent to the user running as root. Root is thus a special account on Unix systems. Users who have or gain access to this account effectively have full control over the system. Some commands that a user might ordinarily carry out during their daily working (such as creating a directory with the mkdir command) are viewed by the system as administrative actions and as such have to be done as root. The Unix designers invented the Set User Identity (SUID) concept to deal with this user inconvenience. Unix allows an administrator to set an executable binary to be SUID via its file permission settings. A SUID program causes an application to effectively run as the owner of its executable file, not the user who is running it. So for example, the mkdir command would be marked as SUID and owned by root. Whenever a user the runs the mkdir command they do so as if they were root running the command. As well as SUID programs, server applications on Unix often have to be able to carry out actions that the system views as privileged (such as binding to a port less than 1024). In practice this results in a large number of server applications being run as root.
38
Security weaknesses in the Unix model
The major weakness of the Unix security model is the root account. If an attacker gains access to the root account then they basically have full control over the machine and any resources on it. There are many ways on a Unix system for an attacker to gain access to the privileges of the root account. For example, they could attempt to log in directly as root, they could attempt to exploit a bug in a SUID bug, they could attempt to exploit a bug in a server application that is running as root. A common method of attack on Unix systems is to exploit some form of buffer overflow bug in an application running as root. More subtle perhaps are problems surrounding the choice of a DAC model for resource access. Amongst other things, this leaves users vulnerable to Trojan horse type attacks. A process operating on behalf of a user can modify the access rules for any resource that that user owns. For example, an email virus could potentially change a user’s private files to be readable and or writable by anybody on the system.
Trusted operating systems Early attempts at producing secure versions of Unix were intended for the classified military information processing arena. The features developed were designed to overcome some of the inherent weaknesses of standard Unix-type systems and thus render them adequate for the hosting and processing of very sensitive information. Some commercial examples of trusted operating systems are Trusted Solaris from Sun Microsystems which is based on their Unix Solaris OS and HP CMW from HewlettPackard Company which is based on their Unix OS, HP-UX.
Information Security Technical Report, Vol. 7, No. 1
ISTR0701.qxd
4/9/02
2:28 PM
Page 39
Design of Secure Unix
Trusted Operating systems have a number of characteristics that differentiate them from their standard Unix counterparts. For this discussion, the most relevant to us are the Mandatory Access Control (MAC) model and fine grained privilege and administration model that they feature. Mandatory access controls
Instead of relying solely on the standard Unix DAC model for protecting system resources, Trusted Operating systems use a Mandatory Access Control (MAC) model. The most common MAC model employed is the BellLapadula [1] formal model for information flow. What this boils down to in practice is a system where it is possible to get guarantees about how information can flow around the system even if that machine is in direct control of an attacker. It is important to note that this information flow policy is implemented in the kernel and thus cannot be subverted by any user (including root) from user space. The model was originally designed to prevent the unauthorized disclosure of sensitive classified information. The model is useful for not only preventing the active distribution of confidential information by a malicious user but also to mitigate the effects of a Trojan operating on behalf of an unknowing user. Fine Grain privilege and administration model
Trusted Operating systems break down the privilege normally associated with UID 0 into a number of individual privileges such as the ability to bind to a port below 1024 or the ability to change UID. Trusted Solaris has about 120 privileges, HP CMW has about 60. Before carrying out a privileged operation the kernel checks that the process requesting
Information Security Technical Report, Vol. 7, No. 1
the operation holds the relevant privilege rather than just checking that the process UID is 0. This facilitates the ability of users to carry out commands viewed as administrative without giving them control over the whole system. From an administrative point of view, the systems typically no longer have an allpowerful root account. They adopt instead a role-based approach to administration. Such roles would be security officer, information officer, etc. The idea here is that no one account holds all the privileges that would make them equivalent to root in conventional Unix systems. It can be seen then that these two features address the more serious drawbacks with the standard Unix security model. More than that, these features also give the systems additional interesting security properties. For example, the combination of Mandatory access controls and fine grain privilege model give the systems the useful property of containment [2]. Containment
In brief, an application (or service) is contained if it has strict controls placed on which resources it can access (and what type of access to those resources it has, e.g. readonly) even if the application has been compromised. Containment also implies that an application that is contained should be protected from external attack and interference. Containment applies to file system, process and network resources. Containment is particularly useful on systems used as network gateways and application hosting platforms between the Internet and an internal network. For example, it is possible to guarantee that if a service on the gateway machine is attacked
39
ISTR0701.qxd
4/9/02
2:28 PM
Page 40
Design of Secure Unix
and compromised from the Internet, the attacker can’t then go on and gain access to the whole internal network. Similarly, on a platform hosting multiple applications, we can be guaranteed that one process cannot interfere with the running of another process or get access to its perhaps sensitive data. Practicalities
Previous research work of ours [3] showed that it is certainly possible to take an existing commercial trusted OS and benefit from its enhanced security properties for hosting networked-based applications and services. However, our research also highlighted some downsides with the use of existing trusted operating system technology. The systems we used during the research (Trusted Solaris, HP CMW, HP VirtualVault) used a MAC scheme based on the BellLapadula model. Whilst this gave us the containment property we found it in practice too restrictive a model. We often had to provide bespoke privileged code to breach some of the mandatory controls. Only in this way could we achieve the flexibility required to integrate and deploy many applications. Another significant downside is that we found that although based on standard counterparts, the overall character or personalities of the trusted operating systems are somewhat different. This has several implications. Firstly, they require additional significant retraining effort on behalf of system operators and administrators. Secondly, they typically do not easily integrate with existing system management environments. Trusted Linux was our attempt at addressing these drawbacks and thus producing a secure version of Unix in a more palatable form.
40
Trusted Linux We had several design goals for Trusted Linux. We wanted it to have the strong containment properties of traditional trusted operating systems but to reduce some of the application integration and management problems associated with them. To ease application migration we wanted the containment property to be as flexible as possible in terms of being able to contain off-the-shelf applications without requiring modifications to those applications. To ease integration with management suites and staff we wanted to keep the underlying Linux personality intact. Finally, we wanted to minimize any Linux kernel source code changes. In the past, Trusted Operating developers have had a hard time keeping up with the current releases of their standard counterparts due to the extensive kernel modifications and re-testing that needed carrying out.
Design overview The key concept of our trusted operating system is the compartment. Services and applications on the machine are run within separate compartments. Figure 1 is a conceptual view of Trusted Linux showing several applications running in their own compartment. We use simple mandatory access controls and process labelling to create the concept of a compartment. Each process is given a label; processes with the same label belong to the same compartment. We enforce kernel-level mandatory checks to ensure that processes from one compartment cannot interfere with processes from another compartment. The access controls are very simple, labels either match or they don’t. There is no hierarchical ordering of labels within the system such as there is in the Bell-Lapadula model.
Information Security Technical Report, Vol. 7, No. 1
ISTR0701.qxd
4/9/02
2:28 PM
Page 41
Design of Secure Unix
Service 0
Service 1
Application data
X
Application data
X
…
Internet
Application data
Service N
Hosting Platform
Figure 1: Compartments on Trusted Linux. Filesystem protection is also mandatory. Unlike traditional Trusted operating systems, we do not use labels to directly control access to the file system; each compartment has a section of file system associated with it. This section of file system is a chroot of the main file system. Processes running within a particular compartment only have access to that section of the file system. Importantly, via kernel controls, we remove the ability of a process to transition to root from within a compartment so that the chroot cannot be escaped1. Flexible communication paths between compartments and network resources are 1
The product version of Trusted Linux also allows for the specification of mandatory file permissions (such as read-only) on a per file or directory basis. These permissions are specified by rules that sit outside the normal Unix DAC permissions. It should be noted that the inode representation of a file is not modified.
Information Security Technical Report, Vol. 7, No. 1
provided via narrow, kernel level controlled interfaces to TCP/UDP plus most IPC mechanisms. Access to these communication interfaces is governed by rules specified by the security administrator on a per compartment basis. Unlike traditional trusted Back-end operating systems we Hosts don’t have to override our mandatory access controls with privilege or resort to the use of user level trusted proxies to allow communication between compartments /network resources. We accepted that for a real system the formal property of isolation would not be possible or useful so we allowed for it to be weakened in a precise manner by the use of these communication rules. The administration model for Trusted Linux is based around the fact that people wish to administer Linux systems as root. Multiple role-based administrative procedures found in traditional trusted operating systems whilst being more secure have found little favour. This is a sociological and personality problem that we cannot solve. At the kernel level, Linux does have support for a finegrained privilege model 2. However, this is typically not used at present at the user or application level. Our approach is to recognize that the root account is used to both administer the system and run applications. We provide kernel level means to distinguish between the two cases and 2
Linux calls them capabilities not privileges.
41
ISTR0701.qxd
4/9/02
2:28 PM
Page 42
Design of Secure Unix
User
Internal Compartments
External Compartments
Admin Compartment MCGA
WEB1 HTTPD
AdminMCGA exec
WEB1-MCGA
Command-line utilities
WEB2 HTTPD
WEB2-MCGA
WEB3 HTTPD
WEB3-MCGA
Configuration Files 1. Rules 2. Routes 3. FCDB ioctl
system calls Kernel TCP/IP Networking
Rule Database
UNIX Domain Sockets
Device Config
Kernel Modules
SysV IPC Other Subsystems
Security Module
Figure 2: Trusted Linux Architecture.
hence act appropriately. The intention here is that the compromise of an application running as root by an attacker will not lead to that attacker being able to modify or subvert the security policy that is being enforced by the system.
embed the majority of our code in a dynamically loadable kernel module (DLKM). Finally, we could attempt to make no changes to the actual kernel code itself and make use of techniques such as system call interposition.
Implementation
The first option is probably the simplest to implement, however, it does not fit in well with our goal of minimal kernel changes. The third option fulfils that goal. It does, however, require us to replicate a lot of the kernel functionality since we cannot get access to some parts of kernel state without modifying the kernel source. We have to reproduce that state for ourselves. The second option is a compromise between the other two options and is the one we adopted.
This section looks at how we implemented our model for a Trusted Operating system under Linux. One of our design goals was to minimize the amount of standard Linux kernel source changes. There are basically three main implementation options. Firstly, we could simply add our code as part of the main kernel source. Secondly, we could just add hooks to the main kernel source and
42
Information Security Technical Report, Vol. 7, No. 1
ISTR0701.qxd
4/9/02
2:28 PM
Page 43
Design of Secure Unix
Process Mgmt
UID / Cap Handling
Process Mgmt
AF_INET
AF_UNIX
AF_INET
UID / Cap Handling
hook
hook
SysV IPC
Exec / binfmt
hook
lns.o
AF_UNIX
SysV IPC
hook
Exec / binfmt
hook
hook
Figure 3: Modified Linux Subsystems.
Architecture Figure 2 shows the architecture of Trusted Linux based on our decision to centre the architecture around a loadable kernel security module. The diagram shows the major Linux kernel subsystems (TCP/IP, SysV IPC, etc.) that we needed to modify to make call outs to our security module. The security module makes access control decisions and is responsible for enforcing our concept of a compartment. The security module consults a rule database when making a decision. The rule database contains information about allowable communication paths between compartments and is how we provide the narrow well controlled interfaces in and out of a compartment. The diagram also shows how our kernel extensions (security module, rule database, etc.) are administered from user space via a
Information Security Technical Report, Vol. 7, No. 1
series of ioctl3 commands. These ioctls take two forms; ones to manipulate the rule table and others to run processes in particular compartments and configure network interfaces. User space services such as the Web servers shown in the diagram are run unmodified on the platform but have a compartment label associated with them via the command line interface to our security extensions. The security module is then responsible for applying our mandatory access controls to them based on their applied compartment label. Importantly, this mechanism ensures that we can contain our user space services without having to modify those services.
General kernel modifications The implementation consists of a loadable kernel module (lns.o) and hooks into various 3
Via system calls in the product version.
43
ISTR0701.qxd
4/9/02
2:28 PM
Page 44
Design of Secure Unix
process
process
process
process
process
process
kernel
process
socket
socket
socket file ipc
socket
socket
ipc file
ipc file
file
socket
ipc
file
file socket
socket
ipc
ipc kernel
Vanilla Linux
Trusted Linux
Figure 4: Tagged kernel data structures. of the Linux subsystems to create call outs to our module. The implementation also requires modifications to some of the Linux kernel data structures so that we can create our compartment abstraction. Kernel module
This is what we call our security module. This kernel module implements the decision function into which hooks added to the standard Linux kernel call into. The module allows rules to be added from user space that determine the communication interfaces that are available in particular compartments. The module also has several other functions that are required to support our compartmentbased model, namely it allows: 1. A calling process to switch compartments. 2. Individual network interfaces to be assigned a compartment number.
44
3. Utility functions such as process listing with compartment numbers and the logging of activity to kernel-level security-checks. Kernel hooks
Hooks are required in several of the Linux subsystems. The hooks are used to implement our access control checks on top of the standard Unix access control checks. Figure 3 shows the areas of the Linux kernel where hooks are needed. The hooks consist of a single function cnet_chk_attr() that implements a yes/no security check for the subsystems that are protected in the kernel. Calls to this function are made at the appropriate points in the kernel sources to implement the compartmented behaviour desired. This function is predicated on the subsystem concerned and may implement slightly different defaults or rule-conventions
Information Security Technical Report, Vol. 7, No. 1
ISTR0701.qxd
4/9/02
2:28 PM
Page 45
Design of Secure Unix
struct csecinfo { unsigned long sl; }; struct sock { … #ifdef CASPER struct csecinfo csi; /* contains compartment number */ #endif /* CASPER */ };
Figure 5: Example of a modified datatype. depending on the subsystem of the operation being queried at that time. For example, most subsystems implement a simple partitioning where only objects/resource having exactly the same compartment number result in a positive return value. However, in certain cases the use of a no-privilege compartment 0 and/or a wildcard compartment –1L can be used e.g. compartment 0 as a default ‘sandbox’ for unclassified resources/ services; a wildcard compartment for supervisory purposes, like listing all processes on the system prior to shutting down.
we have tagged with the additional compartment label. The tag (csec_info) added to the various data structures is simply a 32 bit scalar value. Figure 5 shows the definition of the tag used to hold a label and also how the struct sock kernel data structure has been modified to hold the tag. In general, the addition of this member is typically done at the very end of a data structure to avoid issues related to the common practice casting pointers between two or more differently named structures which begin with common entries.
Kernel data structures Networking modifications
In order to implement our compartment abstraction we need to add additional information to several of the kernel data structures. For example, each process on the system belongs to a compartment. To keep track of which compartment a process belongs to we add an additional field to the data structure (task_struct) used by the kernel to manage individual processes. The additional field contains space for our compartment label. Figure 4 shows the data structures that
Information Security Technical Report, Vol. 7, No. 1
Networking controls form a large part of the implementation of our compartment abstraction so this section looks in more detail at the changes we have made to the networking subsystem on Linux. We begin with a short primer on standard Linux IPnetworking. Each process or thread is represented by a struct task_struct variable in the kernel. A
45
ISTR0701.qxd
4/9/02
2:28 PM
Page 46
Design of Secure Unix
User User process/thread
Kernel struct task_struct
1
AF_INET
AF_INET sockets are represented by a struct sock variable each time they are created
struct socket
struct sock
2
Packet delivery for TCP, UDP et al. via tcp_rcv(), udp_rcv() etc. sk_buff packets travel up/down the stack
struct sk_buff
3 str ct net device
ip_input() – handle incoming packets ip_output() – handle outgoing packets prior to transmission by network driver
Figure 6: Major networking datatypes in Linux IP networking.
process may create sockets in the AF_INET domain for network-communication over TCP/UDP. These are represented by a pair of struct socket and struct sock variables, also in the kernel. The struct sock datatype contains amongst other things queues for incoming packets represented by struct sk_buffs. It may also hold queues for pre-allocated sk_buffs for packet transmission. Each sk_buff represents an IP packet and/or fragment travelling up/down the IP-stack. They either originate at a struct sock (more specifically, from its internally pre-allocated send-queue) and travel downwards for transmission, or they originate from a network-driver and travel upwards from the bottom of the stack starting from a struct net_device which represents a network interface. When travelling downwards, they effectively terminate at a struct net_device. When travelling upwards, they are usually delivered to a waiting struct sock (actually, its pending queue).
46
Struct sock variables are created indirectly by the socket()-call4 and can usually be traced to an owning user-process i.e. a task_struct. There exists a struct net_device variable for each configured interface on the system, including the loopback interface. Localhost and loopback communications appear not to travel via a fastpath across the stack for speed, rather they travel up and down the stack as one would expect for remote host communications. At various points in the stack, calls are made to registered netfiltermodules for the purposes of packet interception. By adding an additional csecinfo datamember to the most commonly used datatypes in Linux IP networking, it becomes possible to trace ownership and hence read/write-dataflows of individual IP packets for all running processes on the system, including internal kernel-generated responses (see Figure 6). Modified networking datatypes
Most of the changes necessary to implement our network controls occur in the networking stack and socket-support routines. The tagged network data structures serve to implement a partitioned IP stack. The following data structures were modified to include a struct csecinfo: 1. struct socket representation
-abstract
socket
2. struct sock
-domain-specific socket
3. struct sk_buff -IP packets or messages between sockets 4
Well, almost. There are private per-protocol sockets owned by various parts of the stack within the kernel itself that cannot be traced to a running process. See the discussion later about this.
Information Security Technical Report, Vol. 7, No. 1
ISTR0701.qxd
4/9/02
2:29 PM
Page 47
Design of Secure Unix
Figure 7: Propagation of struct csecinfo data-members for IP-networking.
4. struct net_device -network interfaces e.g. eth0,lo etc. Once the major datatypes were tagged, the entire IP-stack was checked for points at which these datatypes were used to introduce newly initialised variables into the kernel. Having identified these, code was inserted to ensure that the inheritance of the csecinfo structure was carried out. The next section describes how the csecinfo structure is propagated throughout the IP networking stack. Propagation of struct csecinfo in IP networking
There are two named sources of struct csecinfo data members – per-process task_structs and per-interface net_devices. Each process inherits its csecinfo from its parent, unless explicitly modified by a privileged ioctl(). Currently, the init-process is assigned a compartment number of 0. Therefore, every process spawned by init during system startup will inherit this compartment number
Information Security Technical Report, Vol. 7, No. 1
unless explicitly set otherwise. During system startup, init-scripts are typically called to explicitly set the compartment numbers for each defined network interface. The diagram below illustrates how csecinfo data-members are propagated for the most common cases (see Figure 7). All other data structures inherit their csecinfo structures from either a task_struct or a net_device. For example, if a process creates a socket, a struct socket and/or struct sock may be created which inherits the current csecinfo from the calling process. Subsequent packets generated by calling write() on a socket generate sk_buffs which inherit their csecinfo from the originating socket. Incoming IP packets are stamped with the compartment number of the network interface on which it arrived, so sk_buffs travelling up the stack inherit their csecinfo structure from the originating net_device. Prior to being delivered to a socket, each sk_buff’s csecinfo
47
ISTR0701.qxd
4/9/02
2:29 PM
Page 48
Design of Secure Unix
structure is checked against that of the prospective socket. Handling Loopback communications
Special care has to be taken for non-remote networking. We need to handle the case when a connection is made between compartments X and Y through any number of the configured network interfaces and is allowed by a rule of this form: COMPARTMENT X -> COMPARTMENT Y METHOD tcp
Because the security checks happen twice for IP-networking (once on output and once on input) we may naively end up looking for the existence of these rules instead: COMPARTMENT X -> HOST a.b.c.d METHOD tcp (for output) HOST a.b.c.d -> COMPARTMENT X METHOD tcp (for input)
which although are valid may not be used in preference to the rule specifying source and destination compartments directly. To cater for this, packets sent to the loopback device retain their original compartment numbers and are simply ‘reflected’ off it for eventual delivery. Note that the actual security check happens on delivery and not transmission. Upon receipt of an incoming local packet on the loopback interface, we avoid overwriting the compartment number of the packet with that of the networkinterface and allow it to travel up the stack for the eventual check on delivery. Once there, we perform a check for a rule of the form: COMPARTMENT X -> COMPARTMENT Y METHOD tcp
48
instead of HOST a.b.c.d -> COMPARTMENT Y METHOD tcp
because of the presence on the sk_buff of a compartment number that is not of a form normally allocated to network interfaces.5 Dynamic rules in TCP/IP
Because the rules are unidirectional, the TCP layer has to dynamically insert a rule to handle the reverse data flow once a TCP connection has been setup, either as a result of a connect() or accept(). This happens automatically in the current prototype and the rules are then deleted once the TCP connection is closed. Special handling occurs when a struct tcp_openreq is created to represent the state of a pending connection request, as opposed to one that has been fully set up in the form of a struct sock. A reference to the reverse-rule created is stored with the pending request and is also deleted if the connection request times out or fails for some other reason. An example of this would be when a connection is made from Compartment 2 to a remote host 10.1.1.1. The original rule allowing such an operation might have looked like this: COMPARTMENT 2 -> NET 10.1.1.0/255.255.255.0 METHOD tcp
As a result, the reverse rule would be something like this (abc/xyz being the specific port-numbers used): HOST 10.1.1.1 PORT abc -> COMPARTMENT 2 PORT xyz METHOD tcp 5 Network interfaces as a general rule are allocated compartment numbers in the range 0xFFFF0000 and upwards and can therefore be distinguished from those allocated for running services.
Information Security Technical Report, Vol. 7, No. 1
ISTR0701.qxd
4/9/02
2:29 PM
Page 49
Design of Secure Unix
Per-compartment routing
To support per-compartment routing tables, each routing table entry is tagged with a csecinfo structure. The various modified data structures appear below: 1. struct rt_key 2. struct rtable 3. struct fib_rule 4. struct fib_node Inserting a route using the route-command will cause a routing table entry to be inserted with the csecinfo structure inherited from the calling context of the user-process i.e. if a user invokes the route-command from a shell in compartment N, the route added will be tagged with N as the compartment number. Attempts to view routing table information (usually by inspecting /proc/net/route and /proc/net/rt_cache) are predicated on the value of the csecinfo structure of the calling user-process. The major routines used to determine input and output routes a sk_buff should take are ip_route_output() and ip_route_input(). These have been expanded to include an extra argument consisting of a pointer to the csecinfo structure on which to base any routing table lookup. This extra argument is supplied from either the sk_buff of the packet being routing for input or output. Kernel-inserted routing-entries have a special status and are inserted with a wildcard compartment number (-1L). In the context of per-compartment routing, they allow these entries to be shared across all compartments. The main purpose of such a feature is to allow incoming packets to be
Information Security Technical Report, Vol. 7, No. 1
routed properly up the stack. Any security checks occur at a higher level just prior to the sk_buff being delivered on a socket (or its sk_buff queue). The net effect is that each compartment appears to have their individual routing tables which are empty by default. Every compartment shares the use of system-wide network interfaces — there is currently no support for the concept of an IP-address per compartment, although this can appear to be supported at a higher-level e.g. individual HTTP-servers bound to unique IP addresses. It is possible to restrict individual compartments to a strict subset of the available network interfaces. This is because each network interface is notionally in a compartment of its own (with its own routing table). In fact, to respond to an ICMP-echo request, each individual interface can optionally be configured with tagged routing table entries to allow the per protocol ICMPsocket to route its output packet.
Other major subsystem modifications Unix domain sockets
Each Unix domain socket is also tagged with the csecinfo structure. As they also use sk_buffs to represent messages/data traveling between connected sockets, many of the mechanisms used by the AF_INET domain described above apply similarly. In addition, security checks are also performed at every attempt to connect to a peer. System V IPC
Each IPC mechanism listed above is implemented using a dedicated kernel structure that is similarly tagged with a csecinfo structure. Attempts to list, remove or
49
ISTR0701.qxd
4/9/02
2:29 PM
Page 50
Design of Secure Unix
add messages to these constructs are subject to the same security checks as individual sk_buffs. The security checks are dependent on the exact type of mechanism used. Processes/threads
Since individual processes i.e. task_structs are tagged with the csecinfo structure, most process-related operations will be predicated on the value of the process’s compartment number. In particular, process listing (via the /proc interface) is controlled as such to achieve the effect of a per compartment process-listing. Signal delivery is somewhat more complicated as there remains issues around delivering signals to parent processes that may have switched compartments — thus constituting a 1-bit covert channel. Such cases have not been analyzed in detail in the expectation that many other such covert channels (usually much wider) do exist — such as the consumption of CPU-time/diskspace as a signal in morse, for example.
System defaults Per-protocol sockets
Default kernel threads
Various kernel threads may appear by default e.g. kswapd, kflushd and kupdate, to name a few. These threads are also assigned a csecinfo structure per task_struct and their compartment numbers default to 0 to reflect their relatively unprivileged status. Sealing compartments against assumption of root identity
Individual compartments may optionally be registered as ‘sealed’ to protect against processes in that compartment from successfully calling setuid(0) and friends, and also from executing any SUID-root binaries. This is typically used for externally accessible services that may in general be vulnerable to buffer overflow attacks leading to the execution of malicious code. If such services are constrained to initially run as a pseudo-user (non-root) and if the compartment it executes in is sealed, then any attempt to assume the root identity either by buffer overflow attacks and/or execution of foreign instructions will fail. Note that any existing processes running as root will continue to do so.
Secure administration The Linux IP-stack uses special, private perprotocol sockets to implement various default networking behaviours such as ICMP replies. These per protocol sockets are not bound to any user-level socket and are typically initialized with a wildcard compartment number to enable ICMP et al. to behave normally. Use of compartment 0 as unprivileged default
The convention is to never insert rules that allow compartment 0 any access to other compartments and network resources. This way the default behaviour of initialized objects, or objects that have not been properly accounted for will fall under a sensible (and restrictive) default.
50
This section describes the method we use for securing access to the administration functionality provided by the kernel level components of Trusted Linux. This functionality includes such things as adding/deleting compartment communication rules, changing a process label, etc. In fitting with the rest of the Trusted Linux work, the controls are mandatory and not subvertable from user space. One design goal was to provide a way of ensuring that only bona fide system administrators can make use of the Trusted Linux administration functionality whilst at the same time allowing for automatic configuration of the Trusted Linux kernel components at system boot time. Another design goal was that the implementation should
Information Security Technical Report, Vol. 7, No. 1
ISTR0701.qxd
4/9/02
2:29 PM
Page 51
Design of Secure Unix
be as uninvasive as possible in terms of code changes (kernel and user space) and fit as far as possible within standard system administration models for Linux including remote administration. The overall idea is that we want to be sure that somebody who gets access to the kernel level administration functionality is actually an authorized administrator on the system. We want to prevent access to admin functionality via attacks such as compromise of a service running as root, exploitation of suid programs or simply managing to guess the root passwd and suing to root. We want to be in a position where we have to trust as little user space code as possible.
on within the init kernel_thread prior to it invoking the init user space program. Init is the first user space process and all other user space processes are forked/exec-ed from it. The processes subsequently fork/exec-ed by init are controlled by the /etc/inittab file. We have added the ability to specify which processes should have the bit unset and which processes should have it left set. It is important to note that we provide no method to set the attribute to 1 after it has been set to 0 from user space. It is only possible to unset the attribute or query its value from user space. The attribute value is inherited and its value preserved through fork/exec.
System startup/shutdown Finally, often on a server system the root account is more of a role than an individual user (i.e. several admins on the system know the root passwd). So another design goal was that our solution needed to support accountability requirements. The approach presented here works alongside the Linux capability model. Kernel code still checks for the appropriate capability, but additionally we have the ability to check that the request is coming from a real administrator.
Implementation details Each process (thread) has an additional attribute (tlx_adm) associated with it via its task_struct. This attribute is simply 1 or 0. Processes that should be allowed to make use of the kernel level Trusted Linux admin functionality have tlx_adm equal to 1, other processes have it equal to 0. The kernel code checks for this particular attribute in the context of a particular process requesting access to the admin functionality. In the kernel startup code (pre user space operation) the attribute for all tasks (including kernel threads) is set to 0. The bit is then turned
Information Security Technical Report, Vol. 7, No. 1
We have added the actions ‘t_wait’, ‘t_respawn’ and ‘t_sysinit’ to the existing action options supported in the /etc/inittab file. Processes that are started with actions other than these have their attribute value unset (this also means that any processes descended from them also have it unset). We make use of these special actions to allow automatic system configuration at boot/reboot time and secure local/remote system administration. Some of the Trusted Linux security configuration (such as loading the kernel module, adding default rules, etc.) needs to be done as part of the system boot/shutdown process.
Remote management Some sites may wish to allow the machines to be remotely managed including the Trusted Linux functionality. Our approach here is to combine the strong authentication of remote users with the tlx_adm attribute. We have used openssh-2.5 to demonstrate this. We run the ssh server (sshd) from init with the action ‘t_respawn’. This means that the sshd has the tlx_adm attribute left set for itself and
51
ISTR0701.qxd
4/9/02
2:29 PM
Page 52
Design of Secure Unix
potentially any children it forks/execs. The ssh server configuration file has been extended to support the ‘AdminUsers’ field. This works along similar lines to the existing ‘AllowUsers’ option. The ssh server unsets the tlx_adm bit for users who are not listed as an admin user before execing their shells.
Local management We have at least a couple of choices here. Firstly we could modify the login program so that it consults a list of admin users. Alternatively, we can make use of the PAM functionality already built into Linux systems. Currently we are using the latter approach since it requires no code modification just configuration changes. We use the ‘account’ PAM shared lib (pam_access.so) with its configuration file (access.conf) to restrict certain system access points (such as the console, or tty1, etc.) to specific users (the system administrators say). Modified entries in the inittab file allow us to restrict the propagation of the tlx_adm bit to specific (virtual) terminal lines.
individual compartments. In this case, one would need at least three compartments: •One for the Web-server processes. •One for the trusted gateway agent which executes CGI binaries. •As many compartments as is needed to properly categorize each CGI-binary, as the trusted gateway agent will fork/exec CGIbinaries in their configured compartments.
Directory layout Every compartment has a name and resides as a chroot-able environment under/compt. Examples used in the current prototype include: Location
Description
/compt/admin
Admin HTTP-server
/compt/omailout
Externally visible HTTP-server hosting OpenMail CGIs
Layering user-level services
/compt/omailin0
The kernel modifications described previously serve to support the hosting of individual user-level services in a protected compartment. In addition to this, the layout, location and conventions used in adding or removing services in the current prototype are described here.
Internal compartment hosting OpenMail server processes
/compt/web1
Externally visible HTTP-server
/compt/web1mcga
Internal trusted gateway agent for web1’s CGI-binaries
Individual services are generally allocated a compartment each. However, what an enduser perceives as a service may actually end up using several compartments. An example would be the use of a compartment to host an externally accessible Web server with a narrow interface to another compartment hosting a trusted gateway agent for the execution of CGI binaries in their own
52
In addition, these subdirectories also exist: 1. /compt/etc/cac/bin – various scripts and command-line utilities for managing compartments.
Information Security Technical Report, Vol. 7, No. 1
ISTR0701.qxd
4/9/02
2:29 PM
Page 53
Design of Secure Unix
2. /compt/etc/cac/rules – files containing rules for every registered compartment on the system.
3. startup and shutdown scripts are responsible for inserting rules, creating routing-tables, mounting filesystems (e.g. /proc) and other per-service initialization steps
3. /compt/etc/cac/encoding – configuration file for the cacc-utility e.g. compartmentname mappings
In general, if the compartment is to be externally visible, the processes in that compartment should not run as root by default and the compartment should be sealed after initialization. Sometimes this is not possible due to the nature of a legacy application being integrated/ported — in this case, one should remove as many capabilities as possible in order to prevent the processes from escaping the chroot-jail e.g. cap_mknod.
Layout of a typical compartment To support the generic starting/stopping of a compartment, each compartment has to conform to a few basic requirements: 1. be chroot-able under its compartment location /compt/ 2. provide /compt//startup and /compt//shutdown to start/stop the compartment
Administration scripts Due to the fact that the various administration scripts require access to each configured
Entire Host Filesystem
/ - host root directory
Chroot-environment for Admin scripts
/compt – location of all compartments
Chroot for Admin HTTP
/compt/admin
/bin /usr /lib /etc /dev – system files
Chroot for Web1
/compt/web1
Figure 8: Layered chroot-ed environments in Trusted Linux.
Information Security Technical Report, Vol. 7, No. 1
53
ISTR0701.qxd
4/9/02
2:29 PM
Page 54
Design of Secure Unix
compartment’s filesystem and that these administration scripts are called via the CGIinterface of the administration Web server, it is the case that these scripts then cannot reside as a normal compartment i.e. under /compt/. The approach currently taken is to enclose the chroot-table environment of the administration scripts around every configured compartment, but to ensure that the environment is a strict subset of the host’s filesystem. The natural choice is to make the chroot-jail for the administration scripts to have its root at /compt. The end result is structured as in Figure 8.
Integrating applications Since compartments exist as chroot-ed environment under the /comp directory, application integration will require the usual techniques used for ensuring that they work in a chroot-ed environment. A common technique is to prepare a cpio archive of a minimally running compartment, containing a minimal RPM database of installed software. One would normally install the desired application on top of this. In the case of applications in the form of RPMs, one could perform these steps:
root@tlinux# chroot /compt/app1 root@tlinux# rpm - install root@tlinux# [Change configuration files are required e.g. httpd.conf] root@tlinux [Create startup/shutdown scripts in /compt/app1]
The latter few steps may be integrated into the RPM-install phase. Reductions in disk space can be achieved by inspection: selectively uninstalling unused packages via
54
the rpm command. Additional entries in the compartment’s /dev-directory may be created if required, but /dev is normally left pretty bare in most cases. Further automation may be achieved by providing a Web-based interface to the process above to supply all the necessary parameters for each type of application being installed. No changes to the compiled binaries are needed in general, unless one wishes to install compartment-aware variants of such applications. Example of application integration — OpenMail 6.0
The OpenMail 6.0 distribution for Linux consists of a large 160Mb+ archive of some unspecified format, and an install-script ominstall. To install OpenMail, we first chroot to an allocated bare-bones innercompartment:
root@tlinux# root@tlinux# root@tlinux#
root@tlinux#
chroot/ compt/omailin ominstall [ wait for OpenMailinstall to complete naturally ] [ do additional configuration if required, eg setup mailnodes]
Since OpenMail 6.0 has a Web-based interface which we wish to also install, we allocated another bare-bones compartment (omailout),
Information Security Technical Report, Vol. 7, No. 1
ISTR0701.qxd
4/9/02
2:29 PM
Page 55
Design of Secure Unix
and install an Apache HTTP-server to handle the HTTP-queries. Process
At this point we then have to install the CGI binaries that come with OpenMail 6.0 so that they can be accessed by the Apache HTTP server. There are a couple of methods available: •Install OpenMail again in omailout and remove unnecessary portions e.g. serverprocesses. •Copy the OpenMail CGI-binaries from omailin, taking care to preserve permissions and directory structure. In either case, the CGI-binaries typically are placed in the cgi-bin directory of the Apache Web server. If disk space is not an issue, the former approach is more brute force and works well. The latter method can be used if one needs to be sure of exactly which binaries are to be placed in the externally facing omailout compartment. Finally, we can start both compartments:
root@tlinux#
comp_start omailout omailin
General framework approaches to Linux security Trusted Linux is designed specifically round the containment property. In the Linux space, there are a couple of interesting more general security frameworks available. These are RSBAC and SE-Linux. Rule Set Based Access Control (RSBAC) is a Linux implementation of a General Framework for access control (GFAC) designed by Leonard Lapadula (of Bell-Lapadula). It has been implemented
Information Security Technical Report, Vol. 7, No. 1
USER
System call
KERNEL
Kernel Function (includes access control h k)
Resource
Figure 9: Standard Unix kernel security checks.
under Linux by Amon Ott [4]. SE-Linux is a general framework based on a combination of the Utah flux architecture and Domain Type Enforcement (DTE) [5]. Both these frameworks allow new security models to be plugged into the Linux kernel. Figure 9 shows the conventional Unix security approach. Here it can be seen that each kernel function is responsible for implementing security policy. Taking RSBAC as an example, Figure 10 shows how a more flexible security framework can be built into Linux. In a similar but more heavyweight manner to Trusted Linux, RSBAC adds hooks (ADF) to the kernel functions that call out to the central RSBAC security decision engine (ADF). This engine is configured with the rulesets (ACR) of the policy that is to be enforced. Additional attributes (such as file labels) for any system resources to support the ruleset models can be supplied (ACI). RSBAC allows several different security models to be layered on top of each other. So it could be used to create a combined BellLapadula and Clarke-Wilson Integrity based system for example.
55
ISTR0701.qxd
4/9/02
2:29 PM
Page 56
Design of Secure Unix
Process
USER
System call
KERNEL
Kernel Function
ADF
AEF
AEF - Access Enforcement Facility ADF - Access Decision Facility ACR - Access Control Rules ACI - Access Control Information ACI
ACR
Resource
Figure 10: RSBAC kernel architecture.
Conclusion and summary It is clear that the standard Unix security model is not the most appropriate one for hosting applications and services where security is a prime concern. Driven by military needs, trusted operating systems address the serious weaknesses found in conventional Unixes. However, there are significant overheads associated with them that has
56
prevented their widespread adoption outside of the military arena as more generally secure Unix platforms. Trusted Linux is a lightweight trusted OS based on Linux. It has the strong security properties of Trusted Operating systems but in a more flexible form. It has mandatory access controls but not BellLapadula. It is built specifically for containment and we trade security for usability. A good balance?
References [1]Bell, D. and Lapadula, L. Secure computer systems. Unified exposition and multics interpretation. Mitre Technical Report, MTR-1997 (1975). [2]Dalton, C.I. and Griffin, J.F., 1997. Applying Military grade security to the Internet. Computer Networks and ISDN Systems, November 1997. [3]Dalton, C.I. and Choo, T.H., 2001. An operating system approach to securing E-services. Communications of the ACM, February 2001. [4]Ott, A. Rule Set Based Access Control. www.rsbac.org. [5]Security Enhanced Linux. http://www.nsa.gov/ selinux
Information Security Technical Report, Vol. 7, No. 1