diff options
Diffstat (limited to 'tools')
29 files changed, 0 insertions, 4648 deletions
diff --git a/tools/Android.mk b/tools/Android.mk deleted file mode 100644 index 98f562c..0000000 --- a/tools/Android.mk +++ /dev/null @@ -1,55 +0,0 @@ -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_MODULE := checkseapp -LOCAL_MODULE_TAGS := optional -LOCAL_C_INCLUDES := \ - external/pcre \ - external/selinux/libsepol/include -LOCAL_CFLAGS := -DLINK_SEPOL_STATIC -Wall -Werror -LOCAL_SRC_FILES := check_seapp.c -LOCAL_STATIC_LIBRARIES := libsepol -LOCAL_WHOLE_STATIC_LIBRARIES := libpcre -LOCAL_CXX_STL := none - -include $(BUILD_HOST_EXECUTABLE) - -################################### -include $(CLEAR_VARS) - -LOCAL_MODULE := checkfc -LOCAL_MODULE_TAGS := optional -LOCAL_C_INCLUDES := external/selinux/libsepol/include \ - external/libselinux/include -LOCAL_CFLAGS := -Wall -Werror -LOCAL_SRC_FILES := checkfc.c -LOCAL_STATIC_LIBRARIES := libsepol libselinux -LOCAL_CXX_STL := none - -include $(BUILD_HOST_EXECUTABLE) - -################################## -include $(CLEAR_VARS) - -LOCAL_MODULE := insertkeys.py -LOCAL_SRC_FILES := insertkeys.py -LOCAL_MODULE_CLASS := EXECUTABLES -LOCAL_IS_HOST_MODULE := true -LOCAL_MODULE_TAGS := optional - -include $(BUILD_PREBUILT) -################################### -include $(CLEAR_VARS) - -LOCAL_MODULE := sepolicy-check -LOCAL_MODULE_TAGS := optional -LOCAL_C_INCLUDES := external/selinux/libsepol/include -LOCAL_CFLAGS := -Wall -Werror -LOCAL_SRC_FILES := sepolicy-check.c -LOCAL_STATIC_LIBRARIES := libsepol -LOCAL_CXX_STL := none - -include $(BUILD_HOST_EXECUTABLE) - -include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/tools/README b/tools/README deleted file mode 100644 index 6035c03..0000000 --- a/tools/README +++ /dev/null @@ -1,63 +0,0 @@ -This directory contains a number of tools related to policy, some of -which are used in building and validating the policy and others are -available for help in auditing and analyzing policy. The tools are -described further below. - -checkfc - A utility for checking the validity of a file_contexts or a - property_contexts configuration file. Used as part of the policy - build to validate both files. Requires the sepolicy file as an - argument in order to check the validity of the security contexts - in the file_contexts or property_contexts file. - - Usage1: - checkfc sepolicy file_contexts - checkfc -p sepolicy property_contexts - - Also used to compare two file_contexts or file_contexts.bin files. - Displays one of subset, equal, superset, or incomparable. - - Usage2: - checkfc -c file_contexts1 file_contexts2 - - Example: - $ checkfc -c out/target/product/shamu/system/etc/general_file_contexts out/target/product/shamu/root/file_contexts.bin - subset - -checkseapp - A utility for merging together the main seapp_contexts - configuration and the device-specific one, and simultaneously - checking the validity of the configurations. Used as part of the - policy build process to merge and validate the configuration. - - Usage: - checkseapp -p sepolicy input_seapp_contexts0 [input_seapp_contexts1...] -o seapp_contexts - -insertkeys.py - A helper script for mapping tags in the signature stanzas of - mac_permissions.xml to public keys found in pem files. This - script is described further in the top-level sepolicy/README. - -post_process_mac_perms - A tool to help modify an existing mac_permissions.xml with additional app - certs not already found in that policy. This becomes useful when a directory - containing apps is searched and the certs from those apps are added to the - policy not already explicitly listed. - - Usage: - post_process_mac_perms [-h] -s SEINFO -d DIR -f POLICY - - -s SEINFO, --seinfo SEINFO seinfo tag for each generated stanza - -d DIR, --dir DIR Directory to search for apks - -f POLICY, --file POLICY mac_permissions.xml policy file - -sepolicy-check - A tool for auditing a sepolicy file for any allow rule that grants - a given permission. - - Usage: - sepolicy-check -s <domain> -t <type> -c <class> -p <permission> -P out/target/product/<board>/root/sepolicy - -sepolicy-analyze - A tool for performing various kinds of analysis on a sepolicy - file. diff --git a/tools/check_seapp.c b/tools/check_seapp.c deleted file mode 100644 index 69db388..0000000 --- a/tools/check_seapp.c +++ /dev/null @@ -1,1239 +0,0 @@ -#include <stdio.h> -#include <stdarg.h> -#include <ctype.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <stdint.h> -#include <search.h> -#include <stdbool.h> -#include <sepol/sepol.h> -#include <sepol/policydb/policydb.h> -#include <pcre.h> - -#define TABLE_SIZE 1024 -#define KVP_NUM_OF_RULES (sizeof(rules) / sizeof(key_map)) -#define log_set_verbose() do { logging_verbose = 1; log_info("Enabling verbose\n"); } while(0) -#define log_error(fmt, ...) log_msg(stderr, "Error: ", fmt, ##__VA_ARGS__) -#define log_warn(fmt, ...) log_msg(stderr, "Warning: ", fmt, ##__VA_ARGS__) -#define log_info(fmt, ...) if (logging_verbose ) { log_msg(stdout, "Info: ", fmt, ##__VA_ARGS__); } - -/** - * Initializes an empty, static list. - */ -#define list_init(free_fn) { .head = NULL, .tail = NULL, .freefn = free_fn } - -/** - * given an item in the list, finds the offset for the container - * it was stored in. - * - * @element The element from the list - * @type The container type ie what you allocated that has the list_element structure in it. - * @name The name of the field that is the list_element - * - */ -#define list_entry(element, type, name) \ - (type *)(((uint8_t *)element) - (uint8_t *)&(((type *)NULL)->name)) - -/** - * Iterates over the list, do not free elements from the list when using this. - * @list The list head to walk - * @var The variable name for the cursor - */ -#define list_for_each(list, var) \ - for(var = (list)->head; var != NULL; var = var->next) - - -typedef struct hash_entry hash_entry; -typedef enum key_dir key_dir; -typedef enum data_type data_type; -typedef enum rule_map_switch rule_map_switch; -typedef enum map_match map_match; -typedef struct key_map key_map; -typedef struct kvp kvp; -typedef struct rule_map rule_map; -typedef struct policy_info policy_info; -typedef struct list_element list_element; -typedef struct list list; -typedef struct key_map_regex key_map_regex; -typedef struct file_info file_info; - -enum map_match { - map_no_matches, - map_input_matched, - map_matched -}; - -const char *map_match_str[] = { - "do not match", - "match on all inputs", - "match on everything" -}; - -/** - * Whether or not the "key" from a key vaue pair is considered an - * input or an output. - */ -enum key_dir { - dir_in, dir_out -}; - -struct list_element { - list_element *next; -}; - -struct list { - list_element *head; - list_element *tail; - void (*freefn)(list_element *e); -}; - -struct key_map_regex { - pcre *compiled; - pcre_extra *extra; -}; - -/** - * The workhorse of the logic. This struct maps key value pairs to - * an associated set of meta data maintained in rule_map_new() - */ -struct key_map { - char *name; - key_dir dir; - char *data; - key_map_regex regex; - bool (*fn_validate)(char *value, char **errmsg); -}; - -/** - * Key value pair struct, this represents the raw kvp values coming - * from the rules files. - */ -struct kvp { - char *key; - char *value; -}; - -/** - * Rules are made up of meta data and an associated set of kvp stored in a - * key_map array. - */ -struct rule_map { - bool is_never_allow; - list violations; - list_element listify; - char *key; /** key value before hashing */ - size_t length; /** length of the key map */ - int lineno; /** Line number rule was encounter on */ - char *filename; /** File it was found in */ - key_map m[]; /** key value mapping */ -}; - -struct hash_entry { - list_element listify; - rule_map *r; /** The rule map to store at that location */ -}; - -/** - * Data associated for a policy file - */ -struct policy_info { - - char *policy_file_name; /** policy file path name */ - FILE *policy_file; /** file handle to the policy file */ - sepol_policydb_t *db; - sepol_policy_file_t *pf; - sepol_handle_t *handle; - sepol_context_t *con; -}; - -struct file_info { - FILE *file; /** file itself */ - const char *name; /** name of file. do not free, these are not alloc'd */ - list_element listify; -}; - -static void input_file_list_freefn(list_element *e); -static void line_order_list_freefn(list_element *e); -static void rule_map_free(rule_map *rm, bool is_in_htable); - -/** Set to !0 to enable verbose logging */ -static int logging_verbose = 0; - -/** file handle to the output file */ -static file_info out_file; - -static list input_file_list = list_init(input_file_list_freefn); - -static policy_info pol = { - .policy_file_name = NULL, - .policy_file = NULL, - .db = NULL, - .pf = NULL, - .handle = NULL, - .con = NULL -}; - -/** - * Head pointer to a linked list of - * rule map table entries (hash_entry), used for - * preserving the order of entries - * based on "first encounter" - */ -static list line_order_list = list_init(line_order_list_freefn); - -/* - * List of hash_entrys for never allow rules. - */ -static list nallow_list = list_init(line_order_list_freefn); - -/* validation call backs */ -static bool validate_bool(char *value, char **errmsg); -static bool validate_levelFrom(char *value, char **errmsg); -static bool validate_selinux_type(char *value, char **errmsg); -static bool validate_selinux_level(char *value, char **errmsg); - -/** - * The heart of the mapping process, this must be updated if a new key value pair is added - * to a rule. - */ -key_map rules[] = { - /*Inputs*/ - { .name = "isSystemServer", .dir = dir_in, .fn_validate = validate_bool }, - { .name = "isOwner", .dir = dir_in, .fn_validate = validate_bool }, - { .name = "user", .dir = dir_in, }, - { .name = "seinfo", .dir = dir_in, }, - { .name = "name", .dir = dir_in, }, - { .name = "path", .dir = dir_in, }, - { .name = "isPrivApp", .dir = dir_in, .fn_validate = validate_bool }, - /*Outputs*/ - { .name = "domain", .dir = dir_out, .fn_validate = validate_selinux_type }, - { .name = "type", .dir = dir_out, .fn_validate = validate_selinux_type }, - { .name = "levelFromUid", .dir = dir_out, .fn_validate = validate_bool }, - { .name = "levelFrom", .dir = dir_out, .fn_validate = validate_levelFrom }, - { .name = "level", .dir = dir_out, .fn_validate = validate_selinux_level }, -}; - -/** - * Appends to the end of the list. - * @list The list to append to - * @e the element to append - */ -void list_append(list *list, list_element *e) { - - memset(e, 0, sizeof(*e)); - - if (list->head == NULL ) { - list->head = list->tail = e; - return; - } - - list->tail->next = e; - list->tail = e; - return; -} - -/** - * Free's all the elements in the specified list. - * @list The list to free - */ -static void list_free(list *list) { - - list_element *tmp; - list_element *cursor = list->head; - - while (cursor) { - tmp = cursor; - cursor = cursor->next; - if (list->freefn) { - list->freefn(tmp); - } - } -} - -/* - * called when the lists are freed - */ -static void line_order_list_freefn(list_element *e) { - hash_entry *h = list_entry(e, typeof(*h), listify); - rule_map_free(h->r, true); - free(h); -} - -static void input_file_list_freefn(list_element *e) { - file_info *f = list_entry(e, typeof(*f), listify); - - if (f->file) { - fclose(f->file); - } - free(f); -} - -/** - * Send a logging message to a file - * @param out - * Output file to send message too - * @param prefix - * A special prefix to write to the file, such as "Error:" - * @param fmt - * The printf style formatter to use, such as "%d" - */ -static void __attribute__ ((format(printf, 3, 4))) -log_msg(FILE *out, const char *prefix, const char *fmt, ...) { - - fprintf(out, "%s", prefix); - va_list args; - va_start(args, fmt); - vfprintf(out, fmt, args); - va_end(args); -} - -/** - * Checks for a type in the policy. - * @param db - * The policy db to search - * @param type - * The type to search for - * @return - * 1 if the type is found, 0 otherwise. - * @warning - * This function always returns 1 if libsepol is not linked - * statically to this executable and LINK_SEPOL_STATIC is not - * defined. - */ -static int check_type(sepol_policydb_t *db, char *type) { - - int rc = 1; -#if defined(LINK_SEPOL_STATIC) - policydb_t *d = (policydb_t *)db; - hashtab_datum_t dat; - dat = hashtab_search(d->p_types.table, type); - rc = (dat == NULL) ? 0 : 1; -#endif - return rc; -} - -static bool match_regex(key_map *assert, const key_map *check) { - - char *tomatch = check->data; - - int ret = pcre_exec(assert->regex.compiled, assert->regex.extra, tomatch, - strlen(tomatch), 0, 0, NULL, 0); - - /* 0 from pcre_exec means matched */ - return !ret; -} - -static bool compile_regex(key_map *km, const char **errbuf, int *erroff) { - - size_t size; - char *anchored; - - /* - * Explicitly anchor all regex's - * The size is the length of the string to anchor (km->data), the anchor - * characters ^ and $ and the null byte. Hence strlen(km->data) + 3 - */ - size = strlen(km->data) + 3; - anchored = alloca(size); - sprintf(anchored, "^%s$", km->data); - - km->regex.compiled = pcre_compile(anchored, PCRE_DOTALL, errbuf, erroff, - NULL ); - if (!km->regex.compiled) { - return false; - } - - km->regex.extra = pcre_study(km->regex.compiled, 0, errbuf); - return true; -} - -static bool validate_bool(char *value, char **errmsg) { - - if (!strcmp("true", value) || !strcmp("false", value)) { - return true; - } - - *errmsg = "Expecting \"true\" or \"false\""; - return false; -} - -static bool validate_levelFrom(char *value, char **errmsg) { - - if(strcasecmp(value, "none") && strcasecmp(value, "all") && - strcasecmp(value, "app") && strcasecmp(value, "user")) { - *errmsg = "Expecting one of: \"none\", \"all\", \"app\" or \"user\""; - return false; - } - return true; -} - -static bool validate_selinux_type(char *value, char **errmsg) { - - /* - * No policy file present means we cannot check - * SE Linux types - */ - if (!pol.policy_file) { - return true; - } - - if(!check_type(pol.db, value)) { - *errmsg = "Expecting a valid SELinux type"; - return false; - } - - return true; -} - -static bool validate_selinux_level(char *value, char **errmsg) { - - /* - * No policy file present means we cannot check - * SE Linux MLS - */ - if (!pol.policy_file) { - return true; - } - - int ret = sepol_mls_check(pol.handle, pol.db, value); - if (ret < 0) { - *errmsg = "Expecting a valid SELinux MLS value"; - return false; - } - - return true; -} - -/** - * Validates a key_map against a set of enforcement rules, this - * function exits the application on a type that cannot be properly - * checked - * - * @param m - * The key map to check - * @param lineno - * The line number in the source file for the corresponding key map - * @return - * true if valid, false if invalid - */ -static bool key_map_validate(key_map *m, const char *filename, int lineno, - bool is_neverallow) { - - int erroff; - const char *errbuf; - bool rc = true; - char *key = m->name; - char *value = m->data; - char *errmsg = NULL; - - log_info("Validating %s=%s\n", key, value); - - /* - * Neverallows are completely skipped from sanity checking so you can match - * un-unspecified inputs. - */ - if (is_neverallow) { - if (!m->regex.compiled) { - rc = compile_regex(m, &errbuf, &erroff); - if (!rc) { - log_error("Invalid regex on line %d : %s PCRE error: %s at offset %d", - lineno, value, errbuf, erroff); - } - } - goto out; - } - - /* If the key has a validation routine, call it */ - if (m->fn_validate) { - rc = m->fn_validate(value, &errmsg); - - if (!rc) { - log_error("Could not validate key \"%s\" for value \"%s\" on line: %d in file: \"%s\": %s\n", key, value, - lineno, filename, errmsg); - } - } - -out: - log_info("Key map validate returning: %d\n", rc); - return rc; -} - -/** - * Prints a rule map back to a file - * @param fp - * The file handle to print too - * @param r - * The rule map to print - */ -static void rule_map_print(FILE *fp, rule_map *r) { - - size_t i; - key_map *m; - - for (i = 0; i < r->length; i++) { - m = &(r->m[i]); - if (i < r->length - 1) - fprintf(fp, "%s=%s ", m->name, m->data); - else - fprintf(fp, "%s=%s", m->name, m->data); - } -} - -/** - * Compare two rule maps for equality - * @param rmA - * a rule map to check - * @param rmB - * a rule map to check - * @return - * a map_match enum indicating the result - */ -static map_match rule_map_cmp(rule_map *rmA, rule_map *rmB) { - - size_t i; - size_t j; - int inputs_found = 0; - int num_of_matched_inputs = 0; - int input_mode = 0; - size_t matches = 0; - key_map *mA; - key_map *mB; - - for (i = 0; i < rmA->length; i++) { - mA = &(rmA->m[i]); - - for (j = 0; j < rmB->length; j++) { - mB = &(rmB->m[j]); - input_mode = 0; - - if (strcmp(mA->name, mB->name)) - continue; - - if (strcmp(mA->data, mB->data)) - continue; - - if (mB->dir != mA->dir) - continue; - else if (mB->dir == dir_in) { - input_mode = 1; - inputs_found++; - } - - if (input_mode) { - log_info("Matched input lines: name=%s data=%s\n", mA->name, mA->data); - num_of_matched_inputs++; - } - - /* Match found, move on */ - log_info("Matched lines: name=%s data=%s", mA->name, mA->data); - matches++; - break; - } - } - - /* If they all matched*/ - if (matches == rmA->length) { - log_info("Rule map cmp MATCH\n"); - return map_matched; - } - - /* They didn't all match but the input's did */ - else if (num_of_matched_inputs == inputs_found) { - log_info("Rule map cmp INPUT MATCH\n"); - return map_input_matched; - } - - /* They didn't all match, and the inputs didn't match, ie it didn't - * match */ - else { - log_info("Rule map cmp NO MATCH\n"); - return map_no_matches; - } -} - -/** - * Frees a rule map - * @param rm - * rule map to be freed. - * @is_in_htable - * True if the rule map has been added to the hash table, false - * otherwise. - */ -static void rule_map_free(rule_map *rm, bool is_in_htable) { - - size_t i; - size_t len = rm->length; - for (i = 0; i < len; i++) { - key_map *m = &(rm->m[i]); - free(m->data); - - if (m->regex.compiled) { - pcre_free(m->regex.compiled); - } - - if (m->regex.extra) { - pcre_free_study(m->regex.extra); - } - } - - /* - * hdestroy() frees comparsion keys for non glibc - * on GLIBC we always free on NON-GLIBC we free if - * it is not in the htable. - */ - if (rm->key) { -#ifdef __GLIBC__ - /* silence unused warning */ - (void)is_in_htable; - free(rm->key); -#else - if (!is_in_htable) { - free(rm->key); - } -#endif - } - - free(rm->filename); - free(rm); -} - -static void free_kvp(kvp *k) { - free(k->key); - free(k->value); -} - -/** - * Checks a rule_map for any variation of KVP's that shouldn't be allowed. - * It builds an assertion failure list for each rule map. - * Note that this function logs all errors. - * - * Current Checks: - * 1. That a specified name entry should have a specified seinfo entry as well. - * 2. That no rule violates a neverallow - * @param rm - * The rule map to check for validity. - */ -static void rule_map_validate(rule_map *rm) { - - size_t i, j; - const key_map *rule; - key_map *nrule; - hash_entry *e; - rule_map *assert; - list_element *cursor; - - list_for_each(&nallow_list, cursor) { - e = list_entry(cursor, typeof(*e), listify); - assert = e->r; - - size_t cnt = 0; - - for (j = 0; j < assert->length; j++) { - nrule = &(assert->m[j]); - - // mark that nrule->name is for a null check - bool is_null_check = !strcmp(nrule->data, "\"\""); - - for (i = 0; i < rm->length; i++) { - rule = &(rm->m[i]); - - if (!strcmp(rule->name, nrule->name)) { - - /* the name was found, (data cannot be false) then it was specified */ - is_null_check = false; - - if (match_regex(nrule, rule)) { - cnt++; - } - } - } - - /* - * the nrule was marked in a null check and we never found a match on nrule, thus - * it matched and we update the cnt - */ - if (is_null_check) { - cnt++; - } - } - if (cnt == assert->length) { - list_append(&rm->violations, &assert->listify); - } - } -} - -/** - * Given a set of key value pairs, this will construct a new rule map. - * On error this function calls exit. - * @param keys - * Keys from a rule line to map - * @param num_of_keys - * The length of the keys array - * @param lineno - * The line number the keys were extracted from - * @return - * A rule map pointer. - */ -static rule_map *rule_map_new(kvp keys[], size_t num_of_keys, int lineno, - const char *filename, bool is_never_allow) { - - size_t i = 0, j = 0; - rule_map *new_map = NULL; - kvp *k = NULL; - key_map *r = NULL, *x = NULL; - bool seen[KVP_NUM_OF_RULES]; - - for (i = 0; i < KVP_NUM_OF_RULES; i++) - seen[i] = false; - - new_map = calloc(1, (num_of_keys * sizeof(key_map)) + sizeof(rule_map)); - if (!new_map) - goto oom; - - new_map->is_never_allow = is_never_allow; - new_map->length = num_of_keys; - new_map->lineno = lineno; - new_map->filename = strdup(filename); - if (!new_map->filename) { - goto oom; - } - - /* For all the keys in a rule line*/ - for (i = 0; i < num_of_keys; i++) { - k = &(keys[i]); - r = &(new_map->m[i]); - - for (j = 0; j < KVP_NUM_OF_RULES; j++) { - x = &(rules[j]); - - /* Only assign key name to map name */ - if (strcasecmp(k->key, x->name)) { - if (i == KVP_NUM_OF_RULES) { - log_error("No match for key: %s\n", k->key); - goto err; - } - continue; - } - - if (seen[j]) { - log_error("Duplicated key: %s\n", k->key); - goto err; - } - seen[j] = true; - - memcpy(r, x, sizeof(key_map)); - - /* Assign rule map value to one from file */ - r->data = strdup(k->value); - if (!r->data) - goto oom; - - /* Enforce type check*/ - log_info("Validating keys!\n"); - if (!key_map_validate(r, filename, lineno, new_map->is_never_allow)) { - log_error("Could not validate\n"); - goto err; - } - - /* - * Only build key off of inputs with the exception of neverallows. - * Neverallows are keyed off of all key value pairs, - */ - if (r->dir == dir_in || new_map->is_never_allow) { - char *tmp; - int key_len = strlen(k->key); - int val_len = strlen(k->value); - int l = (new_map->key) ? strlen(new_map->key) : 0; - l = l + key_len + val_len; - l += 1; - - tmp = realloc(new_map->key, l); - if (!tmp) - goto oom; - - if (!new_map->key) - memset(tmp, 0, l); - - new_map->key = tmp; - - strncat(new_map->key, k->key, key_len); - strncat(new_map->key, k->value, val_len); - } - break; - } - free_kvp(k); - } - - if (new_map->key == NULL) { - log_error("Strange, no keys found, input file corrupt perhaps?\n"); - goto err; - } - - return new_map; - -oom: - log_error("Out of memory!\n"); -err: - if(new_map) { - rule_map_free(new_map, false); - for (; i < num_of_keys; i++) { - k = &(keys[i]); - free_kvp(k); - } - } - return NULL; -} - -/** - * Print the usage of the program - */ -static void usage() { - printf( - "checkseapp [options] <input file>\n" - "Processes an seapp_contexts file specified by argument <input file> (default stdin) " - "and allows later declarations to override previous ones on a match.\n" - "Options:\n" - "-h - print this help message\n" - "-v - enable verbose debugging informations\n" - "-p policy file - specify policy file for strict checking of output selectors against the policy\n" - "-o output file - specify output file or - for stdout. No argument runs in silent mode and outputs nothing\n"); -} - -static void init() { - - bool has_out_file; - list_element *cursor; - file_info *tmp; - - /* input files if the list is empty, use stdin */ - if (!input_file_list.head) { - log_info("Using stdin for input\n"); - tmp = malloc(sizeof(*tmp)); - if (!tmp) { - log_error("oom"); - exit(EXIT_FAILURE); - } - tmp->name = "stdin"; - tmp->file = stdin; - list_append(&input_file_list, &(tmp->listify)); - } - else { - list_for_each(&input_file_list, cursor) { - tmp = list_entry(cursor, typeof(*tmp), listify); - - log_info("Opening input file: \"%s\"\n", tmp->name); - tmp->file = fopen(tmp->name, "r"); - if (!tmp->file) { - log_error("Could not open file: %s error: %s\n", tmp->name, - strerror(errno)); - exit(EXIT_FAILURE); - } - } - } - - has_out_file = out_file.name != NULL; - - /* If output file is -, then use stdout, else open the path */ - if (has_out_file && !strcmp(out_file.name, "-")) { - out_file.file = stdout; - out_file.name = "stdout"; - } - else if (has_out_file) { - out_file.file = fopen(out_file.name, "w+"); - } - - if (has_out_file && !out_file.file) { - log_error("Could not open file: \"%s\" error: \"%s\"\n", out_file.name, - strerror(errno)); - exit(EXIT_FAILURE); - } - - if (pol.policy_file_name) { - log_info("Opening policy file: %s\n", pol.policy_file_name); - pol.policy_file = fopen(pol.policy_file_name, "rb"); - if (!pol.policy_file) { - log_error("Could not open file: %s error: %s\n", - pol.policy_file_name, strerror(errno)); - exit(EXIT_FAILURE); - } - - pol.handle = sepol_handle_create(); - if (!pol.handle) { - log_error("Could not create sepolicy handle: %s\n", - strerror(errno)); - exit(EXIT_FAILURE); - } - - if (sepol_policy_file_create(&pol.pf) < 0) { - log_error("Could not create sepolicy file: %s!\n", - strerror(errno)); - exit(EXIT_FAILURE); - } - - sepol_policy_file_set_fp(pol.pf, pol.policy_file); - sepol_policy_file_set_handle(pol.pf, pol.handle); - - if (sepol_policydb_create(&pol.db) < 0) { - log_error("Could not create sepolicy db: %s!\n", - strerror(errno)); - exit(EXIT_FAILURE); - } - - if (sepol_policydb_read(pol.db, pol.pf) < 0) { - log_error("Could not lod policy file to db: %s!\n", - strerror(errno)); - exit(EXIT_FAILURE); - } - } - - list_for_each(&input_file_list, cursor) { - tmp = list_entry(cursor, typeof(*tmp), listify); - log_info("Input file set to: \"%s\"\n", tmp->name); - } - - log_info("Policy file set to: \"%s\"\n", - (pol.policy_file_name == NULL) ? "None" : pol.policy_file_name); - log_info("Output file set to: \"%s\"\n", out_file.name); - -#if !defined(LINK_SEPOL_STATIC) - log_warn("LINK_SEPOL_STATIC is not defined\n""Not checking types!"); -#endif - -} - -/** - * Handle parsing and setting the global flags for the command line - * options. This function calls exit on failure. - * @param argc - * argument count - * @param argv - * argument list - */ -static void handle_options(int argc, char *argv[]) { - - int c; - file_info *input_file; - - while ((c = getopt(argc, argv, "ho:p:v")) != -1) { - switch (c) { - case 'h': - usage(); - exit(EXIT_SUCCESS); - case 'o': - out_file.name = optarg; - break; - case 'p': - pol.policy_file_name = optarg; - break; - case 'v': - log_set_verbose(); - break; - case '?': - if (optopt == 'o' || optopt == 'p') - log_error("Option -%c requires an argument.\n", optopt); - else if (isprint (optopt)) - log_error("Unknown option `-%c'.\n", optopt); - else { - log_error( - "Unknown option character `\\x%x'.\n", - optopt); - } - default: - exit(EXIT_FAILURE); - } - } - - for (c = optind; c < argc; c++) { - - input_file = calloc(1, sizeof(*input_file)); - if (!input_file) { - log_error("oom"); - exit(EXIT_FAILURE); - } - input_file->name = argv[c]; - list_append(&input_file_list, &input_file->listify); - } -} - -/** - * Adds a rule to the hash table and to the ordered list if needed. - * @param rm - * The rule map to add. - */ -static void rule_add(rule_map *rm) { - - map_match cmp; - ENTRY e; - ENTRY *f; - hash_entry *entry; - hash_entry *tmp; - list *list_to_addto; - - e.key = rm->key; - - log_info("Searching for key: %s\n", e.key); - /* Check to see if it has already been added*/ - f = hsearch(e, FIND); - - /* - * Since your only hashing on a partial key, the inputs we need to handle - * when you want to override the outputs for a given input set, as well as - * checking for duplicate entries. - */ - if(f) { - log_info("Existing entry found!\n"); - tmp = (hash_entry *)f->data; - cmp = rule_map_cmp(rm, tmp->r); - log_error("Duplicate line detected in file: %s\n" - "Lines %d and %d %s!\n", - rm->filename, tmp->r->lineno, rm->lineno, - map_match_str[cmp]); - rule_map_free(rm, false); - goto err; - } - /* It wasn't found, just add the rule map to the table */ - else { - - entry = malloc(sizeof(hash_entry)); - if (!entry) - goto oom; - - entry->r = rm; - e.data = entry; - - f = hsearch(e, ENTER); - if(f == NULL) { - goto oom; - } - - /* new entries must be added to the ordered list */ - entry->r = rm; - list_to_addto = rm->is_never_allow ? &nallow_list : &line_order_list; - list_append(list_to_addto, &entry->listify); - } - - return; -oom: - if (e.key) - free(e.key); - if (entry) - free(entry); - if (rm) - free(rm); - log_error("Out of memory in function: %s\n", __FUNCTION__); -err: - exit(EXIT_FAILURE); -} - -static void parse_file(file_info *in_file) { - - char *p; - size_t len; - char *token; - char *saveptr; - bool is_never_allow; - bool found_whitespace; - - size_t lineno = 0; - char *name = NULL; - char *value = NULL; - size_t token_cnt = 0; - - char line_buf[BUFSIZ]; - kvp keys[KVP_NUM_OF_RULES]; - - while (fgets(line_buf, sizeof(line_buf) - 1, in_file->file)) { - lineno++; - is_never_allow = false; - found_whitespace = false; - log_info("Got line %zu\n", lineno); - len = strlen(line_buf); - if (line_buf[len - 1] == '\n') - line_buf[len - 1] = '\0'; - p = line_buf; - - /* neverallow lines must start with neverallow (ie ^neverallow) */ - if (!strncasecmp(p, "neverallow", strlen("neverallow"))) { - p += strlen("neverallow"); - is_never_allow = true; - } - - /* strip trailing whitespace skip comments */ - while (isspace(*p)) { - p++; - found_whitespace = true; - } - if (*p == '#' || *p == '\0') - continue; - - token = strtok_r(p, " \t", &saveptr); - if (!token) - goto err; - - token_cnt = 0; - memset(keys, 0, sizeof(kvp) * KVP_NUM_OF_RULES); - while (1) { - - name = token; - value = strchr(name, '='); - if (!value) - goto err; - *value++ = 0; - - keys[token_cnt].key = strdup(name); - if (!keys[token_cnt].key) - goto oom; - - keys[token_cnt].value = strdup(value); - if (!keys[token_cnt].value) - goto oom; - - token_cnt++; - - token = strtok_r(NULL, " \t", &saveptr); - if (!token) - break; - - } /*End token parsing */ - - rule_map *r = rule_map_new(keys, token_cnt, lineno, in_file->name, is_never_allow); - if (!r) - goto err; - rule_add(r); - - } /* End file parsing */ - return; - -err: - log_error("Reading file: \"%s\" line: %zu name: \"%s\" value: \"%s\"\n", - in_file->name, lineno, name, value); - if(found_whitespace && name && !strcasecmp(name, "neverallow")) { - log_error("perhaps whitespace before neverallow\n"); - } - exit(EXIT_FAILURE); -oom: - log_error("In function %s: Out of memory\n", __FUNCTION__); - exit(EXIT_FAILURE); -} - -/** - * Parses the seapp_contexts file and neverallow file - * and adds them to the hash table and ordered list entries - * when it encounters them. - * Calls exit on failure. - */ -static void parse() { - - file_info *current; - list_element *cursor; - list_for_each(&input_file_list, cursor) { - current = list_entry(cursor, typeof(*current), listify); - parse_file(current); - } -} - -static void validate() { - - list_element *cursor, *v; - bool found_issues = false; - hash_entry *e; - rule_map *r; - list_for_each(&line_order_list, cursor) { - e = list_entry(cursor, typeof(*e), listify); - rule_map_validate(e->r); - } - - list_for_each(&line_order_list, cursor) { - e = list_entry(cursor, typeof(*e), listify); - r = e->r; - list_for_each(&r->violations, v) { - found_issues = true; - log_error("Rule in File \"%s\" on line %d: \"", e->r->filename, e->r->lineno); - rule_map_print(stderr, e->r); - r = list_entry(v, rule_map, listify); - fprintf(stderr, "\" violates neverallow in File \"%s\" on line %d: \"", r->filename, r->lineno); - rule_map_print(stderr, r); - fprintf(stderr, "\"\n"); - } - } - - if (found_issues) { - exit(EXIT_FAILURE); - } -} - -/** - * Should be called after parsing to cause the printing of the rule_maps - * stored in the ordered list, head first, which preserves the "first encountered" - * ordering. - */ -static void output() { - - hash_entry *e; - list_element *cursor; - - if (!out_file.file) { - log_info("No output file, not outputting.\n"); - return; - } - - list_for_each(&line_order_list, cursor) { - e = list_entry(cursor, hash_entry, listify); - rule_map_print(out_file.file, e->r); - fprintf(out_file.file, "\n"); - } -} - -/** - * This function is registered to the at exit handler and should clean up - * the programs dynamic resources, such as memory and fd's. - */ -static void cleanup() { - - /* Only close this when it was opened by me and not the crt */ - if (out_file.name && strcmp(out_file.name, "stdout") && out_file.file) { - log_info("Closing file: %s\n", out_file.name); - fclose(out_file.file); - } - - if (pol.policy_file) { - - log_info("Closing file: %s\n", pol.policy_file_name); - fclose(pol.policy_file); - - if (pol.db) - sepol_policydb_free(pol.db); - - if (pol.pf) - sepol_policy_file_free(pol.pf); - - if (pol.handle) - sepol_handle_destroy(pol.handle); - } - - log_info("Freeing lists\n"); - list_free(&input_file_list); - list_free(&line_order_list); - list_free(&nallow_list); - hdestroy(); -} - -int main(int argc, char *argv[]) { - if (!hcreate(TABLE_SIZE)) { - log_error("Could not create hash table: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } - atexit(cleanup); - handle_options(argc, argv); - init(); - log_info("Starting to parse\n"); - parse(); - log_info("Parsing completed, generating output\n"); - validate(); - output(); - log_info("Success, generated output\n"); - exit(EXIT_SUCCESS); -} diff --git a/tools/checkfc.c b/tools/checkfc.c deleted file mode 100644 index e7d19b0..0000000 --- a/tools/checkfc.c +++ /dev/null @@ -1,379 +0,0 @@ -#include <getopt.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <sepol/module.h> -#include <sepol/policydb/policydb.h> -#include <sepol/sepol.h> -#include <selinux/selinux.h> -#include <selinux/label.h> -#include <sys/stat.h> -#include <sys/types.h> - -static const char * const CHECK_FC_ASSERT_ATTRS[] = { "fs_type", "dev_type", "file_type", NULL }; -static const char * const CHECK_PC_ASSERT_ATTRS[] = { "property_type", NULL }; -static const char * const CHECK_SC_ASSERT_ATTRS[] = { "service_manager_type", NULL }; - -typedef enum filemode filemode; -enum filemode { - filemode_file_contexts = 0, - filemode_property_contexts, - filemode_service_contexts -}; - -static struct { - /* policy */ - struct { - union { - /* Union these so we don't have to cast */ - sepol_policydb_t *sdb; - policydb_t *pdb; - }; - sepol_policy_file_t *pf; - sepol_handle_t *handle; - FILE *file; -#define SEHANDLE_CNT 2 - struct selabel_handle *sehnd[SEHANDLE_CNT]; - } sepolicy; - - /* assertions */ - struct { - const char * const *attrs; /* for the original set to print on error */ - ebitmap_t set; /* the ebitmap representation of the attrs */ - } assert; - -} global_state; - -static const char * const *filemode_to_assert_attrs(filemode mode) -{ - switch (mode) { - case filemode_file_contexts: - return CHECK_FC_ASSERT_ATTRS; - case filemode_property_contexts: - return CHECK_PC_ASSERT_ATTRS; - case filemode_service_contexts: - return CHECK_SC_ASSERT_ATTRS; - } - /* die on invalid parameters */ - fprintf(stderr, "Error: Invalid mode of operation: %d\n", mode); - exit(1); -} - -static int get_attr_bit(policydb_t *policydb, const char *attr_name) -{ - struct type_datum *attr = hashtab_search(policydb->p_types.table, (char *)attr_name); - if (!attr) { - fprintf(stderr, "Error: \"%s\" is not defined in this policy.\n", attr_name); - return -1; - } - - if (attr->flavor != TYPE_ATTRIB) { - fprintf(stderr, "Error: \"%s\" is not an attribute in this policy.\n", attr_name); - return -1; - } - - return attr->s.value - 1; -} - -static bool ebitmap_attribute_assertion_init(ebitmap_t *assertions, const char * const attributes[]) -{ - - while (*attributes) { - - int bit_pos = get_attr_bit(global_state.sepolicy.pdb, *attributes); - if (bit_pos < 0) { - /* get_attr_bit() logs error */ - return false; - } - - int err = ebitmap_set_bit(assertions, bit_pos, 1); - if (err) { - fprintf(stderr, "Error: setting bit on assertion ebitmap!\n"); - return false; - } - attributes++; - } - return true; -} - -static bool is_type_of_attribute_set(policydb_t *policydb, const char *type_name, - ebitmap_t *attr_set) -{ - struct type_datum *type = hashtab_search(policydb->p_types.table, (char *)type_name); - if (!type) { - fprintf(stderr, "Error: \"%s\" is not defined in this policy.\n", type_name); - return false; - } - - if (type->flavor != TYPE_TYPE) { - fprintf(stderr, "Error: \"%s\" is not a type in this policy.\n", type_name); - return false; - } - - ebitmap_t dst; - ebitmap_init(&dst); - - /* Take the intersection, if the set is empty, then its a failure */ - int rc = ebitmap_and(&dst, attr_set, &policydb->type_attr_map[type->s.value - 1]); - if (rc) { - fprintf(stderr, "Error: Could not perform ebitmap_and: %d\n", rc); - exit(1); - } - - bool res = (bool)ebitmap_length(&dst); - - ebitmap_destroy(&dst); - return res; -} - -static void dump_char_array(FILE *stream, const char * const *strings) -{ - - const char * const *p = strings; - - fprintf(stream, "\""); - - while (*p) { - const char *s = *p++; - const char *fmt = *p ? "%s, " : "%s\""; - fprintf(stream, fmt, s); - } -} - -static int validate(char **contextp) -{ - bool res; - char *context = *contextp; - - sepol_context_t *ctx; - int rc = sepol_context_from_string(global_state.sepolicy.handle, context, - &ctx); - if (rc < 0) { - fprintf(stderr, "Error: Could not allocate context from string"); - exit(1); - } - - rc = sepol_context_check(global_state.sepolicy.handle, - global_state.sepolicy.sdb, ctx); - if (rc < 0) { - goto out; - } - - const char *type_name = sepol_context_get_type(ctx); - - uint32_t len = ebitmap_length(&global_state.assert.set); - if (len > 0) { - res = !is_type_of_attribute_set(global_state.sepolicy.pdb, type_name, - &global_state.assert.set); - if (res) { - fprintf(stderr, "Error: type \"%s\" is not of set: ", type_name); - dump_char_array(stderr, global_state.assert.attrs); - fprintf(stderr, "\n"); - /* The calls above did not affect rc, so set error before going to out */ - rc = -1; - goto out; - } - } - /* Success: Although it should be 0, we explicitly set rc to 0 for clarity */ - rc = 0; - - out: - sepol_context_free(ctx); - return rc; -} - -static void usage(char *name) { - fprintf(stderr, "usage1: %s [-p|-s] [-e] sepolicy context_file\n\n" - "Parses a context file and checks for syntax errors.\n" - "The context_file is assumed to be a file_contexts file\n" - "unless the -p or -s option is used to indicate the property or service backend respectively.\n" - "If -e is specified, then the context_file is allowed to be empty.\n\n" - - "usage2: %s -c file_contexts1 file_contexts2\n\n" - "Compares two file contexts files and reports one of subset, equal, superset, or incomparable.\n\n", - name, name); - exit(1); -} - -static void cleanup(void) { - - if (global_state.sepolicy.file) { - fclose(global_state.sepolicy.file); - } - - if (global_state.sepolicy.sdb) { - sepol_policydb_free(global_state.sepolicy.sdb); - } - - if (global_state.sepolicy.pf) { - sepol_policy_file_free(global_state.sepolicy.pf); - } - - if (global_state.sepolicy.handle) { - sepol_handle_destroy(global_state.sepolicy.handle); - } - - ebitmap_destroy(&global_state.assert.set); - - int i; - for (i = 0; i < SEHANDLE_CNT; i++) { - struct selabel_handle *sehnd = global_state.sepolicy.sehnd[i]; - if (sehnd) { - selabel_close(sehnd); - } - } -} - -static void do_compare_and_die_on_error(struct selinux_opt opts[], unsigned int backend, char *paths[]) -{ - enum selabel_cmp_result result; - char *result_str[] = { "subset", "equal", "superset", "incomparable" }; - int i; - - opts[0].value = NULL; /* not validating against a policy when comparing */ - - for (i = 0; i < SEHANDLE_CNT; i++) { - opts[1].value = paths[i]; - global_state.sepolicy.sehnd[i] = selabel_open(backend, opts, 2); - if (!global_state.sepolicy.sehnd[i]) { - fprintf(stderr, "Error: could not load context file from %s\n", paths[i]); - exit(1); - } - } - - result = selabel_cmp(global_state.sepolicy.sehnd[0], global_state.sepolicy.sehnd[1]); - printf("%s\n", result_str[result]); -} - -static void do_fc_check_and_die_on_error(struct selinux_opt opts[], unsigned int backend, filemode mode, - const char *sepolicy_file, const char *context_file, bool allow_empty) -{ - struct stat sb; - if (stat(context_file, &sb) < 0) { - perror("Error: could not get stat on file contexts file"); - exit(1); - } - - if (sb.st_size == 0) { - /* Nothing to check on empty file_contexts file if allowed*/ - if (allow_empty) { - return; - } - /* else: We could throw the error here, but libselinux backend will catch it */ - } - - global_state.sepolicy.file = fopen(sepolicy_file, "r"); - if (!global_state.sepolicy.file) { - perror("Error: could not open policy file"); - exit(1); - } - - global_state.sepolicy.handle = sepol_handle_create(); - if (!global_state.sepolicy.handle) { - fprintf(stderr, "Error: could not create policy handle: %s\n", strerror(errno)); - exit(1); - } - - if (sepol_policy_file_create(&global_state.sepolicy.pf) < 0) { - perror("Error: could not create policy handle"); - exit(1); - } - - sepol_policy_file_set_fp(global_state.sepolicy.pf, global_state.sepolicy.file); - sepol_policy_file_set_handle(global_state.sepolicy.pf, global_state.sepolicy.handle); - - int rc = sepol_policydb_create(&global_state.sepolicy.sdb); - if (rc < 0) { - perror("Error: could not create policy db"); - exit(1); - } - - rc = sepol_policydb_read(global_state.sepolicy.sdb, global_state.sepolicy.pf); - if (rc < 0) { - perror("Error: could not read file into policy db"); - exit(1); - } - - global_state.assert.attrs = filemode_to_assert_attrs(mode); - - bool ret = ebitmap_attribute_assertion_init(&global_state.assert.set, global_state.assert.attrs); - if (!ret) { - /* error messages logged by ebitmap_attribute_assertion_init() */ - exit(1); - } - - selinux_set_callback(SELINUX_CB_VALIDATE, - (union selinux_callback)&validate); - - opts[1].value = context_file; - - global_state.sepolicy.sehnd[0] = selabel_open(backend, opts, 2); - if (!global_state.sepolicy.sehnd[0]) { - fprintf(stderr, "Error: could not load context file from %s\n", context_file); - exit(1); - } -} - -int main(int argc, char **argv) -{ - struct selinux_opt opts[] = { - { SELABEL_OPT_VALIDATE, (void*)1 }, - { SELABEL_OPT_PATH, NULL } - }; - - // Default backend unless changed by input argument. - unsigned int backend = SELABEL_CTX_FILE; - - bool allow_empty = false; - bool compare = false; - char c; - - filemode mode = filemode_file_contexts; - - while ((c = getopt(argc, argv, "cpse")) != -1) { - switch (c) { - case 'c': - compare = true; - break; - case 'e': - allow_empty = true; - break; - case 'p': - mode = filemode_property_contexts; - backend = SELABEL_CTX_ANDROID_PROP; - break; - case 's': - mode = filemode_service_contexts; - backend = SELABEL_CTX_ANDROID_PROP; - break; - case 'h': - default: - usage(argv[0]); - break; - } - } - - int index = optind; - if (argc - optind != 2) { - usage(argv[0]); - } - - if (compare && backend != SELABEL_CTX_FILE) { - usage(argv[0]); - } - - atexit(cleanup); - - if (compare) { - do_compare_and_die_on_error(opts, backend, &(argv[index])); - } else { - /* remaining args are sepolicy file and context file */ - char *sepolicy_file = argv[index]; - char *context_file = argv[index + 1]; - - do_fc_check_and_die_on_error(opts, backend, mode, sepolicy_file, context_file, allow_empty); - } - exit(0); -} diff --git a/tools/fc_sort/Android.mk b/tools/fc_sort/Android.mk deleted file mode 100644 index f78d550..0000000 --- a/tools/fc_sort/Android.mk +++ /dev/null @@ -1,12 +0,0 @@ -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_MODULE := fc_sort -LOCAL_MODULE_TAGS := optional -LOCAL_SRC_FILES := fc_sort.c -LOCAL_CXX_STL := none - -include $(BUILD_HOST_EXECUTABLE) - -################################### diff --git a/tools/fc_sort/MODULE_LICENSE_GPL b/tools/fc_sort/MODULE_LICENSE_GPL deleted file mode 100644 index e69de29..0000000 --- a/tools/fc_sort/MODULE_LICENSE_GPL +++ /dev/null diff --git a/tools/fc_sort/NOTICE b/tools/fc_sort/NOTICE deleted file mode 100644 index 5b6e7c6..0000000 --- a/tools/fc_sort/NOTICE +++ /dev/null @@ -1,340 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - <one line to give the program's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - <signature of Ty Coon>, 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. diff --git a/tools/fc_sort/README b/tools/fc_sort/README deleted file mode 100644 index 0210dc7..0000000 --- a/tools/fc_sort/README +++ /dev/null @@ -1,9 +0,0 @@ -fc_sort is a tool used for sorting the file_contexts entries based on a heuristic that is - covered by a Fedora document. That document can be found here: - * https://fedoraproject.org/wiki/SELinux/ManagingFileContext - -The tool itself originates from: - * https://github.com/TresysTechnology/refpolicy - -It can be updated to the current tip of master branch with the below command: -$ wget https://raw.githubusercontent.com/TresysTechnology/refpolicy/master/support/fc_sort.c diff --git a/tools/fc_sort/fc_sort.c b/tools/fc_sort/fc_sort.c deleted file mode 100644 index f4d2cd0..0000000 --- a/tools/fc_sort/fc_sort.c +++ /dev/null @@ -1,567 +0,0 @@ -/* Copyright 2005,2013 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 <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> - -typedef unsigned char bool_t; - -/* file_context_node - * 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 - * and str_len) can be filled in by using the fc_fill_data - * function after the regular expression has been loaded. - * next points to the next node in the linked list. - */ -typedef struct file_context_node { - char *path; - char *file_type; - char *context; - bool_t meta; - int stem_len; - int str_len; - struct file_context_node *next; -} file_context_node_t; - -void file_context_node_destroy(file_context_node_t *x) -{ - 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. - * Each node contains a pointer to a file_context_node which - * is the header of its linked list. This linked list is the - * content of this bucket. - * next points to the next bucket in the linked list. - */ -typedef struct file_context_bucket { - file_context_node_t *data; - struct file_context_bucket *next; -} file_context_bucket_t; - - - -/* fc_compare - * Compares two file contexts' regular expressions and returns: - * -1 if a is less specific than b - * 0 if a and be are equally specific - * 1 if a is more specific than b - * The comparison is based on the following statements, - * in order from most important to least important, given a and b: - * If a is a regular expression and b is not, - * -> a is less specific than b. - * If a's stem length is shorter than b's stem length, - * -> a is less specific than b. - * If a's string length is shorter than b's string length, - * -> a is less specific than b. - * If a does not have a specified type and b does, - * -> a is less specific than b. - */ -int fc_compare(file_context_node_t *a, file_context_node_t *b) -{ - /* Check to see if either a or b have meta characters - * and the other doesn't. */ - if (a->meta && !b->meta) - return -1; - if (b->meta && !a->meta) - return 1; - - /* Check to see if either a or b have a shorter stem - * length than the other. */ - if (a->stem_len < b->stem_len) - return -1; - if (b->stem_len < a->stem_len) - return 1; - - /* Check to see if either a or b have a shorter string - * length than the other. */ - if (a->str_len < b->str_len) - return -1; - if (b->str_len < a->str_len) - return 1; - - /* Check to see if either a or b has a specified type - * and the other doesn't. */ - if (!a->file_type && b->file_type) - return -1; - if (!b->file_type && a->file_type) - return 1; - - /* If none of the above conditions were satisfied, - * then a and b are equally specific. */ - return 0; -} - - - -/* 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 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. - */ -void fc_fill_data(file_context_node_t *fc_node) -{ - int c = 0; - - fc_node->meta = 0; - fc_node->stem_len = 0; - fc_node->str_len = 0; - - /* Process until the string termination character - * has been reached. - * Note: this while loop has been adapted from - * spec_hasMetaChars in matchpathcon.c from - * libselinux-1.22. */ - while (fc_node->path[c] != '\0') { - switch (fc_node->path[c]) { - case '.': - case '^': - case '$': - case '?': - case '*': - case '+': - case '|': - case '[': - case '(': - case '{': - /* If a meta character is found, - * set meta to one */ - fc_node->meta = 1; - break; - case '\\': - /* If a escape character is found, - * skip the next character. */ - c++; - default: - /* If no meta character has been found yet, - * add one to the stem length. */ - if (!fc_node->meta) - fc_node->stem_len++; - break; - } - - fc_node->str_len++; - c++; - } -} - -/* main - * This program takes in two arguments, the input filename and the - * output filename. The input file should be syntactically correct. - * Overall what is done in the main is read in the file and store each - * line of code, sort it, then output it to the output file. - */ -int main(int argc, char *argv[]) -{ - int lines; - 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_bucket_t *master; - file_context_bucket_t *bcurrent; - - FILE *in_file, *out_file; - - - /* Check for the correct number of command line arguments. */ - if (argc < 2 || argc > 3) { - fprintf(stderr, "Usage: %s <infile> [<outfile>]\n",argv[0]); - return 1; - } - - input_name = argv[1]; - output_name = (argc >= 3) ? argv[2] : NULL; - - i = j = lines = 0; - - /* Open the input file. */ - 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)); - head->next = NULL; - - /* Parse the file into a file_context linked list. */ - 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 (!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 && (!isspace(line_buf[i]))) - i++; - finish = i; - - - regex_len = finish - start; - - if (regex_len == 0) { - file_context_node_destroy(temp); - free(temp); - - - continue; - } - - temp->path = (char*)strndup(&line_buf[start], regex_len); - if (!temp->path) { - file_context_node_destroy(temp); - free(temp); - fprintf(stderr, "Error: failure allocating memory.\n"); - return 1; - } - - /* Get rid of whitespace after the regular expression. */ - 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 type from the line (if it - * is there). */ - if (line_buf[i] == '-') { - 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->file_type[0] = line_buf[i]; - temp->file_type[1] = line_buf[i + 1]; - i += 2; - temp->file_type[2] = 0; - - /* Get rid of whitespace after the type. */ - 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 (i < line_len && (!isspace(line_buf[i]))) - i++; - finish = i; - - context_len = finish - 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 - * expression. */ - fc_fill_data(temp); - - /* Link this line of code at the end of - * the linked list. */ - current->next = temp; - current = current->next; - lines++; - - - free(line_buf); - line_buf = NULL; - } - 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)); - bcurrent->next = NULL; - bcurrent->data = NULL; - - /* Go until all the nodes have been put in individual buckets. */ - while (current) { - /* Copy over the file context line into the bucket. */ - bcurrent->data = current; - current = current->next; - - /* Detach the node in the bucket from the old list. */ - bcurrent->data->next = NULL; - - /* If there should be another bucket, put one at the end. */ - if (current) { - bcurrent->next = - (file_context_bucket_t *) - malloc(sizeof(file_context_bucket_t)); - if (!(bcurrent->next)) { - printf - ("Error: failure allocating memory.\n"); - return -1; - } - - /* Make sure the new bucket thinks it's the end of the - * list. */ - bcurrent->next->next = NULL; - - bcurrent = bcurrent->next; - } - - } - - /* Sort the bucket list. */ - fc_merge_sort(master); - - /* Open the output file. */ - if (output_name) { - if (!(out_file = fopen(output_name, "w"))) { - printf("Error: failure opening output file for write.\n"); - return -1; - } - } else { - out_file = stdout; - } - - /* Output the sorted file_context linked list to the output file. */ - current = master->data; - while (current) { - /* Output the path. */ - fprintf(out_file, "%s\t\t", current->path); - - /* Output the type, if there is one. */ - if (current->file_type) { - fprintf(out_file, "%s\t", current->file_type); - } - - /* Output the context. */ - fprintf(out_file, "%s\n", current->context); - - /* Remove the node. */ - temp = current; - current = current->next; - - file_context_node_destroy(temp); - free(temp); - - } - free(master); - - if (output_name) { - fclose(out_file); - } - - return 0; -} diff --git a/tools/insertkeys.py b/tools/insertkeys.py deleted file mode 100755 index ca1e432..0000000 --- a/tools/insertkeys.py +++ /dev/null @@ -1,267 +0,0 @@ -#!/usr/bin/env python - -from xml.sax import saxutils, handler, make_parser -from optparse import OptionParser -import ConfigParser -import logging -import base64 -import sys -import os - -__VERSION = (0, 1) - -''' -This tool reads a mac_permissions.xml and replaces keywords in the signature -clause with keys provided by pem files. -''' - -class GenerateKeys(object): - def __init__(self, path): - ''' - Generates an object with Base16 and Base64 encoded versions of the keys - found in the supplied pem file argument. PEM files can contain multiple - certs, however this seems to be unused in Android as pkg manager grabs - the first cert in the APK. This will however support multiple certs in - the resulting generation with index[0] being the first cert in the pem - file. - ''' - - self._base64Key = list() - self._base16Key = list() - - if not os.path.isfile(path): - sys.exit("Path " + path + " does not exist or is not a file!") - - pkFile = open(path, 'rb').readlines() - base64Key = "" - lineNo = 1 - certNo = 1 - inCert = False - for line in pkFile: - line = line.strip() - # Are we starting the certificate? - if line == "-----BEGIN CERTIFICATE-----": - if inCert: - sys.exit("Encountered another BEGIN CERTIFICATE without END CERTIFICATE on " + - "line: " + str(lineNo)) - - inCert = True - - # Are we ending the ceritifcate? - elif line == "-----END CERTIFICATE-----": - if not inCert: - sys.exit("Encountered END CERTIFICATE before BEGIN CERTIFICATE on line: " - + str(lineNo)) - - # If we ended the certificate trip the flag - inCert = False - - # Sanity check the input - if len(base64Key) == 0: - sys.exit("Empty certficate , certificate "+ str(certNo) + " found in file: " - + path) - - # ... and append the certificate to the list - # Base 64 includes uppercase. DO NOT tolower() - self._base64Key.append(base64Key) - try: - # Pkgmanager and setool see hex strings with lowercase, lets be consistent - self._base16Key.append(base64.b16encode(base64.b64decode(base64Key)).lower()) - except TypeError: - sys.exit("Invalid certificate, certificate "+ str(certNo) + " found in file: " - + path) - - # After adding the key, reset the accumulator as pem files may have subsequent keys - base64Key="" - - # And increment your cert number - certNo = certNo + 1 - - # If we haven't started the certificate, then we should not encounter any data - elif not inCert: - if line is not "": - sys.exit("Detected erroneous line \""+ line + "\" on " + str(lineNo) - + " in pem file: " + path) - - # else we have started the certicate and need to append the data - elif inCert: - base64Key += line - - else: - # We should never hit this assert, if we do then an unaccounted for state - # was entered that was NOT addressed by the if/elif statements above - assert(False == True) - - # The last thing to do before looping up is to increment line number - lineNo = lineNo + 1 - - def __len__(self): - return len(self._base16Key) - - def __str__(self): - return str(self.getBase16Keys()) - - def getBase16Keys(self): - return self._base16Key - - def getBase64Keys(self): - return self._base64Key - -class ParseConfig(ConfigParser.ConfigParser): - - # This must be lowercase - OPTION_WILDCARD_TAG = "all" - - def generateKeyMap(self, target_build_variant, key_directory): - - keyMap = dict() - - for tag in self.sections(): - - options = self.options(tag) - - for option in options: - - # Only generate the key map for debug or release, - # not both! - if option != target_build_variant and \ - option != ParseConfig.OPTION_WILDCARD_TAG: - logging.info("Skipping " + tag + " : " + option + - " because target build variant is set to " + - str(target_build_variant)) - continue - - if tag in keyMap: - sys.exit("Duplicate tag detected " + tag) - - tag_path = os.path.expandvars(self.get(tag, option)) - path = os.path.join(key_directory, tag_path) - - keyMap[tag] = GenerateKeys(path) - - # Multiple certificates may exist in - # the pem file. GenerateKeys supports - # this however, the mac_permissions.xml - # as well as PMS do not. - assert len(keyMap[tag]) == 1 - - return keyMap - -class ReplaceTags(handler.ContentHandler): - - DEFAULT_TAG = "default" - PACKAGE_TAG = "package" - POLICY_TAG = "policy" - SIGNER_TAG = "signer" - SIGNATURE_TAG = "signature" - - TAGS_WITH_CHILDREN = [ DEFAULT_TAG, PACKAGE_TAG, POLICY_TAG, SIGNER_TAG ] - - XML_ENCODING_TAG = '<?xml version="1.0" encoding="iso-8859-1"?>' - - def __init__(self, keyMap, out=sys.stdout): - - handler.ContentHandler.__init__(self) - self._keyMap = keyMap - self._out = out - self._out.write(ReplaceTags.XML_ENCODING_TAG) - self._out.write("<!-- AUTOGENERATED FILE DO NOT MODIFY -->") - self._out.write("<policy>") - - def __del__(self): - self._out.write("</policy>") - - def startElement(self, tag, attrs): - if tag == ReplaceTags.POLICY_TAG: - return - - self._out.write('<' + tag) - - for (name, value) in attrs.items(): - - if name == ReplaceTags.SIGNATURE_TAG and value in self._keyMap: - for key in self._keyMap[value].getBase16Keys(): - logging.info("Replacing " + name + " " + value + " with " + key) - self._out.write(' %s="%s"' % (name, saxutils.escape(key))) - else: - self._out.write(' %s="%s"' % (name, saxutils.escape(value))) - - if tag in ReplaceTags.TAGS_WITH_CHILDREN: - self._out.write('>') - else: - self._out.write('/>') - - def endElement(self, tag): - if tag == ReplaceTags.POLICY_TAG: - return - - if tag in ReplaceTags.TAGS_WITH_CHILDREN: - self._out.write('</%s>' % tag) - - def characters(self, content): - if not content.isspace(): - self._out.write(saxutils.escape(content)) - - def ignorableWhitespace(self, content): - pass - - def processingInstruction(self, target, data): - self._out.write('<?%s %s?>' % (target, data)) - -if __name__ == "__main__": - - # Intentional double space to line up equls signs and opening " for - # readability. - usage = "usage: %prog [options] CONFIG_FILE MAC_PERMISSIONS_FILE [MAC_PERMISSIONS_FILE...]\n" - usage += "This tool allows one to configure an automatic inclusion\n" - usage += "of signing keys into the mac_permision.xml file(s) from the\n" - usage += "pem files. If mulitple mac_permision.xml files are included\n" - usage += "then they are unioned to produce a final version." - - version = "%prog " + str(__VERSION) - - parser = OptionParser(usage=usage, version=version) - - parser.add_option("-v", "--verbose", - action="store_true", dest="verbose", default=False, - help="Print internal operations to stdout") - - parser.add_option("-o", "--output", default="stdout", dest="output_file", - metavar="FILE", help="Specify an output file, default is stdout") - - parser.add_option("-c", "--cwd", default=os.getcwd(), dest="root", - metavar="DIR", help="Specify a root (CWD) directory to run this from, it" \ - "chdirs' AFTER loading the config file") - - parser.add_option("-t", "--target-build-variant", default="eng", dest="target_build_variant", - help="Specify the TARGET_BUILD_VARIANT, defaults to eng") - - parser.add_option("-d", "--key-directory", default="", dest="key_directory", - help="Specify a parent directory for keys") - - (options, args) = parser.parse_args() - - if len(args) < 2: - parser.error("Must specify a config file (keys.conf) AND mac_permissions.xml file(s)!") - - logging.basicConfig(level=logging.INFO if options.verbose == True else logging.WARN) - - # Read the config file - config = ParseConfig() - config.read(args[0]) - - os.chdir(options.root) - - output_file = sys.stdout if options.output_file == "stdout" else open(options.output_file, "w") - logging.info("Setting output file to: " + options.output_file) - - # Generate the key list - key_map = config.generateKeyMap(options.target_build_variant.lower(), options.key_directory) - logging.info("Generate key map:") - for k in key_map: - logging.info(k + " : " + str(key_map[k])) - # Generate the XML file with markup replaced with keys - parser = make_parser() - parser.setContentHandler(ReplaceTags(key_map, output_file)) - for f in args[1:]: - parser.parse(f) diff --git a/tools/post_process_mac_perms b/tools/post_process_mac_perms deleted file mode 100755 index 25893ed..0000000 --- a/tools/post_process_mac_perms +++ /dev/null @@ -1,106 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (C) 2013 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -""" -Tool to help modify an existing mac_permissions.xml with additional app -certs not already found in that policy. This becomes useful when a directory -containing apps is searched and the certs from those apps are added to the -policy not already explicitly listed. -""" - -import sys -import os -import argparse -from base64 import b16encode, b64decode -import fileinput -import re -import subprocess -import zipfile - -PEM_CERT_RE = """-----BEGIN CERTIFICATE----- -(.+?) ------END CERTIFICATE----- -""" -def collect_certs_for_app(filename): - app_certs = set() - with zipfile.ZipFile(filename, 'r') as apkzip: - for info in apkzip.infolist(): - name = info.filename - if name.startswith('META-INF/') and name.endswith(('.DSA', '.RSA')): - cmd = ['openssl', 'pkcs7', '-inform', 'DER', - '-outform', 'PEM', '-print_certs'] - p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - pem_string, err = p.communicate(apkzip.read(name)) - if err and err.strip(): - raise RuntimeError('Problem running openssl on %s (%s)' % (filename, e)) - - # turn multiline base64 to single line base16 - transform = lambda x: b16encode(b64decode(x.replace('\n', ''))).lower() - results = re.findall(PEM_CERT_RE, pem_string, re.DOTALL) - certs = [transform(i) for i in results] - - app_certs.update(certs) - - return app_certs - -def add_leftover_certs(args): - all_app_certs = set() - for dirpath, _, files in os.walk(args.dir): - transform = lambda x: os.path.join(dirpath, x) - condition = lambda x: x.endswith('.apk') - apps = [transform(i) for i in files if condition(i)] - - # Collect certs for each app found - for app in apps: - app_certs = collect_certs_for_app(app) - all_app_certs.update(app_certs) - - if all_app_certs: - policy_certs = set() - with open(args.policy, 'r') as f: - cert_pattern = 'signature="([a-fA-F0-9]+)"' - policy_certs = re.findall(cert_pattern, f.read()) - - cert_diff = all_app_certs.difference(policy_certs) - - # Build xml stanzas - inner_tag = '<seinfo value="%s"/>' % args.seinfo - stanza = '<signer signature="%s">%s</signer>' - new_stanzas = [stanza % (cert, inner_tag) for cert in cert_diff] - mac_perms_string = ''.join(new_stanzas) - mac_perms_string += '</policy>' - - # Inline replace with new policy stanzas - for line in fileinput.input(args.policy, inplace=True): - sys.stdout.write(line.replace('</policy>', mac_perms_string)) - -def main(argv): - parser = argparse.ArgumentParser(description=__doc__) - - parser.add_argument('-s', '--seinfo', dest='seinfo', required=True, - help='seinfo tag for each generated stanza') - parser.add_argument('-d', '--dir', dest='dir', required=True, - help='Directory to search for apks') - parser.add_argument('-f', '--file', dest='policy', required=True, - help='mac_permissions.xml policy file') - - parser.set_defaults(func=add_leftover_certs) - args = parser.parse_args() - args.func(args) - -if __name__ == '__main__': - main(sys.argv) diff --git a/tools/sepolicy-analyze/Android.mk b/tools/sepolicy-analyze/Android.mk deleted file mode 100644 index 7568351..0000000 --- a/tools/sepolicy-analyze/Android.mk +++ /dev/null @@ -1,14 +0,0 @@ -LOCAL_PATH:= $(call my-dir) - -################################### -include $(CLEAR_VARS) - -LOCAL_MODULE := sepolicy-analyze -LOCAL_MODULE_TAGS := optional -LOCAL_C_INCLUDES := external/selinux/libsepol/include -LOCAL_CFLAGS := -Wall -Werror -LOCAL_SRC_FILES := sepolicy-analyze.c dups.c neverallow.c perm.c typecmp.c booleans.c attribute.c utils.c -LOCAL_STATIC_LIBRARIES := libsepol -LOCAL_CXX_STL := none - -include $(BUILD_HOST_EXECUTABLE) diff --git a/tools/sepolicy-analyze/README b/tools/sepolicy-analyze/README deleted file mode 100644 index d18609a..0000000 --- a/tools/sepolicy-analyze/README +++ /dev/null @@ -1,94 +0,0 @@ -sepolicy-analyze - A component-ized tool for performing various kinds of analysis on a - sepolicy file. The current kinds of analysis that are currently - supported include: - - TYPE EQUIVALENCE (typecmp) - sepolicy-analyze out/target/product/<board>/root/sepolicy typecmp -e - - Display all type pairs that are "equivalent", i.e. they are - identical with respect to allow rules, including indirect allow - rules via attributes and default-enabled conditional rules - (i.e. default boolean values yield a true conditional expression). - - Equivalent types are candidates for being coalesced into a single - type. However, there may be legitimate reasons for them to remain - separate, for example: - the types may differ in a respect not - included in the current analysis, such as default-disabled - conditional rules, audit-related rules (auditallow or dontaudit), - default type transitions, or constraints (e.g. mls), or - the - current policy may be overly permissive with respect to one or the - other of the types and thus the correct action may be to tighten - access to one or the other rather than coalescing them together, - or - the domains that would in fact have different accesses to the - types may not yet be defined or may be unconfined in the policy - you are analyzing. - - TYPE DIFFERENCE (typecmp) - sepolicy-analyze out/target/product/<board>/root/sepolicy typecmp -d - - Display type pairs that differ and the first difference found - between the two types. This may be used in looking for similar - types that are not equivalent but may be candidates for coalescing. - - DUPLICATE ALLOW RULES (dups) - sepolicy-analyze out/target/product/<board>/root/sepolicy dups - - Displays duplicate allow rules, i.e. pairs of allow rules that - grant the same permissions where one allow rule is written - directly in terms of individual types and the other is written in - terms of attributes associated with those same types. The rule - with individual types is a candidate for removal. The rule with - individual types may be directly represented in the source policy - or may be a result of expansion of a type negation (e.g. domain - -foo -bar is expanded to individual allow rules by the policy - compiler). Domains with unconfineddomain will typically have such - duplicate rules as a natural side effect and can be ignored. - - PERMISSIVE DOMAINS (permissive) - sepolicy-analyze out/target/product/<board>/root/sepolicy permissive - - Displays domains in the policy that are permissive, i.e. avc - denials are logged but not enforced for these domains. While - permissive domains can be helpful during development, they - should not be present in a final -user build. - - BOOLEANS (booleans) - sepolicy-analyze out/target/product/<board>/root/sepolicy booleans - - Displays the boolean names in the policy (if any). - Policy booleans are forbidden in Android policy, so if there is any - output, the policy will fail CTS. - - ATTRIBUTE (attribute) - sepolicy-analyze out/target/product/<board>/root/sepolicy attribute <name> - - Displays the types associated with the specified attribute name. - - NEVERALLOW CHECKING (neverallow) - sepolicy-analyze out/target/product/<board>/root/sepolicy neverallow \ - [-w] [-d] [-f neverallows.conf] | [-n "neverallow string"] - - Check whether the sepolicy file violates any of the neverallow rules - from the neverallows.conf file or a given string, which contain neverallow - statements in the same format as the SELinux policy.conf file, i.e. after - m4 macro expansion of the rules from a .te file. You can use an entire - policy.conf file as the neverallows.conf file and sepolicy-analyze will - ignore everything except for the neverallows within it. You can also - specify this as a command-line string argument, which could be useful for - quickly checking an individual expanded rule or group of rules. If there are - no violations, sepolicy-analyze will exit successfully with no output. - Otherwise, sepolicy-analyze will report all violations and exit - with a non-zero exit status. - - The -w or --warn option may be used to warn on any types, attributes, - classes, or permissions from a neverallow rule that could not be resolved - within the sepolicy file. This can be normal due to differences between - the policy from which the neverallow rules were taken and the policy - being checked. Such values are ignored for the purposes of neverallow - checking. - - The -d or --debug option may be used to cause sepolicy-analyze to emit the - neverallow rules as it parses them. This is principally a debugging facility - for the parser but could also be used to extract neverallow rules from - a full policy.conf file and output them in a more easily parsed format. diff --git a/tools/sepolicy-analyze/attribute.c b/tools/sepolicy-analyze/attribute.c deleted file mode 100644 index 474bda2..0000000 --- a/tools/sepolicy-analyze/attribute.c +++ /dev/null @@ -1,39 +0,0 @@ -#include "attribute.h" - -void attribute_usage() { - fprintf(stderr, "\tattribute <attribute-name>\n"); -} - -static int list_attribute(policydb_t * policydb, char *name) -{ - struct type_datum *attr; - struct ebitmap_node *n; - unsigned int bit; - - attr = hashtab_search(policydb->p_types.table, name); - if (!attr) { - fprintf(stderr, "%s is not defined in this policy.\n", name); - return -1; - } - - if (attr->flavor != TYPE_ATTRIB) { - fprintf(stderr, "%s is a type not an attribute in this policy.\n", name); - return -1; - } - - ebitmap_for_each_bit(&policydb->attr_type_map[attr->s.value - 1], n, bit) { - if (!ebitmap_node_get_bit(n, bit)) - continue; - printf("%s\n", policydb->p_type_val_to_name[bit]); - } - - return 0; -} - -int attribute_func (int argc, char **argv, policydb_t *policydb) { - if (argc != 2) { - USAGE_ERROR = true; - return -1; - } - return list_attribute(policydb, argv[1]); -} diff --git a/tools/sepolicy-analyze/attribute.h b/tools/sepolicy-analyze/attribute.h deleted file mode 100644 index 05adcbd..0000000 --- a/tools/sepolicy-analyze/attribute.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef ATTRIBUTE_H -#define ATTRIBUTE_H - -#include <sepol/policydb/policydb.h> - -#include "utils.h" - -void attribute_usage(void); -int attribute_func(int argc, char **argv, policydb_t *policydb); - -#endif /* ATTRIBUTE_H */ diff --git a/tools/sepolicy-analyze/booleans.c b/tools/sepolicy-analyze/booleans.c deleted file mode 100644 index c3b605d..0000000 --- a/tools/sepolicy-analyze/booleans.c +++ /dev/null @@ -1,22 +0,0 @@ -#include "booleans.h" - -void booleans_usage() { - fprintf(stderr, "\tbooleans\n"); -} - -static int list_booleans(hashtab_key_t k, - __attribute__ ((unused)) hashtab_datum_t d, - __attribute__ ((unused)) void *args) -{ - const char *name = k; - printf("%s\n", name); - return 0; -} - -int booleans_func (int argc, __attribute__ ((unused)) char **argv, policydb_t *policydb) { - if (argc != 1) { - USAGE_ERROR = true; - return -1; - } - return hashtab_map(policydb->p_bools.table, list_booleans, NULL); -} diff --git a/tools/sepolicy-analyze/booleans.h b/tools/sepolicy-analyze/booleans.h deleted file mode 100644 index bfbe0e1..0000000 --- a/tools/sepolicy-analyze/booleans.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef BOOLEANS_H -#define BOOLEANS_H - -#include <sepol/policydb/policydb.h> - -#include "utils.h" - -void booleans_usage(void); -int booleans_func(int argc, char **argv, policydb_t *policydb); - -#endif /* BOOLEANS_H */ diff --git a/tools/sepolicy-analyze/dups.c b/tools/sepolicy-analyze/dups.c deleted file mode 100644 index 88c2be2..0000000 --- a/tools/sepolicy-analyze/dups.c +++ /dev/null @@ -1,91 +0,0 @@ -#include <stdbool.h> -#include <stdio.h> -#include <sys/stat.h> -#include <sys/types.h> - -#include "dups.h" - -void dups_usage() { - fprintf(stderr, "\tdups\n"); -} - -static int find_dups_helper(avtab_key_t * k, avtab_datum_t * d, - void *args) -{ - policydb_t *policydb = args; - ebitmap_t *sattr, *tattr; - ebitmap_node_t *snode, *tnode; - unsigned int i, j; - avtab_key_t avkey; - avtab_ptr_t node; - struct type_datum *stype, *ttype, *stype2, *ttype2; - bool attrib1, attrib2; - - if (!(k->specified & AVTAB_ALLOWED)) - return 0; - - if (k->source_type == k->target_type) - return 0; /* self rule */ - - avkey.target_class = k->target_class; - avkey.specified = k->specified; - - sattr = &policydb->type_attr_map[k->source_type - 1]; - tattr = &policydb->type_attr_map[k->target_type - 1]; - stype = policydb->type_val_to_struct[k->source_type - 1]; - ttype = policydb->type_val_to_struct[k->target_type - 1]; - attrib1 = stype->flavor || ttype->flavor; - ebitmap_for_each_bit(sattr, snode, i) { - if (!ebitmap_node_get_bit(snode, i)) - continue; - ebitmap_for_each_bit(tattr, tnode, j) { - if (!ebitmap_node_get_bit(tnode, j)) - continue; - avkey.source_type = i + 1; - avkey.target_type = j + 1; - if (avkey.source_type == k->source_type && - avkey.target_type == k->target_type) - continue; - if (avkey.source_type == avkey.target_type) - continue; /* self rule */ - stype2 = policydb->type_val_to_struct[avkey.source_type - 1]; - ttype2 = policydb->type_val_to_struct[avkey.target_type - 1]; - attrib2 = stype2->flavor || ttype2->flavor; - if (attrib1 && attrib2) - continue; /* overlapping attribute-based rules */ - for (node = avtab_search_node(&policydb->te_avtab, &avkey); - node != NULL; - node = avtab_search_node_next(node, avkey.specified)) { - uint32_t perms = node->datum.data & d->data; - if ((attrib1 && perms == node->datum.data) || - (attrib2 && perms == d->data)) { - /* - * The attribute-based rule is a superset of the - * non-attribute-based rule. This is a dup. - */ - printf("Duplicate allow rule found:\n"); - display_allow(policydb, k, i, d->data); - display_allow(policydb, &node->key, i, node->datum.data); - printf("\n"); - } - } - } - } - - return 0; -} - -static int find_dups(policydb_t * policydb) -{ - if (avtab_map(&policydb->te_avtab, find_dups_helper, policydb)) - return -1; - return 0; -} - -int dups_func (int argc, __attribute__ ((unused)) char **argv, policydb_t *policydb) { - if (argc != 1) { - USAGE_ERROR = true; - return -1; - } - return find_dups(policydb); -} diff --git a/tools/sepolicy-analyze/dups.h b/tools/sepolicy-analyze/dups.h deleted file mode 100644 index 0e77224..0000000 --- a/tools/sepolicy-analyze/dups.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef DUPS_H -#define DUPS_H - -#include <sepol/policydb/policydb.h> - -#include "utils.h" - -void dups_usage(void); -int dups_func(int argc, char **argv, policydb_t *policydb); - -#endif /* DUPS_H */ diff --git a/tools/sepolicy-analyze/neverallow.c b/tools/sepolicy-analyze/neverallow.c deleted file mode 100644 index b288ea7..0000000 --- a/tools/sepolicy-analyze/neverallow.c +++ /dev/null @@ -1,515 +0,0 @@ -#include <ctype.h> -#include <fcntl.h> -#include <getopt.h> -#include <stdbool.h> -#include <stdio.h> -#include <sys/mman.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> - -#include "neverallow.h" - -static int debug; -static int warn; - -void neverallow_usage() { - fprintf(stderr, "\tneverallow [-w|--warn] [-d|--debug] [-n|--neverallows <neverallow-rules>] | [-f|--file <neverallow-file>]\n"); -} - -static int read_typeset(policydb_t *policydb, char **ptr, char *end, - type_set_t *typeset, uint32_t *flags) -{ - const char *keyword = "self"; - size_t keyword_size = strlen(keyword), len; - char *p = *ptr; - unsigned openparens = 0; - char *start, *id; - type_datum_t *type; - struct ebitmap_node *n; - unsigned int bit; - bool negate = false; - int rc; - - do { - while (p < end && isspace(*p)) - p++; - - if (p == end) - goto err; - - if (*p == '~') { - if (debug) - printf(" ~"); - typeset->flags = TYPE_COMP; - p++; - while (p < end && isspace(*p)) - p++; - if (p == end) - goto err; - } - - if (*p == '{') { - if (debug && !openparens) - printf(" {"); - openparens++; - p++; - continue; - } - - if (*p == '}') { - if (debug && openparens == 1) - printf(" }"); - if (openparens == 0) - goto err; - openparens--; - p++; - continue; - } - - if (*p == '*') { - if (debug) - printf(" *"); - typeset->flags = TYPE_STAR; - p++; - continue; - } - - if (*p == '-') { - if (debug) - printf(" -"); - negate = true; - p++; - continue; - } - - if (*p == '#') { - while (p < end && *p != '\n') - p++; - continue; - } - - start = p; - while (p < end && !isspace(*p) && *p != ':' && *p != ';' && *p != '{' && *p != '}' && *p != '#') - p++; - - if (p == start) - goto err; - - len = p - start; - if (len == keyword_size && !strncmp(start, keyword, keyword_size)) { - if (debug) - printf(" self"); - *flags |= RULE_SELF; - continue; - } - - id = calloc(1, len + 1); - if (!id) - goto err; - memcpy(id, start, len); - if (debug) - printf(" %s", id); - type = hashtab_search(policydb->p_types.table, id); - if (!type) { - if (warn) - fprintf(stderr, "Warning! Type or attribute %s used in neverallow undefined in policy being checked.\n", id); - negate = false; - continue; - } - free(id); - - if (type->flavor == TYPE_ATTRIB) { - if (negate) - rc = ebitmap_union(&typeset->negset, &policydb->attr_type_map[type->s.value - 1]); - else - rc = ebitmap_union(&typeset->types, &policydb->attr_type_map[type->s.value - 1]); - } else if (negate) { - rc = ebitmap_set_bit(&typeset->negset, type->s.value - 1, 1); - } else { - rc = ebitmap_set_bit(&typeset->types, type->s.value - 1, 1); - } - - negate = false; - - if (rc) - goto err; - - } while (p < end && openparens); - - if (p == end) - goto err; - - if (typeset->flags & TYPE_STAR) { - for (bit = 0; bit < policydb->p_types.nprim; bit++) { - if (ebitmap_get_bit(&typeset->negset, bit)) - continue; - if (policydb->type_val_to_struct[bit] && - policydb->type_val_to_struct[bit]->flavor == TYPE_ATTRIB) - continue; - if (ebitmap_set_bit(&typeset->types, bit, 1)) - goto err; - } - } - - ebitmap_for_each_bit(&typeset->negset, n, bit) { - if (!ebitmap_node_get_bit(n, bit)) - continue; - if (ebitmap_set_bit(&typeset->types, bit, 0)) - goto err; - } - - if (typeset->flags & TYPE_COMP) { - for (bit = 0; bit < policydb->p_types.nprim; bit++) { - if (policydb->type_val_to_struct[bit] && - policydb->type_val_to_struct[bit]->flavor == TYPE_ATTRIB) - continue; - if (ebitmap_get_bit(&typeset->types, bit)) - ebitmap_set_bit(&typeset->types, bit, 0); - else { - if (ebitmap_set_bit(&typeset->types, bit, 1)) - goto err; - } - } - } - - if (warn && ebitmap_length(&typeset->types) == 0 && !(*flags)) - fprintf(stderr, "Warning! Empty type set\n"); - - *ptr = p; - return 0; -err: - return -1; -} - -static int read_classperms(policydb_t *policydb, char **ptr, char *end, - class_perm_node_t **perms) -{ - char *p = *ptr; - unsigned openparens = 0; - char *id, *start; - class_datum_t *cls = NULL; - perm_datum_t *perm = NULL; - class_perm_node_t *classperms = NULL, *node = NULL; - bool complement = false; - - while (p < end && isspace(*p)) - p++; - - if (p == end || *p != ':') - goto err; - p++; - - if (debug) - printf(" :"); - - do { - while (p < end && isspace(*p)) - p++; - - if (p == end) - goto err; - - if (*p == '{') { - if (debug && !openparens) - printf(" {"); - openparens++; - p++; - continue; - } - - if (*p == '}') { - if (debug && openparens == 1) - printf(" }"); - if (openparens == 0) - goto err; - openparens--; - p++; - continue; - } - - if (*p == '#') { - while (p < end && *p != '\n') - p++; - continue; - } - - start = p; - while (p < end && !isspace(*p) && *p != '{' && *p != '}' && *p != ';' && *p != '#') - p++; - - if (p == start) - goto err; - - id = calloc(1, p - start + 1); - if (!id) - goto err; - memcpy(id, start, p - start); - if (debug) - printf(" %s", id); - cls = hashtab_search(policydb->p_classes.table, id); - if (!cls) { - if (warn) - fprintf(stderr, "Warning! Class %s used in neverallow undefined in policy being checked.\n", id); - continue; - } - - node = calloc(1, sizeof *node); - if (!node) - goto err; - node->tclass = cls->s.value; - node->next = classperms; - classperms = node; - free(id); - } while (p < end && openparens); - - if (p == end) - goto err; - - if (warn && !classperms) - fprintf(stderr, "Warning! Empty class set\n"); - - do { - while (p < end && isspace(*p)) - p++; - - if (p == end) - goto err; - - if (*p == '~') { - if (debug) - printf(" ~"); - complement = true; - p++; - while (p < end && isspace(*p)) - p++; - if (p == end) - goto err; - } - - if (*p == '{') { - if (debug && !openparens) - printf(" {"); - openparens++; - p++; - continue; - } - - if (*p == '}') { - if (debug && openparens == 1) - printf(" }"); - if (openparens == 0) - goto err; - openparens--; - p++; - continue; - } - - if (*p == '#') { - while (p < end && *p != '\n') - p++; - continue; - } - - start = p; - while (p < end && !isspace(*p) && *p != '{' && *p != '}' && *p != ';' && *p != '#') - p++; - - if (p == start) - goto err; - - id = calloc(1, p - start + 1); - if (!id) - goto err; - memcpy(id, start, p - start); - if (debug) - printf(" %s", id); - - if (!strcmp(id, "*")) { - for (node = classperms; node; node = node->next) - node->data = ~0; - continue; - } - - for (node = classperms; node; node = node->next) { - cls = policydb->class_val_to_struct[node->tclass-1]; - perm = hashtab_search(cls->permissions.table, id); - if (cls->comdatum && !perm) - perm = hashtab_search(cls->comdatum->permissions.table, id); - if (!perm) { - if (warn) - fprintf(stderr, "Warning! Permission %s used in neverallow undefined in class %s in policy being checked.\n", id, policydb->p_class_val_to_name[node->tclass-1]); - continue; - } - node->data |= 1U << (perm->s.value - 1); - } - free(id); - } while (p < end && openparens); - - if (p == end) - goto err; - - if (complement) { - for (node = classperms; node; node = node->next) - node->data = ~node->data; - } - - if (warn) { - for (node = classperms; node; node = node->next) - if (!node->data) - fprintf(stderr, "Warning! Empty permission set\n"); - } - - *perms = classperms; - *ptr = p; - return 0; -err: - return -1; -} - -static int check_neverallows(policydb_t *policydb, char *text, char *end) -{ - const char *keyword = "neverallow"; - size_t keyword_size = strlen(keyword), len; - struct avrule *neverallows = NULL, *avrule; - char *p, *start; - - p = text; - while (p < end) { - while (p < end && isspace(*p)) - p++; - - if (*p == '#') { - while (p < end && *p != '\n') - p++; - continue; - } - - start = p; - while (p < end && !isspace(*p)) - p++; - - len = p - start; - if (len != keyword_size || strncmp(start, keyword, keyword_size)) - continue; - - if (debug) - printf("neverallow"); - - avrule = calloc(1, sizeof *avrule); - if (!avrule) - goto err; - - avrule->specified = AVRULE_NEVERALLOW; - - if (read_typeset(policydb, &p, end, &avrule->stypes, &avrule->flags)) - goto err; - - if (read_typeset(policydb, &p, end, &avrule->ttypes, &avrule->flags)) - goto err; - - if (read_classperms(policydb, &p, end, &avrule->perms)) - goto err; - - while (p < end && *p != ';') - p++; - - if (p == end || *p != ';') - goto err; - - if (debug) - printf(";\n"); - - avrule->next = neverallows; - neverallows = avrule; - } - - if (!neverallows) - goto err; - - return check_assertions(NULL, policydb, neverallows); -err: - if (errno == ENOMEM) { - fprintf(stderr, "Out of memory while parsing neverallow rules\n"); - } else - fprintf(stderr, "Error while parsing neverallow rules\n"); - return -1; -} - -static int check_neverallows_file(policydb_t *policydb, const char *filename) -{ - int fd; - struct stat sb; - char *text, *end; - - fd = open(filename, O_RDONLY); - if (fd < 0) { - fprintf(stderr, "Could not open %s: %s\n", filename, strerror(errno)); - return -1; - } - if (fstat(fd, &sb) < 0) { - fprintf(stderr, "Can't stat '%s': %s\n", filename, strerror(errno)); - close(fd); - return -1; - } - text = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); - end = text + sb.st_size; - if (text == MAP_FAILED) { - fprintf(stderr, "Can't mmap '%s': %s\n", filename, strerror(errno)); - close(fd); - return -1; - } - close(fd); - return check_neverallows(policydb, text, end); -} - -static int check_neverallows_string(policydb_t *policydb, char *string, size_t len) -{ - char *text, *end; - text = string; - end = text + len; - return check_neverallows(policydb, text, end); -} - -int neverallow_func (int argc, char **argv, policydb_t *policydb) { - char *rules = 0, *file = 0; - char ch; - - struct option neverallow_options[] = { - {"debug", no_argument, NULL, 'd'}, - {"file_input", required_argument, NULL, 'f'}, - {"neverallow", required_argument, NULL, 'n'}, - {"warn", no_argument, NULL, 'w'}, - {NULL, 0, NULL, 0} - }; - - while ((ch = getopt_long(argc, argv, "df:n:w", neverallow_options, NULL)) != -1) { - switch (ch) { - case 'd': - debug = 1; - break; - case 'f': - file = optarg; - break; - case 'n': - rules = optarg; - break; - case 'w': - warn = 1; - break; - default: - USAGE_ERROR = true; - return -1; - } - } - - if (!(rules || file) || (rules && file)){ - USAGE_ERROR = true; - return -1; - } - if (file) { - return check_neverallows_file(policydb, file); - } else { - return check_neverallows_string(policydb, rules, strlen(rules)); - } -} diff --git a/tools/sepolicy-analyze/neverallow.h b/tools/sepolicy-analyze/neverallow.h deleted file mode 100644 index be80822..0000000 --- a/tools/sepolicy-analyze/neverallow.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef NEVERALLOW_H -#define NEVERALLOW_H - -#include <sepol/policydb/policydb.h> - -#include "utils.h" - -void neverallow_usage(void); -int neverallow_func(int argc, char **argv, policydb_t *policydb); - -#endif /* NEVERALLOW_H */ diff --git a/tools/sepolicy-analyze/perm.c b/tools/sepolicy-analyze/perm.c deleted file mode 100644 index 4cc4869..0000000 --- a/tools/sepolicy-analyze/perm.c +++ /dev/null @@ -1,30 +0,0 @@ -#include "perm.h" - -void permissive_usage() { - fprintf(stderr, "\tpermissive\n"); -} - -static int list_permissive(policydb_t * policydb) -{ - struct ebitmap_node *n; - unsigned int bit; - - /* - * iterate over all domains and check if domain is in permissive - */ - ebitmap_for_each_bit(&policydb->permissive_map, n, bit) - { - if (ebitmap_node_get_bit(n, bit)) { - printf("%s\n", policydb->p_type_val_to_name[bit -1]); - } - } - return 0; -} - -int permissive_func (int argc, __attribute__ ((unused)) char **argv, policydb_t *policydb) { - if (argc != 1) { - USAGE_ERROR = true; - return -1; - } - return list_permissive(policydb); -} diff --git a/tools/sepolicy-analyze/perm.h b/tools/sepolicy-analyze/perm.h deleted file mode 100644 index 16e619a..0000000 --- a/tools/sepolicy-analyze/perm.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef PERM_H -#define PERM_H - -#include <sepol/policydb/policydb.h> - -#include "utils.h" - -void permissive_usage(void); -int permissive_func(int argc, char **argv, policydb_t *policydb); - -#endif /* PERM_H */ diff --git a/tools/sepolicy-analyze/sepolicy-analyze.c b/tools/sepolicy-analyze/sepolicy-analyze.c deleted file mode 100644 index b70eaaa..0000000 --- a/tools/sepolicy-analyze/sepolicy-analyze.c +++ /dev/null @@ -1,65 +0,0 @@ -#include <stddef.h> -#include <stdio.h> -#include <string.h> - -#include "dups.h" -#include "neverallow.h" -#include "perm.h" -#include "typecmp.h" -#include "booleans.h" -#include "attribute.h" -#include "utils.h" - -#define NUM_COMPONENTS (int) (sizeof(analyze_components)/sizeof(analyze_components[0])) - -#define COMP(x) { #x, sizeof(#x) - 1, x ##_usage, x ##_func } -static struct { - const char *key; - size_t keylen; - void (*usage) (void); - int (*func) (int argc, char **argv, policydb_t *policydb); -} analyze_components[] = { - COMP(dups), - COMP(neverallow), - COMP(permissive), - COMP(typecmp), - COMP(booleans), - COMP(attribute) -}; - -void usage(char *arg0) -{ - int i; - - fprintf(stderr, "%s must be called on a policy file with a component and the appropriate arguments specified\n", arg0); - fprintf(stderr, "%s <policy-file>:\n", arg0); - for(i = 0; i < NUM_COMPONENTS; i++) { - analyze_components[i].usage(); - } - exit(1); -} - -int main(int argc, char **argv) -{ - char *policy; - struct policy_file pf; - policydb_t policydb; - int rc; - int i; - - if (argc < 3) - usage(argv[0]); - policy = argv[1]; - if(load_policy(policy, &policydb, &pf)) - exit(1); - for(i = 0; i < NUM_COMPONENTS; i++) { - if (!strcmp(analyze_components[i].key, argv[2])) { - rc = analyze_components[i].func(argc - 2, argv + 2, &policydb); - if (rc && USAGE_ERROR) { - usage(argv[0]); } - return rc; - } - } - usage(argv[0]); - exit(0); -} diff --git a/tools/sepolicy-analyze/typecmp.c b/tools/sepolicy-analyze/typecmp.c deleted file mode 100644 index 5fffd63..0000000 --- a/tools/sepolicy-analyze/typecmp.c +++ /dev/null @@ -1,295 +0,0 @@ -#include <getopt.h> -#include <sepol/policydb/expand.h> - -#include "typecmp.h" - -void typecmp_usage() { - fprintf(stderr, "\ttypecmp [-d|--diff] [-e|--equiv]\n"); -} - -static int insert_type_rule(avtab_key_t * k, avtab_datum_t * d, - struct avtab_node *type_rules) -{ - struct avtab_node *p, *c, *n; - - for (p = type_rules, c = type_rules->next; c; p = c, c = c->next) { - /* - * Find the insertion point, keeping the list - * ordered by source type, then target type, then - * target class. - */ - if (k->source_type < c->key.source_type) - break; - if (k->source_type == c->key.source_type && - k->target_type < c->key.target_type) - break; - if (k->source_type == c->key.source_type && - k->target_type == c->key.target_type && - k->target_class <= c->key.target_class) - break; - } - - if (c && - k->source_type == c->key.source_type && - k->target_type == c->key.target_type && - k->target_class == c->key.target_class) { - c->datum.data |= d->data; - return 0; - } - - /* Insert the rule */ - n = malloc(sizeof(struct avtab_node)); - if (!n) { - fprintf(stderr, "out of memory\n"); - exit(1); - } - - n->key = *k; - n->datum = *d; - n->next = p->next; - p->next = n; - return 0; -} - -static int create_type_rules_helper(avtab_key_t * k, avtab_datum_t * d, - void *args) -{ - struct avtab_node *type_rules = args; - avtab_key_t key; - - /* - * Insert the rule into the list for - * the source type. The source type value - * is cleared as we want to compare against other type - * rules with different source types. - */ - key = *k; - key.source_type = 0; - if (k->source_type == k->target_type) { - /* Clear target type as well; this is a self rule. */ - key.target_type = 0; - } - if (insert_type_rule(&key, d, &type_rules[k->source_type - 1])) - return -1; - - if (k->source_type == k->target_type) - return 0; - - /* - * If the target type differs, then we also - * insert the rule into the list for the target - * type. We clear the target type value so that - * we can compare against other type rules with - * different target types. - */ - key = *k; - key.target_type = 0; - if (insert_type_rule(&key, d, &type_rules[k->target_type - 1])) - return -1; - - return 0; -} - -static int create_type_rules(avtab_key_t * k, avtab_datum_t * d, void *args) -{ - if (k->specified & AVTAB_ALLOWED) - return create_type_rules_helper(k, d, args); - return 0; -} - -static int create_type_rules_cond(avtab_key_t * k, avtab_datum_t * d, - void *args) -{ - if ((k->specified & (AVTAB_ALLOWED|AVTAB_ENABLED)) == - (AVTAB_ALLOWED|AVTAB_ENABLED)) - return create_type_rules_helper(k, d, args); - return 0; -} - -static void free_type_rules(struct avtab_node *l) -{ - struct avtab_node *tmp; - - while (l) { - tmp = l; - l = l->next; - free(tmp); - } -} - -static int find_match(policydb_t *policydb, struct avtab_node *l1, - int idx1, struct avtab_node *l2, int idx2) -{ - struct avtab_node *c; - uint32_t perms1, perms2; - - for (c = l2; c; c = c->next) { - if (l1->key.source_type < c->key.source_type) - break; - if (l1->key.source_type == c->key.source_type && - l1->key.target_type < c->key.target_type) - break; - if (l1->key.source_type == c->key.source_type && - l1->key.target_type == c->key.target_type && - l1->key.target_class <= c->key.target_class) - break; - } - - if (c && - l1->key.source_type == c->key.source_type && - l1->key.target_type == c->key.target_type && - l1->key.target_class == c->key.target_class) { - perms1 = l1->datum.data & ~c->datum.data; - perms2 = c->datum.data & ~l1->datum.data; - if (perms1 || perms2) { - if (perms1) - display_allow(policydb, &l1->key, idx1, perms1); - if (perms2) - display_allow(policydb, &c->key, idx2, perms2); - printf("\n"); - return 1; - } - } - - return 0; -} - -static int analyze_types(policydb_t * policydb, char diff, char equiv) -{ - avtab_t exp_avtab, exp_cond_avtab; - struct avtab_node *type_rules, *l1, *l2; - struct type_datum *type; - size_t i, j; - - /* - * Create a list of access vector rules for each type - * from the access vector table. - */ - type_rules = malloc(sizeof(struct avtab_node) * policydb->p_types.nprim); - if (!type_rules) { - fprintf(stderr, "out of memory\n"); - exit(1); - } - memset(type_rules, 0, sizeof(struct avtab_node) * policydb->p_types.nprim); - - if (avtab_init(&exp_avtab) || avtab_init(&exp_cond_avtab)) { - fputs("out of memory\n", stderr); - return -1; - } - - if (expand_avtab(policydb, &policydb->te_avtab, &exp_avtab)) { - fputs("out of memory\n", stderr); - avtab_destroy(&exp_avtab); - return -1; - } - - if (expand_avtab(policydb, &policydb->te_cond_avtab, &exp_cond_avtab)) { - fputs("out of memory\n", stderr); - avtab_destroy(&exp_avtab); /* */ - return -1; - } - - if (avtab_map(&exp_avtab, create_type_rules, type_rules)) - exit(1); - - if (avtab_map(&exp_cond_avtab, create_type_rules_cond, type_rules)) - exit(1); - - avtab_destroy(&exp_avtab); - avtab_destroy(&exp_cond_avtab); - - /* - * Compare the type lists and identify similar types. - */ - for (i = 0; i < policydb->p_types.nprim - 1; i++) { - if (!type_rules[i].next) - continue; - type = policydb->type_val_to_struct[i]; - if (type->flavor) { - free_type_rules(type_rules[i].next); - type_rules[i].next = NULL; - continue; - } - for (j = i + 1; j < policydb->p_types.nprim; j++) { - type = policydb->type_val_to_struct[j]; - if (type->flavor) { - free_type_rules(type_rules[j].next); - type_rules[j].next = NULL; - continue; - } - for (l1 = type_rules[i].next, l2 = type_rules[j].next; - l1 && l2; l1 = l1->next, l2 = l2->next) { - if (l1->key.source_type != l2->key.source_type) - break; - if (l1->key.target_type != l2->key.target_type) - break; - if (l1->key.target_class != l2->key.target_class - || l1->datum.data != l2->datum.data) - break; - } - if (l1 || l2) { - if (diff) { - printf - ("Types %s and %s differ, starting with:\n", - policydb->p_type_val_to_name[i], - policydb->p_type_val_to_name[j]); - - if (l1 && l2) { - if (find_match(policydb, l1, i, l2, j)) - continue; - if (find_match(policydb, l2, j, l1, i)) - continue; - } - if (l1) - display_allow(policydb, &l1->key, i, l1->datum.data); - if (l2) - display_allow(policydb, &l2->key, j, l2->datum.data); - printf("\n"); - } - continue; - } - free_type_rules(type_rules[j].next); - type_rules[j].next = NULL; - if (equiv) { - printf("Types %s and %s are equivalent.\n", - policydb->p_type_val_to_name[i], - policydb->p_type_val_to_name[j]); - } - } - free_type_rules(type_rules[i].next); - type_rules[i].next = NULL; - } - - free(type_rules); - return 0; -} - -int typecmp_func (int argc, char **argv, policydb_t *policydb) { - char ch, diff = 0, equiv = 0; - - struct option typecmp_options[] = { - {"diff", no_argument, NULL, 'd'}, - {"equiv", no_argument, NULL, 'e'}, - {NULL, 0, NULL, 0} - }; - - while ((ch = getopt_long(argc, argv, "de", typecmp_options, NULL)) != -1) { - switch (ch) { - case 'd': - diff = 1; - break; - case 'e': - equiv = 1; - break; - default: - USAGE_ERROR = true; - return -1; - } - } - - if (!(diff || equiv)) { - USAGE_ERROR = true; - return -1; - } - return analyze_types(policydb, diff, equiv); -} diff --git a/tools/sepolicy-analyze/typecmp.h b/tools/sepolicy-analyze/typecmp.h deleted file mode 100644 index f93daaa..0000000 --- a/tools/sepolicy-analyze/typecmp.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef TYPECMP_H -#define TYPECMP_H - -#include <sepol/policydb/policydb.h> - -#include "utils.h" - -void typecmp_usage(void); -int typecmp_func(int argc, char **argv, policydb_t *policydb); - -#endif /* TYPECMP_H */ diff --git a/tools/sepolicy-analyze/utils.c b/tools/sepolicy-analyze/utils.c deleted file mode 100644 index 5e52f59..0000000 --- a/tools/sepolicy-analyze/utils.c +++ /dev/null @@ -1,68 +0,0 @@ -#include <fcntl.h> -#include <sepol/policydb/policydb.h> -#include <sepol/policydb/util.h> -#include <sys/mman.h> -#include <sys/stat.h> -#include <unistd.h> - -#include "utils.h" - -bool USAGE_ERROR = false; - -void display_allow(policydb_t *policydb, avtab_key_t *key, int idx, uint32_t perms) -{ - printf(" allow %s %s:%s { %s };\n", - policydb->p_type_val_to_name[key->source_type - ? key->source_type - 1 : idx], - key->target_type == key->source_type ? "self" : - policydb->p_type_val_to_name[key->target_type - ? key->target_type - 1 : idx], - policydb->p_class_val_to_name[key->target_class - 1], - sepol_av_to_string - (policydb, key->target_class, perms)); -} - -int load_policy(char *filename, policydb_t * policydb, struct policy_file *pf) -{ - int fd; - struct stat sb; - void *map; - int ret; - - fd = open(filename, O_RDONLY); - if (fd < 0) { - fprintf(stderr, "Can't open '%s': %s\n", filename, strerror(errno)); - return 1; - } - if (fstat(fd, &sb) < 0) { - fprintf(stderr, "Can't stat '%s': %s\n", filename, strerror(errno)); - close(fd); - return 1; - } - map = mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); - if (map == MAP_FAILED) { - fprintf(stderr, "Can't mmap '%s': %s\n", filename, strerror(errno)); - close(fd); - return 1; - } - - policy_file_init(pf); - pf->type = PF_USE_MEMORY; - pf->data = map; - pf->len = sb.st_size; - if (policydb_init(policydb)) { - fprintf(stderr, "Could not initialize policydb!\n"); - close(fd); - munmap(map, sb.st_size); - return 1; - } - ret = policydb_read(policydb, pf, 0); - if (ret) { - fprintf(stderr, "error(s) encountered while parsing configuration\n"); - close(fd); - munmap(map, sb.st_size); - return 1; - } - - return 0; -} diff --git a/tools/sepolicy-analyze/utils.h b/tools/sepolicy-analyze/utils.h deleted file mode 100644 index 83f5a78..0000000 --- a/tools/sepolicy-analyze/utils.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef UTILS_H -#define UTILS_H - -#include <stdbool.h> -#include <stdint.h> -#include <sepol/policydb/avtab.h> -#include <sepol/policydb/policydb.h> - - -extern bool USAGE_ERROR; - -void display_allow(policydb_t *policydb, avtab_key_t *key, int idx, uint32_t perms); - -int load_policy(char *filename, policydb_t * policydb, struct policy_file *pf); - -#endif /* UTILS_H */ diff --git a/tools/sepolicy-check.c b/tools/sepolicy-check.c deleted file mode 100644 index 713e7c1..0000000 --- a/tools/sepolicy-check.c +++ /dev/null @@ -1,296 +0,0 @@ -#include <getopt.h> -#include <unistd.h> -#include <stdlib.h> -#include <sys/mman.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <stdio.h> -#include <sepol/policydb/policydb.h> -#include <sepol/policydb/services.h> -#include <sepol/policydb/expand.h> - -#define EQUALS 0 -#define NOT 1 -#define ANY 2 - -void usage(char *arg0) { - fprintf(stderr, "%s -s <source> -t <target> -c <class> -p <perm> -P <policy file>\n", arg0); - exit(1); -} - -void *cmalloc(size_t s) { - void *t = malloc(s); - if (t == NULL) { - fprintf(stderr, "Out of memory\n"); - exit(1); - } - return t; -} - -int parse_ops(char **arg) { - switch (*arg[0]) { - case '-': - *arg = *arg + 1; - return NOT; - case '*': - return ANY; - default: - return EQUALS; - } -} - -int check(int op, uint16_t arg1, uint16_t arg2) { - switch (op) { - case EQUALS: - return arg1 == arg2; - case NOT: - return arg1 != arg2; - case ANY: - return 1; - default: - fprintf(stderr, "Bad op while checking!"); - return 2; - } -} - -int check_perm(avtab_ptr_t current, perm_datum_t *perm) { - uint16_t perm_bitmask = 1U << (perm->s.value - 1); - return (current->datum.data & perm_bitmask) != 0; -} - - -int expand_and_check(int s_op, uint32_t source_type, - int t_op, uint32_t target_type, - int c_op, uint32_t target_class, - perm_datum_t *perm, policydb_t *policy, avtab_t *avtab) { - avtab_t exp_avtab; - avtab_ptr_t cur; - unsigned int i; - int match; - - if (avtab_init(&exp_avtab)) { - fputs("out of memory\n", stderr); - return -1; - } - - if (expand_avtab(policy, avtab, &exp_avtab)) { - fputs("out of memory\n", stderr); - avtab_destroy(&exp_avtab); - return -1; - } - - for (i = 0; i < exp_avtab.nslot; i++) { - for (cur = exp_avtab.htable[i]; cur; cur = cur->next) { - match = 1; - match &= check(s_op, source_type, cur->key.source_type); - match &= check(t_op, target_type, cur->key.target_type); - match &= check(c_op, target_class, cur->key.target_class); - match &= check_perm(cur, perm); - if (match) { - avtab_destroy(&exp_avtab); - return 1; - } - } - } - - avtab_destroy(&exp_avtab); - return 0; -} - -/* - * Checks to see if a rule matching the given arguments already exists. - * - * The format for the arguments is as follows: - * - * - A bare string is treated as a literal and will be matched by equality. - * - A string starting with "-" will be matched by inequality. - * - A string starting with "*" will be treated as a wildcard. - * - * The return codes for this function are as follows: - * - * - 0 indicates a successful return without a match - * - 1 indicates a successful return with a match - * - -1 indicates an error - */ -int check_rule(char *s, char *t, char *c, char *p, policydb_t *policy) { - type_datum_t *src = NULL; - type_datum_t *tgt = NULL; - class_datum_t *cls = NULL; - perm_datum_t *perm = NULL; - int s_op = parse_ops(&s); - int t_op = parse_ops(&t); - int c_op = parse_ops(&c); - int p_op = parse_ops(&p); - avtab_key_t key; - int match; - - key.source_type = key.target_type = key.target_class = 0; - - if (s_op != ANY) { - src = hashtab_search(policy->p_types.table, s); - if (src == NULL) { - fprintf(stderr, "source type %s does not exist\n", s); - return -1; - } - } - if (t_op != ANY) { - tgt = hashtab_search(policy->p_types.table, t); - if (tgt == NULL) { - fprintf(stderr, "target type %s does not exist\n", t); - return -1; - } - } - if (c_op != ANY) { - cls = hashtab_search(policy->p_classes.table, c); - if (cls == NULL) { - fprintf(stderr, "class %s does not exist\n", c); - return -1; - } - } - if (p_op != ANY) { - perm = hashtab_search(cls->permissions.table, p); - if (perm == NULL) { - if (cls->comdatum == NULL) { - fprintf(stderr, "perm %s does not exist in class %s\n", p, c); - return -1; - } - perm = hashtab_search(cls->comdatum->permissions.table, p); - if (perm == NULL) { - fprintf(stderr, "perm %s does not exist in class %s\n", p, c); - return -1; - } - } - } - - if (s_op != ANY) - key.source_type = src->s.value; - if (t_op != ANY) - key.target_type = tgt->s.value; - if (c_op != ANY) - key.target_class = cls->s.value; - - /* Check unconditional rules after attribute expansion. */ - match = expand_and_check(s_op, key.source_type, - t_op, key.target_type, - c_op, key.target_class, - perm, policy, &policy->te_avtab); - if (match) - return match; - - /* Check conditional rules after attribute expansion. */ - return expand_and_check(s_op, key.source_type, - t_op, key.target_type, - c_op, key.target_class, - perm, policy, &policy->te_cond_avtab); -} - -int load_policy(char *filename, policydb_t *policydb, struct policy_file *pf) { - int fd; - struct stat sb; - void *map; - int ret; - - fd = open(filename, O_RDONLY); - if (fd < 0) { - fprintf(stderr, "Can't open '%s': %s\n", filename, strerror(errno)); - return 1; - } - if (fstat(fd, &sb) < 0) { - fprintf(stderr, "Can't stat '%s': %s\n", filename, strerror(errno)); - close(fd); - return 1; - } - map = mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); - if (map == MAP_FAILED) { - fprintf(stderr, "Can't mmap '%s': %s\n", filename, strerror(errno)); - close(fd); - return 1; - } - - policy_file_init(pf); - pf->type = PF_USE_MEMORY; - pf->data = map; - pf->len = sb.st_size; - if (policydb_init(policydb)) { - fprintf(stderr, "Could not initialize policydb!\n"); - close(fd); - munmap(map, sb.st_size); - return 1; - } - ret = policydb_read(policydb, pf, 0); - if (ret) { - fprintf(stderr, "error(s) encountered while parsing configuration\n"); - close(fd); - munmap(map, sb.st_size); - return 1; - } - - return 0; -} - - -int main(int argc, char **argv) -{ - char *policy = NULL, *source = NULL, *target = NULL, *class = NULL, *perm = NULL; - policydb_t policydb; - struct policy_file pf; - sidtab_t sidtab; - char ch; - int match = 1; - - struct option long_options[] = { - {"source", required_argument, NULL, 's'}, - {"target", required_argument, NULL, 't'}, - {"class", required_argument, NULL, 'c'}, - {"perm", required_argument, NULL, 'p'}, - {"policy", required_argument, NULL, 'P'}, - {NULL, 0, NULL, 0} - }; - - while ((ch = getopt_long(argc, argv, "s:t:c:p:P:", long_options, NULL)) != -1) { - switch (ch) { - case 's': - source = optarg; - break; - case 't': - target = optarg; - break; - case 'c': - class = optarg; - break; - case 'p': - perm = optarg; - break; - case 'P': - policy = optarg; - break; - default: - usage(argv[0]); - } - } - - if (!source || !target || !class || !perm || !policy) - usage(argv[0]); - - sepol_set_policydb(&policydb); - sepol_set_sidtab(&sidtab); - - if (load_policy(policy, &policydb, &pf)) - goto out; - - match = check_rule(source, target, class, perm, &policydb); - if (match < 0) { - fprintf(stderr, "Error checking rules!\n"); - goto out; - } else if (match > 0) { - printf("Match found!\n"); - goto out; - } - - match = 0; - -out: - policydb_destroy(&policydb); - return match; -} |