00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <config.h>
00027
00028 #include "poldiff_internal.h"
00029
00030 #include <apol/policy-query.h>
00031 #include <apol/util.h>
00032 #include <qpol/policy_extend.h>
00033 #include <assert.h>
00034 #include <errno.h>
00035 #include <stdio.h>
00036 #include <string.h>
00037
00038 struct poldiff_terule_summary
00039 {
00040 size_t num_added;
00041 size_t num_removed;
00042 size_t num_modified;
00043 size_t num_added_type;
00044 size_t num_removed_type;
00045 int diffs_sorted;
00046
00047 apol_vector_t *diffs;
00048 };
00049
00050 struct poldiff_terule
00051 {
00052 uint32_t spec;
00053
00054 const char *source, *target;
00055
00056 const char *cls;
00057 poldiff_form_e form;
00058
00059 const char *orig_default, *mod_default;
00060
00061
00062 const qpol_cond_t *cond;
00063 uint32_t branch;
00064
00065 apol_vector_t *orig_linenos;
00066
00067 apol_vector_t *mod_linenos;
00068
00069 qpol_terule_t **orig_rules;
00070 size_t num_orig_rules;
00071
00072 qpol_terule_t **mod_rules;
00073 size_t num_mod_rules;
00074 };
00075
00076 typedef struct pseudo_terule
00077 {
00078 uint32_t spec;
00079
00080 uint32_t source, target, default_type;
00081
00082 const char *cls;
00083
00084 const char *bools[5];
00085 uint32_t bool_val;
00086 uint32_t branch;
00087
00088
00089 const qpol_cond_t *cond;
00090
00091 const qpol_terule_t **rules;
00092 size_t num_rules;
00093 } pseudo_terule_t;
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111 static void poldiff_terule_get_stats(const poldiff_t * diff, size_t stats[5], unsigned int idx)
00112 {
00113 if (diff == NULL || stats == NULL) {
00114 ERR(diff, "%s", strerror(EINVAL));
00115 errno = EINVAL;
00116 return;
00117 }
00118 stats[0] = diff->terule_diffs[idx]->num_added;
00119 stats[1] = diff->terule_diffs[idx]->num_removed;
00120 stats[2] = diff->terule_diffs[idx]->num_modified;
00121 stats[3] = diff->terule_diffs[idx]->num_added_type;
00122 stats[4] = diff->terule_diffs[idx]->num_removed_type;
00123 }
00124
00125 void poldiff_terule_get_stats_change(const poldiff_t * diff, size_t stats[5])
00126 {
00127 poldiff_terule_get_stats(diff, stats, TERULE_OFFSET_CHANGE);
00128 }
00129
00130 void poldiff_terule_get_stats_member(const poldiff_t * diff, size_t stats[5])
00131 {
00132 poldiff_terule_get_stats(diff, stats, TERULE_OFFSET_MEMBER);
00133 }
00134
00135 void poldiff_terule_get_stats_trans(const poldiff_t * diff, size_t stats[5])
00136 {
00137 poldiff_terule_get_stats(diff, stats, TERULE_OFFSET_TRANS);
00138 }
00139
00140 char *poldiff_terule_to_string(const poldiff_t * diff, const void *terule)
00141 {
00142 const poldiff_terule_t *pt = (const poldiff_terule_t *)terule;
00143 apol_policy_t *p;
00144 const char *rule_type;
00145 char *diff_char = "", *s = NULL, *cond_expr = NULL;
00146 size_t len = 0;
00147 int error;
00148 if (diff == NULL || terule == NULL) {
00149 ERR(diff, "%s", strerror(EINVAL));
00150 errno = EINVAL;
00151 return NULL;
00152 }
00153 switch (pt->form) {
00154 case POLDIFF_FORM_ADDED:
00155 case POLDIFF_FORM_ADD_TYPE:
00156 {
00157 diff_char = "+";
00158 p = diff->mod_pol;
00159 break;
00160 }
00161 case POLDIFF_FORM_REMOVED:
00162 case POLDIFF_FORM_REMOVE_TYPE:
00163 {
00164 diff_char = "-";
00165 p = diff->orig_pol;
00166 break;
00167 }
00168 case POLDIFF_FORM_MODIFIED:
00169 {
00170 diff_char = "*";
00171 p = diff->orig_pol;
00172 break;
00173 }
00174 default:
00175 {
00176 ERR(diff, "%s", strerror(ENOTSUP));
00177 errno = ENOTSUP;
00178 return NULL;
00179 }
00180 }
00181 rule_type = apol_rule_type_to_str(pt->spec);
00182 if (apol_str_appendf(&s, &len, "%s %s %s %s : %s ", diff_char, rule_type, pt->source, pt->target, pt->cls) < 0) {
00183 error = errno;
00184 s = NULL;
00185 goto err;
00186 }
00187 switch (pt->form) {
00188 case POLDIFF_FORM_ADDED:
00189 case POLDIFF_FORM_ADD_TYPE:
00190 {
00191 if (apol_str_append(&s, &len, pt->mod_default) < 0) {
00192 error = errno;
00193 goto err;
00194 }
00195 break;
00196 }
00197 case POLDIFF_FORM_REMOVED:
00198 case POLDIFF_FORM_REMOVE_TYPE:
00199 {
00200 if (apol_str_append(&s, &len, pt->orig_default) < 0) {
00201 error = errno;
00202 goto err;
00203 }
00204 break;
00205 }
00206 case POLDIFF_FORM_MODIFIED:
00207 {
00208 if (apol_str_appendf(&s, &len, "{ -%s +%s }", pt->orig_default, pt->mod_default) < 0) {
00209 error = errno;
00210 goto err;
00211 }
00212 break;
00213 }
00214 default:
00215 {
00216 ERR(diff, "%s", strerror(ENOTSUP));
00217 errno = ENOTSUP;
00218 return NULL;
00219 }
00220 }
00221 if (apol_str_append(&s, &len, ";") < 0) {
00222 error = errno;
00223 goto err;
00224 }
00225 if (pt->cond != NULL) {
00226 if ((cond_expr = apol_cond_expr_render(p, pt->cond)) == NULL) {
00227 error = errno;
00228 goto err;
00229 }
00230 if (apol_str_appendf(&s, &len, " [%s]:%s", cond_expr, (pt->branch ? "TRUE" : "FALSE")) < 0) {
00231 error = errno;
00232 goto err;
00233 }
00234 free(cond_expr);
00235 }
00236 return s;
00237 err:
00238 free(s);
00239 free(cond_expr);
00240 ERR(diff, "%s", strerror(error));
00241 errno = error;
00242 return NULL;
00243 }
00244
00245
00246
00247
00248 static int poldiff_terule_cmp(const void *x, const void *y, void *data __attribute__ ((unused)))
00249 {
00250 const poldiff_terule_t *a = (const poldiff_terule_t *)x;
00251 const poldiff_terule_t *b = (const poldiff_terule_t *)y;
00252 int compval;
00253 if (a->spec != b->spec) {
00254 const char *rule_type1 = apol_rule_type_to_str(a->spec);
00255 const char *rule_type2 = apol_rule_type_to_str(b->spec);
00256 compval = strcmp(rule_type1, rule_type2);
00257 if (compval != 0) {
00258 return compval;
00259 }
00260 }
00261 if ((compval = strcmp(a->source, b->source)) != 0) {
00262 return compval;
00263 }
00264 if ((compval = strcmp(a->target, b->target)) != 0) {
00265 return compval;
00266 }
00267 if ((compval = strcmp(a->cls, b->cls)) != 0) {
00268 return compval;
00269 }
00270 if (a->cond != b->cond) {
00271 return (int)((char *)a->cond - (char *)b->cond);
00272 }
00273
00274 return b->branch - a->branch;
00275 }
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290 static const apol_vector_t *poldiff_get_terule_vector(const poldiff_t * diff, terule_offset_e idx)
00291 {
00292 if (diff == NULL) {
00293 errno = EINVAL;
00294 return NULL;
00295 }
00296 if (diff->terule_diffs[idx]->diffs_sorted == 0) {
00297 apol_vector_sort(diff->terule_diffs[idx]->diffs, poldiff_terule_cmp, NULL);
00298 diff->terule_diffs[idx]->diffs_sorted = 1;
00299 }
00300 return diff->terule_diffs[idx]->diffs;
00301 }
00302
00303 const apol_vector_t *poldiff_get_terule_vector_member(const poldiff_t * diff)
00304 {
00305 return poldiff_get_terule_vector(diff, TERULE_OFFSET_MEMBER);
00306 }
00307
00308 const apol_vector_t *poldiff_get_terule_vector_change(const poldiff_t * diff)
00309 {
00310 return poldiff_get_terule_vector(diff, TERULE_OFFSET_CHANGE);
00311 }
00312
00313 const apol_vector_t *poldiff_get_terule_vector_trans(const poldiff_t * diff)
00314 {
00315 return poldiff_get_terule_vector(diff, TERULE_OFFSET_TRANS);
00316 }
00317
00318 poldiff_form_e poldiff_terule_get_form(const void *terule)
00319 {
00320 if (terule == NULL) {
00321 errno = EINVAL;
00322 return 0;
00323 }
00324 return ((const poldiff_terule_t *)terule)->form;
00325 }
00326
00327 uint32_t poldiff_terule_get_rule_type(const poldiff_terule_t * terule)
00328 {
00329 if (terule == NULL) {
00330 errno = EINVAL;
00331 return 0;
00332 }
00333 return terule->spec;
00334 }
00335
00336 const char *poldiff_terule_get_source_type(const poldiff_terule_t * terule)
00337 {
00338 if (terule == NULL) {
00339 errno = EINVAL;
00340 return 0;
00341 }
00342 return terule->source;
00343 }
00344
00345 const char *poldiff_terule_get_target_type(const poldiff_terule_t * terule)
00346 {
00347 if (terule == NULL) {
00348 errno = EINVAL;
00349 return 0;
00350 }
00351 return terule->target;
00352 }
00353
00354 const char *poldiff_terule_get_object_class(const poldiff_terule_t * terule)
00355 {
00356 if (terule == NULL) {
00357 errno = EINVAL;
00358 return 0;
00359 }
00360 return terule->cls;
00361 }
00362
00363 void poldiff_terule_get_cond(const poldiff_t * diff, const poldiff_terule_t * terule,
00364 const qpol_cond_t ** cond, uint32_t * which_list, const apol_policy_t ** p)
00365 {
00366 if (diff == NULL || terule == NULL || cond == NULL || p == NULL) {
00367 errno = EINVAL;
00368 return;
00369 }
00370 *cond = terule->cond;
00371 if (*cond == NULL) {
00372 *which_list = 1;
00373 *p = NULL;
00374 } else if (terule->form == POLDIFF_FORM_ADDED || terule->form == POLDIFF_FORM_ADD_TYPE) {
00375 *which_list = terule->branch;
00376 *p = diff->mod_pol;
00377 } else {
00378 *which_list = terule->branch;
00379 *p = diff->orig_pol;
00380 }
00381 }
00382
00383 const char *poldiff_terule_get_original_default(const poldiff_terule_t * terule)
00384 {
00385 if (terule == NULL) {
00386 errno = EINVAL;
00387 return 0;
00388 }
00389 return terule->orig_default;
00390 }
00391
00392 const char *poldiff_terule_get_modified_default(const poldiff_terule_t * terule)
00393 {
00394 if (terule == NULL) {
00395 errno = EINVAL;
00396 return 0;
00397 }
00398 return terule->mod_default;
00399 }
00400
00401 apol_vector_t *poldiff_terule_get_orig_line_numbers(const poldiff_terule_t * terule)
00402 {
00403 if (terule == NULL) {
00404 errno = EINVAL;
00405 return NULL;
00406 }
00407 return terule->orig_linenos;
00408 }
00409
00410 apol_vector_t *poldiff_terule_get_mod_line_numbers(const poldiff_terule_t * terule)
00411 {
00412 if (terule == NULL) {
00413 errno = EINVAL;
00414 return NULL;
00415 }
00416 return terule->mod_linenos;
00417 }
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427 static void poldiff_terule_free(void *elem)
00428 {
00429 if (elem != NULL) {
00430 poldiff_terule_t *t = elem;
00431 apol_vector_destroy(&t->orig_linenos);
00432 apol_vector_destroy(&t->mod_linenos);
00433 free(t->orig_rules);
00434 free(t->mod_rules);
00435 free(elem);
00436 }
00437 }
00438
00439 poldiff_terule_summary_t *terule_create(void)
00440 {
00441 poldiff_terule_summary_t *rs = calloc(1, sizeof(*rs));
00442 if (rs == NULL) {
00443 return NULL;
00444 }
00445 if ((rs->diffs = apol_vector_create(poldiff_terule_free)) == NULL) {
00446 terule_destroy(&rs);
00447 return NULL;
00448 }
00449 return rs;
00450 }
00451
00452 void terule_destroy(poldiff_terule_summary_t ** rs)
00453 {
00454 if (rs != NULL && *rs != NULL) {
00455 apol_vector_destroy(&(*rs)->diffs);
00456 free(*rs);
00457 *rs = NULL;
00458 }
00459 }
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470 static int terule_reset(poldiff_t * diff, terule_offset_e idx)
00471 {
00472 int error = 0;
00473 terule_destroy(&diff->terule_diffs[idx]);
00474 diff->terule_diffs[idx] = terule_create();
00475 if (diff->terule_diffs[idx] == NULL) {
00476 error = errno;
00477 ERR(diff, "%s", strerror(error));
00478 errno = error;
00479 return -1;
00480 }
00481 return 0;
00482 }
00483
00484 int terule_reset_change(poldiff_t * diff)
00485 {
00486 return terule_reset(diff, TERULE_OFFSET_CHANGE);
00487 }
00488
00489 int terule_reset_member(poldiff_t * diff)
00490 {
00491 return terule_reset(diff, TERULE_OFFSET_MEMBER);
00492 }
00493
00494 int terule_reset_trans(poldiff_t * diff)
00495 {
00496 return terule_reset(diff, TERULE_OFFSET_TRANS);
00497 }
00498
00499 static void terule_free_item(void *item)
00500 {
00501 pseudo_terule_t *t = (pseudo_terule_t *) item;
00502 if (item != NULL) {
00503 free(t->rules);
00504 free(t);
00505 }
00506 }
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526 static int pseudo_terule_comp(const pseudo_terule_t * rule1, const pseudo_terule_t * rule2, int is_sorting)
00527 {
00528 size_t i;
00529 uint32_t bool_val;
00530 if (rule1->target != rule2->target) {
00531 return rule1->target - rule2->target;
00532 }
00533 if (rule1->source != rule2->source) {
00534 return rule1->source - rule2->source;
00535 }
00536 if (rule1->cls != rule2->cls) {
00537 return (int)(rule1->cls - rule2->cls);
00538 }
00539 if (rule1->spec != rule2->spec) {
00540 return rule1->spec - rule2->spec;
00541 }
00542 if (rule1->bools[0] == NULL && rule2->bools[0] == NULL) {
00543
00544 return 0;
00545 } else if (rule1->bools[0] == NULL && rule2->bools[0] != NULL) {
00546
00547 return -1;
00548 } else if (rule1->bools[0] != NULL && rule2->bools[0] == NULL) {
00549
00550 return 1;
00551 }
00552 for (i = 0; i < (sizeof(rule1->bools) / sizeof(rule1->bools[0])); i++) {
00553 if (rule1->bools[i] != rule2->bools[i]) {
00554 return (int)(rule1->bools[i] - rule2->bools[i]);
00555 }
00556 }
00557 if (is_sorting) {
00558 if (rule1->branch != rule2->branch) {
00559 return rule1->branch - rule2->branch;
00560 }
00561 return (int)rule1->bool_val - (int)rule2->bool_val;
00562 } else {
00563 if (rule1->branch == rule2->branch) {
00564 bool_val = rule2->bool_val;
00565 } else {
00566 bool_val = ~rule2->bool_val;
00567 }
00568 if (rule1->bool_val < bool_val) {
00569 return -1;
00570 } else if (rule1->bool_val > bool_val) {
00571 return 1;
00572 }
00573 return 0;
00574 }
00575 }
00576
00577 static int terule_bst_comp(const void *x, const void *y, void *data)
00578 {
00579 const pseudo_terule_t *r1 = (const pseudo_terule_t *)x;
00580 const pseudo_terule_t *r2 = (const pseudo_terule_t *)y;
00581 poldiff_t *diff = data;
00582 int retv;
00583 retv = pseudo_terule_comp(r1, r2, 1);
00584 if (!retv && r1->default_type != r2->default_type)
00585 WARN(diff, "Multiple %s rules for %s %s %s with different default types", apol_rule_type_to_str(r1->spec),
00586 type_map_get_name(diff, r1->source, POLDIFF_POLICY_ORIG), type_map_get_name(diff, r1->target,
00587 POLDIFF_POLICY_ORIG), r1->cls);
00588 return retv;
00589 }
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601 static int terule_build_cond(const poldiff_t * diff, const apol_policy_t * p, const qpol_cond_t * cond, pseudo_terule_t * key)
00602 {
00603 qpol_iterator_t *iter = NULL;
00604 qpol_cond_expr_node_t *node;
00605 uint32_t expr_type, truthiness;
00606 qpol_bool_t *bools[5] = { NULL, NULL, NULL, NULL, NULL }, *qbool;
00607 size_t i, j;
00608 size_t num_bools = 0;
00609 const char *bool_name, *pseudo_bool, *t;
00610 qpol_policy_t *q = apol_policy_get_qpol(p);
00611 int retval = -1, error = 0, compval;
00612 if (qpol_cond_get_expr_node_iter(q, cond, &iter) < 0) {
00613 error = errno;
00614 goto cleanup;
00615 }
00616 for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
00617 if (qpol_iterator_get_item(iter, (void **)&node) < 0 || qpol_cond_expr_node_get_expr_type(q, node, &expr_type) < 0) {
00618 error = errno;
00619 goto cleanup;
00620 }
00621 if (expr_type != QPOL_COND_EXPR_BOOL) {
00622 continue;
00623 }
00624 if (qpol_cond_expr_node_get_bool(q, node, &qbool) < 0) {
00625 error = errno;
00626 goto cleanup;
00627 }
00628 for (i = 0; i < num_bools; i++) {
00629 if (bools[i] == qbool) {
00630 break;
00631 }
00632 }
00633 if (i >= num_bools) {
00634 assert(i < 5);
00635 bools[i] = qbool;
00636 num_bools++;
00637 }
00638 }
00639 for (i = 0; i < num_bools; i++) {
00640 if (qpol_bool_get_name(q, bools[i], &bool_name) < 0) {
00641 error = errno;
00642 goto cleanup;
00643 }
00644 if (apol_bst_get_element(diff->bool_bst, (void *)bool_name, NULL, (void **)&pseudo_bool) < 0) {
00645 error = EBADRQC;
00646 ERR(diff, "%s", strerror(error));
00647 assert(0);
00648 goto cleanup;
00649 }
00650 key->bools[i] = pseudo_bool;
00651 }
00652
00653
00654
00655 for (i = num_bools; i > 1; i--) {
00656 for (j = 1; j < i; j++) {
00657 compval = strcmp(key->bools[j - 1], key->bools[j]);
00658 if (compval > 0) {
00659 t = key->bools[j];
00660 key->bools[j] = key->bools[j - 1];
00661 key->bools[j - 1] = t;
00662 qbool = bools[j];
00663 bools[j] = bools[j - 1];
00664 bools[j - 1] = qbool;
00665 }
00666 }
00667 }
00668
00669
00670 key->bool_val = 0;
00671 for (i = 0; i < 32; i++) {
00672 for (j = 0; j < num_bools; j++) {
00673 int state = ((i & (1 << j)) ? 1 : 0);
00674 if (qpol_bool_set_state_no_eval(q, bools[j], state) < 0) {
00675 error = errno;
00676 goto cleanup;
00677 }
00678 }
00679 if (qpol_cond_eval(q, cond, &truthiness) < 0) {
00680 error = errno;
00681 goto cleanup;
00682 }
00683 key->bool_val = (key->bool_val << 1) | truthiness;
00684 }
00685
00686 key->cond = cond;
00687 retval = 0;
00688 cleanup:
00689 qpol_iterator_destroy(&iter);
00690 return retval;
00691 }
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706 static int terule_add_to_bst(poldiff_t * diff, const apol_policy_t * p,
00707 const qpol_terule_t * rule, uint32_t source, uint32_t target, apol_bst_t * b)
00708 {
00709 pseudo_terule_t *key, *inserted_key;
00710 const qpol_class_t *obj_class;
00711 const qpol_type_t *default_type;
00712 const char *class_name;
00713 const qpol_cond_t *cond;
00714 qpol_policy_t *q = apol_policy_get_qpol(p);
00715 int retval = -1, error = 0, compval;
00716 int which = (p == diff->orig_pol ? POLDIFF_POLICY_ORIG : POLDIFF_POLICY_MOD);
00717 if ((key = calloc(1, sizeof(*key))) == NULL) {
00718 error = errno;
00719 ERR(diff, "%s", strerror(error));
00720 goto cleanup;
00721 }
00722 if (qpol_terule_get_rule_type(q, rule, &(key->spec)) < 0 ||
00723 qpol_terule_get_object_class(q, rule, &obj_class) < 0 ||
00724 qpol_terule_get_default_type(q, rule, &default_type) < 0 || qpol_terule_get_cond(q, rule, &cond) < 0) {
00725 error = errno;
00726 goto cleanup;
00727 }
00728 if (qpol_class_get_name(q, obj_class, &class_name) < 0) {
00729 error = errno;
00730 goto cleanup;
00731 }
00732 if (apol_bst_get_element(diff->class_bst, (void *)class_name, NULL, (void **)&key->cls) < 0) {
00733 error = EBADRQC;
00734 ERR(diff, "%s", strerror(error));
00735 assert(0);
00736 goto cleanup;
00737 }
00738 if ((key->default_type = type_map_lookup(diff, default_type, which)) == 0) {
00739 error = errno;
00740 ERR(diff, "%s", strerror(error));
00741 goto cleanup;
00742 }
00743 key->source = source;
00744 key->target = target;
00745 if (cond != NULL && (qpol_terule_get_which_list(q, rule, &(key->branch)) < 0 || terule_build_cond(diff, p, cond, key) < 0)) {
00746 error = errno;
00747 goto cleanup;
00748 }
00749
00750
00751 if ((compval = apol_bst_insert_and_get(b, (void **)&key, diff)) < 0) {
00752 error = errno;
00753 ERR(diff, "%s", strerror(error));
00754 goto cleanup;
00755 }
00756 inserted_key = key;
00757 key = NULL;
00758
00759
00760 if (qpol_policy_has_capability(q, QPOL_CAP_LINE_NUMBERS)) {
00761 const qpol_terule_t **t = realloc(inserted_key->rules,
00762 (inserted_key->num_rules + 1) * sizeof(*t));
00763 if (t == NULL) {
00764 error = errno;
00765 ERR(diff, "%s", strerror(error));
00766 goto cleanup;
00767 }
00768 inserted_key->rules = t;
00769 inserted_key->rules[inserted_key->num_rules++] = rule;
00770 }
00771
00772 retval = 0;
00773 cleanup:
00774 if (retval < 0) {
00775 terule_free_item(key);
00776 }
00777 errno = error;
00778 return retval;
00779 }
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793 static int terule_expand(poldiff_t * diff, const apol_policy_t * p, const qpol_terule_t * rule, apol_bst_t * b)
00794 {
00795 const qpol_type_t *source, *orig_target, *target;
00796 unsigned char source_attr, target_attr;
00797 qpol_iterator_t *source_iter = NULL, *target_iter = NULL;
00798 uint32_t source_val, target_val;
00799 qpol_policy_t *q = apol_policy_get_qpol(p);
00800 int which = (p == diff->orig_pol ? POLDIFF_POLICY_ORIG : POLDIFF_POLICY_MOD);
00801 int retval = -1, error = 0;
00802 if (qpol_terule_get_source_type(q, rule, &source) < 0 ||
00803 qpol_terule_get_target_type(q, rule, &orig_target) < 0 ||
00804 qpol_type_get_isattr(q, source, &source_attr) < 0 || qpol_type_get_isattr(q, orig_target, &target_attr)) {
00805 error = errno;
00806 goto cleanup;
00807 }
00808 if (source_attr && qpol_type_get_type_iter(q, source, &source_iter) < 0) {
00809 error = errno;
00810 goto cleanup;
00811 }
00812 do {
00813 if (source_attr) {
00814 if (qpol_iterator_get_item(source_iter, (void **)&source) < 0) {
00815 error = errno;
00816 goto cleanup;
00817 }
00818 qpol_iterator_next(source_iter);
00819 }
00820 if (target_attr) {
00821 if (qpol_type_get_type_iter(q, orig_target, &target_iter) < 0) {
00822 error = errno;
00823 goto cleanup;
00824 }
00825 } else {
00826 target = orig_target;
00827 }
00828 do {
00829 if (target_attr) {
00830 if (qpol_iterator_get_item(target_iter, (void **)&target) < 0) {
00831 error = errno;
00832 goto cleanup;
00833 }
00834 qpol_iterator_next(target_iter);
00835 }
00836 const char *n1, *n2;
00837 qpol_type_get_name(q, source, &n1);
00838 qpol_type_get_name(q, target, &n2);
00839 if ((source_val = type_map_lookup(diff, source, which)) == 0 ||
00840 (target_val = type_map_lookup(diff, target, which)) == 0 ||
00841 terule_add_to_bst(diff, p, rule, source_val, target_val, b) < 0) {
00842 error = errno;
00843 goto cleanup;
00844 }
00845 } while (target_attr && !qpol_iterator_end(target_iter));
00846 qpol_iterator_destroy(&target_iter);
00847 } while (source_attr && !qpol_iterator_end(source_iter));
00848 retval = 0;
00849 cleanup:
00850 qpol_iterator_destroy(&source_iter);
00851 qpol_iterator_destroy(&target_iter);
00852 errno = error;
00853 return retval;
00854 }
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870 static apol_vector_t *terule_get_items(poldiff_t * diff, const apol_policy_t * policy, unsigned int which)
00871 {
00872 apol_vector_t *bools = NULL, *bool_states = NULL;
00873 size_t i, num_rules, j;
00874 apol_bst_t *b = NULL;
00875 apol_vector_t *v = NULL;
00876 qpol_iterator_t *iter = NULL;
00877 qpol_terule_t *rule;
00878 qpol_policy_t *q = apol_policy_get_qpol(policy);
00879 int retval = -1, error = 0;
00880 if (poldiff_build_bsts(diff) < 0) {
00881 error = errno;
00882 goto cleanup;
00883 }
00884
00885
00886 if (apol_bool_get_by_query(policy, NULL, &bools) < 0) {
00887 error = errno;
00888 goto cleanup;
00889 }
00890 if ((bool_states = apol_vector_create_with_capacity(apol_vector_get_size(bools), NULL)) == NULL) {
00891 error = errno;
00892 ERR(diff, "%s", strerror(error));
00893 goto cleanup;
00894 }
00895 for (i = 0; i < apol_vector_get_size(bools); i++) {
00896 qpol_bool_t *qbool = apol_vector_get_element(bools, i);
00897 int state;
00898 if (qpol_bool_get_state(q, qbool, &state) < 0) {
00899 error = errno;
00900 goto cleanup;
00901 }
00902 if (apol_vector_append(bool_states, (void *)((size_t) state)) < 0) {
00903 error = errno;
00904 ERR(diff, "%s", strerror(error));
00905 goto cleanup;
00906 }
00907 }
00908 if ((b = apol_bst_create(terule_bst_comp, terule_free_item)) == NULL) {
00909 error = errno;
00910 ERR(diff, "%s", strerror(error));
00911 goto cleanup;
00912 }
00913 if (qpol_policy_get_terule_iter(q, which, &iter) < 0) {
00914 error = errno;
00915 ERR(diff, "%s", strerror(error));
00916 goto cleanup;
00917 }
00918 qpol_iterator_get_size(iter, &num_rules);
00919 for (j = 0; !qpol_iterator_end(iter); qpol_iterator_next(iter), j++) {
00920 if (qpol_iterator_get_item(iter, (void **)&rule) < 0 || terule_expand(diff, policy, rule, b) < 0) {
00921 error = errno;
00922 goto cleanup;
00923 }
00924 if (!(j % 1024)) {
00925 int percent = 50 * j / num_rules + (policy == diff->mod_pol ? 50 : 0);
00926 INFO(diff, "Computing TE rule difference: %02d%% complete", percent);
00927 }
00928 }
00929 if ((v = apol_bst_get_vector(b, 1)) == NULL) {
00930 error = errno;
00931 ERR(diff, "%s", strerror(error));
00932 goto cleanup;
00933 }
00934 retval = 0;
00935 cleanup:
00936
00937 for (i = 0; bools != NULL && i < apol_vector_get_size(bools); i++) {
00938 qpol_bool_t *qbool = apol_vector_get_element(bools, i);
00939 int state = (int)((size_t) apol_vector_get_element(bool_states, i));
00940 qpol_bool_set_state_no_eval(q, qbool, state);
00941 }
00942 apol_vector_destroy(&bools);
00943 apol_vector_destroy(&bool_states);
00944 qpol_policy_reevaluate_conds(q);
00945 apol_bst_destroy(&b);
00946 qpol_iterator_destroy(&iter);
00947 if (retval < 0) {
00948 apol_vector_destroy(&v);
00949 errno = error;
00950 return NULL;
00951 }
00952 return v;
00953 }
00954
00955 apol_vector_t *terule_get_items_change(poldiff_t * diff, const apol_policy_t * policy)
00956 {
00957 return terule_get_items(diff, policy, QPOL_RULE_TYPE_CHANGE);
00958 }
00959
00960 apol_vector_t *terule_get_items_member(poldiff_t * diff, const apol_policy_t * policy)
00961 {
00962 return terule_get_items(diff, policy, QPOL_RULE_TYPE_MEMBER);
00963 }
00964
00965 apol_vector_t *terule_get_items_trans(poldiff_t * diff, const apol_policy_t * policy)
00966 {
00967 return terule_get_items(diff, policy, QPOL_RULE_TYPE_TRANS);
00968 }
00969
00970 int terule_comp(const void *x, const void *y, const poldiff_t * diff __attribute__ ((unused)))
00971 {
00972 const pseudo_terule_t *r1 = (const pseudo_terule_t *)x;
00973 const pseudo_terule_t *r2 = (const pseudo_terule_t *)y;
00974 return pseudo_terule_comp(r1, r2, 0);
00975 }
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990 static poldiff_terule_t *make_tediff(const poldiff_t * diff, poldiff_form_e form, const pseudo_terule_t * rule)
00991 {
00992 poldiff_terule_t *pt;
00993 const char *n1, *n2;
00994 int error;
00995 if (form == POLDIFF_FORM_ADDED || form == POLDIFF_FORM_ADD_TYPE) {
00996 n1 = type_map_get_name(diff, rule->source, POLDIFF_POLICY_MOD);
00997 n2 = type_map_get_name(diff, rule->target, POLDIFF_POLICY_MOD);
00998 } else {
00999 n1 = type_map_get_name(diff, rule->source, POLDIFF_POLICY_ORIG);
01000 n2 = type_map_get_name(diff, rule->target, POLDIFF_POLICY_ORIG);
01001 }
01002 assert(n1 != NULL && n2 != NULL);
01003 if ((pt = calloc(1, sizeof(*pt))) == NULL) {
01004 error = errno;
01005 poldiff_terule_free(pt);
01006 ERR(diff, "%s", strerror(error));
01007 errno = error;
01008 return NULL;
01009 }
01010 pt->spec = rule->spec;
01011 pt->source = n1;
01012 pt->target = n2;
01013 pt->cls = rule->cls;
01014 pt->form = form;
01015 pt->cond = rule->cond;
01016 pt->branch = rule->branch;
01017 return pt;
01018 }
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030
01031
01032 static int terule_new_diff(poldiff_t * diff, poldiff_form_e form, const void *item, terule_offset_e idx)
01033 {
01034 pseudo_terule_t *rule = (pseudo_terule_t *) item;
01035 poldiff_terule_t *pt = NULL;
01036 const apol_vector_t *v1, *v2;
01037 apol_policy_t *p;
01038 const char *orig_default = NULL, *mod_default = NULL;
01039 int retval = -1, error = errno;
01040
01041
01042
01043
01044 if (form == POLDIFF_FORM_ADDED) {
01045 if ((v1 = type_map_lookup_reverse(diff, rule->source, POLDIFF_POLICY_ORIG)) == NULL ||
01046 (v2 = type_map_lookup_reverse(diff, rule->target, POLDIFF_POLICY_ORIG)) == NULL ||
01047 (mod_default = type_map_get_name(diff, rule->default_type, POLDIFF_POLICY_MOD)) == NULL) {
01048 error = errno;
01049 goto cleanup;
01050 }
01051 if (apol_vector_get_size(v1) == 0 || apol_vector_get_size(v2) == 0) {
01052 form = POLDIFF_FORM_ADD_TYPE;
01053 }
01054 p = diff->mod_pol;
01055 } else {
01056 if ((v1 = type_map_lookup_reverse(diff, rule->source, POLDIFF_POLICY_MOD)) == NULL ||
01057 (v2 = type_map_lookup_reverse(diff, rule->target, POLDIFF_POLICY_MOD)) == NULL ||
01058 (orig_default = type_map_get_name(diff, rule->default_type, POLDIFF_POLICY_ORIG)) == NULL) {
01059 error = errno;
01060 goto cleanup;
01061 }
01062 if (apol_vector_get_size(v1) == 0 || apol_vector_get_size(v2) == 0) {
01063 form = POLDIFF_FORM_REMOVE_TYPE;
01064 }
01065 p = diff->orig_pol;
01066 }
01067
01068 pt = make_tediff(diff, form, rule);
01069 if (pt == NULL) {
01070 return -1;
01071 }
01072 pt->orig_default = orig_default;
01073 pt->mod_default = mod_default;
01074
01075
01076 if (qpol_policy_has_capability(apol_policy_get_qpol(p), QPOL_CAP_LINE_NUMBERS)) {
01077 apol_vector_t *vl = NULL;
01078 if ((vl = apol_vector_create(NULL)) == NULL) {
01079 error = errno;
01080 ERR(diff, "%s", strerror(error));
01081 goto cleanup;
01082 }
01083 if (form == POLDIFF_FORM_ADDED || form == POLDIFF_FORM_ADD_TYPE) {
01084 pt->mod_linenos = vl;
01085 } else {
01086 pt->orig_linenos = vl;
01087 }
01088
01089
01090 if (form == POLDIFF_FORM_ADDED || form == POLDIFF_FORM_ADD_TYPE) {
01091 pt->num_mod_rules = rule->num_rules;
01092 pt->mod_rules = calloc(rule->num_rules, sizeof(qpol_terule_t *));
01093 if (!pt->mod_rules) {
01094 error = errno;
01095 ERR(diff, "%s", strerror(error));
01096 goto cleanup;
01097 }
01098 memcpy(pt->mod_rules, rule->rules, rule->num_rules * sizeof(qpol_terule_t *));
01099 } else {
01100 pt->num_orig_rules = rule->num_rules;
01101 pt->orig_rules = calloc(rule->num_rules, sizeof(qpol_terule_t *));
01102 if (!pt->orig_rules) {
01103 error = errno;
01104 ERR(diff, "%s", strerror(error));
01105 goto cleanup;
01106 }
01107 memcpy(pt->orig_rules, rule->rules, rule->num_rules * sizeof(qpol_terule_t *));
01108 }
01109 }
01110
01111 if (apol_vector_append(diff->terule_diffs[idx]->diffs, pt) < 0) {
01112 error = errno;
01113 ERR(diff, "%s", strerror(error));
01114 goto cleanup;
01115 }
01116 switch (form) {
01117 case POLDIFF_FORM_ADDED:
01118 diff->terule_diffs[idx]->num_added++;
01119 break;
01120 case POLDIFF_FORM_ADD_TYPE:
01121 diff->terule_diffs[idx]->num_added_type++;
01122 break;
01123 case POLDIFF_FORM_REMOVED:
01124 diff->terule_diffs[idx]->num_removed++;
01125 break;
01126 case POLDIFF_FORM_REMOVE_TYPE:
01127 diff->terule_diffs[idx]->num_removed_type++;
01128 break;
01129 default:
01130 error = EBADRQC;
01131 ERR(diff, "%s", strerror(error));
01132 assert(0);
01133 goto cleanup;
01134 }
01135 diff->terule_diffs[idx]->diffs_sorted = 0;
01136 retval = 0;
01137 cleanup:
01138 if (retval < 0) {
01139 poldiff_terule_free(pt);
01140 }
01141 errno = error;
01142 return retval;
01143 }
01144
01145 int terule_new_diff_change(poldiff_t * diff, poldiff_form_e form, const void *item)
01146 {
01147 return terule_new_diff(diff, form, item, TERULE_OFFSET_CHANGE);
01148 }
01149
01150 int terule_new_diff_member(poldiff_t * diff, poldiff_form_e form, const void *item)
01151 {
01152 return terule_new_diff(diff, form, item, TERULE_OFFSET_MEMBER);
01153 }
01154
01155 int terule_new_diff_trans(poldiff_t * diff, poldiff_form_e form, const void *item)
01156 {
01157 return terule_new_diff(diff, form, item, TERULE_OFFSET_TRANS);
01158 }
01159
01160
01161
01162
01163
01164
01165
01166
01167
01168
01169
01170
01171
01172
01173
01174
01175
01176 static int terule_deep_diff(poldiff_t * diff, const void *x, const void *y, terule_offset_e idx)
01177 {
01178 pseudo_terule_t *r1 = (pseudo_terule_t *) x;
01179 pseudo_terule_t *r2 = (pseudo_terule_t *) y;
01180 poldiff_terule_t *pt = NULL;
01181 int retval = -1, error = 0;
01182
01183 if (r1->default_type != r2->default_type) {
01184 if ((pt = make_tediff(diff, POLDIFF_FORM_MODIFIED, r1)) == NULL) {
01185 error = errno;
01186 goto cleanup;
01187 }
01188 pt->orig_default = type_map_get_name(diff, r1->default_type, POLDIFF_POLICY_ORIG);
01189 pt->mod_default = type_map_get_name(diff, r2->default_type, POLDIFF_POLICY_MOD);
01190
01191
01192 if (qpol_policy_has_capability(apol_policy_get_qpol(diff->orig_pol), QPOL_CAP_LINE_NUMBERS)) {
01193 if ((pt->orig_linenos = apol_vector_create(NULL)) == NULL) {
01194 error = errno;
01195 ERR(diff, "%s", strerror(error));
01196 goto cleanup;
01197 }
01198
01199
01200 pt->num_orig_rules = r1->num_rules;
01201 pt->orig_rules = calloc(r1->num_rules, sizeof(qpol_terule_t *));
01202 if (!pt->orig_rules) {
01203 error = errno;
01204 ERR(diff, "%s", strerror(error));
01205 goto cleanup;
01206 }
01207 memcpy(pt->orig_rules, r1->rules, r1->num_rules * sizeof(qpol_terule_t *));
01208 }
01209 if (qpol_policy_has_capability(apol_policy_get_qpol(diff->mod_pol), QPOL_CAP_LINE_NUMBERS)) {
01210 if ((pt->mod_linenos = apol_vector_create(NULL)) == NULL) {
01211 error = errno;
01212 ERR(diff, "%s", strerror(error));
01213 goto cleanup;
01214 }
01215
01216
01217 pt->num_mod_rules = r2->num_rules;
01218 pt->mod_rules = calloc(r2->num_rules, sizeof(qpol_terule_t *));
01219 if (!pt->mod_rules) {
01220 error = errno;
01221 ERR(diff, "%s", strerror(error));
01222 goto cleanup;
01223 }
01224 memcpy(pt->mod_rules, r2->rules, r2->num_rules * sizeof(qpol_terule_t *));
01225 }
01226
01227 if (apol_vector_append(diff->terule_diffs[idx]->diffs, pt) < 0) {
01228 error = errno;
01229 ERR(diff, "%s", strerror(error));
01230 goto cleanup;
01231 }
01232 diff->terule_diffs[idx]->num_modified++;
01233 diff->terule_diffs[idx]->diffs_sorted = 0;
01234 }
01235 retval = 0;
01236 cleanup:
01237 if (retval != 0) {
01238 poldiff_terule_free(pt);
01239 }
01240 errno = error;
01241 return retval;
01242 }
01243
01244 int terule_deep_diff_change(poldiff_t * diff, const void *x, const void *y)
01245 {
01246 return terule_deep_diff(diff, x, y, TERULE_OFFSET_CHANGE);
01247 }
01248
01249 int terule_deep_diff_member(poldiff_t * diff, const void *x, const void *y)
01250 {
01251 return terule_deep_diff(diff, x, y, TERULE_OFFSET_MEMBER);
01252 }
01253
01254 int terule_deep_diff_trans(poldiff_t * diff, const void *x, const void *y)
01255 {
01256 return terule_deep_diff(diff, x, y, TERULE_OFFSET_TRANS);
01257 }
01258
01259 int terule_enable_line_numbers(poldiff_t * diff, terule_offset_e idx)
01260 {
01261 const apol_vector_t *te = NULL;
01262 poldiff_terule_t *terule = NULL;
01263 size_t i, j;
01264 qpol_iterator_t *iter = NULL;
01265 qpol_syn_terule_t *ste = NULL;
01266 int error = 0;
01267 unsigned long lineno = 0;
01268
01269 te = poldiff_get_terule_vector(diff, idx);
01270
01271 for (i = 0; i < apol_vector_get_size(te); i++) {
01272 terule = apol_vector_get_element(te, i);
01273 if (apol_vector_get_size(terule->mod_linenos) || apol_vector_get_size(terule->orig_linenos))
01274 continue;
01275 for (j = 0; j < terule->num_orig_rules; j++) {
01276 if (qpol_terule_get_syn_terule_iter(diff->orig_qpol, terule->orig_rules[j], &iter)) {
01277 error = errno;
01278 goto err;
01279 }
01280 for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
01281 if (qpol_iterator_get_item(iter, (void **)&ste) < 0) {
01282 error = errno;
01283 ERR(diff, "%s", strerror(error));
01284 goto err;
01285 }
01286 if (qpol_syn_terule_get_lineno(diff->orig_qpol, ste, &lineno) < 0) {
01287 error = errno;
01288 goto err;
01289 }
01290 if (apol_vector_append(terule->orig_linenos, (void *)lineno) < 0) {
01291 error = errno;
01292 ERR(diff, "%s", strerror(error));
01293 goto err;
01294 }
01295 }
01296 qpol_iterator_destroy(&iter);
01297 }
01298 apol_vector_sort_uniquify(terule->orig_linenos, NULL, NULL);
01299 for (j = 0; j < terule->num_mod_rules; j++) {
01300 if (qpol_terule_get_syn_terule_iter(diff->mod_qpol, terule->mod_rules[j], &iter)) {
01301 error = errno;
01302 goto err;
01303 }
01304 for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
01305 if (qpol_iterator_get_item(iter, (void **)&ste) < 0) {
01306 error = errno;
01307 ERR(diff, "%s", strerror(error));
01308 goto err;
01309 }
01310 if (qpol_syn_terule_get_lineno(diff->mod_qpol, ste, &lineno) < 0) {
01311 error = errno;
01312 goto err;
01313 }
01314 if (apol_vector_append(terule->mod_linenos, (void *)lineno) < 0) {
01315 error = errno;
01316 ERR(diff, "%s", strerror(error));
01317 goto err;
01318 }
01319 }
01320 qpol_iterator_destroy(&iter);
01321 }
01322 apol_vector_sort_uniquify(terule->mod_linenos, NULL, NULL);
01323 }
01324
01325 return 0;
01326 err:
01327 qpol_iterator_destroy(&iter);
01328 return -1;
01329 }