[soen321-f04] Unix considered harmful (Sep 27)

David K. Probst PROBST at vax2.concordia.ca
Mon Sep 27 19:18:20 EDT 2004


Secure operaing systems
_______________________

Discussions of the flawed Unix security model raise a deeper issue: having 
a secure operating-system kernel would have a major positive impact on
computer security.  Indeed, it is unrealistic to suppose that security can
adequately be provided in application space without certain security features
in the operating system.  Indeed, operating-system security mechanisms play a
critical role in supporting security at higher levels.

Unfortunately, the security mechanisms provided by conventional operating
systems are wholly inadequate.

The relevance of operating-system security to overall system security is that
the OS is responsible for protecting application-space mechanisms against
tampering, bypassing, and spoofing attacks.  If it fails to meet this
responsibility, system-wide vulnerabilities will result.

Even a careful and knowledgeable user running on a single-user system is no
longer safe from the threat of malicious code.  Because the effective
distinction between data and code is vanishing (malicious input to weak
programs quickly becomes malicious code, even if the input is not executable
code per se), malicious code may be introduced, without a conscious decision
on the part of the user to install executable code, whenever data is imported
into the system.  More so than ever, secure operating systems are needed to
protect against this threat.

Threats posed by the modern computing environment _cannot_ be addressed
without support from secure operating systems.

Two critical features are discussed that are important in themselves and that
highlight the value of secure operating systems; there would be other features
in a more complete list.

The first is mandatory security, understood as any security policy where the
definition of the policy logic and the assignment of security attributes is
tightly controlled by a system security-policy administrator.  Mandatory
security can implement organization-wide security policies.  This has also
been referred to as _non-discretionary security_ in the context of role-based
access control and type enforcement.

With this definition, _discretionary security_ must be understood as any
security policy where ordinary users may be involved in the definition of
policy functions and/or the assignment of security attributes.

The distinction is thus more general than just MAC versus DAC.

Example: In _discretionary_ access control, either the user, or a process
running under that user's uid, can change the permissions on an object that
was created by that user.  In _mandatory_ access control, only the security
administrator can change the permissions on an object.

An operating system which provides mandatory security may nonetheless suffer
from the presence of high-bandwidth covert channels.  This is an issue
whenever the mandatory security policy is concerned with confidentiality.
However, it does improve security by increasing the sophistication required
from the adversary.

In any system which supports mandatory security, some applications require
privileges in the mandatory policy in order to perform some security-relevant
functions.  Such applications are frequently called trusted applications
because they are trusted to correctly perform some security-related function
and because they are trusted to not misuse privileges required in order to
perform that function.

But, if the mandatory security mechanisms of a secure operating system only
support _coarse-grained_ privileges, then the security of the overall system
may essentially depend on the security of the trusted applications on the
system.  To reduce the dependency on trusted applications, the mandatory
security mechanisms of an operating system should be designed to support the
principle of least privilege.

Type enforcement is an example of a mandatory security mechanism which may be
used both to limit trusted applications to the minimal set of privileges
required for their function and to confine the damage caused by any misuse of
these privileges.

Operating-system mandatory security mechanisms may also be used to rigorously
confine an application to a unique security domain that is strongly separated
from other domains in the system.  Applications may still misbehave, but the
resulting damage can now be restricted to within a single security domain.

A standard application is supporting the safe execution of untrustworthy
software.  (Note that this also applies to executing longstanding application
code that may have been compromised without our noticing it).

Discretionary security mechanisms cannot defend against careless or malicious
users.  Since discretionary security mechanisms place the burden of security
on the individual users, carelessness by any one user at any point in time
may lead to a violation of the mandatory policy.  In contrast, mandatory
security mechanisms limit the burden to the system security-policy
administrator.

With only discretionary mechanisms, a malicious user with access to sensitive
data and applications may directly release sensitive information in violation
of the mandatory policy.  With mandatory security mechanisms, he may only leak
sensitive information through covert channels.

Mandatory security mechanisms may be used to ensure that security mechanisms
are applied as required and can protect the user against inadvertent execution
of untrustworthy applications.  Although the user may have carefully defined
the discretionary policy to properly implement the mandatory policy, an
application may change the discretionary policy without the user's approval 
or knowledge.

The second critical feature is a trusted path, i.e., a mechanism by which a
user may directly interact with trusted software, which can only be activated
by either the user or the trusted software and may not be imitated by other
software.  In the absence of a trusted-path mechanism, malicious software may
impersonate trusted software to the user or may impersonate the user to
trusted software.

Example: In Windows NT, pushing Ctrl/Alt/Del activates a login screen; the
user at the terminal is guaranteed that he is talking to the authorized 
login process.  Windows NT does not have trusted paths in general.  Unix has
_no_ trusted paths.

Such malicious software could potentially obtain sensitive information,
perform functions on behalf of the user in violation of the user's intent, or
trick the user into believing that a function has been invoked without
actually invoking it.

The concept of trusted path can be generalized to include interactions beyond
just those between trusted software and users.  More generally, a mechanism
that gurantees a mutually authenticated channel, or _protected path_, is
necessary to ensure that critical system functions are not being spoofed.

To summarize what has been said so far, the threats posed by the modern 
computing environment cannot be addressed without secure operating systems.
The critical operating-system security features of mandatory security and
trusted path have been explained.  It has been suggested that these features
are _not_ part of the protection mechanisms of mainstream operating systems,
which remain inadequate.  Indeed, both secure operating systems and
application-space security mechanisms must complement each other in order to
provide the correct level of protection.

Unix considered harmful
_______________________

First, a few definitions.  1) An operating system with multilevel security
(MLS) can process information with different security classifications and
categories (security compartments) to simultaneously permit access by users
with different security clearances and deny access to users who lack
authorization.  2) Authentication is the process whereby an entity proves
its identity to another entity.  3) Authorization is the set of access rights
granted to a user, program, or a process.  It is _also_ the operational act of
allowing subjects to access a resource after determining that they hold the
required set of privilege attributes.

Almost all operating systems currently in use rely on a security model based
on the original Unix security model: resources are accessed via processes.
Resources are represented as files (even devices look like a file), and they
have an access attribute consisting of a user name and a group name.  Each
resource has a permission mask, which defines access permissions (read, write,
execute, and others) for the user name, group name, and all others (the world).
Processes are authenticated via an initial process (usually login), which sets
the user and group identifier of the process as well as a set of other groups.
>From that point onwards, the process access attributes allow access from the
process to any resource that matches these attributes.

In Unix, processes cannot re-authenticate and change authorization; the only
mechanism for a change in authorization (protection domain) is the 'setuid'
system call, which is both coarse grained and problematic in other ways.
Processes cannot present different authentication data to different resources
to gain different authorizations.  (This would require something like a
full-fledged capability scheme).  Resources are not active in Unix; they are
passive, and hence cannot engage in authentication or authorization activity
with a client.  Moreover, resources cannot possess access attributes outside
the simple user/group/world model.

The file system of a Unix system is (an instance of) a large name space.  A
Unix process augments its (current) name space via the Unix 'mount' system
call.  When a process modifies the name space of a machine, the modification
is global: all processes on the system will see the modification.  In other
words, mounts have (global) side effects: they modify the global state of the
system, not just the local state of the process.  Unintended sharing can be
the result, which violates the goal of information confinement.

In passing, we note that the Unix 'uid' user-naming mechanism (small integers)
does not scale to truly large configurations.

Finally, Unix operations rely on 'root' as a privilged user.  For the root
user (uid = 0), no operation is off limits or out of bounds.  Privilege checks
are bypassed for the root user.  The root user can attain the privileges, via
setuid, of any other user.  Most Unix exploits (system compromises) revolve
around spoofing programs running as root into doing something that violates
the security of the system.

The existence of the root user will, inevitably, reduce the security of the
system.  Removing root is impossible because so many basic Unix mechanisms
rely on the existence of root.

The lack of sophisticated permissions limits the ability to implement both
strong security and multilevel security.  Because resources are passive rather
than active, they cannot engage in more sophisticated authentication
transactions.  Because resources have simple permissions, the increased
sophistication required for MLS and more fine-grained access controls is not
possible.  Because file name-space modifications are in fact modifications of
the global state of the system, they can lead to unintended leakage of
information.

Is reform possible or is revolution necessary?  Linux is moving forward to a
more generalized form of access-control lists, which will enhance the
protections provided by the file system.  We may eventually see private name
spaces.  Name-space modification may get tied into strong authentication tools.

In the end, however, the Unix security model is not extensible.  It will be
necessary to kill the use of integer UIDs and the existence of root users.
What features might exist in a non-Unix secure operating system?

 - making resources active rather than passive, allowing processes to
   reauthenticate as needed for different resources

 - allowing processes to present different authentication, and gain different
   authorization, for different resources

 - providing a richer and more fine-grained access-control model

 - supporting private name spaces

 - etc.

Logically, we need some kind of capability-based operating system.  For
example, root has _no meaning_ in a capability-based system.  Why is this?  In
the conventional approach, the process says, I have this _arbitrary_ privilege
because my name is "root".  In the capabilty approach, the process says, I
have this (particular) privilege because I can display a capability (a special
kind of token) explicitly granting this privilege to the bearer of the token.

Later, we will study eight (or ten---I forget) fundamental principles or
guidelines for designing secure software from the very beginning.  A very
important one is the principle of least privilege: always grant to a process
the minimum set of privileges it requires to carry out its current task,
repeatedly adjusting the set of privileges as the process moves from task to
task.  Obviously, the concept of root violates both the letter and the spirit
of the principle of least privilege.



More information about the soen321-f04 mailing list