diff options
Diffstat (limited to 'xorg-server/Xext/xselinux_label.c')
-rw-r--r-- | xorg-server/Xext/xselinux_label.c | 755 |
1 files changed, 381 insertions, 374 deletions
diff --git a/xorg-server/Xext/xselinux_label.c b/xorg-server/Xext/xselinux_label.c index 76e537abe..2c33d1cbf 100644 --- a/xorg-server/Xext/xselinux_label.c +++ b/xorg-server/Xext/xselinux_label.c @@ -1,374 +1,381 @@ -/************************************************************
-
-Author: Eamon Walsh <ewalsh@tycho.nsa.gov>
-
-Permission to use, copy, modify, distribute, and sell this software and its
-documentation for any purpose is hereby granted without fee, provided that
-this permission notice appear in supporting documentation. This permission
-notice shall be included in all copies or substantial portions of the
-Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
-AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-********************************************************/
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#include <selinux/label.h>
-
-#include "registry.h"
-#include "xselinuxint.h"
-
-/* selection and property atom cache */
-typedef struct {
- SELinuxObjectRec prp;
- SELinuxObjectRec sel;
-} SELinuxAtomRec;
-
-/* dynamic array */
-typedef struct {
- unsigned size;
- void **array;
-} SELinuxArrayRec;
-
-/* labeling handle */
-static struct selabel_handle *label_hnd;
-
-/* Array of object classes indexed by resource type */
-SELinuxArrayRec arr_types;
-/* Array of event SIDs indexed by event type */
-SELinuxArrayRec arr_events;
-/* Array of property and selection SID structures */
-SELinuxArrayRec arr_atoms;
-
-/*
- * Dynamic array helpers
- */
-static void *
-SELinuxArrayGet(SELinuxArrayRec *rec, unsigned key)
-{
- return (rec->size > key) ? rec->array[key] : 0;
-}
-
-static int
-SELinuxArraySet(SELinuxArrayRec *rec, unsigned key, void *val)
-{
- if (key >= rec->size) {
- /* Need to increase size of array */
- rec->array = realloc(rec->array, (key + 1) * sizeof(val));
- if (!rec->array)
- return FALSE;
- memset(rec->array + rec->size, 0, (key - rec->size + 1) * sizeof(val));
- rec->size = key + 1;
- }
-
- rec->array[key] = val;
- return TRUE;
-}
-
-static void
-SELinuxArrayFree(SELinuxArrayRec *rec, int free_elements)
-{
- if (free_elements) {
- unsigned i = rec->size;
- while (i)
- free(rec->array[--i]);
- }
-
- free(rec->array);
- rec->size = 0;
- rec->array = NULL;
-}
-
-/*
- * Looks up a name in the selection or property mappings
- */
-static int
-SELinuxAtomToSIDLookup(Atom atom, SELinuxObjectRec *obj, int map, int polymap)
-{
- const char *name = NameForAtom(atom);
- security_context_t ctx;
- int rc = Success;
-
- obj->poly = 1;
-
- /* Look in the mappings of names to contexts */
- if (selabel_lookup_raw(label_hnd, &ctx, name, map) == 0) {
- obj->poly = 0;
- } else if (errno != ENOENT) {
- ErrorF("SELinux: a property label lookup failed!\n");
- return BadValue;
- } else if (selabel_lookup_raw(label_hnd, &ctx, name, polymap) < 0) {
- ErrorF("SELinux: a property label lookup failed!\n");
- return BadValue;
- }
-
- /* Get a SID for context */
- if (avc_context_to_sid_raw(ctx, &obj->sid) < 0) {
- ErrorF("SELinux: a context_to_SID_raw call failed!\n");
- rc = BadAlloc;
- }
-
- freecon(ctx);
- return rc;
-}
-
-/*
- * Looks up the SID corresponding to the given property or selection atom
- */
-int
-SELinuxAtomToSID(Atom atom, int prop, SELinuxObjectRec **obj_rtn)
-{
- SELinuxAtomRec *rec;
- SELinuxObjectRec *obj;
- int rc, map, polymap;
-
- rec = SELinuxArrayGet(&arr_atoms, atom);
- if (!rec) {
- rec = calloc(1, sizeof(SELinuxAtomRec));
- if (!rec || !SELinuxArraySet(&arr_atoms, atom, rec))
- return BadAlloc;
- }
-
- if (prop) {
- obj = &rec->prp;
- map = SELABEL_X_PROP;
- polymap = SELABEL_X_POLYPROP;
- } else {
- obj = &rec->sel;
- map = SELABEL_X_SELN;
- polymap = SELABEL_X_POLYSELN;
- }
-
- if (!obj->sid) {
- rc = SELinuxAtomToSIDLookup(atom, obj, map, polymap);
- if (rc != Success)
- goto out;
- }
-
- *obj_rtn = obj;
- rc = Success;
-out:
- return rc;
-}
-
-/*
- * Looks up a SID for a selection/subject pair
- */
-int
-SELinuxSelectionToSID(Atom selection, SELinuxSubjectRec *subj,
- security_id_t *sid_rtn, int *poly_rtn)
-{
- int rc;
- SELinuxObjectRec *obj;
- security_id_t tsid;
-
- /* Get the default context and polyinstantiation bit */
- rc = SELinuxAtomToSID(selection, 0, &obj);
- if (rc != Success)
- return rc;
-
- /* Check for an override context next */
- if (subj->sel_use_sid) {
- tsid = subj->sel_use_sid;
- goto out;
- }
-
- tsid = obj->sid;
-
- /* Polyinstantiate if necessary to obtain the final SID */
- if (obj->poly && avc_compute_member(subj->sid, obj->sid,
- SECCLASS_X_SELECTION, &tsid) < 0) {
- ErrorF("SELinux: a compute_member call failed!\n");
- return BadValue;
- }
-out:
- *sid_rtn = tsid;
- if (poly_rtn)
- *poly_rtn = obj->poly;
- return Success;
-}
-
-/*
- * Looks up a SID for a property/subject pair
- */
-int
-SELinuxPropertyToSID(Atom property, SELinuxSubjectRec *subj,
- security_id_t *sid_rtn, int *poly_rtn)
-{
- int rc;
- SELinuxObjectRec *obj;
- security_id_t tsid, tsid2;
-
- /* Get the default context and polyinstantiation bit */
- rc = SELinuxAtomToSID(property, 1, &obj);
- if (rc != Success)
- return rc;
-
- /* Check for an override context next */
- if (subj->prp_use_sid) {
- tsid = subj->prp_use_sid;
- goto out;
- }
-
- /* Perform a transition */
- if (avc_compute_create(subj->sid, obj->sid,
- SECCLASS_X_PROPERTY, &tsid) < 0) {
- ErrorF("SELinux: a compute_create call failed!\n");
- return BadValue;
- }
-
- /* Polyinstantiate if necessary to obtain the final SID */
- if (obj->poly) {
- tsid2 = tsid;
- if (avc_compute_member(subj->sid, tsid2,
- SECCLASS_X_PROPERTY, &tsid) < 0) {
- ErrorF("SELinux: a compute_member call failed!\n");
- return BadValue;
- }
- }
-out:
- *sid_rtn = tsid;
- if (poly_rtn)
- *poly_rtn = obj->poly;
- return Success;
-}
-
-/*
- * Looks up the SID corresponding to the given event type
- */
-int
-SELinuxEventToSID(unsigned type, security_id_t sid_of_window,
- SELinuxObjectRec *sid_return)
-{
- const char *name = LookupEventName(type);
- security_id_t sid;
- security_context_t ctx;
- type &= 127;
-
- sid = SELinuxArrayGet(&arr_events, type);
- if (!sid) {
- /* Look in the mappings of event names to contexts */
- if (selabel_lookup_raw(label_hnd, &ctx, name, SELABEL_X_EVENT) < 0) {
- ErrorF("SELinux: an event label lookup failed!\n");
- return BadValue;
- }
- /* Get a SID for context */
- if (avc_context_to_sid_raw(ctx, &sid) < 0) {
- ErrorF("SELinux: a context_to_SID_raw call failed!\n");
- freecon(ctx);
- return BadAlloc;
- }
- freecon(ctx);
- /* Cache the SID value */
- if (!SELinuxArraySet(&arr_events, type, sid))
- return BadAlloc;
- }
-
- /* Perform a transition to obtain the final SID */
- if (avc_compute_create(sid_of_window, sid, SECCLASS_X_EVENT,
- &sid_return->sid) < 0) {
- ErrorF("SELinux: a compute_create call failed!\n");
- return BadValue;
- }
-
- return Success;
-}
-
-int
-SELinuxExtensionToSID(const char *name, security_id_t *sid_rtn)
-{
- security_context_t ctx;
-
- /* Look in the mappings of extension names to contexts */
- if (selabel_lookup_raw(label_hnd, &ctx, name, SELABEL_X_EXT) < 0) {
- ErrorF("SELinux: a property label lookup failed!\n");
- return BadValue;
- }
- /* Get a SID for context */
- if (avc_context_to_sid_raw(ctx, sid_rtn) < 0) {
- ErrorF("SELinux: a context_to_SID_raw call failed!\n");
- freecon(ctx);
- return BadAlloc;
- }
- freecon(ctx);
- return Success;
-}
-
-/*
- * Returns the object class corresponding to the given resource type.
- */
-security_class_t
-SELinuxTypeToClass(RESTYPE type)
-{
- void *tmp;
-
- tmp = SELinuxArrayGet(&arr_types, type & TypeMask);
- if (!tmp) {
- unsigned long class = SECCLASS_X_RESOURCE;
-
- if (type & RC_DRAWABLE)
- class = SECCLASS_X_DRAWABLE;
- else if (type == RT_GC)
- class = SECCLASS_X_GC;
- else if (type == RT_FONT)
- class = SECCLASS_X_FONT;
- else if (type == RT_CURSOR)
- class = SECCLASS_X_CURSOR;
- else if (type == RT_COLORMAP)
- class = SECCLASS_X_COLORMAP;
- else {
- /* Need to do a string lookup */
- const char *str = LookupResourceName(type);
- if (!strcmp(str, "PICTURE"))
- class = SECCLASS_X_DRAWABLE;
- else if (!strcmp(str, "GLYPHSET"))
- class = SECCLASS_X_FONT;
- }
-
- tmp = (void *)class;
- SELinuxArraySet(&arr_types, type & TypeMask, tmp);
- }
-
- return (security_class_t)(unsigned long)tmp;
-}
-
-security_context_t
-SELinuxDefaultClientLabel(void)
-{
- security_context_t ctx;
-
- if (selabel_lookup_raw(label_hnd, &ctx, "remote", SELABEL_X_CLIENT) < 0)
- FatalError("SELinux: failed to look up remote-client context\n");
-
- return ctx;
-}
-
-void
-SELinuxLabelInit(void)
-{
- struct selinux_opt selabel_option = { SELABEL_OPT_VALIDATE, (char *)1 };
-
- label_hnd = selabel_open(SELABEL_CTX_X, &selabel_option, 1);
- if (!label_hnd)
- FatalError("SELinux: Failed to open x_contexts mapping in policy\n");
-}
-
-void
-SELinuxLabelReset(void)
-{
- selabel_close(label_hnd);
- label_hnd = NULL;
-
- /* Free local state */
- SELinuxArrayFree(&arr_types, 0);
- SELinuxArrayFree(&arr_events, 0);
- SELinuxArrayFree(&arr_atoms, 1);
-}
+/************************************************************ + +Author: Eamon Walsh <ewalsh@tycho.nsa.gov> + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +this permission notice appear in supporting documentation. This permission +notice shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +********************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <selinux/label.h> + +#include "registry.h" +#include "xselinuxint.h" + +/* selection and property atom cache */ +typedef struct { + SELinuxObjectRec prp; + SELinuxObjectRec sel; +} SELinuxAtomRec; + +/* dynamic array */ +typedef struct { + unsigned size; + void **array; +} SELinuxArrayRec; + +/* labeling handle */ +static struct selabel_handle *label_hnd; + +/* Array of object classes indexed by resource type */ +SELinuxArrayRec arr_types; + +/* Array of event SIDs indexed by event type */ +SELinuxArrayRec arr_events; + +/* Array of property and selection SID structures */ +SELinuxArrayRec arr_atoms; + +/* + * Dynamic array helpers + */ +static void * +SELinuxArrayGet(SELinuxArrayRec * rec, unsigned key) +{ + return (rec->size > key) ? rec->array[key] : 0; +} + +static int +SELinuxArraySet(SELinuxArrayRec * rec, unsigned key, void *val) +{ + if (key >= rec->size) { + /* Need to increase size of array */ + rec->array = realloc(rec->array, (key + 1) * sizeof(val)); + if (!rec->array) + return FALSE; + memset(rec->array + rec->size, 0, (key - rec->size + 1) * sizeof(val)); + rec->size = key + 1; + } + + rec->array[key] = val; + return TRUE; +} + +static void +SELinuxArrayFree(SELinuxArrayRec * rec, int free_elements) +{ + if (free_elements) { + unsigned i = rec->size; + + while (i) + free(rec->array[--i]); + } + + free(rec->array); + rec->size = 0; + rec->array = NULL; +} + +/* + * Looks up a name in the selection or property mappings + */ +static int +SELinuxAtomToSIDLookup(Atom atom, SELinuxObjectRec * obj, int map, int polymap) +{ + const char *name = NameForAtom(atom); + security_context_t ctx; + int rc = Success; + + obj->poly = 1; + + /* Look in the mappings of names to contexts */ + if (selabel_lookup_raw(label_hnd, &ctx, name, map) == 0) { + obj->poly = 0; + } + else if (errno != ENOENT) { + ErrorF("SELinux: a property label lookup failed!\n"); + return BadValue; + } + else if (selabel_lookup_raw(label_hnd, &ctx, name, polymap) < 0) { + ErrorF("SELinux: a property label lookup failed!\n"); + return BadValue; + } + + /* Get a SID for context */ + if (avc_context_to_sid_raw(ctx, &obj->sid) < 0) { + ErrorF("SELinux: a context_to_SID_raw call failed!\n"); + rc = BadAlloc; + } + + freecon(ctx); + return rc; +} + +/* + * Looks up the SID corresponding to the given property or selection atom + */ +int +SELinuxAtomToSID(Atom atom, int prop, SELinuxObjectRec ** obj_rtn) +{ + SELinuxAtomRec *rec; + SELinuxObjectRec *obj; + int rc, map, polymap; + + rec = SELinuxArrayGet(&arr_atoms, atom); + if (!rec) { + rec = calloc(1, sizeof(SELinuxAtomRec)); + if (!rec || !SELinuxArraySet(&arr_atoms, atom, rec)) + return BadAlloc; + } + + if (prop) { + obj = &rec->prp; + map = SELABEL_X_PROP; + polymap = SELABEL_X_POLYPROP; + } + else { + obj = &rec->sel; + map = SELABEL_X_SELN; + polymap = SELABEL_X_POLYSELN; + } + + if (!obj->sid) { + rc = SELinuxAtomToSIDLookup(atom, obj, map, polymap); + if (rc != Success) + goto out; + } + + *obj_rtn = obj; + rc = Success; + out: + return rc; +} + +/* + * Looks up a SID for a selection/subject pair + */ +int +SELinuxSelectionToSID(Atom selection, SELinuxSubjectRec * subj, + security_id_t * sid_rtn, int *poly_rtn) +{ + int rc; + SELinuxObjectRec *obj; + security_id_t tsid; + + /* Get the default context and polyinstantiation bit */ + rc = SELinuxAtomToSID(selection, 0, &obj); + if (rc != Success) + return rc; + + /* Check for an override context next */ + if (subj->sel_use_sid) { + tsid = subj->sel_use_sid; + goto out; + } + + tsid = obj->sid; + + /* Polyinstantiate if necessary to obtain the final SID */ + if (obj->poly && avc_compute_member(subj->sid, obj->sid, + SECCLASS_X_SELECTION, &tsid) < 0) { + ErrorF("SELinux: a compute_member call failed!\n"); + return BadValue; + } + out: + *sid_rtn = tsid; + if (poly_rtn) + *poly_rtn = obj->poly; + return Success; +} + +/* + * Looks up a SID for a property/subject pair + */ +int +SELinuxPropertyToSID(Atom property, SELinuxSubjectRec * subj, + security_id_t * sid_rtn, int *poly_rtn) +{ + int rc; + SELinuxObjectRec *obj; + security_id_t tsid, tsid2; + + /* Get the default context and polyinstantiation bit */ + rc = SELinuxAtomToSID(property, 1, &obj); + if (rc != Success) + return rc; + + /* Check for an override context next */ + if (subj->prp_use_sid) { + tsid = subj->prp_use_sid; + goto out; + } + + /* Perform a transition */ + if (avc_compute_create(subj->sid, obj->sid, SECCLASS_X_PROPERTY, &tsid) < 0) { + ErrorF("SELinux: a compute_create call failed!\n"); + return BadValue; + } + + /* Polyinstantiate if necessary to obtain the final SID */ + if (obj->poly) { + tsid2 = tsid; + if (avc_compute_member(subj->sid, tsid2, + SECCLASS_X_PROPERTY, &tsid) < 0) { + ErrorF("SELinux: a compute_member call failed!\n"); + return BadValue; + } + } + out: + *sid_rtn = tsid; + if (poly_rtn) + *poly_rtn = obj->poly; + return Success; +} + +/* + * Looks up the SID corresponding to the given event type + */ +int +SELinuxEventToSID(unsigned type, security_id_t sid_of_window, + SELinuxObjectRec * sid_return) +{ + const char *name = LookupEventName(type); + security_id_t sid; + security_context_t ctx; + + type &= 127; + + sid = SELinuxArrayGet(&arr_events, type); + if (!sid) { + /* Look in the mappings of event names to contexts */ + if (selabel_lookup_raw(label_hnd, &ctx, name, SELABEL_X_EVENT) < 0) { + ErrorF("SELinux: an event label lookup failed!\n"); + return BadValue; + } + /* Get a SID for context */ + if (avc_context_to_sid_raw(ctx, &sid) < 0) { + ErrorF("SELinux: a context_to_SID_raw call failed!\n"); + freecon(ctx); + return BadAlloc; + } + freecon(ctx); + /* Cache the SID value */ + if (!SELinuxArraySet(&arr_events, type, sid)) + return BadAlloc; + } + + /* Perform a transition to obtain the final SID */ + if (avc_compute_create(sid_of_window, sid, SECCLASS_X_EVENT, + &sid_return->sid) < 0) { + ErrorF("SELinux: a compute_create call failed!\n"); + return BadValue; + } + + return Success; +} + +int +SELinuxExtensionToSID(const char *name, security_id_t * sid_rtn) +{ + security_context_t ctx; + + /* Look in the mappings of extension names to contexts */ + if (selabel_lookup_raw(label_hnd, &ctx, name, SELABEL_X_EXT) < 0) { + ErrorF("SELinux: a property label lookup failed!\n"); + return BadValue; + } + /* Get a SID for context */ + if (avc_context_to_sid_raw(ctx, sid_rtn) < 0) { + ErrorF("SELinux: a context_to_SID_raw call failed!\n"); + freecon(ctx); + return BadAlloc; + } + freecon(ctx); + return Success; +} + +/* + * Returns the object class corresponding to the given resource type. + */ +security_class_t +SELinuxTypeToClass(RESTYPE type) +{ + void *tmp; + + tmp = SELinuxArrayGet(&arr_types, type & TypeMask); + if (!tmp) { + unsigned long class = SECCLASS_X_RESOURCE; + + if (type & RC_DRAWABLE) + class = SECCLASS_X_DRAWABLE; + else if (type == RT_GC) + class = SECCLASS_X_GC; + else if (type == RT_FONT) + class = SECCLASS_X_FONT; + else if (type == RT_CURSOR) + class = SECCLASS_X_CURSOR; + else if (type == RT_COLORMAP) + class = SECCLASS_X_COLORMAP; + else { + /* Need to do a string lookup */ + const char *str = LookupResourceName(type); + + if (!strcmp(str, "PICTURE")) + class = SECCLASS_X_DRAWABLE; + else if (!strcmp(str, "GLYPHSET")) + class = SECCLASS_X_FONT; + } + + tmp = (void *) class; + SELinuxArraySet(&arr_types, type & TypeMask, tmp); + } + + return (security_class_t) (unsigned long) tmp; +} + +security_context_t +SELinuxDefaultClientLabel(void) +{ + security_context_t ctx; + + if (selabel_lookup_raw(label_hnd, &ctx, "remote", SELABEL_X_CLIENT) < 0) + FatalError("SELinux: failed to look up remote-client context\n"); + + return ctx; +} + +void +SELinuxLabelInit(void) +{ + struct selinux_opt selabel_option = { SELABEL_OPT_VALIDATE, (char *) 1 }; + + label_hnd = selabel_open(SELABEL_CTX_X, &selabel_option, 1); + if (!label_hnd) + FatalError("SELinux: Failed to open x_contexts mapping in policy\n"); +} + +void +SELinuxLabelReset(void) +{ + selabel_close(label_hnd); + label_hnd = NULL; + + /* Free local state */ + SELinuxArrayFree(&arr_types, 0); + SELinuxArrayFree(&arr_events, 0); + SELinuxArrayFree(&arr_atoms, 1); +} |