* 8 *

Object orientation as a security model

Fact of the week

RPC (Remote Procedure Call) is about the execution of functions on a remote host. RPC began with Sun Microsystems' (ONC) infra-structure for NFS, supported by Novell and AT&T. Apollo/Hewlett-Packard built a rival system (NCS) supported by IBM, DEC(Compaq) and Microsoft. Recently RPC systems have come to include the Java RMI, Microsoft's DCOM and CORBA.

Chapter 17,10 Gollmann
In last week's lecture we ended with a discussion of the Clark-Wilson model and the way in which it attempts to ensure data integrity by demanding that users employ specific programs, with limited functionality, in order to access data. This idea has an important parallel in object oriented programming techniques. All kinds of philosphical claims are made about the value of object orientation in programming, but perhaps the least controversial interpretation of object orientation is simply as a security framework for software integrity. It makes program data accessible on a need to know basis.

Objects and classes

Roughly speaking, object orientation is a synthesis of two ideas: the classification or taxonomy of data into abstract types, and access control based on scope. Even in non-object based languages we have the idea of access control based on scope. e.g. in Algol, Pascal, C etc, we can define local variables within any set of brackets
 /* begin */

  { int localvar;

  }

 /* end */
When we pass parameters to functions and subroutines, the values of those parameters are copied into local storage. For instance, if we call
function(i,j);
in a program at one point, with the functional definition,

 function (int a, int b)

 { int localvar;

 a = 6;
 b = 7;
 }

elsewhere, the change of a,b in the function has no effect on the value of the actual parameters i,j, unless we specifically ask for the access by passing a reference to the original variable (essentially by pointer).

Semantic quibblers will not doubt argue about what object orientation means. For the purposes of this lecture we shall call anything which is not a linear, global language (GOTO languages with global variables) at least partially object oriented. Scope is a partial admission of objects. Atomic data types are primitive objects. Compound objects are present in Pascal (record) and C (struct). Simula, C++ and Java generalize data types to form classes which can contain not only primitive data objects but also specialized programs or methods which manipulate the data. Java goes even further by removing pointers, and insisting that users go through the compiler to access memeory.

Object orientation involves:

With nesting, we find a decrease in scope with increasing depth, but an increase in privacy.

Like many other security systems, object orientation places demands on programmers. For some, the price is too high and programmers will work around object protection mechanisms. Constructing water-tight object models in non-trivial programs is very hard work. The investment of time is often a huge burden on programmers, since many new (experimental) programs cannot be specified accurately at the design state. Strong security is not conducive to prototyping of program concepts.

Mandatory Access Control or scope in object models

We find a decrease in security scope with increasing depth, but an increase in privacy. Encapsulation and inheritance work by the following rules:
  1. The security level of an object must be higher than the security level of its class object. (Higher means more secure)
  2. The security level of a virtual function/method (subject) must be greater than the security of the function which called it, and of the home or defining object. (This is the scope property)
  3. A virtual method can (execute,read,write) only members of its defining object.
  4. A virtual method can write into its defining object only if its security level is equal to that of the home object (i.e. recursion is protected).
  5. A virtual method can send a return value to the method which invoked it, only if it is at the same security level (as above).
  6. The security level of a newly created object is greater than the level of the object which creates it (objects do not leak).
Global variables, pointers and reference passing act as covert channels, punching a hole in these security mechanisms.

The role of classes in software security

Generalization is the enemy of security. Specialization is security's friend.

Classes in C++ and Java not only classify data for building a private environment for their manipulation, there is a fair amount of supplementary technology which helps avoid programming errors. Let us examine an example from C++. (The only important difference between C++ and Java, in this context is that member functions are not defined within class braces {...} in C++.)

    class Box : public Containers

    {
    public:                       // These can be used by any function

       Box();                     // If properly written should avoid
       ~Box();                    // memory leaks

       virtual void Empty();      // Can be overridden by subclasses. Overrides
                                  // parent class Containers with a more specialized
                                  // (more secure) function.

       static void Explode();     
       const  void Examine();     // This function can be used as a covert channel
                                     to reveal private members to other objects.

    protected:                    // Can be used by member functions, 
                                  // and dervived classes
      int   careful1;
      float careful2;

    private:                      // Can only be used by member functions
                                  // or friends
       int  secret1;
       char secret2;
    }

Constructors/destructors and garbage collection

A problem which occurs in long running server processes is that they gradually use more and more memory, gradually choking the machine on which they are running (this has been a major problem for NT in its early versions). This occurs in programs which allocate memory but never free it again. Such an error is called a memory leak.

Memory leaks are a security issue because programs which eat up a machine's memory can be used as the basis of a denial of service attack. Use of constructors and destructors does two things for us. It hands the problem of memory allocation to the compiler for local instantiations, so that the compiler performs the garbage collection automatically. It also ensures that new objects are initialized. Variables which are not initialised can also cause careless errors, as we saw in last week's exercises.

Java's memory allocation and garbage collection model is one of its main defenses against exploitation.

Static and const methods

Inheritance and virtual functions

The class hierarchy acts like an access control lattice. Multiple inheritance means that we might be able to access a function by several routes! Suppose we have classes

  class alpha
     {
     public:
        int A;
        void functionA();
        void printme();
     };

  class beta
     {
     public:
        int B;
        void functionB();
        void printme();
     };

  class alphabet: public alpha, public beta
     {
     public:
        int *letter;
        void words();
     }

A call to
  alphabet *ptr;

  ptr->printme();
is ambiguous, but not dangerous, since the compiler will complain, at least in C++ (it might be a problem in an interpreted language). The main problem with (multiple) inheritance is that it increases the burden on the programmer. Objects become available to a program, without necessarily becoming visible. The programmer might not be aware of the knock-on effects. In contrast to scope, inheritenance moves us upwards in a hierachy. It is possible that an object will inherit information which was not intented if the inheritance depth becomes too big.

       ^                        --------
       |                       |        |
       |  U                     --------
       |  p                     /      \
       |  w               --------     --------
       |  a              |        |   |        |
       |  r               --------     --------
       |  d                /   \         /  \

                       more  more      more  more

Multiple inheritance is disallowed in Java. Instead, we have interfaces.

Structures and unions

A struct datatype is like a class in which all of the members are public. It is only a conceptual and practical container for related data objects which makes some program syntax more transparent.

A union on the other hand is something quite different. Unions were introduced in C in order to avoid the problem of memory fragmentation, which we discussed in the operating systems course. Unions have nothing to do with security, they have to do with efficiency.

Global variables and global functions

Since the wave of adoration for structured programming languages brainwashed programmers into thinking that object orientation is the panacea of programming paradigms, it has become popular to say that the use of global variables is bad. This has now become dogma.

Any arguments which apply to global variables also apply to public class members, since public members are global within their defining class. The purpose of global variables is to

Here are the arguments for and against global variables: Note that the argument that global variables make code difficult to read is just propaganda. It is easy to keep track of global variables by adopting a naming convention for variables, e.g. using UPPERCASE variable names for globals, or adding a suffix variable_glb etc.

CORBA

One of the purposes of procedural languages is that a procedural structure allows code to be reused in libraries. Unix introduced shared libraries in order to make library access more efficient. Instead of copying an entire library onto every program, every program shares a library built of relocatable code. In order for a program to access a library function, it goes through a function broker or dynamic link loader (ld.so) which loads just the functions required by the process. Windows later adopted there own standard of DLL's (dynamically loadable library).

Imagine now that shared libraries could be shared, not only between the programs on one machine, but across the network itself. This would be a distributed shared library. In an object oriented language, one can go one step further and define objects and object-methods, like the standard libraries of functions in C++, or Java which could be downloaded by any host. Of course, the problem then is that operating systems are not compatible or interoperable.

CORBA (The Common Object Request Broker Architecture) is a solution to this problem. It provides an infra-structure which is standardized, and which conceals the differences between operating systems and programming languages. It is a generic library service for objects. An Object Request Broker (ORB) is a `software bus' between clients (user programs ) and servers. It handles requests from clients and makes sure that they are executed on a server. Objects and methods are thus remotely executed and stored (CORBA is an RPC system). The user program becomes like a stub.

CORBA claims to be a secure architecture, suitable for multiuser environments. The CORBA security includes

Since CORBA is a service, it is able to restrict the operations carried out by clients and is thus able to ensure security. However, the security of the server must be assured in order for this to be true.

Thought for the week

Compiled languages perform many checks and provide warnings about potentially dangerous code. Does this make compiled languages more secure than script languages like, say, Perl or Visual Basic?

Back