1/* Authors: Karl MacMillan <kmacmillan@tresys.com> 2 * Frank Mayer <mayerf@tresys.com> 3 * 4 * Copyright (C) 2003 - 2004 Tresys Technology, LLC 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, version 2. 8 */ 9 10#include <linux/kernel.h> 11#include <linux/errno.h> 12#include <linux/string.h> 13#include <linux/spinlock.h> 14#include <linux/slab.h> 15 16#include "security.h" 17#include "conditional.h" 18 19/* 20 * cond_evaluate_expr evaluates a conditional expr 21 * in reverse polish notation. It returns true (1), false (0), 22 * or undefined (-1). Undefined occurs when the expression 23 * exceeds the stack depth of COND_EXPR_MAXDEPTH. 24 */ 25static int cond_evaluate_expr(struct policydb *p, struct cond_expr *expr) 26{ 27 28 struct cond_expr *cur; 29 int s[COND_EXPR_MAXDEPTH]; 30 int sp = -1; 31 32 for (cur = expr; cur; cur = cur->next) { 33 switch (cur->expr_type) { 34 case COND_BOOL: 35 if (sp == (COND_EXPR_MAXDEPTH - 1)) 36 return -1; 37 sp++; 38 s[sp] = p->bool_val_to_struct[cur->bool - 1]->state; 39 break; 40 case COND_NOT: 41 if (sp < 0) 42 return -1; 43 s[sp] = !s[sp]; 44 break; 45 case COND_OR: 46 if (sp < 1) 47 return -1; 48 sp--; 49 s[sp] |= s[sp + 1]; 50 break; 51 case COND_AND: 52 if (sp < 1) 53 return -1; 54 sp--; 55 s[sp] &= s[sp + 1]; 56 break; 57 case COND_XOR: 58 if (sp < 1) 59 return -1; 60 sp--; 61 s[sp] ^= s[sp + 1]; 62 break; 63 case COND_EQ: 64 if (sp < 1) 65 return -1; 66 sp--; 67 s[sp] = (s[sp] == s[sp + 1]); 68 break; 69 case COND_NEQ: 70 if (sp < 1) 71 return -1; 72 sp--; 73 s[sp] = (s[sp] != s[sp + 1]); 74 break; 75 default: 76 return -1; 77 } 78 } 79 return s[0]; 80} 81 82/* 83 * evaluate_cond_node evaluates the conditional stored in 84 * a struct cond_node and if the result is different than the 85 * current state of the node it sets the rules in the true/false 86 * list appropriately. If the result of the expression is undefined 87 * all of the rules are disabled for safety. 88 */ 89int evaluate_cond_node(struct policydb *p, struct cond_node *node) 90{ 91 int new_state; 92 struct cond_av_list *cur; 93 94 new_state = cond_evaluate_expr(p, node->expr); 95 if (new_state != node->cur_state) { 96 node->cur_state = new_state; 97 if (new_state == -1) 98 printk(KERN_ERR "SELinux: expression result was undefined - disabling all rules.\n"); 99 /* turn the rules on or off */ 100 for (cur = node->true_list; cur; cur = cur->next) { 101 if (new_state <= 0) 102 cur->node->key.specified &= ~AVTAB_ENABLED; 103 else 104 cur->node->key.specified |= AVTAB_ENABLED; 105 } 106 107 for (cur = node->false_list; cur; cur = cur->next) { 108 /* -1 or 1 */ 109 if (new_state) 110 cur->node->key.specified &= ~AVTAB_ENABLED; 111 else 112 cur->node->key.specified |= AVTAB_ENABLED; 113 } 114 } 115 return 0; 116} 117 118int cond_policydb_init(struct policydb *p) 119{ 120 int rc; 121 122 p->bool_val_to_struct = NULL; 123 p->cond_list = NULL; 124 125 rc = avtab_init(&p->te_cond_avtab); 126 if (rc) 127 return rc; 128 129 return 0; 130} 131 132static void cond_av_list_destroy(struct cond_av_list *list) 133{ 134 struct cond_av_list *cur, *next; 135 for (cur = list; cur; cur = next) { 136 next = cur->next; 137 /* the avtab_ptr_t node is destroy by the avtab */ 138 kfree(cur); 139 } 140} 141 142static void cond_node_destroy(struct cond_node *node) 143{ 144 struct cond_expr *cur_expr, *next_expr; 145 146 for (cur_expr = node->expr; cur_expr; cur_expr = next_expr) { 147 next_expr = cur_expr->next; 148 kfree(cur_expr); 149 } 150 cond_av_list_destroy(node->true_list); 151 cond_av_list_destroy(node->false_list); 152 kfree(node); 153} 154 155static void cond_list_destroy(struct cond_node *list) 156{ 157 struct cond_node *next, *cur; 158 159 if (list == NULL) 160 return; 161 162 for (cur = list; cur; cur = next) { 163 next = cur->next; 164 cond_node_destroy(cur); 165 } 166} 167 168void cond_policydb_destroy(struct policydb *p) 169{ 170 kfree(p->bool_val_to_struct); 171 avtab_destroy(&p->te_cond_avtab); 172 cond_list_destroy(p->cond_list); 173} 174 175int cond_init_bool_indexes(struct policydb *p) 176{ 177 kfree(p->bool_val_to_struct); 178 p->bool_val_to_struct = (struct cond_bool_datum **) 179 kmalloc(p->p_bools.nprim * sizeof(struct cond_bool_datum *), GFP_KERNEL); 180 if (!p->bool_val_to_struct) 181 return -1; 182 return 0; 183} 184 185int cond_destroy_bool(void *key, void *datum, void *p) 186{ 187 kfree(key); 188 kfree(datum); 189 return 0; 190} 191 192int cond_index_bool(void *key, void *datum, void *datap) 193{ 194 struct policydb *p; 195 struct cond_bool_datum *booldatum; 196 197 booldatum = datum; 198 p = datap; 199 200 if (!booldatum->value || booldatum->value > p->p_bools.nprim) 201 return -EINVAL; 202 203 p->p_bool_val_to_name[booldatum->value - 1] = key; 204 p->bool_val_to_struct[booldatum->value - 1] = booldatum; 205 206 return 0; 207} 208 209static int bool_isvalid(struct cond_bool_datum *b) 210{ 211 if (!(b->state == 0 || b->state == 1)) 212 return 0; 213 return 1; 214} 215 216int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp) 217{ 218 char *key = NULL; 219 struct cond_bool_datum *booldatum; 220 __le32 buf[3]; 221 u32 len; 222 int rc; 223 224 booldatum = kzalloc(sizeof(struct cond_bool_datum), GFP_KERNEL); 225 if (!booldatum) 226 return -ENOMEM; 227 228 rc = next_entry(buf, fp, sizeof buf); 229 if (rc) 230 goto err; 231 232 booldatum->value = le32_to_cpu(buf[0]); 233 booldatum->state = le32_to_cpu(buf[1]); 234 235 rc = -EINVAL; 236 if (!bool_isvalid(booldatum)) 237 goto err; 238 239 len = le32_to_cpu(buf[2]); 240 241 rc = -ENOMEM; 242 key = kmalloc(len + 1, GFP_KERNEL); 243 if (!key) 244 goto err; 245 rc = next_entry(key, fp, len); 246 if (rc) 247 goto err; 248 key[len] = '\0'; 249 rc = hashtab_insert(h, key, booldatum); 250 if (rc) 251 goto err; 252 253 return 0; 254err: 255 cond_destroy_bool(key, booldatum, NULL); 256 return rc; 257} 258 259struct cond_insertf_data { 260 struct policydb *p; 261 struct cond_av_list *other; 262 struct cond_av_list *head; 263 struct cond_av_list *tail; 264}; 265 266static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum *d, void *ptr) 267{ 268 struct cond_insertf_data *data = ptr; 269 struct policydb *p = data->p; 270 struct cond_av_list *other = data->other, *list, *cur; 271 struct avtab_node *node_ptr; 272 u8 found; 273 int rc = -EINVAL; 274 275 /* 276 * For type rules we have to make certain there aren't any 277 * conflicting rules by searching the te_avtab and the 278 * cond_te_avtab. 279 */ 280 if (k->specified & AVTAB_TYPE) { 281 if (avtab_search(&p->te_avtab, k)) { 282 printk(KERN_ERR "SELinux: type rule already exists outside of a conditional.\n"); 283 goto err; 284 } 285 /* 286 * If we are reading the false list other will be a pointer to 287 * the true list. We can have duplicate entries if there is only 288 * 1 other entry and it is in our true list. 289 * 290 * If we are reading the true list (other == NULL) there shouldn't 291 * be any other entries. 292 */ 293 if (other) { 294 node_ptr = avtab_search_node(&p->te_cond_avtab, k); 295 if (node_ptr) { 296 if (avtab_search_node_next(node_ptr, k->specified)) { 297 printk(KERN_ERR "SELinux: too many conflicting type rules.\n"); 298 goto err; 299 } 300 found = 0; 301 for (cur = other; cur; cur = cur->next) { 302 if (cur->node == node_ptr) { 303 found = 1; 304 break; 305 } 306 } 307 if (!found) { 308 printk(KERN_ERR "SELinux: conflicting type rules.\n"); 309 goto err; 310 } 311 } 312 } else { 313 if (avtab_search(&p->te_cond_avtab, k)) { 314 printk(KERN_ERR "SELinux: conflicting type rules when adding type rule for true.\n"); 315 goto err; 316 } 317 } 318 } 319 320 node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, k, d); 321 if (!node_ptr) { 322 printk(KERN_ERR "SELinux: could not insert rule.\n"); 323 rc = -ENOMEM; 324 goto err; 325 } 326 327 list = kzalloc(sizeof(struct cond_av_list), GFP_KERNEL); 328 if (!list) { 329 rc = -ENOMEM; 330 goto err; 331 } 332 333 list->node = node_ptr; 334 if (!data->head) 335 data->head = list; 336 else 337 data->tail->next = list; 338 data->tail = list; 339 return 0; 340 341err: 342 cond_av_list_destroy(data->head); 343 data->head = NULL; 344 return rc; 345} 346 347static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list **ret_list, struct cond_av_list *other) 348{ 349 int i, rc; 350 __le32 buf[1]; 351 u32 len; 352 struct cond_insertf_data data; 353 354 *ret_list = NULL; 355 356 len = 0; 357 rc = next_entry(buf, fp, sizeof(u32)); 358 if (rc) 359 return rc; 360 361 len = le32_to_cpu(buf[0]); 362 if (len == 0) 363 return 0; 364 365 data.p = p; 366 data.other = other; 367 data.head = NULL; 368 data.tail = NULL; 369 for (i = 0; i < len; i++) { 370 rc = avtab_read_item(&p->te_cond_avtab, fp, p, cond_insertf, 371 &data); 372 if (rc) 373 return rc; 374 } 375 376 *ret_list = data.head; 377 return 0; 378} 379 380static int expr_isvalid(struct policydb *p, struct cond_expr *expr) 381{ 382 if (expr->expr_type <= 0 || expr->expr_type > COND_LAST) { 383 printk(KERN_ERR "SELinux: conditional expressions uses unknown operator.\n"); 384 return 0; 385 } 386 387 if (expr->bool > p->p_bools.nprim) { 388 printk(KERN_ERR "SELinux: conditional expressions uses unknown bool.\n"); 389 return 0; 390 } 391 return 1; 392} 393 394static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp) 395{ 396 __le32 buf[2]; 397 u32 len, i; 398 int rc; 399 struct cond_expr *expr = NULL, *last = NULL; 400 401 rc = next_entry(buf, fp, sizeof(u32)); 402 if (rc) 403 return rc; 404 405 node->cur_state = le32_to_cpu(buf[0]); 406 407 len = 0; 408 rc = next_entry(buf, fp, sizeof(u32)); 409 if (rc) 410 return rc; 411 412 /* expr */ 413 len = le32_to_cpu(buf[0]); 414 415 for (i = 0; i < len; i++) { 416 rc = next_entry(buf, fp, sizeof(u32) * 2); 417 if (rc) 418 goto err; 419 420 rc = -ENOMEM; 421 expr = kzalloc(sizeof(struct cond_expr), GFP_KERNEL); 422 if (!expr) 423 goto err; 424 425 expr->expr_type = le32_to_cpu(buf[0]); 426 expr->bool = le32_to_cpu(buf[1]); 427 428 if (!expr_isvalid(p, expr)) { 429 rc = -EINVAL; 430 kfree(expr); 431 goto err; 432 } 433 434 if (i == 0) 435 node->expr = expr; 436 else 437 last->next = expr; 438 last = expr; 439 } 440 441 rc = cond_read_av_list(p, fp, &node->true_list, NULL); 442 if (rc) 443 goto err; 444 rc = cond_read_av_list(p, fp, &node->false_list, node->true_list); 445 if (rc) 446 goto err; 447 return 0; 448err: 449 cond_node_destroy(node); 450 return rc; 451} 452 453int cond_read_list(struct policydb *p, void *fp) 454{ 455 struct cond_node *node, *last = NULL; 456 __le32 buf[1]; 457 u32 i, len; 458 int rc; 459 460 rc = next_entry(buf, fp, sizeof buf); 461 if (rc) 462 return rc; 463 464 len = le32_to_cpu(buf[0]); 465 466 rc = avtab_alloc(&(p->te_cond_avtab), p->te_avtab.nel); 467 if (rc) 468 goto err; 469 470 for (i = 0; i < len; i++) { 471 rc = -ENOMEM; 472 node = kzalloc(sizeof(struct cond_node), GFP_KERNEL); 473 if (!node) 474 goto err; 475 476 rc = cond_read_node(p, node, fp); 477 if (rc) 478 goto err; 479 480 if (i == 0) 481 p->cond_list = node; 482 else 483 last->next = node; 484 last = node; 485 } 486 return 0; 487err: 488 cond_list_destroy(p->cond_list); 489 p->cond_list = NULL; 490 return rc; 491} 492 493/* Determine whether additional permissions are granted by the conditional 494 * av table, and if so, add them to the result 495 */ 496void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd) 497{ 498 struct avtab_node *node; 499 500 if (!ctab || !key || !avd) 501 return; 502 503 for (node = avtab_search_node(ctab, key); node; 504 node = avtab_search_node_next(node, key->specified)) { 505 if ((u16)(AVTAB_ALLOWED|AVTAB_ENABLED) == 506 (node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED))) 507 avd->allowed |= node->datum.data; 508 if ((u16)(AVTAB_AUDITDENY|AVTAB_ENABLED) == 509 (node->key.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED))) 510 /* Since a '0' in an auditdeny mask represents a 511 * permission we do NOT want to audit (dontaudit), we use 512 * the '&' operand to ensure that all '0's in the mask 513 * are retained (much unlike the allow and auditallow cases). 514 */ 515 avd->auditdeny &= node->datum.data; 516 if ((u16)(AVTAB_AUDITALLOW|AVTAB_ENABLED) == 517 (node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED))) 518 avd->auditallow |= node->datum.data; 519 } 520 return; 521} 522