X Server Security Hooks

SELinux in its current form relies on the Linux Security Modules (LSM) project to provide access to key decision points throughout the kernel [9]. LSM provides general-purpose security hooks and a number of security projects besides SELinux have made use of them. Since X is a general-purpose windowing system just as Linux is a general-purpose operating system, the provision of LSM-style security hooks was determined to be the best method to provide enforcement logic in the X server. These hooks were added by what is now known as the X Access Control Extension (XACE).

The development of XACE was simplified by an existing security extension (``Security'') developed by the X Consortium in 1996 [12][13]. The Security extension provides a simple two-level trust hierarchy for client connections, where ``untrusted'' clients are restricted in several ways. The two-level trust model is too coarse-grained for general use, but the extension authors had conducted an analysis of the core X protocol, identifying places in which untrusted clients should be restricted and introducing checks into the X server code at those places. Much of the XACE development process consisted of simply replacing those checks with more generic callbacks. The Security extension was then rewritten to use the new callbacks, maintaining full backwards compatibility.

XACE has been accepted into the X.org mainline as of xserver release 1.2. A full discussion of the capabilities of XACE is beyond the scope of this paper [11], and the set of hooks may change slightly as work progresses (refer to Section 5.2). However, two specific areas where XACE provides coverage are worth discussing in detail, because they together provide the basis for nearly all of the enforcement activity of the Flask module discussed in the next section.

The first of the two areas is control over access to X server resources. Most X server objects or ``resources,'' including windows, pixmaps, cursors, fonts, and colormaps, are assigned unique ID numbers and stored together in a large hash table. The ID numbers include space for a client index number, allowing resources to be assigned a client ``owner,'' usually the client responsible for creating the resource. The resource system is extensible, allowing X protocol extensions to create new resource types for objects that they introduce [1]. Clients refer to resources by ID number when making protocol requests; the request handling code then calls a lookup function to retrieve a pointer to the object itself. An XACE hook is present in the lookup code. The hook includes as parameters the resource ID (from which the client owner and type of resource can be ascertained) and the client on whose behalf the lookup is being made [13]. This important hook allows security modules to vet any and all resource lookups.

The second of the two areas is control over the X protocol dispatch table. Briefly, X protocol requests include major and minor codes. The major code specifies the protocol extension, with the first several major codes reserved for ``core'' X protocol requests. Major codes are assigned to extensions dynamically, but extensions have fixed names which can be checked to determine which extension is assigned to a given major code [7]. The minor code, by convention, specifies the individual request within the protocol extension. All incoming requests are dispatched through an array indexed by major code, containing function pointers to request handlers. For core protocol requests, the request handler processes the request immediately. For extension protocol requests, by convention, the request handler switches on the minor code, calling a second handler which performs the specific request.

XACE fills the server's dispatch array entirely with calls to an XACE intercept function. This function calls an XACE hook, allowing security modules to examine and potentially reject all incoming requests before they are dispatched to the actual request handlers. Using the published protocol specifications, security module authors can write code to parse the incoming requests, checking resource ID numbers, flags, and other parameters. This powerful capability is used extensively by the Flask module.