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