diff options
Diffstat (limited to 'Xext/xselinux.c')
-rw-r--r-- | Xext/xselinux.c | 1675 |
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(); } |