diff --git a/api.c b/api.c index d5d7c29f4..2193bc510 100644 --- a/api.c +++ b/api.c @@ -31,6 +31,21 @@ int sepol_typetrans(char *s, char *t, char *c, char *d, char *o) { } } +int sepol_allowxperm(char *s, char *t, char *c, char *range) { + // printf("allowxperm %s %s %s %s\n", s, t, c, range); + return add_xperm_rule(s, t, c, range, AVTAB_XPERMS_ALLOWED, 0); +} + +int sepol_auditallowxperm(char *s, char *t, char *c, char *range) { + // printf("auditallowxperm %s %s %s %s\n", s, t, c, range); + return add_xperm_rule(s, t, c, range, AVTAB_XPERMS_AUDITALLOW, 0); +} + +int sepol_dontauditxperm(char *s, char *t, char *c, char *range) { + // printf("dontauditxperm %s %s %s %s\n", s, t, c, range); + return add_xperm_rule(s, t, c, range, AVTAB_XPERMS_DONTAUDIT, 0); +} + int sepol_permissive(char *s) { // printf("permissive %s\n", s); return set_domain_state(s, 1); diff --git a/magiskpolicy.c b/magiskpolicy.c index ca6486f58..9b1b29e43 100644 --- a/magiskpolicy.c +++ b/magiskpolicy.c @@ -26,11 +26,14 @@ static void statements() { "\"deny #source-class #target-class permission-class #permission\"\n" "\"auditallow #source-class #target-class permission-class #permission\"\n" "\"auditdeny #source-class #target-class permission-class #permission\"\n" + "\"typetrans source-class target-class permission-class default-class (optional: object-name)\"\n" + "\"allowxperm #source-class #target-class #permission-class ioctl range\"\n" + "\"auditallowxperm #source-class #target-class #permission-class ioctl range\"\n" + "\"dontauditxperm #source-class #target-class #permission-class ioctl range\"\n" "\"create #class\"\n" "\"permissive #class\"\n" "\"enforcing #class\"\n" "\"attradd #class #attribute\"\n" - "\"typetrans source-class target-class permission-class default-class (optional: object-name)\"\n" "\nsource-class and target-class can be attributes (patches the whole group)\n" "All sections (except typetrans) can be replaced with \'*\' to patch every possible matches\n" "Sections marked with \'#\' can be replaced with collections in curly brackets\n" @@ -263,6 +266,84 @@ static int parse_pattern_4(int action, char* statement) { return 0; } +// Pattern 5: action { source } { target } { class } ioctl range +static int parse_pattern_5(int action, char* statement) { + int state = 0, in_bracket = 0; + char *tok, *range, *saveptr; + struct vector source, target, class, *temp; + vec_init(&source); + vec_init(&target); + vec_init(&class); + tok = strtok_r(statement, " ", &saveptr); + while (tok != NULL) { + if (tok[0] == '{') { + if (in_bracket || state == 3 || state == 4) return 1; + in_bracket = 1; + if (tok[1]) { + ++tok; + continue; + } + } else if (tok[strlen(tok) - 1] == '}') { + if (!in_bracket || state == 3 || state == 4) return 1; + in_bracket = 0; + if (strlen(tok) - 1) { + tok[strlen(tok) - 1] = '\0'; + continue; + } + } else { + if (tok[0] == '*') tok = ALL; + switch (state) { + case 0: + temp = &source; + break; + case 1: + temp = ⌖ + break; + case 2: + temp = &class; + break; + case 3: + // Should always be ioctl + temp = NULL; + break; + case 4: + temp = NULL; + range = tok; + break; + default: + return 1; + } + vec_push_back(temp, tok); + } + if (!in_bracket) ++state; + tok = strtok_r(NULL, " ", &saveptr); + } + if (state != 5) return 1; + for(int i = 0; i < source.size; ++i) + for (int j = 0; j < target.size; ++j) + for (int k = 0; k < class.size; ++k) + switch (action) { + case 0: + if (sepol_allowxperm(source.data[i], target.data[j], class.data[k], range)) + fprintf(stderr, "Error in: allowxperm %s %s %s %s\n", source.data[i], target.data[j], class.data[k], range); + break; + case 1: + if (sepol_auditallowxperm(source.data[i], target.data[j], class.data[k], range)) + fprintf(stderr, "Error in: auditallowxperm %s %s %s %s\n", source.data[i], target.data[j], class.data[k], range); + break; + case 2: + if (sepol_dontauditxperm(source.data[i], target.data[j], class.data[k], range)) + fprintf(stderr, "Error in: dontauditxperm %s %s %s %s\n", source.data[i], target.data[j], class.data[k], range); + break; + default: + return 1; + } + vec_destroy(&source); + vec_destroy(&target); + vec_destroy(&class); + return 0; +} + static void syntax_error_msg() { fprintf(stderr, "Syntax error in \"%s\"\n", err_msg); syntax_err = 1; @@ -339,6 +420,15 @@ int magiskpolicy_main(int argc, char *argv[]) { } else if (strcmp(tok, "typetrans") == 0) { if (parse_pattern_4(0, rules.data[i] + strlen(tok) + 1)) syntax_error_msg(); + } else if (strcmp(tok, "allowxperm") == 0) { + if (parse_pattern_5(0, rules.data[i] + strlen(tok) + 1)) + syntax_error_msg(); + } else if (strcmp(tok, "auditallowxperm") == 0) { + if (parse_pattern_5(1, rules.data[i] + strlen(tok) + 1)) + syntax_error_msg(); + } else if (strcmp(tok, "dontauditxperm") == 0) { + if (parse_pattern_5(2, rules.data[i] + strlen(tok) + 1)) + syntax_error_msg(); } else { syntax_error_msg(); } diff --git a/magiskpolicy.h b/magiskpolicy.h index e45f9cd2d..062e0bb03 100644 --- a/magiskpolicy.h +++ b/magiskpolicy.h @@ -19,6 +19,9 @@ int sepol_deny(char *s, char *t, char *c, char *p); int sepol_auditallow(char *s, char *t, char *c, char *p); int sepol_auditdeny(char *s, char *t, char *c, char *p); int sepol_typetrans(char *s, char *t, char *c, char *d, char *o); +int sepol_allowxperm(char *s, char *t, char *c, char *range); +int sepol_auditallowxperm(char *s, char *t, char *c, char *range); +int sepol_dontauditxperm(char *s, char *t, char *c, char *range); int sepol_create(char *s); int sepol_permissive(char *s); int sepol_enforce(char *s); diff --git a/sepolicy.c b/sepolicy.c index 70ada796c..a0bf5a1d4 100644 --- a/sepolicy.c +++ b/sepolicy.c @@ -50,7 +50,7 @@ static int set_attr(char *type, int value) { return 0; } -static int add_irule(int s, int t, int c, int p, int effect, int not) { +static int __add_rule(int s, int t, int c, int p, int effect, int not) { avtab_key_t key; avtab_datum_t *av; int new_rule = 0; @@ -106,10 +106,90 @@ static int add_rule_auto(type_datum_t *src, type_datum_t *tgt, class_datum_t *cl } else if (cls == NULL) { hashtab_for_each(policydb->p_classes.table, &cur) { cls = cur->datum; - ret |= add_irule(src->s.value, tgt->s.value, cls->s.value, -1, effect, not); + ret |= __add_rule(src->s.value, tgt->s.value, cls->s.value, -1, effect, not); } } else { - return add_irule(src->s.value, tgt->s.value, cls->s.value, perm ? perm->s.value : -1, effect, not); + return __add_rule(src->s.value, tgt->s.value, cls->s.value, perm ? perm->s.value : -1, effect, not); + } + return ret; +} + +#define ioctl_driver(x) (x>>8 & 0xFF) +#define ioctl_func(x) (x & 0xFF) + +static int __add_xperm_rule(int s, int t, int c, uint16_t low, uint16_t high, int effect, int not) { + avtab_key_t key; + avtab_datum_t *av; + int new_rule = 0; + + key.source_type = s; + key.target_type = t; + key.target_class = c; + key.specified = effect; + + av = avtab_search(&policydb->te_avtab, &key); + if (av == NULL) { + av = cmalloc(sizeof(*av)); + av->xperms = cmalloc(sizeof(avtab_extended_perms_t)); + new_rule = 1; + if (ioctl_driver(low) != ioctl_driver(high)) { + av->xperms->specified = AVTAB_XPERMS_IOCTLDRIVER; + av->xperms->driver = 0; + } else { + av->xperms->specified = AVTAB_XPERMS_IOCTLFUNCTION; + av->xperms->driver = ioctl_driver(low); + } + } + + if (av->xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { + for (unsigned i = ioctl_driver(low); i <= ioctl_driver(high); ++i) { + if (not) + xperm_clear(i, av->xperms->perms); + else + xperm_set(i, av->xperms->perms); + } + } else { + for (unsigned i = ioctl_func(low); i <= ioctl_func(high); ++i) { + if (not) + xperm_clear(i, av->xperms->perms); + else + xperm_set(i, av->xperms->perms); + } + } + + if (new_rule) { + if (avtab_insert(&policydb->te_avtab, &key, av)) { + fprintf(stderr, "Error inserting into avtab\n"); + return 1; + } + free(av); + } + + return 0; +} + +static int add_xperm_rule_auto(type_datum_t *src, type_datum_t *tgt, class_datum_t *cls, + uint16_t low, uint16_t high, int effect, int not) { + hashtab_ptr_t cur; + int ret = 0; + + if (src == NULL) { + hashtab_for_each(policydb->p_types.table, &cur) { + src = cur->datum; + ret |= add_xperm_rule_auto(src, tgt, cls, low, high, effect, not); + } + } else if (tgt == NULL) { + hashtab_for_each(policydb->p_types.table, &cur) { + tgt = cur->datum; + ret |= add_xperm_rule_auto(src, tgt, cls, low, high, effect, not); + } + } else if (cls == NULL) { + hashtab_for_each(policydb->p_classes.table, &cur) { + cls = cur->datum; + ret |= __add_xperm_rule(src->s.value, tgt->s.value, cls->s.value, low, high, effect, not); + } + } else { + return __add_xperm_rule(src->s.value, tgt->s.value, cls->s.value, low, high, effect, not); } return ret; } @@ -307,7 +387,6 @@ int add_transition(char *s, char *t, char *c, char *d) { key.target_class = cls->s.value; key.specified = AVTAB_TRANSITION; av = avtab_search(&policydb->te_avtab, &key); - if (av == NULL) { av = cmalloc(sizeof(*av)); new_rule = 1; @@ -446,3 +525,48 @@ int add_rule(char *s, char *t, char *c, char *p, int effect, int not) { } return add_rule_auto(src, tgt, cls, perm, effect, not); } + +int add_xperm_rule(char *s, char *t, char *c, char *range, int effect, int not) { + type_datum_t *src = NULL, *tgt = NULL; + class_datum_t *cls = NULL; + + if (s) { + src = hashtab_search(policydb->p_types.table, s); + if (src == NULL) { + fprintf(stderr, "source type %s does not exist\n", s); + return 1; + } + } + + if (t) { + tgt = hashtab_search(policydb->p_types.table, t); + if (tgt == NULL) { + fprintf(stderr, "target type %s does not exist\n", t); + return 1; + } + } + + if (c) { + cls = hashtab_search(policydb->p_classes.table, c); + if (cls == NULL) { + fprintf(stderr, "class %s does not exist\n", c); + return 1; + } + } + + uint16_t low, high; + + if (range) { + if (strchr(range, '-')){ + sscanf(range, "%hx-%hx", &low, &high); + } else { + sscanf(range, "%hx", &low); + high = low; + } + } else { + low = 0; + high = 0xFFFF; + } + + return add_xperm_rule_auto(src, tgt, cls, low, high, effect, not); +} diff --git a/sepolicy.h b/sepolicy.h index e7e2ca36d..577cdfa05 100644 --- a/sepolicy.h +++ b/sepolicy.h @@ -42,6 +42,7 @@ int add_transition(char *s, char *t, char *c, char *d); int add_file_transition(char *s, char *t, char *c, char *d, char* filename); int add_typeattribute(char *domainS, char *attr); int add_rule(char *s, char *t, char *c, char *p, int effect, int not); +int add_xperm_rule(char *s, char *t, char *c, char *range, int effect, int not); extern int policydb_index_decls(sepol_handle_t * handle, policydb_t * p);