diff --git a/Android.mk b/Android.mk index 881f08482..44accc512 100644 --- a/Android.mk +++ b/Android.mk @@ -4,7 +4,7 @@ include $(CLEAR_VARS) LOCAL_MODULE := sepolicy-inject LOCAL_MODULE_TAGS := optional LOCAL_STATIC_LIBRARIES := libsepol -LOCAL_SRC_FILES := sepolicy-inject.c builtin_rules.c +LOCAL_SRC_FILES := main.c sepolicy.c rules.c utils.c LOCAL_C_INCLUDES := jni/selinux/libsepol/include/ LOCAL_CFLAGS += -std=gnu11 include $(BUILD_EXECUTABLE) diff --git a/main.c b/main.c new file mode 100644 index 000000000..7692028e5 --- /dev/null +++ b/main.c @@ -0,0 +1,247 @@ +#include "sepolicy-inject.h" + +static void usage(char *arg0) { + fprintf(stderr, "%s -s -t -c -p -P \n", arg0); + fprintf(stderr, "\tInject a rule\n\n"); + fprintf(stderr, "%s -s -a -P \n", arg0); + fprintf(stderr, "\tAdd a type_attribute to a domain\n\n"); + fprintf(stderr, "%s -Z -P \n", arg0); + fprintf(stderr, "\tInject a permissive domain\n\n"); + fprintf(stderr, "%s -z -P \n", arg0); + fprintf(stderr, "\tInject a non-permissive domain\n\n"); + fprintf(stderr, "%s -e -s -P \n", arg0); + fprintf(stderr, "\tCheck if a SELinux type exists\n\n"); + fprintf(stderr, "%s -e -c -P \n", arg0); + fprintf(stderr, "\tCheck if a SELinux class exists\n\n"); + fprintf(stderr, "All options can add -o to output to another file\n"); + exit(1); +} + +int main(int argc, char **argv) { + char *infile = NULL, *source = NULL, *target = NULL, *class = NULL, *perm = NULL; + char *fcon = NULL, *outfile = NULL, *permissive = NULL, *attr = NULL, *filetrans = NULL; + int exists = 0, not = 0, live = 0, builtin = 0, magisk = 0; + policydb_t policydb; + struct policy_file pf, outpf; + sidtab_t sidtab; + int ch; + FILE *fp; + int permissive_value = 0, noaudit = 0; + + struct option long_options[] = { + {"attr", required_argument, NULL, 'a'}, + {"exists", no_argument, NULL, 'e'}, + {"source", required_argument, NULL, 's'}, + {"target", required_argument, NULL, 't'}, + {"class", required_argument, NULL, 'c'}, + {"perm", required_argument, NULL, 'p'}, + {"fcon", required_argument, NULL, 'f'}, + {"filetransition", required_argument, NULL, 'g'}, + {"noaudit", no_argument, NULL, 'n'}, + {"file", required_argument, NULL, 'P'}, + {"output", required_argument, NULL, 'o'}, + {"permissive", required_argument, NULL, 'Z'}, + {"not-permissive", required_argument, NULL, 'z'}, + {"not", no_argument, NULL, 0}, + {"live", no_argument, NULL, 0}, + {"magisk", no_argument, NULL, 0}, + {NULL, 0, NULL, 0} + }; + + int option_index = -1; + while ((ch = getopt_long(argc, argv, "a:c:ef:g:s:t:p:P:o:Z:z:n", long_options, &option_index)) != -1) { + switch (ch) { + case 0: + if(strcmp(long_options[option_index].name, "not") == 0) + not = 1; + else if(strcmp(long_options[option_index].name, "live") == 0) + live = 1; + else if(strcmp(long_options[option_index].name, "magisk") == 0) + magisk = 1; + else + usage(argv[0]); + break; + case 'a': + attr = optarg; + break; + case 'e': + exists = 1; + break; + case 'f': + fcon = optarg; + break; + case 'g': + filetrans = optarg; + break; + case 's': + source = optarg; + break; + case 't': + target = optarg; + break; + case 'c': + class = optarg; + break; + case 'p': + perm = optarg; + break; + case 'P': + infile = optarg; + break; + case 'o': + outfile = optarg; + break; + case 'Z': + permissive = optarg; + permissive_value = 1; + break; + case 'z': + permissive = optarg; + permissive_value = 0; + break; + case 'n': + noaudit = 1; + break; + default: + usage(argv[0]); + } + } + + // Use builtin rules if nothing specified + if (!magisk && !source && !target && !class && !perm && !permissive && !fcon && !attr &&!filetrans && !exists) + builtin = 1; + + // Overwrite original if not specified + if(!outfile) + outfile = infile; + + // Use current policy if not specified + if(!infile) + infile = "/sys/fs/selinux/policy"; + + sepol_set_policydb(&policydb); + sepol_set_sidtab(&sidtab); + + if (load_policy(infile, &policydb, &pf)) { + fprintf(stderr, "Could not load policy\n"); + return 1; + } + + if (policydb_load_isids(&policydb, &sidtab)) + return 1; + + policy = &policydb; + + if (builtin) { + su_rules(); + } + else if (magisk) { + magisk_rules(); + } + else if (permissive) { + type_datum_t *type; + create_domain(permissive); + type = hashtab_search(policydb.p_types.table, permissive); + if (type == NULL) { + fprintf(stderr, "type %s does not exist\n", permissive); + return 1; + } + if (ebitmap_set_bit(&policydb.permissive_map, type->s.value, permissive_value)) { + fprintf(stderr, "Could not set bit in permissive map\n"); + return 1; + } + } else if(exists) { + if(source) { + type_datum_t *tmp = hashtab_search(policydb.p_types.table, source); + if (!tmp) + exit(1); + else + exit(0); + } else if(class) { + class_datum_t *tmp = hashtab_search(policydb.p_classes.table, class); + if(!tmp) + exit(1); + else + exit(0); + } else { + usage(argv[0]); + } + } else if(filetrans) { + if(add_file_transition(source, fcon, target, class, filetrans)) + return 1; + } else if(fcon) { + if(add_transition(source, fcon, target, class)) + return 1; + } else if(attr) { + if(add_type(source, attr)) + return 1; + } else if(noaudit) { + if(add_rule(source, target, class, perm, AVTAB_AUDITDENY, not)) + return 1; + } else { + //Add a rule to a whole set of typeattribute, not just a type + if (target != NULL) { + if(*target == '=') { + char *saveptr = NULL; + + char *targetAttribute = strtok_r(target, "-", &saveptr); + + char *vals[64]; + int i = 0; + + char *m = NULL; + while( (m = strtok_r(NULL, "-", &saveptr)) != NULL) { + vals[i++] = m; + } + vals[i] = NULL; + + if(add_typerule(source, targetAttribute+1, vals, class, perm, AVTAB_ALLOWED, not)) + return 1; + } + } + if (perm != NULL) { + char *saveptr = NULL; + + char *p = strtok_r(perm, ",", &saveptr); + do { + if (add_rule(source, target, class, p, AVTAB_ALLOWED, not)) { + fprintf(stderr, "Could not add rule\n"); + return 1; + } + } while( (p = strtok_r(NULL, ",", &saveptr)) != NULL); + } else { + if (add_rule(source, target, class, perm, AVTAB_ALLOWED, not)) { + fprintf(stderr, "Could not add rule\n"); + return 1; + } + } + } + + if (live) { + if (live_patch()) { + fprintf(stderr, "Could not load new policy into kernel\n"); + return 1; + } + } + + if (outfile) { + fp = fopen(outfile, "w"); + if (!fp) { + fprintf(stderr, "Could not open outfile\n"); + return 1; + } + + policy_file_init(&outpf); + outpf.type = PF_USE_STDIO; + outpf.fp = fp; + + if (policydb_write(&policydb, &outpf)) { + fprintf(stderr, "Could not write policy\n"); + return 1; + } + fclose(fp); + } + + policydb_destroy(&policydb); + return 0; +} diff --git a/builtin_rules.c b/rules.c similarity index 88% rename from builtin_rules.c rename to rules.c index 308162bc9..b22246114 100644 --- a/builtin_rules.c +++ b/rules.c @@ -1,44 +1,4 @@ -#include -#include - -#define ALL NULL - -extern int add_rule(char *s, char *t, char *c, char *p, int effect, int not, policydb_t *policy); -extern void create_domain(char *d, policydb_t *policy); -extern int add_transition(char *srcS, char *origS, char *tgtS, char *c, policydb_t *policy); -extern int add_type(char *domainS, char *typeS, policydb_t *policy); - -policydb_t *policy; - -void allow(char *s, char *t, char *c, char *p) { - add_rule(s, t, c, p, AVTAB_ALLOWED, 0, policy); -} - -void noaudit(char *s, char *t, char *c, char *p) { - add_rule(s, t, c, p, AVTAB_AUDITDENY, 0, policy); -} - -void deny(char *s, char *t, char *c, char *p) { - add_rule(s, t, c, p, AVTAB_ALLOWED, 1, policy); -} - -void setPermissive(char* permissive, int permissive_value) { - type_datum_t *type; - create_domain(permissive, policy); - type = hashtab_search(policy->p_types.table, permissive); - if (type == NULL) { - fprintf(stderr, "type %s does not exist\n", permissive); - return; - } - if (ebitmap_set_bit(&policy->permissive_map, type->s.value, permissive_value)) { - fprintf(stderr, "Could not set bit in permissive map\n"); - return; - } -} - -int exists(char* source) { - return (int) hashtab_search(policy->p_types.table, source); -} +#include "sepolicy-inject.h" void samsung() { deny("init", "kernel", "security", "load_policy"); @@ -222,6 +182,12 @@ void suDaemonRights() { allow("su_daemon", "proc", "file", "open"); allow("su_daemon", "su_daemon", "process", "setcurrent"); allow("su_daemon", "system_file", "file", "execute_no_trans"); + + // Allow to adb shell su + allow("su_daemon", "adbd", "fd", "use"); + allow("su_daemon", "adbd", "unix_stream_socket", "read"); + allow("su_daemon", "adbd", "unix_stream_socket", "write"); + allow("su_daemon", "adbd", "unix_stream_socket", "ioctl"); } void suBind() { @@ -274,36 +240,34 @@ void otherToSU() { allow(ALL, "su", "process", "sigchld"); // uNetworkL0 - add_type("su", "netdomain", policy); - add_type("su", "bluetoothdomain", policy); + add_type("su", "netdomain"); + add_type("su", "bluetoothdomain"); // suBackL6 allow("surfaceflinger", "app_data_file", "dir", ALL); allow("surfaceflinger", "app_data_file", "file", ALL); allow("surfaceflinger", "app_data_file", "lnk_file", ALL); - add_type("surfaceflinger", "mlstrustedsubject", policy); + add_type("surfaceflinger", "mlstrustedsubject"); // suMiscL6 if (exists("audioserver")) allow("audioserver", "audioserver", "process", "execmem"); } -void phh_rules(policydb_t *policydb) { - policy = policydb; - +void su_rules() { // Samsung specific // Prevent system from loading policy if(exists("knox_system_app")) samsung(); // Create domains if they don't exist - setPermissive("su", 1); - setPermissive("su_device", 0); - setPermissive("su_daemon", 0); + permissive("su"); + enforce("su_device"); + enforce("su_daemon"); // Autotransition su's socket to su_device - add_transition("su_daemon", "device", "su_device", "file", policy); - add_transition("su_daemon", "device", "su_device", "dir", policy); + add_transition("su_daemon", "device", "su_device", "file"); + add_transition("su_daemon", "device", "su_device", "dir"); allow("su_device", "tmpfs", "filesystem", "associate"); // Transition from untrusted_app to su_client @@ -329,22 +293,21 @@ void phh_rules(policydb_t *policydb) { otherToSU(); // Need to set su_device/su as trusted to be accessible from other categories - add_type("su_device", "mlstrustedobject", policy); - add_type("su_daemon", "mlstrustedsubject", policy); - add_type("su", "mlstrustedsubject", policy); + attradd("su_device", "mlstrustedobject"); + attradd("su_daemon", "mlstrustedsubject"); + attradd("su", "mlstrustedsubject"); - // Allow chcon to rootfs - allow("rootfs", "labeledfs", "filesystem", "associate"); + // Allow chcon to anything + allow(ALL, "labeledfs", "filesystem", "associate"); } // Minimal to run Magisk script before live patching -void magisk_rules(policydb_t *policydb) { - policy = policydb; +void magisk_rules() { - setPermissive("su", 1); - setPermissive("init", 1); + permissive("su"); + permissive("init"); - add_type("su", "mlstrustedsubject", policy); + attradd("su", "mlstrustedsubject"); allow("kernel", "su", "fd", "use"); allow("init", "su", "process", ALL); @@ -427,4 +390,4 @@ void magisk_rules(policydb_t *policydb) { allow("init", "su", "fd", "use"); allow("init", "kernel", "security", "read_policy"); allow("init", "kernel", "security", "load_policy"); -} \ No newline at end of file +} diff --git a/sepolicy-inject.h b/sepolicy-inject.h new file mode 100644 index 000000000..53eb183dd --- /dev/null +++ b/sepolicy-inject.h @@ -0,0 +1,50 @@ +#ifndef SEPOLICY_INJECT_H +#define SEPOLICY_INJECT_H + +#define ALL NULL + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Global policydb +policydb_t *policy; + +// sepolicy manipulation functions +int load_policy(char *filename, policydb_t *policydb, struct policy_file *pf); +void create_domain(char *d); +int add_file_transition(char *srcS, char *origS, char *tgtS, char *c, char* filename); +int add_transition(char *srcS, char *origS, char *tgtS, char *c); +int add_type(char *domainS, char *typeS); +int add_rule(char *s, char *t, char *c, char *p, int effect, int not); +int add_typerule(char *s, char *targetAttribute, char **minusses, char *c, char *p, int effect, int not); +int live_patch(); + +// Handy functions +void allow(char *s, char *t, char *c, char *p); +void deny(char *s, char *t, char *c, char *p); +void auditallow(char *s, char *t, char *c, char *p); +void auditdeny(char *s, char *t, char *c, char *p); +void permissive(char *s); +void enforce(char *s); +void attradd(char *s, char *a); +int exists(char *source); + +// Built in rules +void su_rules(); +void magisk_rules(); + +#endif diff --git a/sepolicy-inject.c b/sepolicy.c similarity index 57% rename from sepolicy-inject.c rename to sepolicy.c index c69d01c99..877b65e57 100644 --- a/sepolicy-inject.c +++ b/sepolicy.c @@ -1,49 +1,6 @@ -/* - * This was derived from public domain works with updates to - * work with more modern SELinux libraries. - * - * It is released into the public domain. - * - */ +#include "sepolicy-inject.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern void phh_rules(policydb_t *policydb); -extern void magisk_rules(policydb_t *policydb); - -void usage(char *arg0) { - fprintf(stderr, "%s -s -t -c -p -P \n", arg0); - fprintf(stderr, "\tInject a rule\n\n"); - fprintf(stderr, "%s -s -a -P \n", arg0); - fprintf(stderr, "\tAdd a type_attribute to a domain\n\n"); - fprintf(stderr, "%s -Z -P \n", arg0); - fprintf(stderr, "\tInject a permissive domain\n\n"); - fprintf(stderr, "%s -z -P \n", arg0); - fprintf(stderr, "\tInject a non-permissive domain\n\n"); - fprintf(stderr, "%s -e -s -P \n", arg0); - fprintf(stderr, "\tCheck if a SELinux type exists\n\n"); - fprintf(stderr, "%s -e -c -P \n", arg0); - fprintf(stderr, "\tCheck if a SELinux class exists\n\n"); - fprintf(stderr, "All options can add -o to output to another file\n"); - exit(1); -} - -void *cmalloc(size_t s) { +static void *cmalloc(size_t s) { void *t = malloc(s); if (t == NULL) { fprintf(stderr, "Out of memory\n"); @@ -52,7 +9,7 @@ void *cmalloc(size_t s) { return t; } -int get_attr(char *type, int value, policydb_t *policy) { +static int get_attr(char *type, int value) { type_datum_t *attr = hashtab_search(policy->p_types.table, type); if (!attr) exit(1); @@ -64,7 +21,7 @@ int get_attr(char *type, int value, policydb_t *policy) { //return !! ebitmap_get_bit(&policy->type_attr_map[value-1], attr->s.value-1); } -int get_attr_id(char *type, policydb_t *policy) { +static int get_attr_id(char *type) { type_datum_t *attr = hashtab_search(policy->p_types.table, type); if (!attr) exit(1); @@ -75,7 +32,7 @@ int get_attr_id(char *type, policydb_t *policy) { return attr->s.value; } -int set_attr(char *type, int value, policydb_t *policy) { +static int set_attr(char *type, int value) { type_datum_t *attr = hashtab_search(policy->p_types.table, type); if (!attr) exit(1); @@ -91,7 +48,143 @@ int set_attr(char *type, int value, policydb_t *policy) { return 0; } -void create_domain(char *d, policydb_t *policy) { +static int add_irule(int s, int t, int c, int p, int effect, int not) { + avtab_datum_t *av; + avtab_key_t key; + + key.source_type = s; + key.target_type = t; + key.target_class = c; + key.specified = effect; + av = avtab_search(&policy->te_avtab, &key); + + if (av == NULL) { + av = cmalloc(sizeof(*av)); + av->data |= 1U << (p - 1); + int ret = avtab_insert(&policy->te_avtab, &key, av); + if (ret) { + fprintf(stderr, "Error inserting into avtab\n"); + return 1; + } + } + + if(not) + av->data &= ~(1U << (p - 1)); + else + av->data |= 1U << (p - 1); + return 0; +} + +static int add_rule_auto(type_datum_t *src, type_datum_t *tgt, class_datum_t *cls, perm_datum_t *perm, int effect, int not) { + hashtab_t type_table, class_table, perm_table; + hashtab_ptr_t cur; + + type_table = policy->p_types.table; + class_table = policy->p_classes.table; + + if (src == NULL) { + for (int i = 0; i < type_table->size; ++i) { + cur = type_table->htable[i]; + while (cur != NULL) { + src = cur->datum; + if(add_rule_auto(src, tgt, cls, perm, effect, not)) + return 1; + cur = cur->next; + } + } + } else if (tgt == NULL) { + for (int i = 0; i < type_table->size; ++i) { + cur = type_table->htable[i]; + while (cur != NULL) { + tgt = cur->datum; + if(add_rule_auto(src, tgt, cls, perm, effect, not)) + return 1; + cur = cur->next; + } + } + } else if (cls == NULL) { + for (int i = 0; i < class_table->size; ++i) { + cur = class_table->htable[i]; + while (cur != NULL) { + cls = cur->datum; + if(add_rule_auto(src, tgt, cls, perm, effect, not)) + return 1; + cur = cur->next; + } + } + } else if (perm == NULL) { + perm_table = cls->permissions.table; + for (int i = 0; i < perm_table->size; ++i) { + cur = perm_table->htable[i]; + while (cur != NULL) { + perm = cur->datum; + if(add_irule(src->s.value, tgt->s.value, cls->s.value, perm->s.value, effect, not)) + return 1; + cur = cur->next; + } + } + + if (cls->comdatum != NULL) { + perm_table = cls->comdatum->permissions.table; + for (int i = 0; i < perm_table->size; ++i) { + cur = perm_table->htable[i]; + while (cur != NULL) { + perm = cur->datum; + if(add_irule(src->s.value, tgt->s.value, cls->s.value, perm->s.value, effect, not)) + return 1; + cur = cur->next; + } + } + } + } else { + return add_irule(src->s.value, tgt->s.value, cls->s.value, perm->s.value, effect, not); + } + return 0; +} + +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)); + 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)); + 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, "policydb_init: Out of memory!\n"); + return 1; + } + ret = policydb_read(policydb, pf, 1); + if (ret) { + fprintf(stderr, "error(s) encountered while parsing configuration\n"); + return 1; + } + + return 0; +} + +void create_domain(char *d) { symtab_datum_t *src = hashtab_search(policy->p_types.table, d); if(src) return; @@ -139,37 +232,10 @@ void create_domain(char *d, policydb_t *policy) { if(policydb_index_others(NULL, policy, 1)) exit(1); - set_attr("domain", value, policy); + set_attr("domain", value); } -int add_irule(int s, int t, int c, int p, int effect, int not, policydb_t* policy) { - avtab_datum_t *av; - avtab_key_t key; - - key.source_type = s; - key.target_type = t; - key.target_class = c; - key.specified = effect; - av = avtab_search(&policy->te_avtab, &key); - - if (av == NULL) { - av = cmalloc(sizeof(*av)); - av->data |= 1U << (p - 1); - int ret = avtab_insert(&policy->te_avtab, &key, av); - if (ret) { - fprintf(stderr, "Error inserting into avtab\n"); - return 1; - } - } - - if(not) - av->data &= ~(1U << (p - 1)); - else - av->data |= 1U << (p - 1); - return 0; -} - -int add_typerule(char *s, char *targetAttribute, char **minusses, char *c, char *p, int effect, int not, policydb_t *policy) { +int add_typerule(char *s, char *targetAttribute, char **minusses, char *c, char *p, int effect, int not) { type_datum_t *src, *tgt; class_datum_t *cls; perm_datum_t *perm; @@ -235,13 +301,13 @@ int add_typerule(char *s, char *targetAttribute, char **minusses, char *c, char } if(!found) - ret |= add_irule(src->s.value, i+1, cls->s.value, perm->s.value, effect, not, policy); + ret |= add_irule(src->s.value, i+1, cls->s.value, perm->s.value, effect, not); } } return ret; } -int add_transition(char *srcS, char *origS, char *tgtS, char *c, policydb_t *policy) { +int add_transition(char *srcS, char *origS, char *tgtS, char *c) { type_datum_t *src, *tgt, *orig; class_datum_t *cls; @@ -291,7 +357,7 @@ int add_transition(char *srcS, char *origS, char *tgtS, char *c, policydb_t *pol return 0; } -int add_file_transition(char *srcS, char *origS, char *tgtS, char *c, char* filename, policydb_t *policy) { +int add_file_transition(char *srcS, char *origS, char *tgtS, char *c, char* filename) { type_datum_t *src, *tgt, *orig; class_datum_t *cls; @@ -329,7 +395,7 @@ int add_file_transition(char *srcS, char *origS, char *tgtS, char *c, char* file return 0; } -int add_type(char *domainS, char *typeS, policydb_t *policy) { +int add_type(char *domainS, char *typeS) { type_datum_t *domain; domain = hashtab_search(policy->p_types.table, domainS); @@ -338,9 +404,9 @@ int add_type(char *domainS, char *typeS, policydb_t *policy) { return 1; } - set_attr(typeS, domain->s.value, policy); + set_attr(typeS, domain->s.value); - int typeId = get_attr_id(typeS, policy); + int typeId = get_attr_id(typeS); //Now let's update all constraints! //(kernel doesn't support (yet?) type_names rules) for(int i=0; ip_classes.nprim; ++i) { @@ -358,116 +424,7 @@ int add_type(char *domainS, char *typeS, policydb_t *policy) { return 0; } -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)); - 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)); - 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, "policydb_init: Out of memory!\n"); - return 1; - } - ret = policydb_read(policydb, pf, 1); - if (ret) { - fprintf(stderr, "error(s) encountered while parsing configuration\n"); - return 1; - } - - return 0; -} - -int add_rule_auto(type_datum_t *src, type_datum_t *tgt, class_datum_t *cls, perm_datum_t *perm, int effect, int not, policydb_t *policy) { - hashtab_t type_table, class_table, perm_table; - hashtab_ptr_t cur; - - type_table = policy->p_types.table; - class_table = policy->p_classes.table; - - if (src == NULL) { - for (int i = 0; i < type_table->size; ++i) { - cur = type_table->htable[i]; - while (cur != NULL) { - src = cur->datum; - if(add_rule_auto(src, tgt, cls, perm, effect, not, policy)) - return 1; - cur = cur->next; - } - } - } else if (tgt == NULL) { - for (int i = 0; i < type_table->size; ++i) { - cur = type_table->htable[i]; - while (cur != NULL) { - tgt = cur->datum; - if(add_rule_auto(src, tgt, cls, perm, effect, not, policy)) - return 1; - cur = cur->next; - } - } - } else if (cls == NULL) { - for (int i = 0; i < class_table->size; ++i) { - cur = class_table->htable[i]; - while (cur != NULL) { - cls = cur->datum; - if(add_rule_auto(src, tgt, cls, perm, effect, not, policy)) - return 1; - cur = cur->next; - } - } - } else if (perm == NULL) { - perm_table = cls->permissions.table; - for (int i = 0; i < perm_table->size; ++i) { - cur = perm_table->htable[i]; - while (cur != NULL) { - perm = cur->datum; - if(add_irule(src->s.value, tgt->s.value, cls->s.value, perm->s.value, effect, not, policy)) - return 1; - cur = cur->next; - } - } - - if (cls->comdatum != NULL) { - perm_table = cls->comdatum->permissions.table; - for (int i = 0; i < perm_table->size; ++i) { - cur = perm_table->htable[i]; - while (cur != NULL) { - perm = cur->datum; - if(add_irule(src->s.value, tgt->s.value, cls->s.value, perm->s.value, effect, not, policy)) - return 1; - cur = cur->next; - } - } - } - } else { - return add_irule(src->s.value, tgt->s.value, cls->s.value, perm->s.value, effect, not, policy); - } - return 0; -} - -int add_rule(char *s, char *t, char *c, char *p, int effect, int not, policydb_t *policy) { +int add_rule(char *s, char *t, char *c, char *p, int effect, int not) { type_datum_t *src = NULL, *tgt = NULL; class_datum_t *cls = NULL; perm_datum_t *perm = NULL; @@ -513,16 +470,16 @@ int add_rule(char *s, char *t, char *c, char *p, int effect, int not, policydb_t } } } - return add_rule_auto(src, tgt, cls, perm, effect, not, policy); + return add_rule_auto(src, tgt, cls, perm, effect, not); } -int live_patch(policydb_t *policydb) { +int live_patch() { char *filename = "/sys/fs/selinux/load"; int fd, ret; void *data = NULL; size_t len; - policydb_to_image(NULL, policydb, &data, &len); + policydb_to_image(NULL, policy, &data, &len); if (data == NULL) fprintf(stderr, "Error!"); // based on libselinux security_load_policy() @@ -541,231 +498,3 @@ int live_patch(policydb_t *policydb) { } return 0; } - -int main(int argc, char **argv) -{ - char *policy = NULL, *source = NULL, *target = NULL, *class = NULL, *perm = NULL; - char *fcon = NULL, *outfile = NULL, *permissive = NULL, *attr = NULL, *filetrans = NULL; - int exists = 0, not = 0, live = 0, builtin = 0, magisk = 0; - policydb_t policydb; - struct policy_file pf, outpf; - sidtab_t sidtab; - int ch; - FILE *fp; - int permissive_value = 0, noaudit = 0; - - struct option long_options[] = { - {"attr", required_argument, NULL, 'a'}, - {"exists", no_argument, NULL, 'e'}, - {"source", required_argument, NULL, 's'}, - {"target", required_argument, NULL, 't'}, - {"class", required_argument, NULL, 'c'}, - {"perm", required_argument, NULL, 'p'}, - {"fcon", required_argument, NULL, 'f'}, - {"filetransition", required_argument, NULL, 'g'}, - {"noaudit", no_argument, NULL, 'n'}, - {"file", required_argument, NULL, 'P'}, - {"output", required_argument, NULL, 'o'}, - {"permissive", required_argument, NULL, 'Z'}, - {"not-permissive", required_argument, NULL, 'z'}, - {"not", no_argument, NULL, 0}, - {"live", no_argument, NULL, 0}, - {"magisk", no_argument, NULL, 0}, - {NULL, 0, NULL, 0} - }; - - int option_index = -1; - while ((ch = getopt_long(argc, argv, "a:c:ef:g:s:t:p:P:o:Z:z:n", long_options, &option_index)) != -1) { - switch (ch) { - case 0: - if(strcmp(long_options[option_index].name, "not") == 0) - not = 1; - else if(strcmp(long_options[option_index].name, "live") == 0) - live = 1; - else if(strcmp(long_options[option_index].name, "magisk") == 0) - magisk = 1; - else - usage(argv[0]); - break; - case 'a': - attr = optarg; - break; - case 'e': - exists = 1; - break; - case 'f': - fcon = optarg; - break; - case 'g': - filetrans = optarg; - break; - 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; - case 'o': - outfile = optarg; - break; - case 'Z': - permissive = optarg; - permissive_value = 1; - break; - case 'z': - permissive = optarg; - permissive_value = 0; - break; - case 'n': - noaudit = 1; - break; - default: - usage(argv[0]); - } - } - - // Use builtin rules if nothing specified - if (!magisk && !source && !target && !class && !perm && !permissive && !fcon && !attr &&!filetrans && !exists) - builtin = 1; - - // Overwrite original if not specified - if(!outfile) - outfile = policy; - - // Use current policy if not specified - if(!policy) - policy = "/sys/fs/selinux/policy"; - - sepol_set_policydb(&policydb); - sepol_set_sidtab(&sidtab); - - if (load_policy(policy, &policydb, &pf)) { - fprintf(stderr, "Could not load policy\n"); - return 1; - } - - if (policydb_load_isids(&policydb, &sidtab)) - return 1; - - if (builtin) { - phh_rules(&policydb); - } - else if (magisk) { - magisk_rules(&policydb); - } - else if (permissive) { - type_datum_t *type; - create_domain(permissive, &policydb); - type = hashtab_search(policydb.p_types.table, permissive); - if (type == NULL) { - fprintf(stderr, "type %s does not exist\n", permissive); - return 1; - } - if (ebitmap_set_bit(&policydb.permissive_map, type->s.value, permissive_value)) { - fprintf(stderr, "Could not set bit in permissive map\n"); - return 1; - } - } else if(exists) { - if(source) { - type_datum_t *tmp = hashtab_search(policydb.p_types.table, source); - if (!tmp) - exit(1); - else - exit(0); - } else if(class) { - class_datum_t *tmp = hashtab_search(policydb.p_classes.table, class); - if(!tmp) - exit(1); - else - exit(0); - } else { - usage(argv[0]); - } - } else if(filetrans) { - if(add_file_transition(source, fcon, target, class, filetrans, &policydb)) - return 1; - } else if(fcon) { - if(add_transition(source, fcon, target, class, &policydb)) - return 1; - } else if(attr) { - if(add_type(source, attr, &policydb)) - return 1; - } else if(noaudit) { - if(add_rule(source, target, class, perm, AVTAB_AUDITDENY, not, &policydb)) - return 1; - } else { - //Add a rule to a whole set of typeattribute, not just a type - if (target != NULL) { - if(*target == '=') { - char *saveptr = NULL; - - char *targetAttribute = strtok_r(target, "-", &saveptr); - - char *vals[64]; - int i = 0; - - char *m = NULL; - while( (m = strtok_r(NULL, "-", &saveptr)) != NULL) { - vals[i++] = m; - } - vals[i] = NULL; - - if(add_typerule(source, targetAttribute+1, vals, class, perm, AVTAB_ALLOWED, not, &policydb)) - return 1; - } - } - if (perm != NULL) { - char *saveptr = NULL; - - char *p = strtok_r(perm, ",", &saveptr); - do { - if (add_rule(source, target, class, p, AVTAB_ALLOWED, not, &policydb)) { - fprintf(stderr, "Could not add rule\n"); - return 1; - } - } while( (p = strtok_r(NULL, ",", &saveptr)) != NULL); - } else { - if (add_rule(source, target, class, perm, AVTAB_ALLOWED, not, &policydb)) { - fprintf(stderr, "Could not add rule\n"); - return 1; - } - } - } - - if (live) { - if (live_patch(&policydb)) { - fprintf(stderr, "Could not load new policy into kernel\n"); - return 1; - } - } - - if (outfile) { - fp = fopen(outfile, "w"); - if (!fp) { - fprintf(stderr, "Could not open outfile\n"); - return 1; - } - - policy_file_init(&outpf); - outpf.type = PF_USE_STDIO; - outpf.fp = fp; - - if (policydb_write(&policydb, &outpf)) { - fprintf(stderr, "Could not write policy\n"); - return 1; - } - fclose(fp); - } - - policydb_destroy(&policydb); - return 0; -} diff --git a/utils.c b/utils.c new file mode 100644 index 000000000..f02b6006c --- /dev/null +++ b/utils.c @@ -0,0 +1,48 @@ +#include "sepolicy-inject.h" + +static void set_domain(char* s, int value) { + type_datum_t *type; + if (!exists(s)) + create_domain(s); + type = hashtab_search(policy->p_types.table, s); + if (type == NULL) { + fprintf(stderr, "type %s does not exist\n", s); + return; + } + if (ebitmap_set_bit(&policy->permissive_map, type->s.value, value)) { + fprintf(stderr, "Could not set bit in permissive map\n"); + return; + } +} + +void allow(char *s, char *t, char *c, char *p) { + add_rule(s, t, c, p, AVTAB_ALLOWED, 0); +} + +void deny(char *s, char *t, char *c, char *p) { + add_rule(s, t, c, p, AVTAB_ALLOWED, 1); +} + +void auditallow(char *s, char *t, char *c, char *p) { + add_rule(s, t, c, p, AVTAB_AUDITALLOW, 0); +} + +void auditdeny(char *s, char *t, char *c, char *p) { + add_rule(s, t, c, p, AVTAB_AUDITDENY, 0); +} + +void permissive(char *s) { + set_domain(s, 1); +} + +void enforce(char *s) { + set_domain(s, 0); +} + +void attradd(char *s, char *a) { + add_type(s, a); +} + +int exists(char* source) { + return !! hashtab_search(policy->p_types.table, source); +}