From dc5daf8b99b92bf6b2516d9d331b19a2086edc8a Mon Sep 17 00:00:00 2001 From: Chris PeBenito Date: Wed, 8 Jun 2005 19:57:26 +0000 Subject: [PATCH] overhaul --- refpolicy/support/fc_sort.c | 449 ++++++++++++++++++++---------------- 1 file changed, 244 insertions(+), 205 deletions(-) diff --git a/refpolicy/support/fc_sort.c b/refpolicy/support/fc_sort.c index 8d0272ca..b969479a 100644 --- a/refpolicy/support/fc_sort.c +++ b/refpolicy/support/fc_sort.c @@ -1,11 +1,32 @@ -/* Copyright 2005, Tresys Technology */ +/* Copyright 2005, Tresys Technology + * + * Some parts of this came from matchpathcon.c in libselinux + */ + +/* PURPOSE OF THIS PROGRAM + * The original setfiles sorting algorithm did not take into + * account regular expression specificity. With the current + * strict and targeted policies this is not an issue because + * the file contexts are partially hand sorted and concatenated + * in the right order so that the matches are generally correct. + * The way reference policy and loadable policy modules handle + * file contexts makes them come out in an unpredictable order + * and therefore setfiles (or this standalone tool) need to sort + * the regular expressions in a deterministic and stable way. + */ + +#define BUF_SIZE 4096; +#define _GNU_SOURCE #include +#include +#include +#include typedef unsigned char bool_t; /* file_context_node - * A node used in a linked list of file contexts. + * A node used in a linked list of file contexts.c * Each node contains the regular expression, the type and * the context, as well as information about the regular * expression. The regular expression data (meta, stem_len @@ -14,7 +35,7 @@ typedef unsigned char bool_t; * next points to the next node in the linked list. */ typedef struct file_context_node { - char *regex; + char *path; char *file_type; char *context; bool_t meta; @@ -25,11 +46,13 @@ typedef struct file_context_node { void file_context_node_destroy(file_context_node_t *x) { - free(x->regex); + free(x->path); free(x->file_type); free(x->context); } + + /* file_context_bucket * A node used in a linked list of buckets that contain * file_context_node's. @@ -45,123 +68,6 @@ typedef struct file_context_bucket { -/* fc_merge - * Merges two sorted file context linked lists into one - * sorted one. - * Pass two lists a and b, and after the completion of fc_merge, - * the final list is contained in a, and b is empty. - */ -file_context_node_t *fc_merge(file_context_node_t *a, - file_context_node_t *b) -{ - file_context_node_t *a_current; - file_context_node_t *b_current; - file_context_node_t *temp; - file_context_node_t *jumpto; - - /* If a is a empty list, and b is not, - * set a as b and proceed to the end. */ - if (!a && b) - a = b; - /* If b is an empty list, leave a as it is. */ - else if (!b) { - } else { - /* Make it so the list a has the lesser - * first element always. */ - if (fc_compare(a, b) == 1) { - temp = a; - a = b; - b = temp; - } - a_current = a; - b_current = b; - - /* Merge by inserting b's nodes inbetween a's nodes. */ - while (a_current->next && b_current) { - jumpto = a_current->next; - - /* Insert b's nodes inbetween the current a node - * and the next a node.*/ - while (b_current && a_current->next && - fc_compare(a_current->next, - b_current) != -1) { - temp = a_current->next; - a_current->next = b_current; - b_current = b_current->next; - a_current->next->next = temp; - a_current = a_current->next; - } - - /* Skip all the inserted node from b to the - * next node in the original a. */ - a_current = jumpto; - } - - - /* if there is anything left in b to be inserted, - put it on the end */ - if (b_current) { - a_current->next = b_current; - } - } - - b = NULL; - - return a; -} - - - -/* fc_merge_sort - * Sorts file contexts from least specific to more specific. - * The bucket linked list is passed and after the completion - * of the fc_merge_sort function, there is only one bucket - * (pointed to by master) that contains a linked list - * of all the file contexts, in sorted order. - * Explanation of the algorithm: - * The algorithm implemented in fc_merge_sort is an iterative - * implementation of merge sort. - * At first, each bucket has a linked list of file contexts - * that are 1 element each. - * Each pass, each odd numbered bucket is merged into the bucket - * before it. This halves the number of buckets each pass. - * It will continue passing over the buckets (as described above) - * until there is only one bucket left, containing the list of - * file contexts, sorted. - */ -void fc_merge_sort(file_context_bucket_t *master) -{ - int i; - - file_context_bucket_t *current; - file_context_bucket_t *temp; - - file_context_node_t *ncurrent; - file_context_node_t *ntemp; - - /* Loop until master is the only bucket left - * so that this will stop when master contains - * the sorted list. */ - while (master->next) { - current = master; - - /* This loop merges buckets two-by-two. */ - while (current) { - if (current->next) { - /* Merge the next one into the current one. */ - current->data = - fc_merge(current->data, - current->next->data); - /* remove the next bucket that is now empty. */ - temp = current->next; - current->next = current->next->next; - free(temp); - } - current = current->next; - } - } -} - /* fc_compare * Compares two file contexts' regular expressions and returns: * -1 if a is less specific than b @@ -203,9 +109,9 @@ int fc_compare(file_context_node_t *a, file_context_node_t *b) /* Check to see if either a or b has a specified type * and the other doesn't. */ - if (!a->type && b->type) + if (!a->file_type && b->file_type) return -1; - if (!b->type && a->type) + if (!b->file_type && a->file_type) return 1; /* If none of the above conditions were satisfied, @@ -215,16 +121,141 @@ int fc_compare(file_context_node_t *a, file_context_node_t *b) +/* fc_merge + * Merges two sorted file context linked lists into one + * sorted one. + * Pass two lists a and b, and after the completion of fc_merge, + * the final list is contained in a, and b is empty. + */ +file_context_node_t *fc_merge(file_context_node_t *a, + file_context_node_t *b) +{ + file_context_node_t *a_current; + file_context_node_t *b_current; + file_context_node_t *temp; + file_context_node_t *jumpto; + + + + /* If a is a empty list, and b is not, + * set a as b and proceed to the end. */ + if (!a && b) + a = b; + /* If b is an empty list, leave a as it is. */ + else if (!b) { + } else { + /* Make it so the list a has the lesser + * first element always. */ + if (fc_compare(a, b) == 1) { + temp = a; + a = b; + b = temp; + } + a_current = a; + b_current = b; + + /* Merge by inserting b's nodes in between a's nodes. */ + while (a_current->next && b_current) { + jumpto = a_current->next; + + /* Insert b's nodes in between the current a node + * and the next a node.*/ + while (b_current && a_current->next && + fc_compare(a_current->next, + b_current) != -1) { + + + temp = a_current->next; + a_current->next = b_current; + b_current = b_current->next; + a_current->next->next = temp; + a_current = a_current->next; + } + + /* Skip all the inserted node from b to the + * next node in the original a. */ + a_current = jumpto; + } + + + /* if there is anything left in b to be inserted, + put it on the end */ + if (b_current) { + a_current->next = b_current; + } + } + + return a; +} + + + +/* fc_merge_sort + * Sorts file contexts from least specific to more specific. + * The bucket linked list is passed and after the completion + * of the fc_merge_sort function, there is only one bucket + * (pointed to by master) that contains a linked list + * of all the file contexts, in sorted order. + * Explanation of the algorithm: + * The algorithm implemented in fc_merge_sort is an iterative + * implementation of merge sort. + * At first, each bucket has a linked list of file contexts + * that are 1 element each. + * Each pass, each odd numbered bucket is merged into the bucket + * before it. This halves the number of buckets each pass. + * It will continue passing over the buckets (as described above) + * until there is only one bucket left, containing the list of + * file contexts, sorted. + */ +void fc_merge_sort(file_context_bucket_t *master) +{ + + + file_context_bucket_t *current; + file_context_bucket_t *temp; + + /* Loop until master is the only bucket left + * so that this will stop when master contains + * the sorted list. */ + while (master->next) { + current = master; + + /* This loop merges buckets two-by-two. */ + while (current) { + + if (current->next) { + + current->data = + fc_merge(current->data, + current->next->data); + + + + temp = current->next; + current->next = current->next->next; + + free(temp); + + } + + + current = current->next; + } + } + + +} + + + /* fc_fill_data * This processes a regular expression in a file context * and sets the data held in file_context_node, namely * meta, str_len and stem_len. * The following changes are made to fc_node after the * the completion of the function: - * fc_node->meta = 1 if regex has a meta character, - * 0 if not. - * fc_node->str_len = The string length of the regular - * expression. + * fc_node->meta = 1 if path has a meta character, 0 if not. + * fc_node->str_len = The string length of the entire path * fc_node->stem_len = The number of characters up until * the first meta character. */ @@ -241,8 +272,8 @@ void fc_fill_data(file_context_node_t *fc_node) * Note: this while loop has been adapted from * spec_hasMetaChars in matchpathcon.c from * libselinux-1.22. */ - while (fc_node->regex[c] != 0) { - switch (fc_node->regex[c]) { + while (fc_node->path[c] != '\0') { + switch (fc_node->path[c]) { case '.': case '^': case '$': @@ -283,22 +314,22 @@ void fc_fill_data(file_context_node_t *fc_node) int main(int argc, char *argv[]) { int lines; - size_t start, finish, regex_len; - size_t line_len, i, j; - char *str, *input_name, *output_name, *line_buf; - + size_t start, finish, regex_len, context_len; + size_t line_len, buf_len, i, j; + char *input_name, *output_name, *line_buf; + file_context_node_t *temp; file_context_node_t *head; file_context_node_t *current; - file_context_node_t *array; file_context_bucket_t *master; file_context_bucket_t *bcurrent; FILE *in_file, *out_file; + /* Check for the correct number of command line arguments. */ if (argc != 3) { - fprintf(stderr, "Error: invalid number of command line arguments.\n"); + fprintf(stderr, "Usage: %s \n",argv[0]); return 1; } @@ -307,66 +338,78 @@ int main(int argc, char *argv[]) i = j = lines = 0; - /* Make sure to have a terminating character, always. */ - line_buf[BUF_SIZE - 1] = '\0'; - /* Open the input file. */ - if (!(in_file = fopen(input_name), "r")) { + if (!(in_file = fopen(input_name, "r"))) { fprintf(stderr, "Error: failure opening input file for read.\n"); return 1; } + /* Initialize the head of the linked list. */ + head = current = (file_context_node_t*)malloc(sizeof(file_context_node_t)); + /* Parse the file into a file_context linked list. */ - buf = NULL; - while (getline(&line_buf, &line_len, in_file) { + line_buf = NULL; + + while ( getline(&line_buf, &buf_len, in_file) != -1 ){ + line_len = strlen(line_buf); + if( line_len == 0 || line_len == 1) + continue; /* Get rid of whitespace from the front of the line. */ for (i = 0; i < line_len; i++) { - if (line_buf[i] != ' ' || line_buf[i] != '\t') + if (!isspace(line_buf[i])) break; } - + + if (i >= line_len) continue; /* Check if the line isn't empty and isn't a comment */ if (line_buf[i] == '#') continue; - + /* We have a valid line - allocate a new node. */ temp = (file_context_node_t *)malloc(sizeof(file_context_node_t)); if (!temp) { fprintf(stderr, "Error: failure allocating memory.\n"); return 1; } + temp->next = NULL; memset(temp, 0, sizeof(file_context_node_t)); /* Parse out the regular expression from the line. */ start = i; - while (i < line_len && (line_buf[i] != ' ' || line_buf[i] != '\t')) + + + while (i < line_len && (!isspace(line_buf[i]))) i++; finish = i; - - regex_len = start - finish; - + + + regex_len = finish - start; + if (regex_len == 0) { file_context_node_destroy(temp); free(temp); + + continue; } - - temp->path = strndup(&line_buf[start], regex_len); + + temp->path = (char*)strndup(&line_buf[start], regex_len); if (!temp->path) { file_context_node_destroy(temp); free(temp); - fprintf(stderr, "Memory error\n"); + fprintf(stderr, "Error: failure allocating memory.\n"); return 1; } /* Get rid of whitespace after the regular expression. */ for (; i < line_len; i++) { - if (line_buf[i] != ' ' || line_buf[i] != '\t') + + if (!isspace(line_buf[i])) break; - } - + } + if (i == line_len) { file_context_node_destroy(temp); free(temp); @@ -376,45 +419,53 @@ int main(int argc, char *argv[]) /* Parse out the type from the line (if it * is there). */ if (line_buf[i] == '-') { - - temp->type = (char *)malloc(sizeof(char) * 3); - if (!(temp->type)) { + temp->file_type = (char *)malloc(sizeof(char) * 3); + if (!(temp->file_type)) { fprintf(stderr, "Error: failure allocating memory.\n"); return 1; } + if( i + 2 >= line_len ) { + file_context_node_destroy(temp); + free(temp); + + continue; + } + /* Fill the type into the array. */ - temp->type[0] = line_buf[i]; - temp->type[1] = line_buf[i + 1]; + temp->file_type[0] = line_buf[i]; + temp->file_type[1] = line_buf[i + 1]; i += 2; - temp->type[2] = 0; + temp->file_type[2] = 0; /* Get rid of whitespace after the type. */ - while (line_buf[i] <= ' ') - i++; + for (; i < line_len; i++) { + if (!isspace(line_buf[i])) + break; + } + + if (i == line_len) { + + file_context_node_destroy(temp); + free(temp); + continue; + } } /* Parse out the context from the line. */ start = i; - while (line_buf[i] > ' ') + while (i < line_len && (!isspace(line_buf[i]))) i++; finish = i; - /* Allocate a character array to hold the context. */ - temp->context = - (char *) malloc(sizeof(char) * - (finish - start + 1)); - if (!(temp->context)) { - printf - ("Error: failure allocating memory.\n"); - return -1; - } - temp->context[0] = 0; + context_len = finish - start; - /* Fill the context array. */ - temp->context[(finish - start)] = 0; - for (j = 0; j < finish - start; j++) { - temp->context[j] = line_buf[j + start]; + temp->context = (char*)strndup(&line_buf[start], context_len); + if (!temp->context) { + file_context_node_destroy(temp); + free(temp); + fprintf(stderr, "Error: failure allocating memory.\n"); + return 1; } /* Set all the data about the regular @@ -426,15 +477,19 @@ int main(int argc, char *argv[]) current->next = temp; current = current->next; lines++; + + + free(line_buf); + line_buf = NULL; } - free(buf); - fclose(path); + fclose(in_file); /* Create the bucket linked list from the earlier linked list. */ current = head->next; bcurrent = master = (file_context_bucket_t *) malloc(sizeof(file_context_bucket_t)); + /* Go until all the nodes have been put in individual buckets. */ while (current) { /* Copy over the file context line into the bucket. */ @@ -461,13 +516,14 @@ int main(int argc, char *argv[]) bcurrent = bcurrent->next; } + } /* Sort the bucket list. */ fc_merge_sort(master); /* Open the output file. */ - if (!(path = fopen(argv[2], "w"))) { + if (!(out_file = fopen(argv[2], "w"))) { printf("Error: failure opening output file for write.\n"); return -1; } @@ -475,45 +531,28 @@ int main(int argc, char *argv[]) /* Output the sorted file_context linked list to the output file. */ current = master->data; while (current) { - /* Output the regular expression. */ - i = 0; - while (current->regex[i] != 0) { - fprintf(path, "%c", current->regex[i]); - i++; - } - fprintf(path, "\t"); + /* Output the path. */ + fprintf(out_file, "%s\t\t", current->path); /* Output the type, if there is one. */ - if (current->type) { - i = 0; - while (current->type[i] != 0) { - fprintf(path, "%c", current->type[i]); - i++; - } - fprintf(path, "\t"); + if (current->file_type) { + fprintf(out_file, "%s\t", current->file_type); } /* Output the context. */ - i = 0; - while (current->context[i] != 0) { - fprintf(path, "%c", current->context[i]); - i++; - } - fprintf(path, "\n"); + fprintf(out_file, "%s\n", current->context); /* Remove the node. */ temp = current; current = current->next; - free(temp->regex); - if (temp->type) - free(temp->type); - free(temp->context); + file_context_node_destroy(temp); free(temp); + } free(master); - fclose(path); + fclose(out_file); return 0; }