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