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