Pierre-Hugues Husson | 2acef1d | 2018-04-05 20:10:30 +0200 | [diff] [blame^] | 1 | From 9b009c3354946ec04c60b87d344ed2abbe63c4ba Mon Sep 17 00:00:00 2001 |
| 2 | From: James Carter <jwcart2@tycho.nsa.gov> |
| 3 | Date: Thu, 29 Mar 2018 16:06:49 -0400 |
| 4 | Subject: [PATCH 5/5] libsepol/cil: Improve processing of context rules |
| 5 | |
| 6 | Improve the processing of netifcon, genfscon, ibpkeycon, ibendportcon, |
| 7 | portcon, nodecon, fsuse, filecon, iomemcon, ioportcon, pcidevicecon, |
| 8 | and devicetreecon rules. |
| 9 | |
| 10 | If the multiple-decls option is not used then report errors if duplicate |
| 11 | context rules are found. If it is used then remove duplicate context rules |
| 12 | and report errors when two rules are identical except for the context. |
| 13 | |
| 14 | This also changes the ordering of portcon and filecon rules. The protocol |
| 15 | of portcon rules will be compared if the port numbers are the same and the |
| 16 | path strings of filecon rules will be compared if the number of meta |
| 17 | characters, the stem length, string length and file types are the same. |
| 18 | |
| 19 | Based on an initial patch by Pierre-Hugues Husson (phh@phh.me) |
| 20 | |
| 21 | Signed-off-by: James Carter <jwcart2@tycho.nsa.gov> |
| 22 | --- |
| 23 | libsepol/cil/src/cil_post.c | 303 ++++++++++++++++++++++++++++++++++++++++++-- |
| 24 | 1 file changed, 292 insertions(+), 11 deletions(-) |
| 25 | |
| 26 | diff --git a/libsepol/cil/src/cil_post.c b/libsepol/cil/src/cil_post.c |
| 27 | index a30de0e..3799350 100644 |
| 28 | --- a/libsepol/cil/src/cil_post.c |
| 29 | +++ b/libsepol/cil/src/cil_post.c |
| 30 | @@ -53,6 +53,83 @@ |
| 31 | static int __cil_expr_to_bitmap(struct cil_list *expr, ebitmap_t *out, int max, struct cil_db *db); |
| 32 | static int __cil_expr_list_to_bitmap(struct cil_list *expr_list, ebitmap_t *out, int max, struct cil_db *db); |
| 33 | |
| 34 | +static int cats_compare(struct cil_cats *a, struct cil_cats *b) |
| 35 | +{ |
| 36 | + struct cil_list_item *i, *j; |
| 37 | + int rc; |
| 38 | + |
| 39 | + if (a == b) return 0; |
| 40 | + if (!a) return -1; |
| 41 | + if (!b) return 1; |
| 42 | + |
| 43 | + /* Expects cat expression to have been evaluated */ |
| 44 | + cil_list_for_each(i, a->datum_expr) { |
| 45 | + cil_list_for_each(j, b->datum_expr) { |
| 46 | + rc = strcmp(DATUM(i->data)->fqn, DATUM(j->data)->fqn); |
| 47 | + if (!rc) return rc; |
| 48 | + } |
| 49 | + } |
| 50 | + return 0; |
| 51 | +} |
| 52 | + |
| 53 | +static int level_compare(struct cil_level *a, struct cil_level *b) |
| 54 | +{ |
| 55 | + int rc; |
| 56 | + |
| 57 | + if (a == b) return 0; |
| 58 | + if (!a) return -1; |
| 59 | + if (!b) return 1; |
| 60 | + |
| 61 | + if (a->sens != b->sens) { |
| 62 | + rc = strcmp(DATUM(a->sens)->fqn, DATUM(b->sens)->fqn); |
| 63 | + if (rc != 0) return rc; |
| 64 | + } |
| 65 | + if (a->cats != b->cats) { |
| 66 | + return cats_compare(a->cats, b->cats); |
| 67 | + } |
| 68 | + return 0; |
| 69 | +} |
| 70 | + |
| 71 | +static int range_compare(struct cil_levelrange *a, struct cil_levelrange *b) |
| 72 | +{ |
| 73 | + int rc; |
| 74 | + |
| 75 | + if (a == b) return 0; |
| 76 | + if (!a) return -1; |
| 77 | + if (!b) return 1; |
| 78 | + |
| 79 | + if (a->low != b->low) { |
| 80 | + rc = level_compare(a->low, b->low); |
| 81 | + if (rc != 0) return rc; |
| 82 | + } |
| 83 | + if (a->high != b->high) { |
| 84 | + return level_compare(a->high, b->high); |
| 85 | + } |
| 86 | + return 0; |
| 87 | +} |
| 88 | + |
| 89 | +static int context_compare(struct cil_context *a, struct cil_context *b) |
| 90 | +{ |
| 91 | + int rc; |
| 92 | + |
| 93 | + if (a->user != b->user) { |
| 94 | + rc = strcmp(DATUM(a->user)->fqn, DATUM(b->user)->fqn); |
| 95 | + if (rc != 0) return rc; |
| 96 | + } |
| 97 | + if (a->role != b->role) { |
| 98 | + rc = strcmp(DATUM(a->role)->fqn, DATUM(b->role)->fqn); |
| 99 | + if (rc != 0) return rc; |
| 100 | + } |
| 101 | + if (a->type != b->type) { |
| 102 | + rc = strcmp(DATUM(a->type)->fqn, DATUM(b->type)->fqn); |
| 103 | + if (rc != 0) return rc; |
| 104 | + } |
| 105 | + if (a->range != b->range) { |
| 106 | + return range_compare(a->range, b->range); |
| 107 | + } |
| 108 | + return 0; |
| 109 | +} |
| 110 | + |
| 111 | static int cil_verify_is_list(struct cil_list *list, enum cil_flavor flavor) |
| 112 | { |
| 113 | struct cil_list_item *curr; |
| 114 | @@ -144,6 +221,8 @@ int cil_post_filecon_compare(const void *a, const void *b) |
| 115 | rc = -1; |
| 116 | } else if (b_filecon->type < a_filecon->type) { |
| 117 | rc = 1; |
| 118 | + } else { |
| 119 | + rc = strcmp(a_filecon->path_str, b_filecon->path_str); |
| 120 | } |
| 121 | |
| 122 | free(a_path); |
| 123 | @@ -167,6 +246,10 @@ int cil_post_portcon_compare(const void *a, const void *b) |
| 124 | rc = -1; |
| 125 | } else if (bportcon->port_low < aportcon->port_low) { |
| 126 | rc = 1; |
| 127 | + } else if (aportcon->proto < bportcon->proto) { |
| 128 | + rc = -1; |
| 129 | + } else if (aportcon->proto > bportcon->proto) { |
| 130 | + rc = 1; |
| 131 | } |
| 132 | } |
| 133 | |
| 134 | @@ -327,6 +410,88 @@ int cil_post_fsuse_compare(const void *a, const void *b) |
| 135 | return rc; |
| 136 | } |
| 137 | |
| 138 | +int cil_post_filecon_context_compare(const void *a, const void *b) |
| 139 | +{ |
| 140 | + struct cil_filecon *a_filecon = *(struct cil_filecon**)a; |
| 141 | + struct cil_filecon *b_filecon = *(struct cil_filecon**)b; |
| 142 | + return context_compare(a_filecon->context, b_filecon->context); |
| 143 | +} |
| 144 | + |
| 145 | +int cil_post_portcon_context_compare(const void *a, const void *b) |
| 146 | +{ |
| 147 | + struct cil_portcon *a_portcon = *(struct cil_portcon**)a; |
| 148 | + struct cil_portcon *b_portcon = *(struct cil_portcon**)b; |
| 149 | + return context_compare(a_portcon->context, b_portcon->context); |
| 150 | +} |
| 151 | + |
| 152 | +int cil_post_genfscon_context_compare(const void *a, const void *b) |
| 153 | +{ |
| 154 | + struct cil_genfscon *a_genfscon = *(struct cil_genfscon**)a; |
| 155 | + struct cil_genfscon *b_genfscon = *(struct cil_genfscon**)b; |
| 156 | + return context_compare(a_genfscon->context, b_genfscon->context); |
| 157 | +} |
| 158 | + |
| 159 | +int cil_post_netifcon_context_compare(const void *a, const void *b) |
| 160 | +{ |
| 161 | + int rc; |
| 162 | + struct cil_netifcon *a_netifcon = *(struct cil_netifcon**)a; |
| 163 | + struct cil_netifcon *b_netifcon = *(struct cil_netifcon**)b; |
| 164 | + rc = context_compare(a_netifcon->if_context, b_netifcon->if_context); |
| 165 | + if (rc != 0) { |
| 166 | + return rc; |
| 167 | + } |
| 168 | + return context_compare(a_netifcon->packet_context, b_netifcon->packet_context); |
| 169 | +} |
| 170 | + |
| 171 | +int cil_post_nodecon_context_compare(const void *a, const void *b) |
| 172 | +{ |
| 173 | + struct cil_nodecon *a_nodecon = *(struct cil_nodecon **)a; |
| 174 | + struct cil_nodecon *b_nodecon = *(struct cil_nodecon **)b; |
| 175 | + return context_compare(a_nodecon->context, b_nodecon->context); |
| 176 | +} |
| 177 | + |
| 178 | +int cil_post_pirqcon_context_compare(const void *a, const void *b) |
| 179 | +{ |
| 180 | + struct cil_pirqcon *a_pirqcon = *(struct cil_pirqcon**)a; |
| 181 | + struct cil_pirqcon *b_pirqcon = *(struct cil_pirqcon**)b; |
| 182 | + return context_compare(a_pirqcon->context, b_pirqcon->context); |
| 183 | +} |
| 184 | + |
| 185 | +int cil_post_iomemcon_context_compare(const void *a, const void *b) |
| 186 | +{ |
| 187 | + struct cil_iomemcon *a_iomemcon = *(struct cil_iomemcon**)a; |
| 188 | + struct cil_iomemcon *b_iomemcon = *(struct cil_iomemcon**)b; |
| 189 | + return context_compare(a_iomemcon->context, b_iomemcon->context); |
| 190 | +} |
| 191 | + |
| 192 | +int cil_post_ioportcon_context_compare(const void *a, const void *b) |
| 193 | +{ |
| 194 | + struct cil_ioportcon *a_ioportcon = *(struct cil_ioportcon**)a; |
| 195 | + struct cil_ioportcon *b_ioportcon = *(struct cil_ioportcon**)b; |
| 196 | + return context_compare(a_ioportcon->context, b_ioportcon->context); |
| 197 | +} |
| 198 | + |
| 199 | +int cil_post_pcidevicecon_context_compare(const void *a, const void *b) |
| 200 | +{ |
| 201 | + struct cil_pcidevicecon *a_pcidevicecon = *(struct cil_pcidevicecon**)a; |
| 202 | + struct cil_pcidevicecon *b_pcidevicecon = *(struct cil_pcidevicecon**)b; |
| 203 | + return context_compare(a_pcidevicecon->context, b_pcidevicecon->context); |
| 204 | +} |
| 205 | + |
| 206 | +int cil_post_devicetreecon_context_compare(const void *a, const void *b) |
| 207 | +{ |
| 208 | + struct cil_devicetreecon *a_devicetreecon = *(struct cil_devicetreecon**)a; |
| 209 | + struct cil_devicetreecon *b_devicetreecon = *(struct cil_devicetreecon**)b; |
| 210 | + return context_compare(a_devicetreecon->context, b_devicetreecon->context); |
| 211 | +} |
| 212 | + |
| 213 | +int cil_post_fsuse_context_compare(const void *a, const void *b) |
| 214 | +{ |
| 215 | + struct cil_fsuse *a_fsuse = *(struct cil_fsuse**)a; |
| 216 | + struct cil_fsuse *b_fsuse = *(struct cil_fsuse**)b; |
| 217 | + return context_compare(a_fsuse->context, b_fsuse->context); |
| 218 | +} |
| 219 | + |
| 220 | static int __cil_post_db_count_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args) |
| 221 | { |
| 222 | struct cil_db *db = extra_args; |
| 223 | @@ -1929,6 +2094,74 @@ exit: |
| 224 | return rc; |
| 225 | } |
| 226 | |
| 227 | +static int __cil_post_report_conflict(struct cil_tree_node *node, uint32_t *finished, void *extra_args) |
| 228 | +{ |
| 229 | + struct cil_list_item *li = extra_args; |
| 230 | + |
| 231 | + if (node->flavor == CIL_BLOCK) { |
| 232 | + struct cil_block *blk = node->data; |
| 233 | + if (blk->is_abstract == CIL_TRUE) { |
| 234 | + *finished = CIL_TREE_SKIP_HEAD; |
| 235 | + } |
| 236 | + } else if (node->flavor == CIL_MACRO) { |
| 237 | + *finished = CIL_TREE_SKIP_HEAD; |
| 238 | + } else if (node->flavor == li->flavor) { |
| 239 | + if (node->data == li->data) { |
| 240 | + char *path = cil_tree_get_cil_path(node); |
| 241 | + cil_log(CIL_WARN, " at %s:%d\n", path, node->line); |
| 242 | + } |
| 243 | + } |
| 244 | + return SEPOL_OK; |
| 245 | +} |
| 246 | + |
| 247 | +static int __cil_post_process_context_rules(struct cil_sort *sort, int (*compar)(const void *, const void *), int (*concompar)(const void *, const void *), struct cil_db *db, enum cil_flavor flavor, const char *flavor_str) |
| 248 | +{ |
| 249 | + uint32_t count = sort->count; |
| 250 | + uint32_t i, j = 0, removed = 0; |
| 251 | + int rc = SEPOL_OK; |
| 252 | + |
| 253 | + if (count < 2) { |
| 254 | + return SEPOL_OK; |
| 255 | + } |
| 256 | + |
| 257 | + qsort(sort->array, sort->count, sizeof(sort->array), compar); |
| 258 | + |
| 259 | + for (i=1; i<count; i++) { |
| 260 | + if (compar(&sort->array[i], &sort->array[j]) != 0) { |
| 261 | + j++; |
| 262 | + } else { |
| 263 | + removed++; |
| 264 | + if (!db->multiple_decls || |
| 265 | + concompar(&sort->array[i], &sort->array[j]) != 0) { |
| 266 | + struct cil_list_item li; |
| 267 | + int rc2; |
| 268 | + cil_log(CIL_WARN, "Found conflicting %s rules\n", |
| 269 | + flavor_str); |
| 270 | + rc = SEPOL_ERR; |
| 271 | + li.flavor = flavor; |
| 272 | + li.data = sort->array[i]; |
| 273 | + rc2 = cil_tree_walk(db->ast->root, |
| 274 | + __cil_post_report_conflict, |
| 275 | + NULL, NULL, &li); |
| 276 | + if (rc2 != SEPOL_OK) goto exit; |
| 277 | + li.data = sort->array[j]; |
| 278 | + rc2 = cil_tree_walk(db->ast->root, |
| 279 | + __cil_post_report_conflict, |
| 280 | + NULL, NULL, &li); |
| 281 | + if (rc2 != SEPOL_OK) goto exit; |
| 282 | + } |
| 283 | + } |
| 284 | + if (i != j) { |
| 285 | + sort->array[j] = sort->array[i]; |
| 286 | + } |
| 287 | + } |
| 288 | + |
| 289 | + sort->count = count - removed; |
| 290 | + |
| 291 | +exit: |
| 292 | + return rc; |
| 293 | +} |
| 294 | + |
| 295 | static int cil_post_db(struct cil_db *db) |
| 296 | { |
| 297 | int rc = SEPOL_ERR; |
| 298 | @@ -1975,17 +2208,65 @@ static int cil_post_db(struct cil_db *db) |
| 299 | goto exit; |
| 300 | } |
| 301 | |
| 302 | - qsort(db->netifcon->array, db->netifcon->count, sizeof(db->netifcon->array), cil_post_netifcon_compare); |
| 303 | - qsort(db->genfscon->array, db->genfscon->count, sizeof(db->genfscon->array), cil_post_genfscon_compare); |
| 304 | - qsort(db->portcon->array, db->portcon->count, sizeof(db->portcon->array), cil_post_portcon_compare); |
| 305 | - qsort(db->nodecon->array, db->nodecon->count, sizeof(db->nodecon->array), cil_post_nodecon_compare); |
| 306 | - qsort(db->fsuse->array, db->fsuse->count, sizeof(db->fsuse->array), cil_post_fsuse_compare); |
| 307 | - qsort(db->filecon->array, db->filecon->count, sizeof(db->filecon->array), cil_post_filecon_compare); |
| 308 | - qsort(db->pirqcon->array, db->pirqcon->count, sizeof(db->pirqcon->array), cil_post_pirqcon_compare); |
| 309 | - qsort(db->iomemcon->array, db->iomemcon->count, sizeof(db->iomemcon->array), cil_post_iomemcon_compare); |
| 310 | - qsort(db->ioportcon->array, db->ioportcon->count, sizeof(db->ioportcon->array), cil_post_ioportcon_compare); |
| 311 | - qsort(db->pcidevicecon->array, db->pcidevicecon->count, sizeof(db->pcidevicecon->array), cil_post_pcidevicecon_compare); |
| 312 | - qsort(db->devicetreecon->array, db->devicetreecon->count, sizeof(db->devicetreecon->array), cil_post_devicetreecon_compare); |
| 313 | + rc = __cil_post_process_context_rules(db->netifcon, cil_post_netifcon_compare, cil_post_netifcon_context_compare, db, CIL_NETIFCON, CIL_KEY_NETIFCON); |
| 314 | + if (rc != SEPOL_OK) { |
| 315 | + cil_log(CIL_ERR, "Problems processing netifcon rules\n"); |
| 316 | + goto exit; |
| 317 | + } |
| 318 | + |
| 319 | + rc = __cil_post_process_context_rules(db->genfscon, cil_post_genfscon_compare, cil_post_genfscon_context_compare, db, CIL_GENFSCON, CIL_KEY_GENFSCON); |
| 320 | + if (rc != SEPOL_OK) { |
| 321 | + cil_log(CIL_ERR, "Problems processing genfscon rules\n"); |
| 322 | + goto exit; |
| 323 | + } |
| 324 | + |
| 325 | + rc = __cil_post_process_context_rules(db->portcon, cil_post_portcon_compare, cil_post_portcon_context_compare, db, CIL_PORTCON, CIL_KEY_PORTCON); |
| 326 | + if (rc != SEPOL_OK) { |
| 327 | + cil_log(CIL_ERR, "Problems processing portcon rules\n"); |
| 328 | + goto exit; |
| 329 | + } |
| 330 | + |
| 331 | + rc = __cil_post_process_context_rules(db->nodecon, cil_post_nodecon_compare, cil_post_nodecon_context_compare, db, CIL_NODECON, CIL_KEY_NODECON); |
| 332 | + if (rc != SEPOL_OK) { |
| 333 | + cil_log(CIL_ERR, "Problems processing nodecon rules\n"); |
| 334 | + goto exit; |
| 335 | + } |
| 336 | + |
| 337 | + rc = __cil_post_process_context_rules(db->fsuse, cil_post_fsuse_compare, cil_post_fsuse_context_compare, db, CIL_FSUSE, CIL_KEY_FSUSE); |
| 338 | + if (rc != SEPOL_OK) { |
| 339 | + cil_log(CIL_ERR, "Problems processing fsuse rules\n"); |
| 340 | + goto exit; |
| 341 | + } |
| 342 | + |
| 343 | + rc = __cil_post_process_context_rules(db->filecon, cil_post_filecon_compare, cil_post_filecon_context_compare, db, CIL_FILECON, CIL_KEY_FILECON); |
| 344 | + if (rc != SEPOL_OK) { |
| 345 | + cil_log(CIL_ERR, "Problems processing filecon rules\n"); |
| 346 | + goto exit; |
| 347 | + } |
| 348 | + |
| 349 | + rc = __cil_post_process_context_rules(db->iomemcon, cil_post_iomemcon_compare, cil_post_iomemcon_context_compare, db, CIL_IOMEMCON, CIL_KEY_IOMEMCON); |
| 350 | + if (rc != SEPOL_OK) { |
| 351 | + cil_log(CIL_ERR, "Problems processing iomemcon rules\n"); |
| 352 | + goto exit; |
| 353 | + } |
| 354 | + |
| 355 | + rc = __cil_post_process_context_rules(db->ioportcon, cil_post_ioportcon_compare, cil_post_ioportcon_context_compare, db, CIL_IOPORTCON, CIL_KEY_IOPORTCON); |
| 356 | + if (rc != SEPOL_OK) { |
| 357 | + cil_log(CIL_ERR, "Problems processing ioportcon rules\n"); |
| 358 | + goto exit; |
| 359 | + } |
| 360 | + |
| 361 | + rc = __cil_post_process_context_rules(db->pcidevicecon, cil_post_pcidevicecon_compare, cil_post_pcidevicecon_context_compare, db, CIL_PCIDEVICECON, CIL_KEY_PCIDEVICECON); |
| 362 | + if (rc != SEPOL_OK) { |
| 363 | + cil_log(CIL_ERR, "Problems processing pcidevicecon rules\n"); |
| 364 | + goto exit; |
| 365 | + } |
| 366 | + |
| 367 | + rc = __cil_post_process_context_rules(db->devicetreecon, cil_post_devicetreecon_compare, cil_post_devicetreecon_context_compare, db, CIL_DEVICETREECON, CIL_KEY_DEVICETREECON); |
| 368 | + if (rc != SEPOL_OK) { |
| 369 | + cil_log(CIL_ERR, "Problems processing devicetreecon rules\n"); |
| 370 | + goto exit; |
| 371 | + } |
| 372 | |
| 373 | exit: |
| 374 | return rc; |
| 375 | -- |
| 376 | 2.7.4 |
| 377 | |