aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/Android.mk55
-rw-r--r--tools/README63
-rw-r--r--tools/check_seapp.c1239
-rw-r--r--tools/checkfc.c379
-rw-r--r--tools/fc_sort/Android.mk12
-rw-r--r--tools/fc_sort/MODULE_LICENSE_GPL0
-rw-r--r--tools/fc_sort/NOTICE340
-rw-r--r--tools/fc_sort/README9
-rw-r--r--tools/fc_sort/fc_sort.c567
-rwxr-xr-xtools/insertkeys.py267
-rwxr-xr-xtools/post_process_mac_perms106
-rw-r--r--tools/sepolicy-analyze/Android.mk14
-rw-r--r--tools/sepolicy-analyze/README94
-rw-r--r--tools/sepolicy-analyze/attribute.c39
-rw-r--r--tools/sepolicy-analyze/attribute.h11
-rw-r--r--tools/sepolicy-analyze/booleans.c22
-rw-r--r--tools/sepolicy-analyze/booleans.h11
-rw-r--r--tools/sepolicy-analyze/dups.c91
-rw-r--r--tools/sepolicy-analyze/dups.h11
-rw-r--r--tools/sepolicy-analyze/neverallow.c515
-rw-r--r--tools/sepolicy-analyze/neverallow.h11
-rw-r--r--tools/sepolicy-analyze/perm.c30
-rw-r--r--tools/sepolicy-analyze/perm.h11
-rw-r--r--tools/sepolicy-analyze/sepolicy-analyze.c65
-rw-r--r--tools/sepolicy-analyze/typecmp.c295
-rw-r--r--tools/sepolicy-analyze/typecmp.h11
-rw-r--r--tools/sepolicy-analyze/utils.c68
-rw-r--r--tools/sepolicy-analyze/utils.h16
-rw-r--r--tools/sepolicy-check.c296
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;
-}