/************************************************************ Author: Eamon Walsh Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that this permission notice appear in supporting documentation. This permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ********************************************************/ /* * Portions of this code copyright (c) 2005 by Trusted Computer Solutions, Inc. * All rights reserved. */ #ifdef HAVE_DIX_CONFIG_H #include #endif #include #include #include #include #include #include "selection.h" #include "inputstr.h" #include "scrnintstr.h" #include "windowstr.h" #include "propertyst.h" #include "extnsionst.h" #include "xacestr.h" #include "../os/osdep.h" #define _XSELINUX_NEED_FLASK_MAP #include "xselinuxint.h" /* structure passed to auditing callback */ typedef struct { ClientPtr client; /* client */ DeviceIntPtr dev; /* device */ char *command; /* client's executable path */ unsigned id; /* resource id, if any */ int restype; /* resource type, if any */ int event; /* event type, if any */ Atom property; /* property name, if any */ Atom selection; /* selection name, if any */ char *extension; /* extension name, if any */ } SELinuxAuditRec; /* private state keys */ static int subjectKeyIndex; DevPrivateKey subjectKey = &subjectKeyIndex; static int objectKeyIndex; DevPrivateKey objectKey = &objectKeyIndex; static int dataKeyIndex; DevPrivateKey dataKey = &dataKeyIndex; /* audit file descriptor */ static int audit_fd; /* whether AVC is active */ static int avc_active; /* atoms for window label properties */ static Atom atom_ctx; static Atom atom_client_ctx; /* The unlabeled SID */ static security_id_t unlabeled_sid; /* forward declarations */ static void SELinuxScreen(CallbackListPtr *, pointer, pointer); /* "true" pointer value for use as callback data */ static pointer truep = (pointer)1; /* * Performs an SELinux permission check. */ static int SELinuxDoCheck(SELinuxSubjectRec *subj, SELinuxObjectRec *obj, security_class_t class, Mask mode, SELinuxAuditRec *auditdata) { /* serverClient requests OK */ if (subj->privileged) return Success; auditdata->command = subj->command; errno = 0; if (avc_has_perm(subj->sid, obj->sid, class, mode, &subj->aeref, auditdata) < 0) { if (mode == DixUnknownAccess) return Success; /* DixUnknownAccess requests OK ... for now */ if (errno == EACCES) return BadAccess; ErrorF("SELinux: avc_has_perm: unexpected error %d\n", errno); return BadValue; } return Success; } /* * Labels a newly connected client. */ static void SELinuxLabelClient(ClientPtr client) { int fd = XaceGetConnectionNumber(client); SELinuxSubjectRec *subj; SELinuxObjectRec *obj; security_context_t ctx; subj = dixLookupPrivate(&client->devPrivates, subjectKey); sidput(subj->sid); obj = dixLookupPrivate(&client->devPrivates, objectKey); sidput(obj->sid); /* Try to get a context from the socket */ if (fd < 0 || getpeercon_raw(fd, &ctx) < 0) { /* Otherwise, fall back to a default context */ ctx = SELinuxDefaultClientLabel(); } /* For local clients, try and determine the executable name */ if (XaceIsLocal(client)) { struct ucred creds; socklen_t len = sizeof(creds); char path[PATH_MAX + 1]; size_t bytes; memset(&creds, 0, sizeof(creds)); if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &creds, &len) < 0) goto finish; snprintf(path, PATH_MAX + 1, "/proc/%d/cmdline", creds.pid); fd = open(path, O_RDONLY); if (fd < 0) goto finish; bytes = read(fd, path, PATH_MAX + 1); close(fd); if (bytes <= 0) goto finish; subj->command = xalloc(bytes); if (!subj->command) goto finish; memcpy(subj->command, path, bytes); subj->command[bytes - 1] = 0; } finish: /* Get a SID from the context */ if (avc_context_to_sid_raw(ctx, &subj->sid) < 0) FatalError("SELinux: client %d: context_to_sid_raw(%s) failed\n", client->index, ctx); sidget(obj->sid = subj->sid); freecon(ctx); } /* * Labels initial server objects. */ static void SELinuxLabelInitial(void) { int i; XaceScreenAccessRec srec; SELinuxSubjectRec *subj; SELinuxObjectRec *obj; security_context_t ctx; pointer unused; /* Do the serverClient */ subj = dixLookupPrivate(&serverClient->devPrivates, subjectKey); obj = dixLookupPrivate(&serverClient->devPrivates, objectKey); subj->privileged = 1; sidput(subj->sid); /* Use the context of the X server process for the serverClient */ if (getcon_raw(&ctx) < 0) FatalError("SELinux: couldn't get context of X server process\n"); /* Get a SID from the context */ if (avc_context_to_sid_raw(ctx, &subj->sid) < 0) FatalError("SELinux: serverClient: context_to_sid(%s) failed\n", ctx); sidget(obj->sid = subj->sid); 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 */ dixLookupResourceByType(&unused, screenInfo.screens[i]->defColormap, RT_COLORMAP, serverClient, DixCreateAccess); } } /* * Labels new resource objects. */ static int SELinuxLabelResource(XaceResourceAccessRec *rec, SELinuxSubjectRec *subj, SELinuxObjectRec *obj, security_class_t class) { int offset; security_id_t tsid; /* Check for a create context */ if (rec->rtype == RT_WINDOW && subj->win_create_sid) { sidget(obj->sid = subj->win_create_sid); return Success; } if (rec->parent) offset = dixLookupPrivateOffset(rec->ptype); if (rec->parent && offset >= 0) { /* Use the SID of the parent object in the labeling operation */ PrivateRec **privatePtr = DEVPRIV_AT(rec->parent, offset); SELinuxObjectRec *pobj = dixLookupPrivate(privatePtr, objectKey); tsid = pobj->sid; } else { /* Use the SID of the subject */ tsid = subj->sid; } /* Perform a transition to obtain the final SID */ if (avc_compute_create(subj->sid, tsid, class, &obj->sid) < 0) { ErrorF("SELinux: a compute_create call failed!\n"); return BadValue; } return Success; } /* * Libselinux Callbacks */ static int SELinuxAudit(void *auditdata, security_class_t class, char *msgbuf, size_t msgbufsize) { SELinuxAuditRec *audit = auditdata; ClientPtr client = audit->client; char idNum[16]; const char *propertyName, *selectionName; int major = -1, minor = -1; if (client) { REQUEST(xReq); if (stuff) { major = stuff->reqType; minor = MinorOpcodeOfRequest(client); } } if (audit->id) snprintf(idNum, 16, "%x", audit->id); propertyName = audit->property ? NameForAtom(audit->property) : NULL; selectionName = audit->selection ? NameForAtom(audit->selection) : NULL; return snprintf(msgbuf, msgbufsize, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", (major >= 0) ? "request=" : "", (major >= 0) ? LookupRequestName(major, minor) : "", audit->command ? " comm=" : "", audit->command ? audit->command : "", audit->dev ? " xdevice=\"" : "", audit->dev ? audit->dev->name : "", audit->dev ? "\"" : "", audit->id ? " resid=" : "", audit->id ? idNum : "", audit->restype ? " restype=" : "", audit->restype ? LookupResourceName(audit->restype) : "", audit->event ? " event=" : "", audit->event ? LookupEventName(audit->event & 127) : "", audit->property ? " property=" : "", audit->property ? propertyName : "", audit->selection ? " selection=" : "", audit->selection ? selectionName : "", audit->extension ? " extension=" : "", audit->extension ? audit->extension : ""); } static int SELinuxLog(int type, const char *fmt, ...) { va_list ap; char buf[MAX_AUDIT_MESSAGE_LENGTH]; int rc, aut; switch (type) { case SELINUX_INFO: aut = AUDIT_USER_MAC_POLICY_LOAD; break; case SELINUX_AVC: aut = AUDIT_USER_AVC; break; default: aut = AUDIT_USER_SELINUX_ERR; break; } va_start(ap, fmt); vsnprintf(buf, MAX_AUDIT_MESSAGE_LENGTH, fmt, ap); rc = audit_log_user_avc_message(audit_fd, aut, buf, NULL, NULL, NULL, 0); va_end(ap); LogMessageVerb(X_WARNING, 0, "%s", buf); return 0; } /* * XACE Callbacks */ static void SELinuxDevice(CallbackListPtr *pcbl, pointer unused, pointer calldata) { XaceDeviceAccessRec *rec = calldata; SELinuxSubjectRec *subj; SELinuxObjectRec *obj; SELinuxAuditRec auditdata = { .client = rec->client, .dev = rec->dev }; int rc; subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); obj = dixLookupPrivate(&rec->dev->devPrivates, objectKey); /* If this is a new object that needs labeling, do it now */ if (rec->access_mode & DixCreateAccess) { SELinuxSubjectRec *dsubj; dsubj = dixLookupPrivate(&rec->dev->devPrivates, subjectKey); sidput(dsubj->sid); sidput(obj->sid); if (subj->dev_create_sid) { /* Label the device with the create context */ sidget(obj->sid = subj->dev_create_sid); sidget(dsubj->sid = subj->dev_create_sid); } else { /* Label the device directly with the process SID */ sidget(obj->sid = subj->sid); sidget(dsubj->sid = subj->sid); } } rc = SELinuxDoCheck(subj, obj, SECCLASS_X_DEVICE, rec->access_mode, &auditdata); if (rc != Success) rec->status = rc; } static void SELinuxSend(CallbackListPtr *pcbl, pointer unused, pointer calldata) { XaceSendAccessRec *rec = calldata; SELinuxSubjectRec *subj; SELinuxObjectRec *obj, ev_sid; SELinuxAuditRec auditdata = { .client = rec->client, .dev = rec->dev }; security_class_t class; int rc, i, type; if (rec->dev) subj = dixLookupPrivate(&rec->dev->devPrivates, subjectKey); else subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); obj = dixLookupPrivate(&rec->pWin->devPrivates, objectKey); /* Check send permission on window */ rc = SELinuxDoCheck(subj, obj, SECCLASS_X_DRAWABLE, DixSendAccess, &auditdata); if (rc != Success) goto err; /* Check send permission on specific event types */ for (i = 0; i < rec->count; i++) { type = rec->events[i].u.u.type; class = (type & 128) ? SECCLASS_X_FAKEEVENT : SECCLASS_X_EVENT; rc = SELinuxEventToSID(type, obj->sid, &ev_sid); if (rc != Success) goto err; auditdata.event = type; rc = SELinuxDoCheck(subj, &ev_sid, class, DixSendAccess, &auditdata); if (rc != Success) goto err; } return; err: rec->status = rc; } static void SELinuxReceive(CallbackListPtr *pcbl, pointer unused, pointer calldata) { XaceReceiveAccessRec *rec = calldata; SELinuxSubjectRec *subj; SELinuxObjectRec *obj, ev_sid; SELinuxAuditRec auditdata = { .client = NULL }; security_class_t class; int rc, i, type; subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); obj = dixLookupPrivate(&rec->pWin->devPrivates, objectKey); /* Check receive permission on window */ rc = SELinuxDoCheck(subj, obj, SECCLASS_X_DRAWABLE, DixReceiveAccess, &auditdata); if (rc != Success) goto err; /* Check receive permission on specific event types */ for (i = 0; i < rec->count; i++) { type = rec->events[i].u.u.type; class = (type & 128) ? SECCLASS_X_FAKEEVENT : SECCLASS_X_EVENT; rc = SELinuxEventToSID(type, obj->sid, &ev_sid); if (rc != Success) goto err; auditdata.event = type; rc = SELinuxDoCheck(subj, &ev_sid, class, DixReceiveAccess, &auditdata); if (rc != Success) goto err; } return; err: rec->status = rc; } static void SELinuxExtension(CallbackListPtr *pcbl, pointer unused, pointer calldata) { XaceExtAccessRec *rec = calldata; SELinuxSubjectRec *subj, *serv; SELinuxObjectRec *obj; SELinuxAuditRec auditdata = { .client = rec->client }; int rc; subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); obj = dixLookupPrivate(&rec->ext->devPrivates, objectKey); /* 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) { security_id_t sid; serv = dixLookupPrivate(&serverClient->devPrivates, subjectKey); rc = SELinuxExtensionToSID(rec->ext->name, &sid); if (rc != Success) { rec->status = rc; return; } sidput(obj->sid); /* Perform a transition to obtain the final SID */ if (avc_compute_create(serv->sid, sid, SECCLASS_X_EXTENSION, &obj->sid) < 0) { ErrorF("SELinux: a SID transition call failed!\n"); rec->status = BadValue; return; } } /* Perform the security check */ auditdata.extension = rec->ext->name; rc = SELinuxDoCheck(subj, obj, SECCLASS_X_EXTENSION, rec->access_mode, &auditdata); if (rc != Success) rec->status = rc; } static void SELinuxSelection(CallbackListPtr *pcbl, pointer unused, pointer calldata) { XaceSelectionAccessRec *rec = calldata; SELinuxSubjectRec *subj; SELinuxObjectRec *obj, *data; Selection *pSel = *rec->ppSel; Atom name = pSel->selection; Mask access_mode = rec->access_mode; SELinuxAuditRec auditdata = { .client = rec->client, .selection = name }; security_id_t tsid; int rc; subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); obj = dixLookupPrivate(&pSel->devPrivates, objectKey); /* If this is a new object that needs labeling, do it now */ if (access_mode & DixCreateAccess) { sidput(obj->sid); rc = SELinuxSelectionToSID(name, subj, &obj->sid, &obj->poly); if (rc != Success) obj->sid = unlabeled_sid; access_mode = DixSetAttrAccess; } /* If this is a polyinstantiated object, find the right instance */ else if (obj->poly) { rc = SELinuxSelectionToSID(name, subj, &tsid, NULL); if (rc != Success) { rec->status = rc; return; } while (pSel->selection != name || obj->sid != tsid) { if ((pSel = pSel->next) == NULL) break; obj = dixLookupPrivate(&pSel->devPrivates, objectKey); } sidput(tsid); if (pSel) *rec->ppSel = pSel; else { rec->status = BadMatch; return; } } /* Perform the security check */ rc = SELinuxDoCheck(subj, obj, SECCLASS_X_SELECTION, access_mode, &auditdata); if (rc != Success) rec->status = rc; /* Label the content (advisory only) */ if (access_mode & DixSetAttrAccess) { data = dixLookupPrivate(&pSel->devPrivates, dataKey); sidput(data->sid); if (subj->sel_create_sid) sidget(data->sid = subj->sel_create_sid); else sidget(data->sid = obj->sid); } } static void SELinuxProperty(CallbackListPtr *pcbl, pointer unused, pointer calldata) { XacePropertyAccessRec *rec = calldata; SELinuxSubjectRec *subj; SELinuxObjectRec *obj, *data; PropertyPtr pProp = *rec->ppProp; Atom name = pProp->propertyName; SELinuxAuditRec auditdata = { .client = rec->client, .property = name }; security_id_t tsid; int rc; /* Don't care about the new content check */ if (rec->access_mode & DixPostAccess) return; subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); obj = dixLookupPrivate(&pProp->devPrivates, objectKey); /* If this is a new object that needs labeling, do it now */ if (rec->access_mode & DixCreateAccess) { sidput(obj->sid); rc = SELinuxPropertyToSID(name, subj, &obj->sid, &obj->poly); if (rc != Success) { rec->status = rc; return; } } /* If this is a polyinstantiated object, find the right instance */ else if (obj->poly) { rc = SELinuxPropertyToSID(name, subj, &tsid, NULL); if (rc != Success) { rec->status = rc; return; } while (pProp->propertyName != name || obj->sid != tsid) { if ((pProp = pProp->next) == NULL) break; obj = dixLookupPrivate(&pProp->devPrivates, objectKey); } sidput(tsid); if (pProp) *rec->ppProp = pProp; else { rec->status = BadMatch; return; } } /* Perform the security check */ rc = SELinuxDoCheck(subj, obj, SECCLASS_X_PROPERTY, rec->access_mode, &auditdata); if (rc != Success) rec->status = rc; /* Label the content (advisory only) */ if (rec->access_mode & DixWriteAccess) { data = dixLookupPrivate(&pProp->devPrivates, dataKey); sidput(data->sid); if (subj->prp_create_sid) sidget(data->sid = subj->prp_create_sid); else sidget(data->sid = obj->sid); } } static void SELinuxResource(CallbackListPtr *pcbl, pointer unused, pointer calldata) { XaceResourceAccessRec *rec = calldata; SELinuxSubjectRec *subj; SELinuxObjectRec *obj; SELinuxAuditRec auditdata = { .client = rec->client }; Mask access_mode = rec->access_mode; PrivateRec **privatePtr; security_class_t class; int rc, offset; subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); /* 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, objectKey); } else { /* Yes: use the SID from the resource object itself */ class = SELinuxTypeToClass(rec->rtype); privatePtr = DEVPRIV_AT(rec->res, offset); obj = dixLookupPrivate(privatePtr, objectKey); } /* If this is a new object that needs labeling, do it now */ if (access_mode & DixCreateAccess && offset >= 0) { rc = SELinuxLabelResource(rec, subj, obj, class); if (rc != Success) { rec->status = rc; return; } } /* Collapse generic resource permissions down to read/write */ if (class == SECCLASS_X_RESOURCE) { access_mode = !!(rec->access_mode & SELinuxReadMask); /* rd */ access_mode |= !!(rec->access_mode & ~SELinuxReadMask) << 1; /* wr */ } /* Perform the security check */ auditdata.restype = rec->rtype; auditdata.id = rec->id; rc = SELinuxDoCheck(subj, obj, class, access_mode, &auditdata); if (rc != Success) rec->status = rc; /* Perform the background none check on windows */ if (access_mode & DixCreateAccess && rec->rtype == RT_WINDOW) { rc = SELinuxDoCheck(subj, obj, class, DixBlendAccess, &auditdata); if (rc != Success) ((WindowPtr)rec->res)->forcedBG = TRUE; } } static void SELinuxScreen(CallbackListPtr *pcbl, pointer is_saver, pointer calldata) { XaceScreenAccessRec *rec = calldata; SELinuxSubjectRec *subj; SELinuxObjectRec *obj; SELinuxAuditRec auditdata = { .client = rec->client }; Mask access_mode = rec->access_mode; int rc; subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); obj = dixLookupPrivate(&rec->screen->devPrivates, objectKey); /* If this is a new object that needs labeling, do it now */ if (access_mode & DixCreateAccess) { sidput(obj->sid); /* Perform a transition to obtain the final SID */ if (avc_compute_create(subj->sid, subj->sid, SECCLASS_X_SCREEN, &obj->sid) < 0) { ErrorF("SELinux: a compute_create call failed!\n"); rec->status = BadValue; return; } } if (is_saver) access_mode <<= 2; rc = SELinuxDoCheck(subj, obj, SECCLASS_X_SCREEN, access_mode, &auditdata); if (rc != Success) rec->status = rc; } static void SELinuxClient(CallbackListPtr *pcbl, pointer unused, pointer calldata) { XaceClientAccessRec *rec = calldata; SELinuxSubjectRec *subj; SELinuxObjectRec *obj; SELinuxAuditRec auditdata = { .client = rec->client }; int rc; subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); obj = dixLookupPrivate(&rec->target->devPrivates, objectKey); rc = SELinuxDoCheck(subj, obj, SECCLASS_X_CLIENT, rec->access_mode, &auditdata); if (rc != Success) rec->status = rc; } static void SELinuxServer(CallbackListPtr *pcbl, pointer unused, pointer calldata) { XaceServerAccessRec *rec = calldata; SELinuxSubjectRec *subj; SELinuxObjectRec *obj; SELinuxAuditRec auditdata = { .client = rec->client }; int rc; subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); obj = dixLookupPrivate(&serverClient->devPrivates, objectKey); rc = SELinuxDoCheck(subj, obj, SECCLASS_X_SERVER, rec->access_mode, &auditdata); if (rc != Success) rec->status = rc; } /* * DIX Callbacks */ static void SELinuxClientState(CallbackListPtr *pcbl, pointer unused, pointer calldata) { NewClientInfoRec *pci = calldata; switch (pci->client->clientState) { case ClientStateInitial: SELinuxLabelClient(pci->client); break; default: break; } } static void SELinuxResourceState(CallbackListPtr *pcbl, pointer unused, pointer calldata) { ResourceStateInfoRec *rec = calldata; SELinuxSubjectRec *subj; SELinuxObjectRec *obj; WindowPtr pWin; if (rec->type != RT_WINDOW) return; if (rec->state != ResourceStateAdding) return; pWin = (WindowPtr)rec->value; subj = dixLookupPrivate(&wClient(pWin)->devPrivates, subjectKey); if (subj->sid) { security_context_t ctx; int rc = avc_sid_to_context_raw(subj->sid, &ctx); if (rc < 0) FatalError("SELinux: 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("SELinux: Failed to set label property on window!\n"); freecon(ctx); } else FatalError("SELinux: Unexpected unlabeled client found\n"); obj = dixLookupPrivate(&pWin->devPrivates, objectKey); if (obj->sid) { security_context_t ctx; int rc = avc_sid_to_context_raw(obj->sid, &ctx); if (rc < 0) FatalError("SELinux: Failed to get security context!\n"); rc = dixChangeWindowProperty(serverClient, pWin, atom_ctx, XA_STRING, 8, PropModeReplace, strlen(ctx), ctx, FALSE); if (rc != Success) FatalError("SELinux: Failed to set label property on window!\n"); freecon(ctx); } else FatalError("SELinux: Unexpected unlabeled window found\n"); } /* * DevPrivates Callbacks */ static void SELinuxSubjectInit(CallbackListPtr *pcbl, pointer unused, pointer calldata) { PrivateCallbackRec *rec = calldata; SELinuxSubjectRec *subj = *rec->value; sidget(unlabeled_sid); subj->sid = unlabeled_sid; avc_entry_ref_init(&subj->aeref); } static void SELinuxSubjectFree(CallbackListPtr *pcbl, pointer unused, pointer calldata) { PrivateCallbackRec *rec = calldata; SELinuxSubjectRec *subj = *rec->value; xfree(subj->command); if (avc_active) { sidput(subj->sid); sidput(subj->dev_create_sid); sidput(subj->win_create_sid); sidput(subj->sel_create_sid); sidput(subj->prp_create_sid); } } static void SELinuxObjectInit(CallbackListPtr *pcbl, pointer unused, pointer calldata) { PrivateCallbackRec *rec = calldata; SELinuxObjectRec *obj = *rec->value; sidget(unlabeled_sid); obj->sid = unlabeled_sid; } static void SELinuxObjectFree(CallbackListPtr *pcbl, pointer unused, pointer calldata) { PrivateCallbackRec *rec = calldata; SELinuxObjectRec *obj = *rec->value; if (avc_active) sidput(obj->sid); } #ifdef HAVE_AVC_NETLINK_ACQUIRE_FD static int netlink_fd; static void SELinuxBlockHandler(void *data, struct timeval **tv, void *read_mask) { } static void SELinuxWakeupHandler(void *data, int err, void *read_mask) { if (FD_ISSET(netlink_fd, (fd_set *)read_mask)) avc_netlink_check_nb(); } #endif void SELinuxFlaskReset(void) { /* Unregister callbacks */ DeleteCallback(&ClientStateCallback, SELinuxClientState, NULL); DeleteCallback(&ResourceStateCallback, SELinuxResourceState, NULL); XaceDeleteCallback(XACE_EXT_DISPATCH, SELinuxExtension, NULL); XaceDeleteCallback(XACE_RESOURCE_ACCESS, SELinuxResource, NULL); XaceDeleteCallback(XACE_DEVICE_ACCESS, SELinuxDevice, NULL); XaceDeleteCallback(XACE_PROPERTY_ACCESS, SELinuxProperty, NULL); XaceDeleteCallback(XACE_SEND_ACCESS, SELinuxSend, NULL); XaceDeleteCallback(XACE_RECEIVE_ACCESS, SELinuxReceive, NULL); XaceDeleteCallback(XACE_CLIENT_ACCESS, SELinuxClient, NULL); XaceDeleteCallback(XACE_EXT_ACCESS, SELinuxExtension, NULL); XaceDeleteCallback(XACE_SERVER_ACCESS, SELinuxServer, NULL); XaceDeleteCallback(XACE_SELECTION_ACCESS, SELinuxSelection, NULL); XaceDeleteCallback(XACE_SCREEN_ACCESS, SELinuxScreen, NULL); XaceDeleteCallback(XACE_SCREENSAVER_ACCESS, SELinuxScreen, truep); /* Tear down SELinux stuff */ audit_close(audit_fd); #ifdef HAVE_AVC_NETLINK_ACQUIRE_FD avc_netlink_release_fd(); RemoveBlockAndWakeupHandlers(SELinuxBlockHandler, SELinuxWakeupHandler, NULL); RemoveGeneralSocket(netlink_fd); #endif avc_destroy(); avc_active = 0; } void SELinuxFlaskInit(void) { struct selinux_opt avc_option = { AVC_OPT_SETENFORCE, (char *)0 }; security_context_t ctx; int ret = TRUE; switch(selinuxEnforcingState) { case SELINUX_MODE_ENFORCING: LogMessage(X_INFO, "SELinux: Configured in enforcing mode\n"); avc_option.value = (char *)1; break; case SELINUX_MODE_PERMISSIVE: LogMessage(X_INFO, "SELinux: Configured in permissive mode\n"); avc_option.value = (char *)0; break; default: avc_option.type = AVC_OPT_UNUSED; break; } /* Set up SELinux stuff */ 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) { if (errno == EINVAL) { ErrorF("SELinux: Invalid object class mapping, disabling SELinux support.\n"); return; } FatalError("SELinux: Failed to set up security class mapping\n"); } if (avc_open(&avc_option, 1) < 0) FatalError("SELinux: Couldn't initialize SELinux userspace AVC\n"); avc_active = 1; if (security_get_initial_context_raw("unlabeled", &ctx) < 0) FatalError("SELinux: Failed to look up unlabeled context\n"); if (avc_context_to_sid_raw(ctx, &unlabeled_sid) < 0) FatalError("SELinux: a context_to_SID call failed!\n"); freecon(ctx); /* Prepare for auditing */ audit_fd = audit_open(); if (audit_fd < 0) FatalError("SELinux: Failed to open the system audit log\n"); /* Allocate private storage */ if (!dixRequestPrivate(subjectKey, sizeof(SELinuxSubjectRec)) || !dixRequestPrivate(objectKey, sizeof(SELinuxObjectRec)) || !dixRequestPrivate(dataKey, sizeof(SELinuxObjectRec))) FatalError("SELinux: Failed to allocate private storage.\n"); /* Create atoms for doing window labeling */ atom_ctx = MakeAtom("_SELINUX_CONTEXT", 16, TRUE); if (atom_ctx == BAD_RESOURCE) FatalError("SELinux: Failed to create atom\n"); atom_client_ctx = MakeAtom("_SELINUX_CLIENT_CONTEXT", 23, TRUE); if (atom_client_ctx == BAD_RESOURCE) FatalError("SELinux: Failed to create atom\n"); #ifdef HAVE_AVC_NETLINK_ACQUIRE_FD netlink_fd = avc_netlink_acquire_fd(); AddGeneralSocket(netlink_fd); RegisterBlockAndWakeupHandlers(SELinuxBlockHandler, SELinuxWakeupHandler, NULL); #endif /* Register callbacks */ ret &= dixRegisterPrivateInitFunc(subjectKey, SELinuxSubjectInit, NULL); ret &= dixRegisterPrivateDeleteFunc(subjectKey, SELinuxSubjectFree, NULL); ret &= dixRegisterPrivateInitFunc(objectKey, SELinuxObjectInit, NULL); ret &= dixRegisterPrivateDeleteFunc(objectKey, SELinuxObjectFree, NULL); ret &= dixRegisterPrivateInitFunc(dataKey, SELinuxObjectInit, NULL); ret &= dixRegisterPrivateDeleteFunc(dataKey, SELinuxObjectFree, NULL); ret &= AddCallback(&ClientStateCallback, SELinuxClientState, NULL); ret &= AddCallback(&ResourceStateCallback, SELinuxResourceState, NULL); ret &= XaceRegisterCallback(XACE_EXT_DISPATCH, SELinuxExtension, NULL); ret &= XaceRegisterCallback(XACE_RESOURCE_ACCESS, SELinuxResource, NULL); ret &= XaceRegisterCallback(XACE_DEVICE_ACCESS, SELinuxDevice, NULL); ret &= XaceRegisterCallback(XACE_PROPERTY_ACCESS, SELinuxProperty, NULL); ret &= XaceRegisterCallback(XACE_SEND_ACCESS, SELinuxSend, NULL); ret &= XaceRegisterCallback(XACE_RECEIVE_ACCESS, SELinuxReceive, NULL); ret &= XaceRegisterCallback(XACE_CLIENT_ACCESS, SELinuxClient, NULL); ret &= XaceRegisterCallback(XACE_EXT_ACCESS, SELinuxExtension, NULL); ret &= XaceRegisterCallback(XACE_SERVER_ACCESS, SELinuxServer, NULL); ret &= XaceRegisterCallback(XACE_SELECTION_ACCESS, SELinuxSelection, NULL); ret &= XaceRegisterCallback(XACE_SCREEN_ACCESS, SELinuxScreen, NULL); ret &= XaceRegisterCallback(XACE_SCREENSAVER_ACCESS, SELinuxScreen, truep); if (!ret) FatalError("SELinux: Failed to register one or more callbacks\n"); /* Label objects that were created before we could register ourself */ SELinuxLabelInitial(); }