1/************************************************************ 2 3Author: Eamon Walsh <ewalsh@tycho.nsa.gov> 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7this permission notice appear in supporting documentation. This permission 8notice shall be included in all copies or substantial portions of the 9Software. 10 11THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 13FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 15AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 16CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 18********************************************************/ 19 20/* 21 * Portions of this code copyright (c) 2005 by Trusted Computer Solutions, Inc. 22 * All rights reserved. 23 */ 24 25#ifdef HAVE_DIX_CONFIG_H 26#include <dix-config.h> 27#endif 28 29#include <sys/socket.h> 30#include <stdio.h> 31#include <stdarg.h> 32 33#include <libaudit.h> 34 35#include <X11/Xatom.h> 36#include "selection.h" 37#include "inputstr.h" 38#include "scrnintstr.h" 39#include "windowstr.h" 40#include "propertyst.h" 41#include "extnsionst.h" 42#include "xacestr.h" 43#include "../os/osdep.h" 44#define _XSELINUX_NEED_FLASK_MAP 45#include "xselinuxint.h" 46 47 48/* structure passed to auditing callback */ 49typedef struct { 50 ClientPtr client; /* client */ 51 DeviceIntPtr dev; /* device */ 52 char *command; /* client's executable path */ 53 unsigned id; /* resource id, if any */ 54 int restype; /* resource type, if any */ 55 int event; /* event type, if any */ 56 Atom property; /* property name, if any */ 57 Atom selection; /* selection name, if any */ 58 char *extension; /* extension name, if any */ 59} SELinuxAuditRec; 60 61/* private state keys */ 62DevPrivateKeyRec subjectKeyRec; 63DevPrivateKeyRec objectKeyRec; 64DevPrivateKeyRec dataKeyRec; 65 66/* audit file descriptor */ 67static int audit_fd; 68 69/* atoms for window label properties */ 70static Atom atom_ctx; 71static Atom atom_client_ctx; 72 73/* The unlabeled SID */ 74static security_id_t unlabeled_sid; 75 76/* forward declarations */ 77static void SELinuxScreen(CallbackListPtr *, pointer, pointer); 78 79/* "true" pointer value for use as callback data */ 80static pointer truep = (pointer)1; 81 82 83/* 84 * Performs an SELinux permission check. 85 */ 86static int 87SELinuxDoCheck(SELinuxSubjectRec *subj, SELinuxObjectRec *obj, 88 security_class_t class, Mask mode, SELinuxAuditRec *auditdata) 89{ 90 /* serverClient requests OK */ 91 if (subj->privileged) 92 return Success; 93 94 auditdata->command = subj->command; 95 errno = 0; 96 97 if (avc_has_perm(subj->sid, obj->sid, class, mode, &subj->aeref, 98 auditdata) < 0) { 99 if (mode == DixUnknownAccess) 100 return Success; /* DixUnknownAccess requests OK ... for now */ 101 if (errno == EACCES) 102 return BadAccess; 103 ErrorF("SELinux: avc_has_perm: unexpected error %d\n", errno); 104 return BadValue; 105 } 106 107 return Success; 108} 109 110/* 111 * Labels a newly connected client. 112 */ 113static void 114SELinuxLabelClient(ClientPtr client) 115{ 116 int fd = XaceGetConnectionNumber(client); 117 SELinuxSubjectRec *subj; 118 SELinuxObjectRec *obj; 119 security_context_t ctx; 120 121 subj = dixLookupPrivate(&client->devPrivates, subjectKey); 122 obj = dixLookupPrivate(&client->devPrivates, objectKey); 123 124 /* Try to get a context from the socket */ 125 if (fd < 0 || getpeercon_raw(fd, &ctx) < 0) { 126 /* Otherwise, fall back to a default context */ 127 ctx = SELinuxDefaultClientLabel(); 128 } 129 130 /* For local clients, try and determine the executable name */ 131 if (XaceIsLocal(client)) { 132 struct ucred creds; 133 socklen_t len = sizeof(creds); 134 char path[PATH_MAX + 1]; 135 size_t bytes; 136 137 memset(&creds, 0, sizeof(creds)); 138 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &creds, &len) < 0) 139 goto finish; 140 141 snprintf(path, PATH_MAX + 1, "/proc/%d/cmdline", creds.pid); 142 fd = open(path, O_RDONLY); 143 if (fd < 0) 144 goto finish; 145 146 bytes = read(fd, path, PATH_MAX + 1); 147 close(fd); 148 if (bytes <= 0) 149 goto finish; 150 151 strncpy(subj->command, path, COMMAND_LEN - 1); 152 } 153 154finish: 155 /* Get a SID from the context */ 156 if (avc_context_to_sid_raw(ctx, &subj->sid) < 0) 157 FatalError("SELinux: client %d: context_to_sid_raw(%s) failed\n", 158 client->index, ctx); 159 160 obj->sid = subj->sid; 161 freecon(ctx); 162} 163 164/* 165 * Labels initial server objects. 166 */ 167static void 168SELinuxLabelInitial(void) 169{ 170 int i; 171 XaceScreenAccessRec srec; 172 SELinuxSubjectRec *subj; 173 SELinuxObjectRec *obj; 174 security_context_t ctx; 175 pointer unused; 176 177 /* Do the serverClient */ 178 subj = dixLookupPrivate(&serverClient->devPrivates, subjectKey); 179 obj = dixLookupPrivate(&serverClient->devPrivates, objectKey); 180 subj->privileged = 1; 181 182 /* Use the context of the X server process for the serverClient */ 183 if (getcon_raw(&ctx) < 0) 184 FatalError("SELinux: couldn't get context of X server process\n"); 185 186 /* Get a SID from the context */ 187 if (avc_context_to_sid_raw(ctx, &subj->sid) < 0) 188 FatalError("SELinux: serverClient: context_to_sid(%s) failed\n", ctx); 189 190 obj->sid = subj->sid; 191 freecon(ctx); 192 193 srec.client = serverClient; 194 srec.access_mode = DixCreateAccess; 195 srec.status = Success; 196 197 for (i = 0; i < screenInfo.numScreens; i++) { 198 /* Do the screen object */ 199 srec.screen = screenInfo.screens[i]; 200 SELinuxScreen(NULL, NULL, &srec); 201 202 /* Do the default colormap */ 203 dixLookupResourceByType(&unused, screenInfo.screens[i]->defColormap, 204 RT_COLORMAP, serverClient, DixCreateAccess); 205 } 206} 207 208/* 209 * Labels new resource objects. 210 */ 211static int 212SELinuxLabelResource(XaceResourceAccessRec *rec, SELinuxSubjectRec *subj, 213 SELinuxObjectRec *obj, security_class_t class) 214{ 215 int offset; 216 security_id_t tsid; 217 218 /* Check for a create context */ 219 if (rec->rtype & RC_DRAWABLE && subj->win_create_sid) { 220 obj->sid = subj->win_create_sid; 221 return Success; 222 } 223 224 if (rec->parent) 225 offset = dixLookupPrivateOffset(rec->ptype); 226 227 if (rec->parent && offset >= 0) { 228 /* Use the SID of the parent object in the labeling operation */ 229 PrivateRec **privatePtr = DEVPRIV_AT(rec->parent, offset); 230 SELinuxObjectRec *pobj = dixLookupPrivate(privatePtr, objectKey); 231 tsid = pobj->sid; 232 } else { 233 /* Use the SID of the subject */ 234 tsid = subj->sid; 235 } 236 237 /* Perform a transition to obtain the final SID */ 238 if (avc_compute_create(subj->sid, tsid, class, &obj->sid) < 0) { 239 ErrorF("SELinux: a compute_create call failed!\n"); 240 return BadValue; 241 } 242 243 return Success; 244} 245 246 247/* 248 * Libselinux Callbacks 249 */ 250 251static int 252SELinuxAudit(void *auditdata, 253 security_class_t class, 254 char *msgbuf, 255 size_t msgbufsize) 256{ 257 SELinuxAuditRec *audit = auditdata; 258 ClientPtr client = audit->client; 259 char idNum[16]; 260 const char *propertyName, *selectionName; 261 int major = -1, minor = -1; 262 263 if (client) { 264 REQUEST(xReq); 265 if (stuff) { 266 major = stuff->reqType; 267 minor = MinorOpcodeOfRequest(client); 268 } 269 } 270 if (audit->id) 271 snprintf(idNum, 16, "%x", audit->id); 272 273 propertyName = audit->property ? NameForAtom(audit->property) : NULL; 274 selectionName = audit->selection ? NameForAtom(audit->selection) : NULL; 275 276 return snprintf(msgbuf, msgbufsize, 277 "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", 278 (major >= 0) ? "request=" : "", 279 (major >= 0) ? LookupRequestName(major, minor) : "", 280 audit->command ? " comm=" : "", 281 audit->command ? audit->command : "", 282 audit->dev ? " xdevice=\"" : "", 283 audit->dev ? audit->dev->name : "", 284 audit->dev ? "\"" : "", 285 audit->id ? " resid=" : "", 286 audit->id ? idNum : "", 287 audit->restype ? " restype=" : "", 288 audit->restype ? LookupResourceName(audit->restype) : "", 289 audit->event ? " event=" : "", 290 audit->event ? LookupEventName(audit->event & 127) : "", 291 audit->property ? " property=" : "", 292 audit->property ? propertyName : "", 293 audit->selection ? " selection=" : "", 294 audit->selection ? selectionName : "", 295 audit->extension ? " extension=" : "", 296 audit->extension ? audit->extension : ""); 297} 298 299static int 300SELinuxLog(int type, const char *fmt, ...) 301{ 302 va_list ap; 303 char buf[MAX_AUDIT_MESSAGE_LENGTH]; 304 int rc, aut; 305 306 switch (type) { 307 case SELINUX_INFO: 308 aut = AUDIT_USER_MAC_POLICY_LOAD; 309 break; 310 case SELINUX_AVC: 311 aut = AUDIT_USER_AVC; 312 break; 313 default: 314 aut = AUDIT_USER_SELINUX_ERR; 315 break; 316 } 317 318 va_start(ap, fmt); 319 vsnprintf(buf, MAX_AUDIT_MESSAGE_LENGTH, fmt, ap); 320 rc = audit_log_user_avc_message(audit_fd, aut, buf, NULL, NULL, NULL, 0); 321 va_end(ap); 322 LogMessageVerb(X_WARNING, 0, "%s", buf); 323 return 0; 324} 325 326/* 327 * XACE Callbacks 328 */ 329 330static void 331SELinuxDevice(CallbackListPtr *pcbl, pointer unused, pointer calldata) 332{ 333 XaceDeviceAccessRec *rec = calldata; 334 SELinuxSubjectRec *subj; 335 SELinuxObjectRec *obj; 336 SELinuxAuditRec auditdata = { .client = rec->client, .dev = rec->dev }; 337 security_class_t cls; 338 int rc; 339 340 subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); 341 obj = dixLookupPrivate(&rec->dev->devPrivates, objectKey); 342 343 /* If this is a new object that needs labeling, do it now */ 344 if (rec->access_mode & DixCreateAccess) { 345 SELinuxSubjectRec *dsubj; 346 dsubj = dixLookupPrivate(&rec->dev->devPrivates, subjectKey); 347 348 if (subj->dev_create_sid) { 349 /* Label the device with the create context */ 350 obj->sid = subj->dev_create_sid; 351 dsubj->sid = subj->dev_create_sid; 352 } else { 353 /* Label the device directly with the process SID */ 354 obj->sid = subj->sid; 355 dsubj->sid = subj->sid; 356 } 357 } 358 359 cls = IsPointerDevice(rec->dev) ? SECCLASS_X_POINTER : SECCLASS_X_KEYBOARD; 360 rc = SELinuxDoCheck(subj, obj, cls, rec->access_mode, &auditdata); 361 if (rc != Success) 362 rec->status = rc; 363} 364 365static void 366SELinuxSend(CallbackListPtr *pcbl, pointer unused, pointer calldata) 367{ 368 XaceSendAccessRec *rec = calldata; 369 SELinuxSubjectRec *subj; 370 SELinuxObjectRec *obj, ev_sid; 371 SELinuxAuditRec auditdata = { .client = rec->client, .dev = rec->dev }; 372 security_class_t class; 373 int rc, i, type; 374 375 if (rec->dev) 376 subj = dixLookupPrivate(&rec->dev->devPrivates, subjectKey); 377 else 378 subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); 379 380 obj = dixLookupPrivate(&rec->pWin->devPrivates, objectKey); 381 382 /* Check send permission on window */ 383 rc = SELinuxDoCheck(subj, obj, SECCLASS_X_DRAWABLE, DixSendAccess, 384 &auditdata); 385 if (rc != Success) 386 goto err; 387 388 /* Check send permission on specific event types */ 389 for (i = 0; i < rec->count; i++) { 390 type = rec->events[i].u.u.type; 391 class = (type & 128) ? SECCLASS_X_FAKEEVENT : SECCLASS_X_EVENT; 392 393 rc = SELinuxEventToSID(type, obj->sid, &ev_sid); 394 if (rc != Success) 395 goto err; 396 397 auditdata.event = type; 398 rc = SELinuxDoCheck(subj, &ev_sid, class, DixSendAccess, &auditdata); 399 if (rc != Success) 400 goto err; 401 } 402 return; 403err: 404 rec->status = rc; 405} 406 407static void 408SELinuxReceive(CallbackListPtr *pcbl, pointer unused, pointer calldata) 409{ 410 XaceReceiveAccessRec *rec = calldata; 411 SELinuxSubjectRec *subj; 412 SELinuxObjectRec *obj, ev_sid; 413 SELinuxAuditRec auditdata = { .client = NULL }; 414 security_class_t class; 415 int rc, i, type; 416 417 subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); 418 obj = dixLookupPrivate(&rec->pWin->devPrivates, objectKey); 419 420 /* Check receive permission on window */ 421 rc = SELinuxDoCheck(subj, obj, SECCLASS_X_DRAWABLE, DixReceiveAccess, 422 &auditdata); 423 if (rc != Success) 424 goto err; 425 426 /* Check receive permission on specific event types */ 427 for (i = 0; i < rec->count; i++) { 428 type = rec->events[i].u.u.type; 429 class = (type & 128) ? SECCLASS_X_FAKEEVENT : SECCLASS_X_EVENT; 430 431 rc = SELinuxEventToSID(type, obj->sid, &ev_sid); 432 if (rc != Success) 433 goto err; 434 435 auditdata.event = type; 436 rc = SELinuxDoCheck(subj, &ev_sid, class, DixReceiveAccess, &auditdata); 437 if (rc != Success) 438 goto err; 439 } 440 return; 441err: 442 rec->status = rc; 443} 444 445static void 446SELinuxExtension(CallbackListPtr *pcbl, pointer unused, pointer calldata) 447{ 448 XaceExtAccessRec *rec = calldata; 449 SELinuxSubjectRec *subj, *serv; 450 SELinuxObjectRec *obj; 451 SELinuxAuditRec auditdata = { .client = rec->client }; 452 int rc; 453 454 subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); 455 obj = dixLookupPrivate(&rec->ext->devPrivates, objectKey); 456 457 /* If this is a new object that needs labeling, do it now */ 458 /* XXX there should be a separate callback for this */ 459 if (obj->sid == NULL) { 460 security_id_t sid; 461 462 serv = dixLookupPrivate(&serverClient->devPrivates, subjectKey); 463 rc = SELinuxExtensionToSID(rec->ext->name, &sid); 464 if (rc != Success) { 465 rec->status = rc; 466 return; 467 } 468 469 /* Perform a transition to obtain the final SID */ 470 if (avc_compute_create(serv->sid, sid, SECCLASS_X_EXTENSION, 471 &obj->sid) < 0) { 472 ErrorF("SELinux: a SID transition call failed!\n"); 473 rec->status = BadValue; 474 return; 475 } 476 } 477 478 /* Perform the security check */ 479 auditdata.extension = rec->ext->name; 480 rc = SELinuxDoCheck(subj, obj, SECCLASS_X_EXTENSION, rec->access_mode, 481 &auditdata); 482 if (rc != Success) 483 rec->status = rc; 484} 485 486static void 487SELinuxSelection(CallbackListPtr *pcbl, pointer unused, pointer calldata) 488{ 489 XaceSelectionAccessRec *rec = calldata; 490 SELinuxSubjectRec *subj; 491 SELinuxObjectRec *obj, *data; 492 Selection *pSel = *rec->ppSel; 493 Atom name = pSel->selection; 494 Mask access_mode = rec->access_mode; 495 SELinuxAuditRec auditdata = { .client = rec->client, .selection = name }; 496 security_id_t tsid; 497 int rc; 498 499 subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); 500 obj = dixLookupPrivate(&pSel->devPrivates, objectKey); 501 502 /* If this is a new object that needs labeling, do it now */ 503 if (access_mode & DixCreateAccess) { 504 rc = SELinuxSelectionToSID(name, subj, &obj->sid, &obj->poly); 505 if (rc != Success) 506 obj->sid = unlabeled_sid; 507 access_mode = DixSetAttrAccess; 508 } 509 /* If this is a polyinstantiated object, find the right instance */ 510 else if (obj->poly) { 511 rc = SELinuxSelectionToSID(name, subj, &tsid, NULL); 512 if (rc != Success) { 513 rec->status = rc; 514 return; 515 } 516 while (pSel->selection != name || obj->sid != tsid) { 517 if ((pSel = pSel->next) == NULL) 518 break; 519 obj = dixLookupPrivate(&pSel->devPrivates, objectKey); 520 } 521 522 if (pSel) 523 *rec->ppSel = pSel; 524 else { 525 rec->status = BadMatch; 526 return; 527 } 528 } 529 530 /* Perform the security check */ 531 rc = SELinuxDoCheck(subj, obj, SECCLASS_X_SELECTION, access_mode, 532 &auditdata); 533 if (rc != Success) 534 rec->status = rc; 535 536 /* Label the content (advisory only) */ 537 if (access_mode & DixSetAttrAccess) { 538 data = dixLookupPrivate(&pSel->devPrivates, dataKey); 539 if (subj->sel_create_sid) 540 data->sid = subj->sel_create_sid; 541 else 542 data->sid = obj->sid; 543 } 544} 545 546static void 547SELinuxProperty(CallbackListPtr *pcbl, pointer unused, pointer calldata) 548{ 549 XacePropertyAccessRec *rec = calldata; 550 SELinuxSubjectRec *subj; 551 SELinuxObjectRec *obj, *data; 552 PropertyPtr pProp = *rec->ppProp; 553 Atom name = pProp->propertyName; 554 SELinuxAuditRec auditdata = { .client = rec->client, .property = name }; 555 security_id_t tsid; 556 int rc; 557 558 /* Don't care about the new content check */ 559 if (rec->access_mode & DixPostAccess) 560 return; 561 562 subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); 563 obj = dixLookupPrivate(&pProp->devPrivates, objectKey); 564 565 /* If this is a new object that needs labeling, do it now */ 566 if (rec->access_mode & DixCreateAccess) { 567 rc = SELinuxPropertyToSID(name, subj, &obj->sid, &obj->poly); 568 if (rc != Success) { 569 rec->status = rc; 570 return; 571 } 572 } 573 /* If this is a polyinstantiated object, find the right instance */ 574 else if (obj->poly) { 575 rc = SELinuxPropertyToSID(name, subj, &tsid, NULL); 576 if (rc != Success) { 577 rec->status = rc; 578 return; 579 } 580 while (pProp->propertyName != name || obj->sid != tsid) { 581 if ((pProp = pProp->next) == NULL) 582 break; 583 obj = dixLookupPrivate(&pProp->devPrivates, objectKey); 584 } 585 586 if (pProp) 587 *rec->ppProp = pProp; 588 else { 589 rec->status = BadMatch; 590 return; 591 } 592 } 593 594 /* Perform the security check */ 595 rc = SELinuxDoCheck(subj, obj, SECCLASS_X_PROPERTY, rec->access_mode, 596 &auditdata); 597 if (rc != Success) 598 rec->status = rc; 599 600 /* Label the content (advisory only) */ 601 if (rec->access_mode & DixWriteAccess) { 602 data = dixLookupPrivate(&pProp->devPrivates, dataKey); 603 if (subj->prp_create_sid) 604 data->sid = subj->prp_create_sid; 605 else 606 data->sid = obj->sid; 607 } 608} 609 610static void 611SELinuxResource(CallbackListPtr *pcbl, pointer unused, pointer calldata) 612{ 613 XaceResourceAccessRec *rec = calldata; 614 SELinuxSubjectRec *subj; 615 SELinuxObjectRec *obj; 616 SELinuxAuditRec auditdata = { .client = rec->client }; 617 Mask access_mode = rec->access_mode; 618 PrivateRec **privatePtr; 619 security_class_t class; 620 int rc, offset; 621 622 subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); 623 624 /* Determine if the resource object has a devPrivates field */ 625 offset = dixLookupPrivateOffset(rec->rtype); 626 if (offset < 0) { 627 /* No: use the SID of the owning client */ 628 class = SECCLASS_X_RESOURCE; 629 privatePtr = &clients[CLIENT_ID(rec->id)]->devPrivates; 630 obj = dixLookupPrivate(privatePtr, objectKey); 631 } else { 632 /* Yes: use the SID from the resource object itself */ 633 class = SELinuxTypeToClass(rec->rtype); 634 privatePtr = DEVPRIV_AT(rec->res, offset); 635 obj = dixLookupPrivate(privatePtr, objectKey); 636 } 637 638 /* If this is a new object that needs labeling, do it now */ 639 if (access_mode & DixCreateAccess && offset >= 0) { 640 rc = SELinuxLabelResource(rec, subj, obj, class); 641 if (rc != Success) { 642 rec->status = rc; 643 return; 644 } 645 } 646 647 /* Collapse generic resource permissions down to read/write */ 648 if (class == SECCLASS_X_RESOURCE) { 649 access_mode = !!(rec->access_mode & SELinuxReadMask); /* rd */ 650 access_mode |= !!(rec->access_mode & ~SELinuxReadMask) << 1; /* wr */ 651 } 652 653 /* Perform the security check */ 654 auditdata.restype = rec->rtype; 655 auditdata.id = rec->id; 656 rc = SELinuxDoCheck(subj, obj, class, access_mode, &auditdata); 657 if (rc != Success) 658 rec->status = rc; 659 660 /* Perform the background none check on windows */ 661 if (access_mode & DixCreateAccess && rec->rtype == RT_WINDOW) { 662 rc = SELinuxDoCheck(subj, obj, class, DixBlendAccess, &auditdata); 663 if (rc != Success) 664 ((WindowPtr)rec->res)->forcedBG = TRUE; 665 } 666} 667 668static void 669SELinuxScreen(CallbackListPtr *pcbl, pointer is_saver, pointer calldata) 670{ 671 XaceScreenAccessRec *rec = calldata; 672 SELinuxSubjectRec *subj; 673 SELinuxObjectRec *obj; 674 SELinuxAuditRec auditdata = { .client = rec->client }; 675 Mask access_mode = rec->access_mode; 676 int rc; 677 678 subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); 679 obj = dixLookupPrivate(&rec->screen->devPrivates, objectKey); 680 681 /* If this is a new object that needs labeling, do it now */ 682 if (access_mode & DixCreateAccess) { 683 /* Perform a transition to obtain the final SID */ 684 if (avc_compute_create(subj->sid, subj->sid, SECCLASS_X_SCREEN, 685 &obj->sid) < 0) { 686 ErrorF("SELinux: a compute_create call failed!\n"); 687 rec->status = BadValue; 688 return; 689 } 690 } 691 692 if (is_saver) 693 access_mode <<= 2; 694 695 rc = SELinuxDoCheck(subj, obj, SECCLASS_X_SCREEN, access_mode, &auditdata); 696 if (rc != Success) 697 rec->status = rc; 698} 699 700static void 701SELinuxClient(CallbackListPtr *pcbl, pointer unused, pointer calldata) 702{ 703 XaceClientAccessRec *rec = calldata; 704 SELinuxSubjectRec *subj; 705 SELinuxObjectRec *obj; 706 SELinuxAuditRec auditdata = { .client = rec->client }; 707 int rc; 708 709 subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); 710 obj = dixLookupPrivate(&rec->target->devPrivates, objectKey); 711 712 rc = SELinuxDoCheck(subj, obj, SECCLASS_X_CLIENT, rec->access_mode, 713 &auditdata); 714 if (rc != Success) 715 rec->status = rc; 716} 717 718static void 719SELinuxServer(CallbackListPtr *pcbl, pointer unused, pointer calldata) 720{ 721 XaceServerAccessRec *rec = calldata; 722 SELinuxSubjectRec *subj; 723 SELinuxObjectRec *obj; 724 SELinuxAuditRec auditdata = { .client = rec->client }; 725 int rc; 726 727 subj = dixLookupPrivate(&rec->client->devPrivates, subjectKey); 728 obj = dixLookupPrivate(&serverClient->devPrivates, objectKey); 729 730 rc = SELinuxDoCheck(subj, obj, SECCLASS_X_SERVER, rec->access_mode, 731 &auditdata); 732 if (rc != Success) 733 rec->status = rc; 734} 735 736 737/* 738 * DIX Callbacks 739 */ 740 741static void 742SELinuxClientState(CallbackListPtr *pcbl, pointer unused, pointer calldata) 743{ 744 NewClientInfoRec *pci = calldata; 745 746 switch (pci->client->clientState) { 747 case ClientStateInitial: 748 SELinuxLabelClient(pci->client); 749 break; 750 751 default: 752 break; 753 } 754} 755 756static void 757SELinuxResourceState(CallbackListPtr *pcbl, pointer unused, pointer calldata) 758{ 759 ResourceStateInfoRec *rec = calldata; 760 SELinuxSubjectRec *subj; 761 SELinuxObjectRec *obj; 762 WindowPtr pWin; 763 764 if (rec->type != RT_WINDOW) 765 return; 766 if (rec->state != ResourceStateAdding) 767 return; 768 769 pWin = (WindowPtr)rec->value; 770 subj = dixLookupPrivate(&wClient(pWin)->devPrivates, subjectKey); 771 772 if (subj->sid) { 773 security_context_t ctx; 774 int rc = avc_sid_to_context_raw(subj->sid, &ctx); 775 if (rc < 0) 776 FatalError("SELinux: Failed to get security context!\n"); 777 rc = dixChangeWindowProperty(serverClient, 778 pWin, atom_client_ctx, XA_STRING, 8, 779 PropModeReplace, strlen(ctx), ctx, FALSE); 780 if (rc != Success) 781 FatalError("SELinux: Failed to set label property on window!\n"); 782 freecon(ctx); 783 } else 784 FatalError("SELinux: Unexpected unlabeled client found\n"); 785 786 obj = dixLookupPrivate(&pWin->devPrivates, objectKey); 787 788 if (obj->sid) { 789 security_context_t ctx; 790 int rc = avc_sid_to_context_raw(obj->sid, &ctx); 791 if (rc < 0) 792 FatalError("SELinux: Failed to get security context!\n"); 793 rc = dixChangeWindowProperty(serverClient, 794 pWin, atom_ctx, XA_STRING, 8, 795 PropModeReplace, strlen(ctx), ctx, FALSE); 796 if (rc != Success) 797 FatalError("SELinux: Failed to set label property on window!\n"); 798 freecon(ctx); 799 } else 800 FatalError("SELinux: Unexpected unlabeled window found\n"); 801} 802 803 804static int netlink_fd; 805 806static void 807SELinuxBlockHandler(void *data, struct timeval **tv, void *read_mask) 808{ 809} 810 811static void 812SELinuxWakeupHandler(void *data, int err, void *read_mask) 813{ 814 if (FD_ISSET(netlink_fd, (fd_set *)read_mask)) 815 avc_netlink_check_nb(); 816} 817 818void 819SELinuxFlaskReset(void) 820{ 821 /* Unregister callbacks */ 822 DeleteCallback(&ClientStateCallback, SELinuxClientState, NULL); 823 DeleteCallback(&ResourceStateCallback, SELinuxResourceState, NULL); 824 825 XaceDeleteCallback(XACE_EXT_DISPATCH, SELinuxExtension, NULL); 826 XaceDeleteCallback(XACE_RESOURCE_ACCESS, SELinuxResource, NULL); 827 XaceDeleteCallback(XACE_DEVICE_ACCESS, SELinuxDevice, NULL); 828 XaceDeleteCallback(XACE_PROPERTY_ACCESS, SELinuxProperty, NULL); 829 XaceDeleteCallback(XACE_SEND_ACCESS, SELinuxSend, NULL); 830 XaceDeleteCallback(XACE_RECEIVE_ACCESS, SELinuxReceive, NULL); 831 XaceDeleteCallback(XACE_CLIENT_ACCESS, SELinuxClient, NULL); 832 XaceDeleteCallback(XACE_EXT_ACCESS, SELinuxExtension, NULL); 833 XaceDeleteCallback(XACE_SERVER_ACCESS, SELinuxServer, NULL); 834 XaceDeleteCallback(XACE_SELECTION_ACCESS, SELinuxSelection, NULL); 835 XaceDeleteCallback(XACE_SCREEN_ACCESS, SELinuxScreen, NULL); 836 XaceDeleteCallback(XACE_SCREENSAVER_ACCESS, SELinuxScreen, truep); 837 838 /* Tear down SELinux stuff */ 839 audit_close(audit_fd); 840 avc_netlink_release_fd(); 841 RemoveBlockAndWakeupHandlers(SELinuxBlockHandler, SELinuxWakeupHandler, 842 NULL); 843 RemoveGeneralSocket(netlink_fd); 844 845 avc_destroy(); 846} 847 848void 849SELinuxFlaskInit(void) 850{ 851 struct selinux_opt avc_option = { AVC_OPT_SETENFORCE, (char *)0 }; 852 security_context_t ctx; 853 int ret = TRUE; 854 855 switch(selinuxEnforcingState) { 856 case SELINUX_MODE_ENFORCING: 857 LogMessage(X_INFO, "SELinux: Configured in enforcing mode\n"); 858 avc_option.value = (char *)1; 859 break; 860 case SELINUX_MODE_PERMISSIVE: 861 LogMessage(X_INFO, "SELinux: Configured in permissive mode\n"); 862 avc_option.value = (char *)0; 863 break; 864 default: 865 avc_option.type = AVC_OPT_UNUSED; 866 break; 867 } 868 869 /* Set up SELinux stuff */ 870 selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback)SELinuxLog); 871 selinux_set_callback(SELINUX_CB_AUDIT, (union selinux_callback)SELinuxAudit); 872 873 if (selinux_set_mapping(map) < 0) { 874 if (errno == EINVAL) { 875 ErrorF("SELinux: Invalid object class mapping, disabling SELinux support.\n"); 876 return; 877 } 878 FatalError("SELinux: Failed to set up security class mapping\n"); 879 } 880 881 if (avc_open(&avc_option, 1) < 0) 882 FatalError("SELinux: Couldn't initialize SELinux userspace AVC\n"); 883 884 if (security_get_initial_context_raw("unlabeled", &ctx) < 0) 885 FatalError("SELinux: Failed to look up unlabeled context\n"); 886 if (avc_context_to_sid_raw(ctx, &unlabeled_sid) < 0) 887 FatalError("SELinux: a context_to_SID call failed!\n"); 888 freecon(ctx); 889 890 /* Prepare for auditing */ 891 audit_fd = audit_open(); 892 if (audit_fd < 0) 893 FatalError("SELinux: Failed to open the system audit log\n"); 894 895 /* Allocate private storage */ 896 if (!dixRegisterPrivateKey(subjectKey, PRIVATE_XSELINUX, sizeof(SELinuxSubjectRec)) || 897 !dixRegisterPrivateKey(objectKey, PRIVATE_XSELINUX, sizeof(SELinuxObjectRec)) || 898 !dixRegisterPrivateKey(dataKey, PRIVATE_XSELINUX, sizeof(SELinuxObjectRec))) 899 FatalError("SELinux: Failed to allocate private storage.\n"); 900 901 /* Create atoms for doing window labeling */ 902 atom_ctx = MakeAtom("_SELINUX_CONTEXT", 16, TRUE); 903 if (atom_ctx == BAD_RESOURCE) 904 FatalError("SELinux: Failed to create atom\n"); 905 atom_client_ctx = MakeAtom("_SELINUX_CLIENT_CONTEXT", 23, TRUE); 906 if (atom_client_ctx == BAD_RESOURCE) 907 FatalError("SELinux: Failed to create atom\n"); 908 909 netlink_fd = avc_netlink_acquire_fd(); 910 AddGeneralSocket(netlink_fd); 911 RegisterBlockAndWakeupHandlers(SELinuxBlockHandler, SELinuxWakeupHandler, 912 NULL); 913 914 /* Register callbacks */ 915 ret &= AddCallback(&ClientStateCallback, SELinuxClientState, NULL); 916 ret &= AddCallback(&ResourceStateCallback, SELinuxResourceState, NULL); 917 918 ret &= XaceRegisterCallback(XACE_EXT_DISPATCH, SELinuxExtension, NULL); 919 ret &= XaceRegisterCallback(XACE_RESOURCE_ACCESS, SELinuxResource, NULL); 920 ret &= XaceRegisterCallback(XACE_DEVICE_ACCESS, SELinuxDevice, NULL); 921 ret &= XaceRegisterCallback(XACE_PROPERTY_ACCESS, SELinuxProperty, NULL); 922 ret &= XaceRegisterCallback(XACE_SEND_ACCESS, SELinuxSend, NULL); 923 ret &= XaceRegisterCallback(XACE_RECEIVE_ACCESS, SELinuxReceive, NULL); 924 ret &= XaceRegisterCallback(XACE_CLIENT_ACCESS, SELinuxClient, NULL); 925 ret &= XaceRegisterCallback(XACE_EXT_ACCESS, SELinuxExtension, NULL); 926 ret &= XaceRegisterCallback(XACE_SERVER_ACCESS, SELinuxServer, NULL); 927 ret &= XaceRegisterCallback(XACE_SELECTION_ACCESS, SELinuxSelection, NULL); 928 ret &= XaceRegisterCallback(XACE_SCREEN_ACCESS, SELinuxScreen, NULL); 929 ret &= XaceRegisterCallback(XACE_SCREENSAVER_ACCESS, SELinuxScreen, truep); 930 if (!ret) 931 FatalError("SELinux: Failed to register one or more callbacks\n"); 932 933 /* Label objects that were created before we could register ourself */ 934 SELinuxLabelInitial(); 935} 936