Flask Module

The first step in the development of a Flask module for X was to determine the appropriate set of object classes and permissions for X. In 2003, Kilpatrick, Salamon, and Vance described a set of object classes and permissions[*] for use in securing the core X protocol [4]. This set is the one in use today, with the following deviations:

The next step was to begin implementing the Flask module as an extension to the X server. Extensions make use of internal X server API's to initialize themselves, obtain a major code and provide a dispatch handler for new protocol requests, and register callbacks for various events, including XACE hooks. Extensions can be built as loadable modules provided that they rely only on the published API's and do not change the core X server code; the Flask module meets these requirements. All loading and initialization of extensions occurs before the server begins accepting client connections; clients cannot interfere with this process.

Figure 1: Example cut buffer access policy.

Figure 2: Example screen capture policy.

One of the first operations performed in the module initialization code is to register for space in server objects through the devPrivates mechanism described above. Of the eleven X object classes, ten correspond directly to internal objects, and ideally all instances of those objects would carry labels. However, due to the current limitations of devPrivates, many of the objects in question, including resource objects such as font, cursor, and color, do not have devPrivates support and cannot be directly labeled. For the time being, the Flask module maintains a list of labels attached to the main client object, one for each object class. The trouble with this scheme is that it limits to one label all objects of a given class belonging to a given client. Thus it is not currently possible for a client to have, for example, two windows of different types.

When a new client connection is made, the Flask module is notified via a client state callback. The callback function obtains the security context of the new client by calling the getpeercon SELinux library call on the client's socket descriptor (if the connection is from a remote machine, a default context is used). Then, successive security_compute_create library calls are used to determine labels for each of the client's object classes and these are stored in the list attached to the client structure. Once devPrivates support is available, this step will be performed at object creation time, and the label will be stored with the object.

A peculiar concept in the X server is that of the ``server client.'' The X server itself owns resources and other objects, notably the root windows on each screen. A fake client object called the server client is present as a stub in the resource system to server as the owner of these objects. The Flask module treats this client the same way as regular clients, but uses the context of the X server process as the starting point for computing labels.

The property and extension object classes are not associated with a particular client, but rather are labeled based on the name of the object instance as described above. When labeling these objects, the Flask module combines the user and role fields from a base context with a type looked up from the name. The base context used for extensions is that of the server process, and the one used for properties is that of the client object owning the window to which the property is attached. The type-to-name mapping is kept in a configuration file read by the Flask module on startup, although ideally this information would be maintained as part of the SELinux policy configuration in the same manner as the file_contexts database, which serves a similar purpose.

Also at initialization time, the Flask module registers callbacks on XACE hooks, the major one being the dispatch intercept hook described above. After this is done, initialization is complete and the X server proceeds into its dispatch loop, waiting for client requests to arrive. For the most part, the permissions on each object class correspond closely to the core protocol requests involving that class, and this is reflected in the dispatch-oriented structure of the module's enforcement code.

For example, suppose a ChangeWindowAttri- butes request arrives at the server. This request contains the resource ID of a window along with new window attributes to be set. The XACE dispatch intercept hook calls the Flask module callback, which drops through a switch statement to the ChangeWindowAttributes handler. That handler parses the incoming request, first determining the context of the client making the request (the source), then extracting the window ID and from it determining the client owner of the resource. The list of labels in the owner's client structure is consulted to determine the context of the window (the target). Finally, a call to avc_has_perm is made, passing the source and target contexts, window class value, and the setattr permission. If the result is a denial, XACE returns a BadAccess error to the client, otherwise the request continues on to its ``real'' handler. All of the core protocol requests are handled in this manner, and extension protocol requests will likely be handled in the same manner.

The Flask module also includes preliminary support for window labeling. Via an XACE hook, a callback function is called whenever new windows are created. That callback function sets a property on the window containing the window's security context, and in the future additional properties may be added to communicate other contexts, such as that of the client connection owning each window. The property name begins with an _SELINUX prefix and it can be protected from modification via SELinux policy. Window managers can be modified to display the property contexts alongside or in lieu of the normal window title; Figure 4 (located on the last page) shows a screen shot of a modified twm that does this. Secure window labeling is discussed further in Section 5.4.