Design of Secure Unix

Design of Secure Unix

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 ...

623KB Sizes 1 Downloads 89 Views

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