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#ifdef HAVE_DIX_CONFIG_H 21#include <dix-config.h> 22#endif 23 24#include <selinux/label.h> 25 26#include "registry.h" 27#include "xselinuxint.h" 28 29/* selection and property atom cache */ 30typedef struct { 31 SELinuxObjectRec prp; 32 SELinuxObjectRec sel; 33} SELinuxAtomRec; 34 35/* dynamic array */ 36typedef struct { 37 unsigned size; 38 void **array; 39} SELinuxArrayRec; 40 41/* labeling handle */ 42static struct selabel_handle *label_hnd; 43 44/* Array of object classes indexed by resource type */ 45SELinuxArrayRec arr_types; 46/* Array of event SIDs indexed by event type */ 47SELinuxArrayRec arr_events; 48/* Array of property and selection SID structures */ 49SELinuxArrayRec arr_atoms; 50 51/* 52 * Dynamic array helpers 53 */ 54static void * 55SELinuxArrayGet(SELinuxArrayRec *rec, unsigned key) 56{ 57 return (rec->size > key) ? rec->array[key] : 0; 58} 59 60static int 61SELinuxArraySet(SELinuxArrayRec *rec, unsigned key, void *val) 62{ 63 if (key >= rec->size) { 64 /* Need to increase size of array */ 65 rec->array = realloc(rec->array, (key + 1) * sizeof(val)); 66 if (!rec->array) 67 return FALSE; 68 memset(rec->array + rec->size, 0, (key - rec->size + 1) * sizeof(val)); 69 rec->size = key + 1; 70 } 71 72 rec->array[key] = val; 73 return TRUE; 74} 75 76static void 77SELinuxArrayFree(SELinuxArrayRec *rec, int free_elements) 78{ 79 if (free_elements) { 80 unsigned i = rec->size; 81 while (i) 82 free(rec->array[--i]); 83 } 84 85 free(rec->array); 86 rec->size = 0; 87 rec->array = NULL; 88} 89 90/* 91 * Looks up a name in the selection or property mappings 92 */ 93static int 94SELinuxAtomToSIDLookup(Atom atom, SELinuxObjectRec *obj, int map, int polymap) 95{ 96 const char *name = NameForAtom(atom); 97 security_context_t ctx; 98 int rc = Success; 99 100 obj->poly = 1; 101 102 /* Look in the mappings of names to contexts */ 103 if (selabel_lookup_raw(label_hnd, &ctx, name, map) == 0) { 104 obj->poly = 0; 105 } else if (errno != ENOENT) { 106 ErrorF("SELinux: a property label lookup failed!\n"); 107 return BadValue; 108 } else if (selabel_lookup_raw(label_hnd, &ctx, name, polymap) < 0) { 109 ErrorF("SELinux: a property label lookup failed!\n"); 110 return BadValue; 111 } 112 113 /* Get a SID for context */ 114 if (avc_context_to_sid_raw(ctx, &obj->sid) < 0) { 115 ErrorF("SELinux: a context_to_SID_raw call failed!\n"); 116 rc = BadAlloc; 117 } 118 119 freecon(ctx); 120 return rc; 121} 122 123/* 124 * Looks up the SID corresponding to the given property or selection atom 125 */ 126int 127SELinuxAtomToSID(Atom atom, int prop, SELinuxObjectRec **obj_rtn) 128{ 129 SELinuxAtomRec *rec; 130 SELinuxObjectRec *obj; 131 int rc, map, polymap; 132 133 rec = SELinuxArrayGet(&arr_atoms, atom); 134 if (!rec) { 135 rec = calloc(1, sizeof(SELinuxAtomRec)); 136 if (!rec || !SELinuxArraySet(&arr_atoms, atom, rec)) 137 return BadAlloc; 138 } 139 140 if (prop) { 141 obj = &rec->prp; 142 map = SELABEL_X_PROP; 143 polymap = SELABEL_X_POLYPROP; 144 } else { 145 obj = &rec->sel; 146 map = SELABEL_X_SELN; 147 polymap = SELABEL_X_POLYSELN; 148 } 149 150 if (!obj->sid) { 151 rc = SELinuxAtomToSIDLookup(atom, obj, map, polymap); 152 if (rc != Success) 153 goto out; 154 } 155 156 *obj_rtn = obj; 157 rc = Success; 158out: 159 return rc; 160} 161 162/* 163 * Looks up a SID for a selection/subject pair 164 */ 165int 166SELinuxSelectionToSID(Atom selection, SELinuxSubjectRec *subj, 167 security_id_t *sid_rtn, int *poly_rtn) 168{ 169 int rc; 170 SELinuxObjectRec *obj; 171 security_id_t tsid; 172 173 /* Get the default context and polyinstantiation bit */ 174 rc = SELinuxAtomToSID(selection, 0, &obj); 175 if (rc != Success) 176 return rc; 177 178 /* Check for an override context next */ 179 if (subj->sel_use_sid) { 180 tsid = subj->sel_use_sid; 181 goto out; 182 } 183 184 tsid = obj->sid; 185 186 /* Polyinstantiate if necessary to obtain the final SID */ 187 if (obj->poly && avc_compute_member(subj->sid, obj->sid, 188 SECCLASS_X_SELECTION, &tsid) < 0) { 189 ErrorF("SELinux: a compute_member call failed!\n"); 190 return BadValue; 191 } 192out: 193 *sid_rtn = tsid; 194 if (poly_rtn) 195 *poly_rtn = obj->poly; 196 return Success; 197} 198 199/* 200 * Looks up a SID for a property/subject pair 201 */ 202int 203SELinuxPropertyToSID(Atom property, SELinuxSubjectRec *subj, 204 security_id_t *sid_rtn, int *poly_rtn) 205{ 206 int rc; 207 SELinuxObjectRec *obj; 208 security_id_t tsid, tsid2; 209 210 /* Get the default context and polyinstantiation bit */ 211 rc = SELinuxAtomToSID(property, 1, &obj); 212 if (rc != Success) 213 return rc; 214 215 /* Check for an override context next */ 216 if (subj->prp_use_sid) { 217 tsid = subj->prp_use_sid; 218 goto out; 219 } 220 221 /* Perform a transition */ 222 if (avc_compute_create(subj->sid, obj->sid, 223 SECCLASS_X_PROPERTY, &tsid) < 0) { 224 ErrorF("SELinux: a compute_create call failed!\n"); 225 return BadValue; 226 } 227 228 /* Polyinstantiate if necessary to obtain the final SID */ 229 if (obj->poly) { 230 tsid2 = tsid; 231 if (avc_compute_member(subj->sid, tsid2, 232 SECCLASS_X_PROPERTY, &tsid) < 0) { 233 ErrorF("SELinux: a compute_member call failed!\n"); 234 return BadValue; 235 } 236 } 237out: 238 *sid_rtn = tsid; 239 if (poly_rtn) 240 *poly_rtn = obj->poly; 241 return Success; 242} 243 244/* 245 * Looks up the SID corresponding to the given event type 246 */ 247int 248SELinuxEventToSID(unsigned type, security_id_t sid_of_window, 249 SELinuxObjectRec *sid_return) 250{ 251 const char *name = LookupEventName(type); 252 security_id_t sid; 253 security_context_t ctx; 254 type &= 127; 255 256 sid = SELinuxArrayGet(&arr_events, type); 257 if (!sid) { 258 /* Look in the mappings of event names to contexts */ 259 if (selabel_lookup_raw(label_hnd, &ctx, name, SELABEL_X_EVENT) < 0) { 260 ErrorF("SELinux: an event label lookup failed!\n"); 261 return BadValue; 262 } 263 /* Get a SID for context */ 264 if (avc_context_to_sid_raw(ctx, &sid) < 0) { 265 ErrorF("SELinux: a context_to_SID_raw call failed!\n"); 266 freecon(ctx); 267 return BadAlloc; 268 } 269 freecon(ctx); 270 /* Cache the SID value */ 271 if (!SELinuxArraySet(&arr_events, type, sid)) 272 return BadAlloc; 273 } 274 275 /* Perform a transition to obtain the final SID */ 276 if (avc_compute_create(sid_of_window, sid, SECCLASS_X_EVENT, 277 &sid_return->sid) < 0) { 278 ErrorF("SELinux: a compute_create call failed!\n"); 279 return BadValue; 280 } 281 282 return Success; 283} 284 285int 286SELinuxExtensionToSID(const char *name, security_id_t *sid_rtn) 287{ 288 security_context_t ctx; 289 290 /* Look in the mappings of extension names to contexts */ 291 if (selabel_lookup_raw(label_hnd, &ctx, name, SELABEL_X_EXT) < 0) { 292 ErrorF("SELinux: a property label lookup failed!\n"); 293 return BadValue; 294 } 295 /* Get a SID for context */ 296 if (avc_context_to_sid_raw(ctx, sid_rtn) < 0) { 297 ErrorF("SELinux: a context_to_SID_raw call failed!\n"); 298 freecon(ctx); 299 return BadAlloc; 300 } 301 freecon(ctx); 302 return Success; 303} 304 305/* 306 * Returns the object class corresponding to the given resource type. 307 */ 308security_class_t 309SELinuxTypeToClass(RESTYPE type) 310{ 311 void *tmp; 312 313 tmp = SELinuxArrayGet(&arr_types, type & TypeMask); 314 if (!tmp) { 315 unsigned long class = SECCLASS_X_RESOURCE; 316 317 if (type & RC_DRAWABLE) 318 class = SECCLASS_X_DRAWABLE; 319 else if (type == RT_GC) 320 class = SECCLASS_X_GC; 321 else if (type == RT_FONT) 322 class = SECCLASS_X_FONT; 323 else if (type == RT_CURSOR) 324 class = SECCLASS_X_CURSOR; 325 else if (type == RT_COLORMAP) 326 class = SECCLASS_X_COLORMAP; 327 else { 328 /* Need to do a string lookup */ 329 const char *str = LookupResourceName(type); 330 if (!strcmp(str, "PICTURE")) 331 class = SECCLASS_X_DRAWABLE; 332 else if (!strcmp(str, "GLYPHSET")) 333 class = SECCLASS_X_FONT; 334 } 335 336 tmp = (void *)class; 337 SELinuxArraySet(&arr_types, type & TypeMask, tmp); 338 } 339 340 return (security_class_t)(unsigned long)tmp; 341} 342 343security_context_t 344SELinuxDefaultClientLabel(void) 345{ 346 security_context_t ctx; 347 348 if (selabel_lookup_raw(label_hnd, &ctx, "remote", SELABEL_X_CLIENT) < 0) 349 FatalError("SELinux: failed to look up remote-client context\n"); 350 351 return ctx; 352} 353 354void 355SELinuxLabelInit(void) 356{ 357 struct selinux_opt selabel_option = { SELABEL_OPT_VALIDATE, (char *)1 }; 358 359 label_hnd = selabel_open(SELABEL_CTX_X, &selabel_option, 1); 360 if (!label_hnd) 361 FatalError("SELinux: Failed to open x_contexts mapping in policy\n"); 362} 363 364void 365SELinuxLabelReset(void) 366{ 367 selabel_close(label_hnd); 368 label_hnd = NULL; 369 370 /* Free local state */ 371 SELinuxArrayFree(&arr_types, 0); 372 SELinuxArrayFree(&arr_events, 0); 373 SELinuxArrayFree(&arr_atoms, 1); 374} 375