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 */ 25 static 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 */ 89 int 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 118 int cond_policydb_init(struct policydb *p) 119 { 120 p->bool_val_to_struct = NULL; 121 p->cond_list = NULL; 122 if (avtab_init(&p->te_cond_avtab)) 123 return -1; 124 125 return 0; 126 } 127 128 static void cond_av_list_destroy(struct cond_av_list *list) 129 { 130 struct cond_av_list *cur, *next; 131 for (cur = list; cur; cur = next) { 132 next = cur->next; 133 /* the avtab_ptr_t node is destroy by the avtab */ 134 kfree(cur); 135 } 136 } 137 138 static void cond_node_destroy(struct cond_node *node) 139 { 140 struct cond_expr *cur_expr, *next_expr; 141 142 for (cur_expr = node->expr; cur_expr; cur_expr = next_expr) { 143 next_expr = cur_expr->next; 144 kfree(cur_expr); 145 } 146 cond_av_list_destroy(node->true_list); 147 cond_av_list_destroy(node->false_list); 148 kfree(node); 149 } 150 151 static void cond_list_destroy(struct cond_node *list) 152 { 153 struct cond_node *next, *cur; 154 155 if (list == NULL) 156 return; 157 158 for (cur = list; cur; cur = next) { 159 next = cur->next; 160 cond_node_destroy(cur); 161 } 162 } 163 164 void cond_policydb_destroy(struct policydb *p) 165 { 166 kfree(p->bool_val_to_struct); 167 avtab_destroy(&p->te_cond_avtab); 168 cond_list_destroy(p->cond_list); 169 } 170 171 int cond_init_bool_indexes(struct policydb *p) 172 { 173 kfree(p->bool_val_to_struct); 174 p->bool_val_to_struct = (struct cond_bool_datum **) 175 kmalloc(p->p_bools.nprim * sizeof(struct cond_bool_datum *), GFP_KERNEL); 176 if (!p->bool_val_to_struct) 177 return -1; 178 return 0; 179 } 180 181 int cond_destroy_bool(void *key, void *datum, void *p) 182 { 183 kfree(key); 184 kfree(datum); 185 return 0; 186 } 187 188 int cond_index_bool(void *key, void *datum, void *datap) 189 { 190 struct policydb *p; 191 struct cond_bool_datum *booldatum; 192 193 booldatum = datum; 194 p = datap; 195 196 if (!booldatum->value || booldatum->value > p->p_bools.nprim) 197 return -EINVAL; 198 199 p->p_bool_val_to_name[booldatum->value - 1] = key; 200 p->bool_val_to_struct[booldatum->value - 1] = booldatum; 201 202 return 0; 203 } 204 205 static int bool_isvalid(struct cond_bool_datum *b) 206 { 207 if (!(b->state == 0 || b->state == 1)) 208 return 0; 209 return 1; 210 } 211 212 int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp) 213 { 214 char *key = NULL; 215 struct cond_bool_datum *booldatum; 216 __le32 buf[3]; 217 u32 len; 218 int rc; 219 220 booldatum = kzalloc(sizeof(struct cond_bool_datum), GFP_KERNEL); 221 if (!booldatum) 222 return -1; 223 224 rc = next_entry(buf, fp, sizeof buf); 225 if (rc < 0) 226 goto err; 227 228 booldatum->value = le32_to_cpu(buf[0]); 229 booldatum->state = le32_to_cpu(buf[1]); 230 231 if (!bool_isvalid(booldatum)) 232 goto err; 233 234 len = le32_to_cpu(buf[2]); 235 236 key = kmalloc(len + 1, GFP_KERNEL); 237 if (!key) 238 goto err; 239 rc = next_entry(key, fp, len); 240 if (rc < 0) 241 goto err; 242 key[len] = '\0'; 243 if (hashtab_insert(h, key, booldatum)) 244 goto err; 245 246 return 0; 247 err: 248 cond_destroy_bool(key, booldatum, NULL); 249 return -1; 250 } 251 252 struct cond_insertf_data { 253 struct policydb *p; 254 struct cond_av_list *other; 255 struct cond_av_list *head; 256 struct cond_av_list *tail; 257 }; 258 259 static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum *d, void *ptr) 260 { 261 struct cond_insertf_data *data = ptr; 262 struct policydb *p = data->p; 263 struct cond_av_list *other = data->other, *list, *cur; 264 struct avtab_node *node_ptr; 265 u8 found; 266 267 268 /* 269 * For type rules we have to make certain there aren't any 270 * conflicting rules by searching the te_avtab and the 271 * cond_te_avtab. 272 */ 273 if (k->specified & AVTAB_TYPE) { 274 if (avtab_search(&p->te_avtab, k)) { 275 printk(KERN_ERR "SELinux: type rule already exists outside of a conditional.\n"); 276 goto err; 277 } 278 /* 279 * If we are reading the false list other will be a pointer to 280 * the true list. We can have duplicate entries if there is only 281 * 1 other entry and it is in our true list. 282 * 283 * If we are reading the true list (other == NULL) there shouldn't 284 * be any other entries. 285 */ 286 if (other) { 287 node_ptr = avtab_search_node(&p->te_cond_avtab, k); 288 if (node_ptr) { 289 if (avtab_search_node_next(node_ptr, k->specified)) { 290 printk(KERN_ERR "SELinux: too many conflicting type rules.\n"); 291 goto err; 292 } 293 found = 0; 294 for (cur = other; cur; cur = cur->next) { 295 if (cur->node == node_ptr) { 296 found = 1; 297 break; 298 } 299 } 300 if (!found) { 301 printk(KERN_ERR "SELinux: conflicting type rules.\n"); 302 goto err; 303 } 304 } 305 } else { 306 if (avtab_search(&p->te_cond_avtab, k)) { 307 printk(KERN_ERR "SELinux: conflicting type rules when adding type rule for true.\n"); 308 goto err; 309 } 310 } 311 } 312 313 node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, k, d); 314 if (!node_ptr) { 315 printk(KERN_ERR "SELinux: could not insert rule.\n"); 316 goto err; 317 } 318 319 list = kzalloc(sizeof(struct cond_av_list), GFP_KERNEL); 320 if (!list) 321 goto err; 322 323 list->node = node_ptr; 324 if (!data->head) 325 data->head = list; 326 else 327 data->tail->next = list; 328 data->tail = list; 329 return 0; 330 331 err: 332 cond_av_list_destroy(data->head); 333 data->head = NULL; 334 return -1; 335 } 336 337 static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list **ret_list, struct cond_av_list *other) 338 { 339 int i, rc; 340 __le32 buf[1]; 341 u32 len; 342 struct cond_insertf_data data; 343 344 *ret_list = NULL; 345 346 len = 0; 347 rc = next_entry(buf, fp, sizeof(u32)); 348 if (rc < 0) 349 return -1; 350 351 len = le32_to_cpu(buf[0]); 352 if (len == 0) 353 return 0; 354 355 data.p = p; 356 data.other = other; 357 data.head = NULL; 358 data.tail = NULL; 359 for (i = 0; i < len; i++) { 360 rc = avtab_read_item(&p->te_cond_avtab, fp, p, cond_insertf, 361 &data); 362 if (rc) 363 return rc; 364 365 } 366 367 *ret_list = data.head; 368 return 0; 369 } 370 371 static int expr_isvalid(struct policydb *p, struct cond_expr *expr) 372 { 373 if (expr->expr_type <= 0 || expr->expr_type > COND_LAST) { 374 printk(KERN_ERR "SELinux: conditional expressions uses unknown operator.\n"); 375 return 0; 376 } 377 378 if (expr->bool > p->p_bools.nprim) { 379 printk(KERN_ERR "SELinux: conditional expressions uses unknown bool.\n"); 380 return 0; 381 } 382 return 1; 383 } 384 385 static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp) 386 { 387 __le32 buf[2]; 388 u32 len, i; 389 int rc; 390 struct cond_expr *expr = NULL, *last = NULL; 391 392 rc = next_entry(buf, fp, sizeof(u32)); 393 if (rc < 0) 394 return -1; 395 396 node->cur_state = le32_to_cpu(buf[0]); 397 398 len = 0; 399 rc = next_entry(buf, fp, sizeof(u32)); 400 if (rc < 0) 401 return -1; 402 403 /* expr */ 404 len = le32_to_cpu(buf[0]); 405 406 for (i = 0; i < len; i++) { 407 rc = next_entry(buf, fp, sizeof(u32) * 2); 408 if (rc < 0) 409 goto err; 410 411 expr = kzalloc(sizeof(struct cond_expr), GFP_KERNEL); 412 if (!expr) 413 goto err; 414 415 expr->expr_type = le32_to_cpu(buf[0]); 416 expr->bool = le32_to_cpu(buf[1]); 417 418 if (!expr_isvalid(p, expr)) { 419 kfree(expr); 420 goto err; 421 } 422 423 if (i == 0) 424 node->expr = expr; 425 else 426 last->next = expr; 427 last = expr; 428 } 429 430 if (cond_read_av_list(p, fp, &node->true_list, NULL) != 0) 431 goto err; 432 if (cond_read_av_list(p, fp, &node->false_list, node->true_list) != 0) 433 goto err; 434 return 0; 435 err: 436 cond_node_destroy(node); 437 return -1; 438 } 439 440 int cond_read_list(struct policydb *p, void *fp) 441 { 442 struct cond_node *node, *last = NULL; 443 __le32 buf[1]; 444 u32 i, len; 445 int rc; 446 447 rc = next_entry(buf, fp, sizeof buf); 448 if (rc < 0) 449 return -1; 450 451 len = le32_to_cpu(buf[0]); 452 453 rc = avtab_alloc(&(p->te_cond_avtab), p->te_avtab.nel); 454 if (rc) 455 goto err; 456 457 for (i = 0; i < len; i++) { 458 node = kzalloc(sizeof(struct cond_node), GFP_KERNEL); 459 if (!node) 460 goto err; 461 462 if (cond_read_node(p, node, fp) != 0) 463 goto err; 464 465 if (i == 0) 466 p->cond_list = node; 467 else 468 last->next = node; 469 last = node; 470 } 471 return 0; 472 err: 473 cond_list_destroy(p->cond_list); 474 p->cond_list = NULL; 475 return -1; 476 } 477 478 /* Determine whether additional permissions are granted by the conditional 479 * av table, and if so, add them to the result 480 */ 481 void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd) 482 { 483 struct avtab_node *node; 484 485 if (!ctab || !key || !avd) 486 return; 487 488 for (node = avtab_search_node(ctab, key); node; 489 node = avtab_search_node_next(node, key->specified)) { 490 if ((u16)(AVTAB_ALLOWED|AVTAB_ENABLED) == 491 (node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED))) 492 avd->allowed |= node->datum.data; 493 if ((u16)(AVTAB_AUDITDENY|AVTAB_ENABLED) == 494 (node->key.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED))) 495 /* Since a '0' in an auditdeny mask represents a 496 * permission we do NOT want to audit (dontaudit), we use 497 * the '&' operand to ensure that all '0's in the mask 498 * are retained (much unlike the allow and auditallow cases). 499 */ 500 avd->auditdeny &= node->datum.data; 501 if ((u16)(AVTAB_AUDITALLOW|AVTAB_ENABLED) == 502 (node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED))) 503 avd->auditallow |= node->datum.data; 504 } 505 return; 506 } 507