summaryrefslogtreecommitdiff
path: root/Xext/xselinux.c
diff options
context:
space:
mode:
Diffstat (limited to 'Xext/xselinux.c')
-rw-r--r--Xext/xselinux.c1675
1 files changed, 510 insertions, 1165 deletions
diff --git a/Xext/xselinux.c b/Xext/xselinux.c
index bc86a3294..9ff055484 100644
--- a/Xext/xselinux.c
+++ b/Xext/xselinux.c
@@ -32,13 +32,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <dix-config.h>
#endif
-#include <X11/X.h>
#include <X11/Xatom.h>
-#include <X11/Xproto.h>
-#include <X11/Xfuncproto.h>
+#include "resource.h"
+#include "privates.h"
+#include "registry.h"
#include "dixstruct.h"
#include "extnsionst.h"
-#include "resource.h"
+#include "scrnintstr.h"
#include "selection.h"
#include "xacestr.h"
#include "xselinux.h"
@@ -50,14 +50,15 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <stdarg.h>
#include "modinit.h"
-#ifndef XSELINUXCONFIGFILE
-#warning "XSELinux Policy file is not defined"
-#define XSELINUXCONFIGFILE NULL
-#endif
+/* private state record */
+static DevPrivateKey stateKey = &stateKey;
-/* devPrivates in client and extension */
-static int clientPrivateIndex;
-static int extnsnPrivateIndex;
+/* This is what we store for security state */
+typedef struct {
+ security_id_t sid;
+ struct avc_entry_ref aeref;
+ char *client_path;
+} SELinuxStateRec;
/* audit file descriptor */
static int audit_fd;
@@ -65,1337 +66,681 @@ static int audit_fd;
/* structure passed to auditing callback */
typedef struct {
ClientPtr client; /* client */
- char *property; /* property name, if any */
+ char *client_path; /* client's executable path */
+ unsigned id; /* resource id, if any */
+ int restype; /* resource type, if any */
+ Atom property; /* property name, if any */
char *extension; /* extension name, if any */
-} XSELinuxAuditRec;
+} SELinuxAuditRec;
/* labeling handle */
static struct selabel_handle *label_hnd;
-/* Atoms for SELinux window labeling properties */
-Atom atom_ctx;
-Atom atom_client_ctx;
+/* whether AVC is active */
+static int avc_active;
+
+/* atoms for window label properties */
+static Atom atom_ctx;
+static Atom atom_client_ctx;
-/* Selection stuff from dix */
-extern Selection *CurrentSelections;
-extern int NumCurrentSelections;
+/* The unlabeled SID */
+static security_id_t unlabeled_sid;
-/* Dynamically allocated security classes and permissions */
+/* Array of object classes indexed by resource type */
+static security_class_t *knownTypes;
+static unsigned numKnownTypes;
+
+/* dynamically allocated security classes and permissions */
static struct security_class_mapping map[] = {
- { "drawable",
- { "create", "destroy", "draw", "copy", "getattr", NULL }},
- { "window",
- { "addchild", "create", "destroy", "map", "unmap", "chstack",
- "chproplist", "chprop", "listprop", "getattr", "setattr", "setfocus",
- "move", "chselection", "chparent", "ctrllife", "enumerate",
- "transparent", "mousemotion", "clientcomevent", "inputevent",
- "drawevent", "windowchangeevent", "windowchangerequest",
- "serverchangeevent", "extensionevent", NULL }},
- { "gc",
- { "create", "free", "getattr", "setattr", NULL }},
- { "font",
- { "load", "free", "getattr", "use", NULL }},
- { "colormap",
- { "create", "free", "install", "uninstall", "list", "read", "store",
- "getattr", "setattr", NULL }},
- { "property",
- { "create", "free", "read", "write", NULL }},
- { "cursor",
- { "create", "createglyph", "free", "assign", "setattr", NULL }},
- { "xclient",
- { "kill", NULL }},
- { "xinput",
- { "lookup", "getattr", "setattr", "setfocus", "warppointer",
- "activegrab", "passivegrab", "ungrab", "bell", "mousemotion",
- "relabelinput", NULL }},
- { "xserver",
- { "screensaver", "gethostlist", "sethostlist", "getfontpath",
- "setfontpath", "getattr", "grab", "ungrab", NULL }},
- { "xextension",
- { "query", "use", NULL }},
+ { "x_drawable", { "read", "write", "destroy", "create", "getattr", "setattr", "list_property", "get_property", "set_property", "", "", "list_child", "add_child", "remove_child", "hide", "show", "blend", "override", "", "", "", "", "send", "receive", "", "manage", NULL }},
+ { "x_screen", { "", "", "", "", "getattr", "setattr", "saver_getattr", "saver_setattr", "", "", "", "", "", "", "hide_cursor", "show_cursor", "saver_hide", "saver_show", NULL }},
+ { "x_gc", { "", "", "destroy", "create", "getattr", "setattr", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "use", NULL }},
+ { "x_font", { "", "", "destroy", "create", "getattr", "", "", "", "", "", "", "", "add_glyph", "remove_glyph", "", "", "", "", "", "", "", "", "", "", "use", NULL }},
+ { "x_colormap", { "read", "write", "destroy", "create", "getattr", "", "", "", "", "", "", "", "add_color", "remove_color", "", "", "", "", "", "", "install", "uninstall", "", "", "use", NULL }},
+ { "x_property", { "read", "write", "destroy", "create", NULL }},
+ { "x_selection", { "read", "", "", "", "getattr", "setattr", NULL }},
+ { "x_cursor", { "read", "write", "destroy", "create", "getattr", "setattr", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "use", NULL }},
+ { "x_client", { "", "", "destroy", "", "getattr", "setattr", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "manage", NULL }},
+ { "x_device", { "read", "write", "", "", "getattr", "setattr", "", "", "", "getfocus", "setfocus", "", "", "", "", "", "", "grab", "freeze", "force_cursor", "", "", "", "", "", "manage", "", "bell", NULL }},
+ { "x_server", { "record", "", "", "", "getattr", "setattr", "", "", "", "", "", "", "", "", "", "", "", "grab", "", "", "", "", "", "", "", "manage", "debug", NULL }},
+ { "x_extension", { "", "", "", "", "query", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "use", NULL }},
+ { "x_resource", { "read", "write", "write", "write", "read", "write", "read", "read", "write", "read", "write", "read", "write", "write", "write", "read", "read", "write", "write", "write", "write", "write", "write", "read", "read", "write", "read", "write", NULL }},
{ NULL }
};
/*
- * list of classes corresponding to SIDs in the
- * rsid array of the security state structure (below).
- *
- * XXX SIDs should be stored in their native objects, not all
- * bunched together in the client structure. However, this will
- * require modification to the resource manager.
+ * Returns the object class corresponding to the given resource type.
*/
-static security_class_t sClasses[] = {
- SECCLASS_WINDOW,
- SECCLASS_DRAWABLE,
- SECCLASS_GC,
- SECCLASS_CURSOR,
- SECCLASS_FONT,
- SECCLASS_COLORMAP,
- SECCLASS_PROPERTY,
- SECCLASS_XCLIENT,
- SECCLASS_XINPUT,
- SECCLASS_XSERVER
-};
-#define NRES (sizeof(sClasses)/sizeof(sClasses[0]))
-
-/* This is what we store for client security state */
-typedef struct {
- int haveState;
- security_id_t sid;
- security_id_t rsid[NRES];
- struct avc_entry_ref aeref;
-} XSELinuxClientStateRec;
-
-/* Convenience macros for accessing security state fields */
-#define STATEPTR(client) \
- ((client)->devPrivates[clientPrivateIndex].ptr)
-#define HAVESTATE(client) \
- (((XSELinuxClientStateRec*)STATEPTR(client))->haveState)
-#define SID(client) \
- (((XSELinuxClientStateRec*)STATEPTR(client))->sid)
-#define RSID(client,n) \
- (((XSELinuxClientStateRec*)STATEPTR(client))->rsid[n])
-#define AEREF(client) \
- (((XSELinuxClientStateRec*)STATEPTR(client))->aeref)
-#define EXTENSIONSID(ext) \
- ((ext)->devPrivates[extnsnPrivateIndex].ptr)
-
-/*
- * Returns the index into the rsid array where the SID for the
- * given class is stored.
- */
-static int
-IndexByClass(security_class_t class)
+static security_class_t
+SELinuxTypeToClass(RESTYPE type)
{
- int i;
- for (i=0; i<NRES; i++)
- if (class == sClasses[i])
- return i;
- return 0;
-}
-
-/*
- * Does sanity checking on a resource ID. This can be removed after
- * testing.
- */
-static void
-CheckXID(XID id)
-{
- /*
- XID c = CLIENT_ID(id);
-
- if (c > 10)
- ErrorF("Warning: possibly mangled ID %x\n", id);
-
- c = id & RESOURCE_ID_MASK;
- if (c > 100)
- ErrorF("Warning: possibly mangled ID %x\n", id);
- */
-}
-
-/*
- * Byte-swap a CARD32 id if necessary.
- */
-static XID
-SwapXID(ClientPtr client, XID id)
-{
- register char n;
- if (client->swapped)
- swapl(&id, n);
- return id;
-}
-
-/*
- * ServerPerm - check access permissions on a server-owned object.
- *
- * Arguments:
- * client: Client doing the request.
- * class: Security class of the server object being accessed.
- * perm: Permissions required on the object.
- *
- * Returns: X status code.
- */
-static int
-ServerPerm(ClientPtr client,
- security_class_t class,
- access_vector_t perm)
-{
- int idx = IndexByClass(class);
- if (HAVESTATE(client))
- {
- XSELinuxAuditRec auditdata;
- auditdata.client = client;
- auditdata.property = NULL;
- auditdata.extension = NULL;
- errno = 0;
- if (avc_has_perm(SID(client), RSID(serverClient,idx), class,
- perm, &AEREF(client), &auditdata) < 0)
- {
- if (errno == EACCES)
- return BadAccess;
- ErrorF("ServerPerm: unexpected error %d\n", errno);
- return BadValue;
- }
+ RESTYPE fulltype = type;
+ type &= TypeMask;
+
+ if (type >= numKnownTypes) {
+ /* Need to increase size of classes array */
+ unsigned size = sizeof(security_class_t);
+ knownTypes = xrealloc(knownTypes, (type + 1) * size);
+ if (!knownTypes)
+ return 0;
+ memset(knownTypes + numKnownTypes, 0,
+ (type - numKnownTypes + 1) * size);
}
- else
- {
- ErrorF("No client state in server-perm check!\n");
- return Success;
+
+ if (!knownTypes[type]) {
+ const char *str;
+ knownTypes[type] = SECCLASS_X_RESOURCE;
+
+ if (fulltype & RC_DRAWABLE)
+ knownTypes[type] = SECCLASS_X_DRAWABLE;
+ if (fulltype == RT_GC)
+ knownTypes[type] = SECCLASS_X_GC;
+ if (fulltype == RT_FONT)
+ knownTypes[type] = SECCLASS_X_FONT;
+ if (fulltype == RT_CURSOR)
+ knownTypes[type] = SECCLASS_X_CURSOR;
+ if (fulltype == RT_COLORMAP)
+ knownTypes[type] = SECCLASS_X_COLORMAP;
+
+ /* Need to do a string lookup */
+ str = LookupResourceName(fulltype);
+ if (!strcmp(str, "PICTURE"))
+ knownTypes[type] = SECCLASS_X_DRAWABLE;
+ if (!strcmp(str, "GLYPHSET"))
+ knownTypes[type] = SECCLASS_X_FONT;
}
- return Success;
+// ErrorF("Returning a class of %d for a type of %d\n", knownTypes[type], type);
+ return knownTypes[type];
}
/*
- * IDPerm - check access permissions on a resource.
- *
- * Arguments:
- * client: Client doing the request.
- * id: resource id of the resource being accessed.
- * class: Security class of the resource being accessed.
- * perm: Permissions required on the resource.
- *
- * Returns: X status code.
+ * Performs an SELinux permission check.
*/
static int
-IDPerm(ClientPtr sclient,
- XID id,
- security_class_t class,
- access_vector_t perm)
+SELinuxDoCheck(ClientPtr client, SELinuxStateRec *obj, security_class_t class,
+ Mask access_mode, SELinuxAuditRec *auditdata)
{
- ClientPtr tclient;
- int idx = IndexByClass(class);
- XSELinuxAuditRec auditdata;
+ SELinuxStateRec *subj;
- if (id == None)
- return Success;
-
- CheckXID(id);
- tclient = clients[CLIENT_ID(id)];
+// ErrorF("SuperCheck: client=%d, class=%d, access_mode=%x\n", client->index, class, access_mode);
- /*
- * This happens in the case where a client has
- * disconnected. XXX might want to make the server
- * own orphaned resources...
- */
- if (!tclient || !HAVESTATE(tclient) || !HAVESTATE(sclient))
- {
+ /* serverClient requests OK */
+ if (client->index == 0)
return Success;
- }
- auditdata.client = sclient;
- auditdata.property = NULL;
- auditdata.extension = NULL;
+ subj = dixLookupPrivate(&client->devPrivates, stateKey);
+ auditdata->client = client;
+ auditdata->client_path = subj->client_path;
errno = 0;
- if (avc_has_perm(SID(sclient), RSID(tclient,idx), class,
- perm, &AEREF(sclient), &auditdata) < 0)
- {
+
+ if (avc_has_perm(subj->sid, obj->sid, class, access_mode, &subj->aeref,
+ auditdata) < 0) {
if (errno == EACCES)
return BadAccess;
- ErrorF("IDPerm: unexpected error %d\n", errno);
+ ErrorF("ServerPerm: unexpected error %d\n", errno);
return BadValue;
}
return Success;
}
-/*
- * GetPropertySID - compute SID for a property object.
- *
- * Arguments:
- * basecontext: context of client owning the property.
- * name: name of the property.
- *
- * Returns: proper SID for the object or NULL on error.
- */
-static security_id_t
-GetPropertySID(security_context_t base, const char *name)
-{
- security_context_t con, result;
- security_id_t sid = NULL;
-
- /* look in the mappings of names to types */
- if (selabel_lookup(label_hnd, &con, name, SELABEL_X_PROP) < 0)
- goto out;
-
- /* perform a transition to obtain the final context */
- if (security_compute_create(base, con, SECCLASS_PROPERTY, &result) < 0)
- goto out2;
-
- /* get a SID for the context */
- avc_context_to_sid(result, &sid);
- freecon(result);
- out2:
- freecon(con);
- out:
- return sid;
-}
-
-/*
- * GetExtensionSID - compute SID for an extension object.
- *
- * Arguments:
- * name: name of the extension.
- *
- * Returns: proper SID for the object or NULL on error.
- */
-static security_id_t
-GetExtensionSID(const char *name)
-{
- security_context_t base, con, result;
- security_id_t sid = NULL;
-
- /* get server context */
- if (getcon(&base) < 0)
- goto out;
-
- /* look in the mappings of names to types */
- if (selabel_lookup(label_hnd, &con, name, SELABEL_X_EXT) < 0)
- goto out2;
-
- /* perform a transition to obtain the final context */
- if (security_compute_create(base, con, SECCLASS_XEXTENSION, &result) < 0)
- goto out3;
-
- /* get a SID for the context */
- avc_context_to_sid(result, &sid);
- freecon(result);
- out3:
- freecon(con);
- out2:
- freecon(base);
- out:
- return sid;
-}
+//static void
+//SELinuxSelection(CallbackListPtr *pcbl, pointer unused, pointer calldata)
+//{
+// XaceSelectionAccessRec *rec = calldata;
+//}
-/*
- * AssignServerState - set up server security state.
- *
- * Arguments:
- */
static void
-AssignServerState(void)
+SELinuxExtension(CallbackListPtr *pcbl, pointer unused, pointer calldata)
{
- int i;
- security_context_t basectx, objctx;
- XSELinuxClientStateRec *state;
+ XaceExtAccessRec *rec = calldata;
+ SELinuxStateRec *subj, *obj, *serv;
+ SELinuxAuditRec auditdata = { NULL, NULL, 0, 0, 0, NULL };
+ int rc;
- state = (XSELinuxClientStateRec*)STATEPTR(serverClient);
- avc_entry_ref_init(&state->aeref);
+ subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
+ obj = dixLookupPrivate(&rec->ext->devPrivates, stateKey);
- /* use the context of the X server process for the serverClient */
- if (getcon(&basectx) < 0)
- FatalError("Couldn't get context of X server process\n");
+ /* If this is a new object that needs labeling, do it now */
+ /* XXX there should be a separate callback for this */
+ if (obj->sid == unlabeled_sid) {
+ const char *name = rec->ext->name;
+ security_context_t con;
+ security_id_t sid;
- /* get a SID from the context */
- if (avc_context_to_sid(basectx, &state->sid) < 0)
- FatalError("Client %d: context_to_sid(%s) failed\n", 0, basectx);
+ serv = dixLookupPrivate(&serverClient->devPrivates, stateKey);
- /* get contexts and then SIDs for each resource type */
- for (i=0; i<NRES; i++) {
- if (security_compute_create(basectx, basectx, sClasses[i],
- &objctx) < 0)
- FatalError("Client %d: compute_create(base=%s, cls=%d) failed\n",
- 0, basectx, sClasses[i]);
+ /* Look in the mappings of property names to contexts */
+ if (selabel_lookup(label_hnd, &con, name, SELABEL_X_EXT) < 0) {
+ ErrorF("XSELinux: a property label lookup failed!\n");
+ rec->status = BadValue;
+ return;
+ }
+ /* Get a SID for context */
+ if (avc_context_to_sid(con, &sid) < 0) {
+ ErrorF("XSELinux: a context_to_SID call failed!\n");
+ rec->status = BadAlloc;
+ return;
+ }
- if (avc_context_to_sid(objctx, &state->rsid[i]) < 0)
- FatalError("Client %d: context_to_sid(%s) failed\n",
- 0, objctx);
+ sidput(obj->sid);
- freecon(objctx);
+ /* Perform a transition to obtain the final SID */
+ if (avc_compute_create(serv->sid, sid, SECCLASS_X_EXTENSION,
+ &obj->sid) < 0) {
+ ErrorF("XSELinux: a SID transition call failed!\n");
+ freecon(con);
+ rec->status = BadValue;
+ return;
+ }
+ freecon(con);
}
- /* mark as set up, free base context, and return */
- state->haveState = TRUE;
- freecon(basectx);
+ /* Perform the security check */
+ auditdata.extension = rec->ext->name;
+ rc = SELinuxDoCheck(rec->client, obj, SECCLASS_X_EXTENSION,
+ rec->access_mode, &auditdata);
+ if (rc != Success)
+ rec->status = rc;
}
-/*
- * AssignClientState - set up client security state.
- *
- * Arguments:
- * client: client to set up (can be serverClient).
- */
static void
-AssignClientState(ClientPtr client)
+SELinuxProperty(CallbackListPtr *pcbl, pointer unused, pointer calldata)
{
- int i;
- security_context_t basectx, objctx;
- XSELinuxClientStateRec *state;
-
- state = (XSELinuxClientStateRec*)STATEPTR(client);
- avc_entry_ref_init(&state->aeref);
+ XacePropertyAccessRec *rec = calldata;
+ SELinuxStateRec *subj, *obj;
+ SELinuxAuditRec auditdata = { NULL, NULL, 0, 0, 0, NULL };
+ int rc;
- XtransConnInfo ci = ((OsCommPtr)client->osPrivate)->trans_conn;
- if (_XSERVTransIsLocal(ci)) {
- /* for local clients, can get context from the socket */
- int fd = _XSERVTransGetConnectionNumber(ci);
- if (getpeercon(fd, &basectx) < 0)
- FatalError("Client %d: couldn't get context from socket\n",
- client->index);
- }
- else
- /* for remote clients, need to use a default context */
- if (selabel_lookup(label_hnd, &basectx, NULL, SELABEL_X_CLIENT) < 0)
- FatalError("Client %d: couldn't get default remote connection context\n",
- client->index);
+ subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
+ obj = dixLookupPrivate(&rec->pProp->devPrivates, stateKey);
- /* get a SID from the context */
- if (avc_context_to_sid(basectx, &state->sid) < 0)
- FatalError("Client %d: context_to_sid(%s) failed\n",
- client->index, basectx);
+ /* If this is a new object that needs labeling, do it now */
+ if (rec->access_mode & DixCreateAccess) {
+ const char *name = NameForAtom(rec->pProp->propertyName);
+ security_context_t con;
+ security_id_t sid;
- /* get contexts and then SIDs for each resource type */
- for (i=0; i<NRES; i++) {
- if (security_compute_create(basectx, basectx, sClasses[i],
- &objctx) < 0)
- FatalError("Client %d: compute_create(base=%s, cls=%d) failed\n",
- client->index, basectx, sClasses[i]);
+ /* Look in the mappings of property names to contexts */
+ if (selabel_lookup(label_hnd, &con, name, SELABEL_X_PROP) < 0) {
+ ErrorF("XSELinux: a property label lookup failed!\n");
+ rec->status = BadValue;
+ return;
+ }
+ /* Get a SID for context */
+ if (avc_context_to_sid(con, &sid) < 0) {
+ ErrorF("XSELinux: a context_to_SID call failed!\n");
+ rec->status = BadAlloc;
+ return;
+ }
- if (avc_context_to_sid(objctx, &state->rsid[i]) < 0)
- FatalError("Client %d: context_to_sid(%s) failed\n",
- client->index, objctx);
+ sidput(obj->sid);
- freecon(objctx);
+ /* Perform a transition to obtain the final SID */
+ if (avc_compute_create(subj->sid, sid, SECCLASS_X_PROPERTY,
+ &obj->sid) < 0) {
+ ErrorF("XSELinux: a SID transition call failed!\n");
+ freecon(con);
+ rec->status = BadValue;
+ return;
+ }
+ freecon(con);
+ avc_entry_ref_init(&obj->aeref);
}
- /* mark as set up, free base context, and return */
- state->haveState = TRUE;
- freecon(basectx);
+ /* Perform the security check */
+ auditdata.property = rec->pProp->propertyName;
+ rc = SELinuxDoCheck(rec->client, obj, SECCLASS_X_PROPERTY,
+ rec->access_mode, &auditdata);
+ if (rc != Success)
+ rec->status = rc;
}
-/*
- * FreeClientState - tear down client security state.
- *
- * Arguments:
- * client: client to release (can be serverClient).
- */
static void
-FreeClientState(ClientPtr client)
+SELinuxResource(CallbackListPtr *pcbl, pointer unused, pointer calldata)
{
- int i;
- XSELinuxClientStateRec *state = (XSELinuxClientStateRec*)STATEPTR(client);
-
- /* client state may not be set up if its auth was rejected */
- if (state->haveState) {
- state = (XSELinuxClientStateRec*)STATEPTR(client);
- sidput(state->sid);
- for (i=0; i<NRES; i++)
- sidput(state->rsid[i]);
- state->haveState = FALSE;
+ XaceResourceAccessRec *rec = calldata;
+ SELinuxStateRec *subj, *obj, *pobj;
+ SELinuxAuditRec auditdata = { NULL, NULL, 0, 0, 0, NULL };
+ PrivateRec **privatePtr;
+ security_class_t class;
+ int rc, offset;
+
+ subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
+
+ /* Determine if the resource object has a devPrivates field */
+ offset = dixLookupPrivateOffset(rec->rtype);
+ if (offset < 0) {
+ /* No: use the SID of the owning client */
+ class = SECCLASS_X_RESOURCE;
+ privatePtr = &clients[CLIENT_ID(rec->id)]->devPrivates;
+ obj = dixLookupPrivate(privatePtr, stateKey);
+ } else {
+ /* Yes: use the SID from the resource object itself */
+ class = SELinuxTypeToClass(rec->rtype);
+ privatePtr = DEVPRIV_AT(rec->res, offset);
+ obj = dixLookupPrivate(privatePtr, stateKey);
}
-}
-#define REQUEST_SIZE_CHECK(client, req) \
- (client->req_len >= (sizeof(req) >> 2))
-#define IDPERM(client, req, field, class, perm) \
- (REQUEST_SIZE_CHECK(client,req) ? \
- IDPerm(client, SwapXID(client,((req*)stuff)->field), class, perm) : \
- BadLength)
-
-static int
-CheckSendEventPerms(ClientPtr client)
-{
- register char n;
- access_vector_t perm = 0;
- REQUEST(xSendEventReq);
-
- /* might need type bounds checking here */
- if (!REQUEST_SIZE_CHECK(client, xSendEventReq))
- return BadLength;
-
- switch (stuff->event.u.u.type) {
- case SelectionClear:
- case SelectionNotify:
- case SelectionRequest:
- case ClientMessage:
- case PropertyNotify:
- perm = WINDOW__CLIENTCOMEVENT;
- break;
- case ButtonPress:
- case ButtonRelease:
- case KeyPress:
- case KeyRelease:
- case KeymapNotify:
- case MotionNotify:
- case EnterNotify:
- case LeaveNotify:
- case FocusIn:
- case FocusOut:
- perm = WINDOW__INPUTEVENT;
- break;
- case Expose:
- case GraphicsExpose:
- case NoExpose:
- case VisibilityNotify:
- perm = WINDOW__DRAWEVENT;
- break;
- case CirculateNotify:
- case ConfigureNotify:
- case CreateNotify:
- case DestroyNotify:
- case MapNotify:
- case UnmapNotify:
- case GravityNotify:
- case ReparentNotify:
- perm = WINDOW__WINDOWCHANGEEVENT;
- break;
- case CirculateRequest:
- case ConfigureRequest:
- case MapRequest:
- case ResizeRequest:
- perm = WINDOW__WINDOWCHANGEREQUEST;
- break;
- case ColormapNotify:
- case MappingNotify:
- perm = WINDOW__SERVERCHANGEEVENT;
- break;
- default:
- perm = WINDOW__EXTENSIONEVENT;
- break;
+ /* If this is a new object that needs labeling, do it now */
+ if (rec->access_mode & DixCreateAccess && offset >= 0) {
+ if (rec->parent)
+ offset = dixLookupPrivateOffset(rec->ptype);
+ if (rec->parent && offset >= 0)
+ /* Use the SID of the parent object in the labeling operation */
+ pobj = dixLookupPrivate(DEVPRIV_AT(rec->parent, offset), stateKey);
+ else
+ /* Use the SID of the subject */
+ pobj = subj;
+
+ sidput(obj->sid);
+
+ /* Perform a transition to obtain the final SID */
+ if (avc_compute_create(subj->sid, pobj->sid, class, &obj->sid) < 0) {
+ ErrorF("XSELinux: a compute_create call failed!\n");
+ rec->status = BadValue;
+ return;
+ }
}
- if (client->swapped)
- swapl(&stuff->destination, n);
- return IDPerm(client, stuff->destination, SECCLASS_WINDOW, perm);
+
+ /* Perform the security check */
+ auditdata.restype = rec->rtype;
+ auditdata.id = rec->id;
+ rc = SELinuxDoCheck(rec->client, obj, class, rec->access_mode, &auditdata);
+ if (rc != Success)
+ rec->status = rc;
}
-static int
-CheckConvertSelectionPerms(ClientPtr client)
+static void
+SELinuxScreen(CallbackListPtr *pcbl, pointer is_saver, pointer calldata)
{
- register char n;
- int rval = Success;
- REQUEST(xConvertSelectionReq);
+ XaceScreenAccessRec *rec = calldata;
+ SELinuxStateRec *subj, *obj;
+ SELinuxAuditRec auditdata = { NULL, NULL, 0, 0, 0, NULL };
+ Mask access_mode = rec->access_mode;
+ int rc;
- if (!REQUEST_SIZE_CHECK(client, xConvertSelectionReq))
- return BadLength;
+ subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
+ obj = dixLookupPrivate(&rec->screen->devPrivates, stateKey);
- if (client->swapped)
- {
- swapl(&stuff->selection, n);
- swapl(&stuff->requestor, n);
- }
+ /* If this is a new object that needs labeling, do it now */
+ if (access_mode & DixCreateAccess) {
+ sidput(obj->sid);
- if (ValidAtom(stuff->selection))
- {
- int i = 0;
- while ((i < NumCurrentSelections) &&
- CurrentSelections[i].selection != stuff->selection) i++;
- if (i < NumCurrentSelections) {
- rval = IDPerm(client, CurrentSelections[i].window,
- SECCLASS_WINDOW, WINDOW__CLIENTCOMEVENT);
- if (rval != Success)
- return rval;
+ /* Perform a transition to obtain the final SID */
+ if (avc_compute_create(subj->sid, subj->sid, SECCLASS_X_SCREEN,
+ &obj->sid) < 0) {
+ ErrorF("XSELinux: a compute_create call failed!\n");
+ rec->status = BadValue;
+ return;
}
}
- return IDPerm(client, stuff->requestor,
- SECCLASS_WINDOW, WINDOW__CLIENTCOMEVENT);
+
+ if (is_saver)
+ access_mode <<= 2;
+
+ rc = SELinuxDoCheck(rec->client, obj, SECCLASS_X_SCREEN,
+ access_mode, &auditdata);
+ if (rc != Success)
+ rec->status = rc;
}
-static int
-CheckSetSelectionOwnerPerms(ClientPtr client)
+static void
+SELinuxClient(CallbackListPtr *pcbl, pointer unused, pointer calldata)
{
- register char n;
- int rval = Success;
- REQUEST(xSetSelectionOwnerReq);
-
- if (!REQUEST_SIZE_CHECK(client, xSetSelectionOwnerReq))
- return BadLength;
+ XaceClientAccessRec *rec = calldata;
+ SELinuxStateRec *obj;
+ SELinuxAuditRec auditdata = { NULL, NULL, 0, 0, 0, NULL };
+ int rc;
- if (client->swapped)
- {
- swapl(&stuff->selection, n);
- swapl(&stuff->window, n);
- }
+ obj = dixLookupPrivate(&rec->target->devPrivates, stateKey);
- if (ValidAtom(stuff->selection))
- {
- int i = 0;
- while ((i < NumCurrentSelections) &&
- CurrentSelections[i].selection != stuff->selection) i++;
- if (i < NumCurrentSelections) {
- rval = IDPerm(client, CurrentSelections[i].window,
- SECCLASS_WINDOW, WINDOW__CHSELECTION);
- if (rval != Success)
- return rval;
- }
- }
- return IDPerm(client, stuff->window,
- SECCLASS_WINDOW, WINDOW__CHSELECTION);
+ rc = SELinuxDoCheck(rec->client, obj, SECCLASS_X_CLIENT,
+ rec->access_mode, &auditdata);
+ if (rc != Success)
+ rec->status = rc;
}
static void
-XSELinuxCoreDispatch(CallbackListPtr *pcbl, pointer unused, pointer calldata)
+SELinuxServer(CallbackListPtr *pcbl, pointer unused, pointer calldata)
{
- XaceCoreDispatchRec *rec = (XaceCoreDispatchRec*)calldata;
- ClientPtr client = rec->client;
- REQUEST(xReq);
- int rval = Success, rval2 = Success, rval3 = Success;
-
- switch(stuff->reqType) {
- /* Drawable class control requirements */
- case X_ClearArea:
- rval = IDPERM(client, xClearAreaReq, window,
- SECCLASS_DRAWABLE, DRAWABLE__DRAW);
- break;
- case X_PolySegment:
- case X_PolyRectangle:
- case X_PolyArc:
- case X_PolyFillRectangle:
- case X_PolyFillArc:
- rval = IDPERM(client, xPolySegmentReq, drawable,
- SECCLASS_DRAWABLE, DRAWABLE__DRAW);
- break;
- case X_PolyPoint:
- case X_PolyLine:
- rval = IDPERM(client, xPolyPointReq, drawable,
- SECCLASS_DRAWABLE, DRAWABLE__DRAW);
- break;
- case X_FillPoly:
- rval = IDPERM(client, xFillPolyReq, drawable,
- SECCLASS_DRAWABLE, DRAWABLE__DRAW);
- break;
- case X_PutImage:
- rval = IDPERM(client, xPutImageReq, drawable,
- SECCLASS_DRAWABLE, DRAWABLE__DRAW);
- break;
- case X_CopyArea:
- case X_CopyPlane:
- rval = IDPERM(client, xCopyAreaReq, srcDrawable,
- SECCLASS_DRAWABLE, DRAWABLE__COPY);
- rval2 = IDPERM(client, xCopyAreaReq, dstDrawable,
- SECCLASS_DRAWABLE, DRAWABLE__DRAW);
- break;
- case X_GetImage:
- rval = IDPERM(client, xGetImageReq, drawable,
- SECCLASS_DRAWABLE, DRAWABLE__COPY);
- break;
- case X_GetGeometry:
- rval = IDPERM(client, xResourceReq, id,
- SECCLASS_DRAWABLE, DRAWABLE__GETATTR);
- break;
-
- /* Window class control requirements */
- case X_ChangeProperty:
- rval = IDPERM(client, xChangePropertyReq, window,
- SECCLASS_WINDOW,
- WINDOW__CHPROPLIST | WINDOW__CHPROP |
- WINDOW__LISTPROP);
- break;
- case X_ChangeSaveSet:
- rval = IDPERM(client, xChangeSaveSetReq, window,
- SECCLASS_WINDOW,
- WINDOW__CTRLLIFE | WINDOW__CHPARENT);
- break;
- case X_ChangeWindowAttributes:
- rval = IDPERM(client, xChangeWindowAttributesReq, window,
- SECCLASS_WINDOW, WINDOW__SETATTR);
- break;
- case X_CirculateWindow:
- rval = IDPERM(client, xCirculateWindowReq, window,
- SECCLASS_WINDOW, WINDOW__CHSTACK);
- break;
- case X_ConfigureWindow:
- rval = IDPERM(client, xConfigureWindowReq, window,
- SECCLASS_WINDOW,
- WINDOW__SETATTR | WINDOW__MOVE | WINDOW__CHSTACK);
- break;
- case X_ConvertSelection:
- rval = CheckConvertSelectionPerms(client);
- break;
- case X_CreateWindow:
- rval = IDPERM(client, xCreateWindowReq, wid,
- SECCLASS_WINDOW,
- WINDOW__CREATE | WINDOW__SETATTR | WINDOW__MOVE);
- rval2 = IDPERM(client, xCreateWindowReq, parent,
- SECCLASS_WINDOW,
- WINDOW__CHSTACK | WINDOW__ADDCHILD);
- rval3 = IDPERM(client, xCreateWindowReq, wid,
- SECCLASS_DRAWABLE, DRAWABLE__CREATE);
- break;
- case X_DeleteProperty:
- rval = IDPERM(client, xDeletePropertyReq, window,
- SECCLASS_WINDOW,
- WINDOW__CHPROP | WINDOW__CHPROPLIST);
- break;
- case X_DestroyWindow:
- case X_DestroySubwindows:
- rval = IDPERM(client, xResourceReq, id,
- SECCLASS_WINDOW,
- WINDOW__ENUMERATE | WINDOW__UNMAP | WINDOW__DESTROY);
- rval2 = IDPERM(client, xResourceReq, id,
- SECCLASS_DRAWABLE, DRAWABLE__DESTROY);
- break;
- case X_GetMotionEvents:
- rval = IDPERM(client, xGetMotionEventsReq, window,
- SECCLASS_WINDOW, WINDOW__MOUSEMOTION);
- break;
- case X_GetProperty:
- rval = IDPERM(client, xGetPropertyReq, window,
- SECCLASS_WINDOW, WINDOW__LISTPROP);
- break;
- case X_GetWindowAttributes:
- rval = IDPERM(client, xResourceReq, id,
- SECCLASS_WINDOW, WINDOW__GETATTR);
- break;
- case X_KillClient:
- rval = IDPERM(client, xResourceReq, id,
- SECCLASS_XCLIENT, XCLIENT__KILL);
- break;
- case X_ListProperties:
- rval = IDPERM(client, xResourceReq, id,
- SECCLASS_WINDOW, WINDOW__LISTPROP);
- break;
- case X_MapWindow:
- case X_MapSubwindows:
- rval = IDPERM(client, xResourceReq, id,
- SECCLASS_WINDOW,
- WINDOW__ENUMERATE | WINDOW__GETATTR | WINDOW__MAP);
- break;
- case X_QueryTree:
- rval = IDPERM(client, xResourceReq, id,
- SECCLASS_WINDOW, WINDOW__ENUMERATE | WINDOW__GETATTR);
- break;
- case X_RotateProperties:
- rval = IDPERM(client, xRotatePropertiesReq, window,
- SECCLASS_WINDOW, WINDOW__CHPROP | WINDOW__CHPROPLIST);
- break;
- case X_ReparentWindow:
- rval = IDPERM(client, xReparentWindowReq, window,
- SECCLASS_WINDOW, WINDOW__CHPARENT | WINDOW__MOVE);
- rval2 = IDPERM(client, xReparentWindowReq, parent,
- SECCLASS_WINDOW, WINDOW__CHSTACK | WINDOW__ADDCHILD);
- break;
- case X_SendEvent:
- rval = CheckSendEventPerms(client);
- break;
- case X_SetInputFocus:
- rval = IDPERM(client, xSetInputFocusReq, focus,
- SECCLASS_WINDOW, WINDOW__SETFOCUS);
- rval2 = ServerPerm(client, SECCLASS_XINPUT, XINPUT__SETFOCUS);
- break;
- case X_SetSelectionOwner:
- rval = CheckSetSelectionOwnerPerms(client);
- break;
- case X_TranslateCoords:
- rval = IDPERM(client, xTranslateCoordsReq, srcWid,
- SECCLASS_WINDOW, WINDOW__GETATTR);
- rval2 = IDPERM(client, xTranslateCoordsReq, dstWid,
- SECCLASS_WINDOW, WINDOW__GETATTR);
- break;
- case X_UnmapWindow:
- case X_UnmapSubwindows:
- rval = IDPERM(client, xResourceReq, id,
- SECCLASS_WINDOW,
- WINDOW__ENUMERATE | WINDOW__GETATTR |
- WINDOW__UNMAP);
- break;
- case X_WarpPointer:
- rval = IDPERM(client, xWarpPointerReq, srcWid,
- SECCLASS_WINDOW, WINDOW__GETATTR);
- rval2 = IDPERM(client, xWarpPointerReq, dstWid,
- SECCLASS_WINDOW, WINDOW__GETATTR);
- rval3 = ServerPerm(client, SECCLASS_XINPUT, XINPUT__WARPPOINTER);
- break;
-
- /* Input class control requirements */
- case X_GrabButton:
- case X_GrabKey:
- rval = ServerPerm(client, SECCLASS_XINPUT, XINPUT__PASSIVEGRAB);
- break;
- case X_GrabKeyboard:
- case X_GrabPointer:
- case X_ChangeActivePointerGrab:
- rval = ServerPerm(client, SECCLASS_XINPUT, XINPUT__ACTIVEGRAB);
- break;
- case X_AllowEvents:
- case X_UngrabButton:
- case X_UngrabKey:
- case X_UngrabKeyboard:
- case X_UngrabPointer:
- rval = ServerPerm(client, SECCLASS_XINPUT, XINPUT__UNGRAB);
- break;
- case X_GetKeyboardControl:
- case X_GetKeyboardMapping:
- case X_GetPointerControl:
- case X_GetPointerMapping:
- case X_GetModifierMapping:
- case X_QueryKeymap:
- case X_QueryPointer:
- rval = ServerPerm(client, SECCLASS_XINPUT, XINPUT__GETATTR);
- break;
- case X_ChangeKeyboardControl:
- case X_ChangePointerControl:
- case X_ChangeKeyboardMapping:
- case X_SetModifierMapping:
- case X_SetPointerMapping:
- rval = ServerPerm(client, SECCLASS_XINPUT, XINPUT__SETATTR);
- break;
- case X_Bell:
- rval = ServerPerm(client, SECCLASS_XINPUT, XINPUT__BELL);
- break;
-
- /* Colormap class control requirements */
- case X_AllocColor:
- case X_AllocColorCells:
- case X_AllocColorPlanes:
- case X_AllocNamedColor:
- rval = IDPERM(client, xResourceReq, id,
- SECCLASS_COLORMAP,
- COLORMAP__READ | COLORMAP__STORE);
- break;
- case X_CopyColormapAndFree:
- rval = IDPERM(client, xCopyColormapAndFreeReq, mid,
- SECCLASS_COLORMAP, COLORMAP__CREATE);
- rval2 = IDPERM(client, xCopyColormapAndFreeReq, srcCmap,
- SECCLASS_COLORMAP,
- COLORMAP__READ | COLORMAP__FREE);
- break;
- case X_CreateColormap:
- rval = IDPERM(client, xCreateColormapReq, mid,
- SECCLASS_COLORMAP, COLORMAP__CREATE);
- rval2 = IDPERM(client, xCreateColormapReq, window,
- SECCLASS_DRAWABLE, DRAWABLE__DRAW);
- break;
- case X_FreeColormap:
- rval = IDPERM(client, xResourceReq, id,
- SECCLASS_COLORMAP, COLORMAP__FREE);
- break;
- case X_FreeColors:
- rval = IDPERM(client, xFreeColorsReq, cmap,
- SECCLASS_COLORMAP, COLORMAP__STORE);
- break;
- case X_InstallColormap:
- rval = IDPERM(client, xResourceReq, id,
- SECCLASS_COLORMAP, COLORMAP__INSTALL);
- rval2 = ServerPerm(client, SECCLASS_COLORMAP, COLORMAP__INSTALL);
- break;
- case X_ListInstalledColormaps:
- rval = ServerPerm(client, SECCLASS_COLORMAP, COLORMAP__LIST);
- break;
- case X_LookupColor:
- case X_QueryColors:
- rval = IDPERM(client, xResourceReq, id,
- SECCLASS_COLORMAP, COLORMAP__READ);
- break;
- case X_StoreColors:
- case X_StoreNamedColor:
- rval = IDPERM(client, xResourceReq, id,
- SECCLASS_COLORMAP, COLORMAP__STORE);
- break;
- case X_UninstallColormap:
- rval = IDPERM(client, xResourceReq, id,
- SECCLASS_COLORMAP, COLORMAP__UNINSTALL);
- rval2 = ServerPerm(client, SECCLASS_COLORMAP, COLORMAP__UNINSTALL);
- break;
-
- /* Font class control requirements */
- case X_CloseFont:
- rval = IDPERM(client, xResourceReq, id,
- SECCLASS_FONT, FONT__FREE);
- break;
- case X_ImageText8:
- case X_ImageText16:
- /* Font accesses checked through the resource manager */
- rval = IDPERM(client, xImageTextReq, drawable,
- SECCLASS_DRAWABLE, DRAWABLE__DRAW);
- break;
- case X_OpenFont:
- rval = ServerPerm(client, SECCLASS_FONT, FONT__LOAD);
- rval2 = IDPERM(client, xOpenFontReq, fid,
- SECCLASS_FONT, FONT__USE);
- break;
- case X_PolyText8:
- case X_PolyText16:
- /* Font accesses checked through the resource manager */
- rval = ServerPerm(client, SECCLASS_FONT, FONT__LOAD);
- rval2 = IDPERM(client, xPolyTextReq, gc,
- SECCLASS_GC, GC__SETATTR);
- rval3 = IDPERM(client, xPolyTextReq, drawable,
- SECCLASS_DRAWABLE, DRAWABLE__DRAW);
- break;
-
- /* Pixmap class control requirements */
- case X_CreatePixmap:
- rval = IDPERM(client, xCreatePixmapReq, pid,
- SECCLASS_DRAWABLE, DRAWABLE__CREATE);
- break;
- case X_FreePixmap:
- rval = IDPERM(client, xResourceReq, id,
- SECCLASS_DRAWABLE, DRAWABLE__DESTROY);
- break;
-
- /* Cursor class control requirements */
- case X_CreateCursor:
- rval = IDPERM(client, xCreateCursorReq, cid,
- SECCLASS_CURSOR, CURSOR__CREATE);
- rval2 = IDPERM(client, xCreateCursorReq, source,
- SECCLASS_DRAWABLE, DRAWABLE__DRAW);
- rval3 = IDPERM(client, xCreateCursorReq, mask,
- SECCLASS_DRAWABLE, DRAWABLE__COPY);
- break;
- case X_CreateGlyphCursor:
- rval = IDPERM(client, xCreateGlyphCursorReq, cid,
- SECCLASS_CURSOR, CURSOR__CREATEGLYPH);
- rval2 = IDPERM(client, xCreateGlyphCursorReq, source,
- SECCLASS_FONT, FONT__USE);
- rval3 = IDPERM(client, xCreateGlyphCursorReq, mask,
- SECCLASS_FONT, FONT__USE);
- break;
- case X_RecolorCursor:
- rval = IDPERM(client, xRecolorCursorReq, cursor,
- SECCLASS_CURSOR, CURSOR__SETATTR);
- break;
- case X_FreeCursor:
- rval = IDPERM(client, xResourceReq, id,
- SECCLASS_CURSOR, CURSOR__FREE);
- break;
-
- /* GC class control requirements */
- case X_CreateGC:
- rval = IDPERM(client, xCreateGCReq, gc,
- SECCLASS_GC, GC__CREATE | GC__SETATTR);
- break;
- case X_ChangeGC:
- case X_SetDashes:
- case X_SetClipRectangles:
- rval = IDPERM(client, xResourceReq, id,
- SECCLASS_GC, GC__SETATTR);
- break;
- case X_CopyGC:
- rval = IDPERM(client, xCopyGCReq, srcGC,
- SECCLASS_GC, GC__GETATTR);
- rval2 = IDPERM(client, xCopyGCReq, dstGC,
- SECCLASS_GC, GC__SETATTR);
- break;
- case X_FreeGC:
- rval = IDPERM(client, xResourceReq, id,
- SECCLASS_GC, GC__FREE);
- break;
-
- /* Server class control requirements */
- case X_GrabServer:
- rval = ServerPerm(client, SECCLASS_XSERVER, XSERVER__GRAB);
- break;
- case X_UngrabServer:
- rval = ServerPerm(client, SECCLASS_XSERVER, XSERVER__UNGRAB);
- break;
- case X_ForceScreenSaver:
- case X_GetScreenSaver:
- case X_SetScreenSaver:
- rval = ServerPerm(client, SECCLASS_XSERVER, XSERVER__SCREENSAVER);
- break;
- case X_ListHosts:
- rval = ServerPerm(client, SECCLASS_XSERVER, XSERVER__GETHOSTLIST);
- break;
- case X_ChangeHosts:
- case X_SetAccessControl:
- rval = ServerPerm(client, SECCLASS_XSERVER, XSERVER__SETHOSTLIST);
- break;
- case X_GetFontPath:
- rval = ServerPerm(client, SECCLASS_XSERVER, XSERVER__GETFONTPATH);
- break;
- case X_SetFontPath:
- rval = ServerPerm(client, SECCLASS_XSERVER, XSERVER__SETFONTPATH);
- break;
- case X_QueryBestSize:
- rval = ServerPerm(client, SECCLASS_XSERVER, XSERVER__GETATTR);
- break;
-
- default:
- break;
- }
- if (rval != Success)
- rec->status = rval;
- if (rval2 != Success)
- rec->status = rval2;
- if (rval != Success)
- rec->status = rval3;
+ XaceServerAccessRec *rec = calldata;
+ SELinuxStateRec *obj;
+ SELinuxAuditRec auditdata = { NULL, NULL, 0, 0, 0, NULL };
+ int rc;
+
+ obj = dixLookupPrivate(&serverClient->devPrivates, stateKey);
+
+ rc = SELinuxDoCheck(rec->client, obj, SECCLASS_X_SERVER,
+ rec->access_mode, &auditdata);
+ if (rc != Success)
+ rec->status = rc;
}
+/* Extension callbacks */
static void
-XSELinuxExtDispatch(CallbackListPtr *pcbl, pointer unused, pointer calldata)
+SELinuxStateInit(CallbackListPtr *pcbl, pointer unused, pointer calldata)
{
- XaceExtAccessRec *rec = (XaceExtAccessRec*)calldata;
- ClientPtr client = rec->client;
- ExtensionEntry *ext = rec->ext;
- security_id_t extsid;
- access_vector_t perm;
- REQUEST(xReq);
+ PrivateCallbackRec *rec = calldata;
+ SELinuxStateRec *state = *rec->value;
- /* XXX there should be a separate callback for this */
- if (!EXTENSIONSID(ext))
- {
- extsid = GetExtensionSID(ext->name);
- if (!extsid)
- return;
- EXTENSIONSID(ext) = extsid;
- }
+ sidget(unlabeled_sid);
+ state->sid = unlabeled_sid;
- extsid = (security_id_t)EXTENSIONSID(ext);
- perm = ((stuff->reqType == X_QueryExtension) ||
- (stuff->reqType == X_ListExtensions)) ?
- XEXTENSION__QUERY : XEXTENSION__USE;
-
- if (HAVESTATE(client))
- {
- XSELinuxAuditRec auditdata;
- auditdata.client = client;
- auditdata.property = NULL;
- auditdata.extension = ext->name;
- errno = 0;
- if (avc_has_perm(SID(client), extsid, SECCLASS_XEXTENSION,
- perm, &AEREF(client), &auditdata) < 0)
- {
- if (errno == EACCES)
- rec->status = BadAccess;
- ErrorF("ExtDispatch: unexpected error %d\n", errno);
- rec->status = BadValue;
- }
- } else
- ErrorF("No client state in extension dispatcher!\n");
-} /* XSELinuxExtDispatch */
+ avc_entry_ref_init(&state->aeref);
+}
static void
-XSELinuxProperty(CallbackListPtr *pcbl, pointer unused, pointer calldata)
+SELinuxStateFree(CallbackListPtr *pcbl, pointer unused, pointer calldata)
{
- XacePropertyAccessRec *rec = (XacePropertyAccessRec*)calldata;
- WindowPtr pWin = rec->pWin;
- ClientPtr client = rec->client;
- ClientPtr tclient;
- access_vector_t perm = 0;
- security_id_t propsid;
- char *propname = NameForAtom(rec->pProp->propertyName);
-
- tclient = wClient(pWin);
- if (!tclient || !HAVESTATE(tclient))
- return;
+ PrivateCallbackRec *rec = calldata;
+ SELinuxStateRec *state = *rec->value;
- propsid = GetPropertySID(SID(tclient)->ctx, propname);
- if (!propsid)
- return;
-
- if (rec->access_mode & DixReadAccess)
- perm |= PROPERTY__READ;
- if (rec->access_mode & DixWriteAccess)
- perm |= PROPERTY__WRITE;
- if (rec->access_mode & DixDestroyAccess)
- perm |= PROPERTY__FREE;
- if (!rec->access_mode)
- perm = PROPERTY__READ | PROPERTY__WRITE | PROPERTY__FREE;
-
- if (HAVESTATE(client))
- {
- XSELinuxAuditRec auditdata;
- auditdata.client = client;
- auditdata.property = propname;
- auditdata.extension = NULL;
- errno = 0;
- if (avc_has_perm(SID(client), propsid, SECCLASS_PROPERTY,
- perm, &AEREF(client), &auditdata) < 0)
- {
- if (errno == EACCES)
- rec->status = BadAccess;
- ErrorF("Property: unexpected error %d\n", errno);
- rec->status = BadValue;
- }
- } else
- ErrorF("No client state in property callback!\n");
+ xfree(state->client_path);
- /* XXX this should be saved in the property structure */
- sidput(propsid);
-} /* XSELinuxProperty */
+ if (avc_active)
+ sidput(state->sid);
+}
static void
-XSELinuxResLookup(CallbackListPtr *pcbl, pointer unused, pointer calldata)
+SELinuxClientState(CallbackListPtr *pcbl, pointer unused, pointer calldata)
{
- XaceResourceAccessRec *rec = (XaceResourceAccessRec*)calldata;
- ClientPtr client = rec->client;
- REQUEST(xReq);
- access_vector_t perm = 0;
- int rval = Success;
+ NewClientInfoRec *pci = calldata;
+ ClientPtr client = pci->client;
+ XtransConnInfo ci = ((OsCommPtr)client->osPrivate)->trans_conn;
+ SELinuxStateRec *state;
+ security_context_t ctx;
- /* serverClient requests OK */
- if (client->index == 0)
+ if (client->clientState != ClientStateInitial)
return;
- switch(rec->rtype) {
- case RT_FONT: {
- switch(stuff->reqType) {
- case X_ImageText8:
- case X_ImageText16:
- case X_PolyText8:
- case X_PolyText16:
- perm = FONT__USE;
- break;
- case X_ListFonts:
- case X_ListFontsWithInfo:
- case X_QueryFont:
- case X_QueryTextExtents:
- perm = FONT__GETATTR;
- break;
- default:
- break;
- }
- if (perm)
- rval = IDPerm(client, rec->id, SECCLASS_FONT, perm);
- break;
- }
- default:
- break;
- }
- if (rval != Success)
- rec->status = rval;
-} /* XSELinuxResLookup */
+ state = dixLookupPrivate(&client->devPrivates, stateKey);
+ sidput(state->sid);
-static void
-XSELinuxMap(CallbackListPtr *pcbl, pointer unused, pointer calldata)
-{
- XaceMapAccessRec *rec = (XaceMapAccessRec*)calldata;
- if (IDPerm(rec->client, rec->pWin->drawable.id,
- SECCLASS_WINDOW, WINDOW__MAP) != Success)
- rec->status = BadAccess;
-} /* XSELinuxMap */
+ if (_XSERVTransIsLocal(ci)) {
+ int fd = _XSERVTransGetConnectionNumber(ci);
+ struct ucred creds;
+ socklen_t len = sizeof(creds);
+ char path[PATH_MAX + 1];
+ size_t bytes;
-static void
-XSELinuxDrawable(CallbackListPtr *pcbl, pointer unused, pointer calldata)
-{
- XaceDrawableAccessRec *rec = (XaceDrawableAccessRec*)calldata;
- if (IDPerm(rec->client, rec->pDraw->id,
- SECCLASS_DRAWABLE, DRAWABLE__COPY) != Success)
- rec->status = BadAccess;
-} /* XSELinuxDrawable */
+ /* For local clients, can get context from the socket */
+ if (getpeercon(fd, &ctx) < 0)
+ FatalError("Client %d: couldn't get context from socket\n",
+ client->index);
-static void
-XSELinuxServer(CallbackListPtr *pcbl, pointer unused, pointer calldata)
-{
- XaceServerAccessRec *rec = (XaceServerAccessRec*)calldata;
- access_vector_t perm = (rec->access_mode == DixReadAccess) ?
- XSERVER__GETHOSTLIST : XSERVER__SETHOSTLIST;
+ /* Try and determine the client's executable name */
+ memset(&creds, 0, sizeof(creds));
+ if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &creds, &len) < 0)
+ goto finish;
- if (ServerPerm(rec->client, SECCLASS_XSERVER, perm) != Success)
- rec->status = BadAccess;
-} /* XSELinuxServer */
+ snprintf(path, PATH_MAX + 1, "/proc/%d/cmdline", creds.pid);
+ fd = open(path, O_RDONLY);
+ if (fd < 0)
+ goto finish;
-/* Extension callbacks */
-static void
-XSELinuxClientState(CallbackListPtr *pcbl, pointer unused, pointer calldata)
-{
- NewClientInfoRec *pci = (NewClientInfoRec *)calldata;
- ClientPtr client = pci->client;
+ bytes = read(fd, path, PATH_MAX + 1);
+ close(fd);
+ if (bytes <= 0)
+ goto finish;
- switch(client->clientState)
- {
- case ClientStateInitial:
- AssignServerState();
- break;
+ state->client_path = xalloc(bytes);
+ if (!state->client_path)
+ goto finish;
- case ClientStateRunning:
- {
- AssignClientState(client);
- break;
- }
- case ClientStateGone:
- case ClientStateRetained:
- {
- FreeClientState(client);
- break;
- }
- default: break;
- }
-} /* XSELinuxClientState */
+ memcpy(state->client_path, path, bytes);
+ state->client_path[bytes - 1] = 0;
+ } else
+ /* For remote clients, need to use a default context */
+ if (selabel_lookup(label_hnd, &ctx, NULL, SELABEL_X_CLIENT) < 0)
+ FatalError("Client %d: couldn't get default remote context\n",
+ client->index);
+
+finish:
+ /* Get a SID from the context */
+ if (avc_context_to_sid(ctx, &state->sid) < 0)
+ FatalError("Client %d: context_to_sid(%s) failed\n",
+ client->index, ctx);
+
+ freecon(ctx);
+}
/* Labeling callbacks */
static void
-XSELinuxResourceState(CallbackListPtr *pcbl, pointer unused, pointer calldata)
+SELinuxResourceState(CallbackListPtr *pcbl, pointer unused, pointer calldata)
{
- ResourceStateInfoRec *rec = (ResourceStateInfoRec *)calldata;
+ ResourceStateInfoRec *rec = calldata;
+ SELinuxStateRec *state;
WindowPtr pWin;
- ClientPtr client;
- security_context_t ctx;
- int rc;
if (rec->type != RT_WINDOW)
return;
pWin = (WindowPtr)rec->value;
- client = wClient(pWin);
+ state = dixLookupPrivate(&wClient(pWin)->devPrivates, stateKey);
- if (HAVESTATE(client)) {
- rc = avc_sid_to_context(SID(client), &ctx);
+ if (state->sid) {
+ security_context_t ctx;
+ int rc = avc_sid_to_context(state->sid, &ctx);
if (rc < 0)
FatalError("XSELinux: Failed to get security context!\n");
rc = dixChangeWindowProperty(serverClient,
pWin, atom_client_ctx, XA_STRING, 8,
PropModeReplace, strlen(ctx), ctx, FALSE);
+ if (rc != Success)
+ FatalError("XSELinux: Failed to set label property on window!\n");
freecon(ctx);
}
else
- rc = dixChangeWindowProperty(serverClient,
- pWin, atom_client_ctx, XA_STRING, 8,
- PropModeReplace, 10, "UNLABELED!", FALSE);
- if (rc != Success)
- FatalError("XSELinux: Failed to set context property on window!\n");
-} /* XSELinuxResourceState */
-
-static Bool
-XSELinuxLoadConfigFile(void)
-{
- struct selinux_opt options[] = {
- { SELABEL_OPT_PATH, XSELINUXCONFIGFILE },
- { SELABEL_OPT_VALIDATE, (char *)1 },
- };
-
- if (!XSELINUXCONFIGFILE)
- return FALSE;
+ FatalError("XSELinux: Unexpected unlabeled client found\n");
- label_hnd = selabel_open(SELABEL_CTX_X, options, 2);
- return !!label_hnd;
-} /* XSELinuxLoadConfigFile */
+ state = dixLookupPrivate(&pWin->devPrivates, stateKey);
-static void
-XSELinuxFreeConfigData(void)
-{
- selabel_close(label_hnd);
- label_hnd = NULL;
-} /* XSELinuxFreeConfigData */
+ if (state->sid) {
+ security_context_t ctx;
+ int rc = avc_sid_to_context(state->sid, &ctx);
+ if (rc < 0)
+ FatalError("XSELinux: Failed to get security context!\n");
+ rc = dixChangeWindowProperty(serverClient,
+ pWin, atom_ctx, XA_STRING, 8,
+ PropModeReplace, strlen(ctx), ctx, FALSE);
+ if (rc != Success)
+ FatalError("XSELinux: Failed to set label property on window!\n");
+ freecon(ctx);
+ }
+ else
+ FatalError("XSELinux: Unexpected unlabeled window found\n");
+}
/* Extension dispatch functions */
static int
-ProcXSELinuxDispatch(ClientPtr client)
+ProcSELinuxDispatch(ClientPtr client)
{
return BadRequest;
-} /* ProcXSELinuxDispatch */
+}
static void
-XSELinuxResetProc(ExtensionEntry *extEntry)
+SELinuxResetProc(ExtensionEntry *extEntry)
{
- FreeClientState(serverClient);
+ /* XXX unregister all callbacks here */
- XSELinuxFreeConfigData();
+ selabel_close(label_hnd);
+ label_hnd = NULL;
audit_close(audit_fd);
avc_destroy();
-} /* XSELinuxResetProc */
+ avc_active = 0;
-static void
-XSELinuxAVCAudit(void *auditdata,
- security_class_t class,
- char *msgbuf,
- size_t msgbufsize)
+ xfree(knownTypes);
+ knownTypes = NULL;
+ numKnownTypes = 0;
+}
+
+static int
+SELinuxAudit(void *auditdata,
+ security_class_t class,
+ char *msgbuf,
+ size_t msgbufsize)
{
- XSELinuxAuditRec *audit = (XSELinuxAuditRec*)auditdata;
+ SELinuxAuditRec *audit = auditdata;
ClientPtr client = audit->client;
- char requestNum[8];
+ char idNum[16], *propertyName;
+ int major = 0, minor = 0;
REQUEST(xReq);
- if (stuff)
- snprintf(requestNum, 8, "%d", stuff->reqType);
+ if (audit->id)
+ snprintf(idNum, 16, "%x", audit->id);
+ if (stuff) {
+ major = stuff->reqType;
+ minor = (major < 128) ? 0 : MinorOpcodeOfRequest(client);
+ }
- snprintf(msgbuf, msgbufsize, "%s%s%s%s%s%s",
- stuff ? "request=" : "",
- stuff ? requestNum : "",
- audit->property ? " property=" : "",
- audit->property ? audit->property : "",
- audit->extension ? " extension=" : "",
- audit->extension ? audit->extension : "");
+ propertyName = audit->property ? NameForAtom(audit->property) : NULL;
+
+ return snprintf(msgbuf, msgbufsize, "%s%s%s%s%s%s%s%s%s%s%s%s",
+ stuff ? "request=" : "",
+ stuff ? LookupRequestName(major, minor) : "",
+ audit->client_path ? " client=" : "",
+ audit->client_path ? audit->client_path : "",
+ audit->id ? " resid=" : "",
+ audit->id ? idNum : "",
+ audit->restype ? " restype=" : "",
+ audit->restype ? LookupResourceName(audit->restype) : "",
+ audit->property ? " property=" : "",
+ audit->property ? propertyName : "",
+ audit->extension ? " extension=" : "",
+ audit->extension ? audit->extension : "");
}
-static void
-XSELinuxAVCLog(const char *fmt, ...)
+static int
+SELinuxLog(int type, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
VErrorF(fmt, ap);
va_end(ap);
+ return 0;
}
-/* XSELinuxExtensionSetup
- *
- * Set up the XSELinux Extension (pre-init)
- */
-void
-XSELinuxExtensionSetup(INITARGS)
+static void
+SELinuxFixupLabels(void)
{
- /* Allocate the client private index */
- clientPrivateIndex = AllocateClientPrivateIndex();
- if (!AllocateClientPrivate(clientPrivateIndex,
- sizeof (XSELinuxClientStateRec)))
- FatalError("XSELinux: Failed to allocate client private.\n");
-
- /* Allocate the extension private index */
- extnsnPrivateIndex = AllocateExtensionPrivateIndex();
- if (!AllocateExtensionPrivate(extnsnPrivateIndex, 0))
- FatalError("XSELinux: Failed to allocate extension private.\n");
+ int i;
+ XaceScreenAccessRec srec;
+ SELinuxStateRec *state;
+ security_context_t ctx;
+ pointer unused;
+
+ /* Do the serverClient */
+ state = dixLookupPrivate(&serverClient->devPrivates, stateKey);
+ sidput(state->sid);
+
+ /* Use the context of the X server process for the serverClient */
+ if (getcon(&ctx) < 0)
+ FatalError("Couldn't get context of X server process\n");
+
+ /* Get a SID from the context */
+ if (avc_context_to_sid(ctx, &state->sid) < 0)
+ FatalError("serverClient: context_to_sid(%s) failed\n", ctx);
+
+ freecon(ctx);
+
+ srec.client = serverClient;
+ srec.access_mode = DixCreateAccess;
+ srec.status = Success;
+
+ for (i = 0; i < screenInfo.numScreens; i++) {
+ /* Do the screen object */
+ srec.screen = screenInfo.screens[i];
+ SELinuxScreen(NULL, NULL, &srec);
+
+ /* Do the default colormap */
+ dixLookupResource(&unused, screenInfo.screens[i]->defColormap,
+ RT_COLORMAP, serverClient, DixCreateAccess);
+ }
}
-/* XSELinuxExtensionInit
- *
- * Initialize the XSELinux Extension
- */
void
XSELinuxExtensionInit(INITARGS)
{
- ExtensionEntry *extEntry;
- struct avc_log_callback alc = {XSELinuxAVCLog, XSELinuxAVCAudit};
+ ExtensionEntry *extEntry;
+ struct selinux_opt options[] = { { SELABEL_OPT_VALIDATE, (char *)1 } };
+ security_context_t con;
+ int ret = TRUE;
- if (!is_selinux_enabled())
- {
+ /* Setup SELinux stuff */
+ if (!is_selinux_enabled()) {
ErrorF("XSELinux: Extension failed to load: SELinux not enabled\n");
return;
}
- if (selinux_set_mapping(map) < 0) {
+ selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback)SELinuxLog);
+ selinux_set_callback(SELINUX_CB_AUDIT, (union selinux_callback)SELinuxAudit);
+
+ if (selinux_set_mapping(map) < 0)
FatalError("XSELinux: Failed to set up security class mapping\n");
- }
- if (avc_init("xserver", NULL, &alc, NULL, NULL) < 0)
- {
+ if (avc_open(NULL, 0) < 0)
FatalError("XSELinux: Couldn't initialize SELinux userspace AVC\n");
- }
+ avc_active = 1;
- if (!AddCallback(&ClientStateCallback, XSELinuxClientState, NULL))
- return;
- if (!AddCallback(&ResourceStateCallback, XSELinuxResourceState, NULL))
- return;
+ label_hnd = selabel_open(SELABEL_CTX_X, options, 1);
+ if (!label_hnd)
+ FatalError("XSELinux: Failed to open x_contexts mapping in policy\n");
+
+ if (security_get_initial_context("unlabeled", &con) < 0)
+ FatalError("XSELinux: Failed to look up unlabeled context\n");
+ if (avc_context_to_sid(con, &unlabeled_sid) < 0)
+ FatalError("XSELinux: a context_to_SID call failed!\n");
+ freecon(con);
+
+ /* Prepare for auditing */
+ audit_fd = audit_open();
+ if (audit_fd < 0)
+ FatalError("XSELinux: Failed to open the system audit log\n");
+
+ /* Allocate private storage */
+ if (!dixRequestPrivate(stateKey, sizeof(SELinuxStateRec)))
+ FatalError("XSELinux: Failed to allocate private storage.\n");
/* Create atoms for doing window labeling */
- atom_ctx = MakeAtom("_SELINUX_CONTEXT", 16, 1);
+ atom_ctx = MakeAtom("_SELINUX_CONTEXT", 16, TRUE);
if (atom_ctx == BAD_RESOURCE)
FatalError("XSELinux: Failed to create atom\n");
- atom_client_ctx = MakeAtom("_SELINUX_CLIENT_CONTEXT", 23, 1);
+ atom_client_ctx = MakeAtom("_SELINUX_CLIENT_CONTEXT", 23, TRUE);
if (atom_client_ctx == BAD_RESOURCE)
FatalError("XSELinux: Failed to create atom\n");
- /* Load the config file. If this fails, shut down the server,
- * since an unknown security status is worse than no security.
- */
- if (XSELinuxLoadConfigFile() != TRUE)
- {
- FatalError("XSELinux: Failed to load security policy\n");
- }
-
- /* prepare for auditing */
- audit_fd = audit_open();
- if (audit_fd < 0)
- {
- FatalError("XSELinux: Failed to open the system audit log\n");
- }
-
- /* register security callbacks */
- XaceRegisterCallback(XACE_CORE_DISPATCH, XSELinuxCoreDispatch, NULL);
- XaceRegisterCallback(XACE_EXT_ACCESS, XSELinuxExtDispatch, NULL);
- XaceRegisterCallback(XACE_EXT_DISPATCH, XSELinuxExtDispatch, NULL);
- XaceRegisterCallback(XACE_RESOURCE_ACCESS, XSELinuxResLookup, NULL);
- XaceRegisterCallback(XACE_MAP_ACCESS, XSELinuxMap, NULL);
- XaceRegisterCallback(XACE_SERVER_ACCESS, XSELinuxServer, NULL);
- XaceRegisterCallback(XACE_PROPERTY_ACCESS, XSELinuxProperty, NULL);
- /* XaceRegisterCallback(XACE_DECLARE_EXT_SECURE, XSELinuxDeclare, NULL);
- XaceRegisterCallback(XACE_DEVICE_ACCESS, XSELinuxDevice, NULL); */
-
- /* register extension with server */
+ /* Register callbacks */
+ ret &= dixRegisterPrivateInitFunc(stateKey, SELinuxStateInit, NULL);
+ ret &= dixRegisterPrivateDeleteFunc(stateKey, SELinuxStateFree, NULL);
+
+ ret &= AddCallback(&ClientStateCallback, SELinuxClientState, 0);
+ ret &= AddCallback(&ResourceStateCallback, SELinuxResourceState, 0);
+
+ ret &= XaceRegisterCallback(XACE_EXT_DISPATCH, SELinuxExtension, 0);
+ ret &= XaceRegisterCallback(XACE_RESOURCE_ACCESS, SELinuxResource, 0);
+// ret &= XaceRegisterCallback(XACE_DEVICE_ACCESS, SELinuxDevice, 0);
+ ret &= XaceRegisterCallback(XACE_PROPERTY_ACCESS, SELinuxProperty, 0);
+// ret &= XaceRegisterCallback(XACE_SEND_ACCESS, SELinuxSend, 0);
+// ret &= XaceRegisterCallback(XACE_RECEIVE_ACCESS, SELinuxReceive, 0);
+ ret &= XaceRegisterCallback(XACE_CLIENT_ACCESS, SELinuxClient, 0);
+ ret &= XaceRegisterCallback(XACE_EXT_ACCESS, SELinuxExtension, 0);
+ ret &= XaceRegisterCallback(XACE_SERVER_ACCESS, SELinuxServer, 0);
+// ret &= XaceRegisterCallback(XACE_SELECTION_ACCESS, SELinuxSelection, 0);
+ ret &= XaceRegisterCallback(XACE_SCREEN_ACCESS, SELinuxScreen, 0);
+ ret &= XaceRegisterCallback(XACE_SCREENSAVER_ACCESS, SELinuxScreen, &ret);
+ if (!ret)
+ FatalError("XSELinux: Failed to register one or more callbacks\n");
+
+ /* Add extension to server */
extEntry = AddExtension(XSELINUX_EXTENSION_NAME,
XSELinuxNumberEvents, XSELinuxNumberErrors,
- ProcXSELinuxDispatch, ProcXSELinuxDispatch,
- XSELinuxResetProc, StandardMinorOpcode);
+ ProcSELinuxDispatch, ProcSELinuxDispatch,
+ SELinuxResetProc, StandardMinorOpcode);
+
+ /* Label objects that were created before we could register ourself */
+ SELinuxFixupLabels();
}