diff --git a/native/jni/magiskpolicy/api.cpp b/native/jni/magiskpolicy/api.cpp index 6ee0fefda..5f5d4bd9a 100644 --- a/native/jni/magiskpolicy/api.cpp +++ b/native/jni/magiskpolicy/api.cpp @@ -21,16 +21,6 @@ int sepol_auditdeny(const char *s, const char *t, const char *c, const char *p) return add_rule(s, t, c, p, AVTAB_AUDITDENY, 0); } -int sepol_typetrans(const char *s, const char *t, const char *c, const char *d, const char *o) { - if (o == nullptr) { - // printf("add_trans %s %s %s %s\n", s, t, c ,d); - return add_transition(s, t, c, d); - } else { - // printf("add_file_trans %s %s %s %s %s\n", s, t, c ,d, o); - return add_file_transition(s, t, c, d, o); - } -} - int sepol_allowxperm(const char *s, const char *t, const char *c, const 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); @@ -46,6 +36,21 @@ int sepol_dontauditxperm(const char *s, const char *t, const char *c, const char return add_xperm_rule(s, t, c, range, AVTAB_XPERMS_DONTAUDIT, 0); } +int sepol_typetrans(const char *s, const char *t, const char *c, const char *d) { + // printf("type_transition %s %s %s %s\n", s, t, c, d); + return add_type_rule(s, t, c, d, AVTAB_TRANSITION); +} + +int sepol_typechange(const char *s, const char *t, const char *c, const char *d) { + // printf("type_change %s %s %s %s\n", s, t, c, d); + return add_type_rule(s, t, c, d, AVTAB_CHANGE); +} + +int sepol_typemember(const char *s, const char *t, const char *c, const char *d) { + // printf("type_member %s %s %s %s\n", s, t, c, d); + return add_type_rule(s, t, c, d, AVTAB_MEMBER); +} + int sepol_permissive(const char *s) { // printf("permissive %s\n", s); return set_domain_state(s, 1); diff --git a/native/jni/magiskpolicy/magiskpolicy.cpp b/native/jni/magiskpolicy/magiskpolicy.cpp index dc32d0ff4..93d3ef6a6 100644 --- a/native/jni/magiskpolicy/magiskpolicy.cpp +++ b/native/jni/magiskpolicy/magiskpolicy.cpp @@ -14,18 +14,20 @@ static const char *type_msg_1 = "Type 1:\n" -"\" source-class target-class permission-class permission\"\n" -"Action: allow, deny, auditallow, auditdeny\n"; +"\" source_type target_type class perm_set\"\n" +"Rules: allow, deny, auditallow, auditdeny\n"; static const char *type_msg_2 = "Type 2:\n" -"\" source-class target-class permission-class ioctl range\"\n" -"Action: allowxperm, auditallowxperm, dontauditxperm\n"; +"\" source_type target_type class operation xperm_set\"\n" +"Rules: allowxperm, auditallowxperm, dontauditxperm\n" +"* The only supported operation is ioctl\n" +"* The only supported xperm_set format is range ([low-high])\n"; static const char *type_msg_3 = "Type 3:\n" -"\" class\"\n" -"Action: create, permissive, enforcing\n"; +"\" class\"\n" +"Rules: create, permissive, enforcing\n"; static const char *type_msg_4 = "Type 4:\n" @@ -33,7 +35,12 @@ static const char *type_msg_4 = static const char *type_msg_5 = "Type 5:\n" -"\"typetrans source-class target-class permission-class default-class (optional: object-name)\"\n"; +"\" source_type target_type class default_type\"\n" +"Rules: type_transition, type_change, type_member\n"; + +static const char *type_msg_6 = +"Type 6:\n" +"\"name_transition source_type target_type class default_type object_name\"\n"; [[noreturn]] static void statements() { @@ -42,9 +49,10 @@ static const char *type_msg_5 = "this means a full policy statement should be enclosed in quotes;\n" "multiple policy statements can be provided in a single command\n" "\n" - "The statements has a format of \" [args...]\"\n" - "Use '*' in args to represent every possible match.\n" - "Collections wrapped in curly brackets can also be used as args.\n" + "The statements has a format of \" [args...]\"\n" + "Multiple types and permissions can be grouped into collections\n" + "wrapped in curly brackets.\n" + "'*' represents a collection containing all valid matches.\n" "\n" "Supported policy statements:\n" "\n" @@ -53,20 +61,21 @@ static const char *type_msg_5 = "%s\n" "%s\n" "%s\n" + "%s\n" "Notes:\n" - "- typetrans does not support the all match '*' syntax\n" - "- permission-class cannot be collections\n" - "- source-class and target-class can also be attributes\n" + "* Type 4 - 6 does not support collections\n" + "* Object classes cannot be collections\n" + "* source_type and target_type can also be attributes\n" "\n" - "Example: allow { source1 source2 } { target1 target2 } permission-class *\n" + "Example: allow { s1 s2 } { t1 t2 } class *\n" "Will be expanded to:\n" "\n" - "allow source1 target1 permission-class { all-permissions }\n" - "allow source1 target2 permission-class { all-permissions }\n" - "allow source2 target1 permission-class { all-permissions }\n" - "allow source2 target2 permission-class { all-permissions }\n" + "allow s1 t1 class { all permissions }\n" + "allow s1 t2 class { all permissions }\n" + "allow s2 t1 class { all permissions }\n" + "allow s2 t2 class { all permissions }\n" "\n", - type_msg_1, type_msg_2, type_msg_3, type_msg_4, type_msg_5); + type_msg_1, type_msg_2, type_msg_3, type_msg_4, type_msg_5, type_msg_6); exit(0); } @@ -207,6 +216,8 @@ static int parse_pattern_2(int action, const char *action_str, char *stmt) { break; case 3: // Currently only support ioctl + if (strcmp(cur, "ioctl")) + return 1; vec = nullptr; break; case 4: @@ -310,11 +321,25 @@ static int parse_pattern_4(int action, const char *action_str, char *stmt) { return 0; } -// Pattern 5: action source target class default (filename) +// Pattern 5: action source target class default static int parse_pattern_5(int action, const char *action_str, char *stmt) { + int (*action_func)(const char*, const char*, const char*, const char*); + switch (action) { + case 0: + action_func = sepol_typetrans; + break; + case 1: + action_func = sepol_typechange; + break; + case 2: + action_func = sepol_typemember; + break; + default: + return 1; + } int state = 0; char *cur; - char *source, *target, *cls, *def, *filename = nullptr; + char *source, *target, *cls, *def; while ((cur = strtok_r(nullptr, " ", &stmt)) != nullptr) { switch(state) { case 0: @@ -329,18 +354,48 @@ static int parse_pattern_5(int action, const char *action_str, char *stmt) { case 3: def = cur; break; - case 4: - filename = cur; - break; default: return 1; } ++state; } if (state < 4) return 1; - if (sepol_typetrans(source, target, cls, def, filename)) + if (action_func(source, target, cls, def)) + fprintf(stderr, "Error in: %s %s %s %s %s\n", action_str, source, target, cls, def); + return 0; +} + +// Pattern 6: action source target class default filename +static int parse_pattern_6(int action, const char *action_str, char *stmt) { + int state = 0; + char *cur; + char *source, *target, *cls, *def, *filename; + while ((cur = strtok_r(nullptr, " ", &stmt)) != nullptr) { + switch(state) { + case 0: + source = cur; + break; + case 1: + target = cur; + break; + case 2: + cls = cur; + break; + case 3: + def = cur; + break; + case 4: + filename = cur; + break; + default: + return 1; + } + ++state; + } + if (state < 4) return 1; + if (sepol_nametrans(source, target, cls, def, filename)) fprintf(stderr, "Error in: %s %s %s %s %s %s\n", - action_str, source, target, cls, def, filename ? filename : ""); + action_str, source, target, cls, def, filename); return 0; } @@ -371,7 +426,10 @@ static void parse_statement(char *statement) { add_action("permissive", 3, 1) add_action("enforce", 3, 2) add_action("attradd", 4, 0) - add_action("typetrans", 5, 0) + add_action("type_transition", 5, 0) + add_action("type_change", 5, 1) + add_action("type_member", 5, 2) + add_action("name_transition", 6, 0) else { fprintf(stderr, "Unknown statement: '%s'\n\n", orig.c_str()); } } diff --git a/native/jni/magiskpolicy/magiskpolicy.h b/native/jni/magiskpolicy/magiskpolicy.h index f5f0e8c44..7edd93c15 100644 --- a/native/jni/magiskpolicy/magiskpolicy.h +++ b/native/jni/magiskpolicy/magiskpolicy.h @@ -31,7 +31,10 @@ int sepol_allow(const char *s, const char *t, const char *c, const char *p); int sepol_deny(const char *s, const char *t, const char *c, const char *p); int sepol_auditallow(const char *s, const char *t, const char *c, const char *p); int sepol_auditdeny(const char *s, const char *t, const char *c, const char *p); -int sepol_typetrans(const char *s, const char *t, const char *c, const char *d, const char *o); +int sepol_typetrans(const char *s, const char *t, const char *c, const char *d); +int sepol_typechange(const char *s, const char *t, const char *c, const char *d); +int sepol_typemember(const char *s, const char *t, const char *c, const char *d); +int sepol_nametrans(const char *s, const char *t, const char *c, const char *d, const char *o); int sepol_allowxperm(const char *s, const char *t, const char *c, const char *range); int sepol_auditallowxperm(const char *s, const char *t, const char *c, const char *range); int sepol_dontauditxperm(const char *s, const char *t, const char *c, const char *range); diff --git a/native/jni/magiskpolicy/sepolicy.c b/native/jni/magiskpolicy/sepolicy.c index 850d0b8fd..5489203bb 100644 --- a/native/jni/magiskpolicy/sepolicy.c +++ b/native/jni/magiskpolicy/sepolicy.c @@ -27,15 +27,6 @@ policydb_t *policydb = NULL; extern int policydb_index_decls(sepol_handle_t * handle, policydb_t * p); -static void *cmalloc(size_t s) { - void *t = calloc(s, 1); - if (t == NULL) { - LOGE("Out of memory\n"); - exit(1); - } - return t; -} - static int get_attr(const char *type, int value) { type_datum_t *attr = hashtab_search(policydb->p_types.table, type); if (!attr) @@ -44,7 +35,7 @@ static int get_attr(const char *type, int value) { if (attr->flavor != TYPE_ATTRIB) return 1; - return !! ebitmap_get_bit(&policydb->attr_type_map[attr->s.value-1], value-1); + return ebitmap_get_bit(&policydb->attr_type_map[attr->s.value - 1], value - 1) != 0; } static int get_attr_id(const char *type) { @@ -74,46 +65,62 @@ static int set_attr(const char *type, int value) { return 0; } -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; +static avtab_ptr_t get_avtab_node(avtab_key_t *key, avtab_extended_perms_t *xperms) { + avtab_ptr_t node; + avtab_datum_t avdatum; + int match = 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)); - new_rule = 1; + /* AVTAB_XPERMS entries are not necessarily unique */ + if (key->specified & AVTAB_XPERMS) { + node = avtab_search_node(&policydb->te_avtab, key); + while (node) { + if ((node->datum.xperms->specified == xperms->specified) && + (node->datum.xperms->driver == xperms->driver)) { + match = 1; + break; + } + node = avtab_search_node_next(node, key->specified); + } + if (!match) + node = NULL; + } else { + node = avtab_search_node(&policydb->te_avtab, key); } + if (!node) { + memset(&avdatum, 0, sizeof avdatum); + /* + * AUDITDENY, aka DONTAUDIT, are &= assigned, versus |= for + * others. Initialize the data accordingly. + */ + avdatum.data = key->specified == AVTAB_AUDITDENY ? ~0U : 0U; + /* this is used to get the node - insertion is actually unique */ + node = avtab_insert_nonunique(&policydb->te_avtab, key, &avdatum); + } + + return node; +} + +static int add_avrule(avtab_key_t *key, int p, int not) { + avtab_datum_t *datum = &get_avtab_node(key, NULL)->datum; if(not) { if (p < 0) - av->data = 0U; + datum->data = 0U; else - av->data &= ~(1U << (p - 1)); + datum->data &= ~(1U << (p - 1)); } else { if (p < 0) - av->data = ~0U; + datum->data = ~0U; else - av->data |= 1U << (p - 1); - } - - if (new_rule) { - if (avtab_insert(&policydb->te_avtab, &key, av)) { - LOGW("Error inserting into avtab\n"); - return 1; - } - free(av); + datum->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) { +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) { + avtab_key_t key; hashtab_ptr_t cur; int ret = 0; @@ -130,10 +137,14 @@ 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_rule(src->s.value, tgt->s.value, cls->s.value, -1, effect, not); + ret |= add_rule_auto(src, tgt, cls, perm, effect, not); } } else { - return __add_rule(src->s.value, tgt->s.value, cls->s.value, perm ? perm->s.value : -1, effect, not); + key.source_type = src->s.value; + key.target_type = tgt->s.value; + key.target_class = cls->s.value; + key.specified = effect; + return add_avrule(&key, perm ? perm->s.value : -1, not); } return ret; } @@ -141,59 +152,47 @@ static int add_rule_auto(type_datum_t *src, type_datum_t *tgt, class_datum_t *cl #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; +static int add_avxrule(avtab_key_t *key, uint16_t low, uint16_t high, int not) { + avtab_datum_t *datum; + avtab_extended_perms_t xperms; - 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); - } + memset(&xperms, 0, sizeof(xperms)); + if (ioctl_driver(low) != ioctl_driver(high)) { + xperms.specified = AVTAB_XPERMS_IOCTLDRIVER; + xperms.driver = 0; + } else { + xperms.specified = AVTAB_XPERMS_IOCTLFUNCTION; + xperms.driver = ioctl_driver(low); } - if (av->xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { - for (unsigned i = ioctl_driver(low); i <= ioctl_driver(high); ++i) { + if (xperms.specified == AVTAB_XPERMS_IOCTLDRIVER) { + for (int i = ioctl_driver(low); i <= ioctl_driver(high); ++i) { if (not) - xperm_clear(i, av->xperms->perms); + xperm_clear(i, xperms.perms); else - xperm_set(i, av->xperms->perms); + xperm_set(i, xperms.perms); } } else { - for (unsigned i = ioctl_func(low); i <= ioctl_func(high); ++i) { + for (int i = ioctl_func(low); i <= ioctl_func(high); ++i) { if (not) - xperm_clear(i, av->xperms->perms); + xperm_clear(i, xperms.perms); else - xperm_set(i, av->xperms->perms); + xperm_set(i, xperms.perms); } } - if (new_rule) { - if (avtab_insert(&policydb->te_avtab, &key, av)) { - LOGW("Error inserting into avtab\n"); - return 1; - } - free(av); - } + datum = &get_avtab_node(key, &xperms)->datum; + if (datum->xperms == NULL) + datum->xperms = xmalloc(sizeof(xperms)); + + memcpy(datum->xperms, &xperms, sizeof(xperms)); 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) { + avtab_key_t key; hashtab_ptr_t cur; int ret = 0; @@ -210,10 +209,14 @@ static int add_xperm_rule_auto(type_datum_t *src, type_datum_t *tgt, class_datum } 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); + ret |= add_xperm_rule_auto(src, tgt, cls, low, high, effect, not); } } else { - return __add_xperm_rule(src->s.value, tgt->s.value, cls->s.value, low, high, effect, not); + key.source_type = src->s.value; + key.target_type = tgt->s.value; + key.target_class = cls->s.value; + key.specified = effect; + return add_avxrule(&key, low, high, not); } return ret; } @@ -227,7 +230,7 @@ int load_policydb(const char *filename) { if (policydb) destroy_policydb(); - policydb = cmalloc(sizeof(*policydb)); + policydb = xcalloc(sizeof(*policydb), 1); mmap_ro(filename, &map, &size); @@ -417,59 +420,7 @@ int set_domain_state(const char *s, int state) { return 0; } -int add_transition(const char *s, const char *t, const char *c, const char *d) { - type_datum_t *src, *tgt, *def; - class_datum_t *cls; - - avtab_key_t key; - avtab_datum_t *av; - int new_rule = 0; - - src = hashtab_search(policydb->p_types.table, s); - if (src == NULL) { - LOGW("source type %s does not exist\n", s); - return 1; - } - tgt = hashtab_search(policydb->p_types.table, t); - if (tgt == NULL) { - LOGW("target type %s does not exist\n", t); - return 1; - } - cls = hashtab_search(policydb->p_classes.table, c); - if (cls == NULL) { - LOGW("class %s does not exist\n", c); - return 1; - } - def = hashtab_search(policydb->p_types.table, d); - if (def == NULL) { - LOGW("default type %s does not exist\n", d); - return 1; - } - - key.source_type = src->s.value; - key.target_type = tgt->s.value; - 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; - } - - av->data = def->s.value; - - if (new_rule) { - if (avtab_insert(&policydb->te_avtab, &key, av)) { - LOGW("Error inserting into avtab\n"); - return 1; - } - free(av); - } - return 0; -} - -int add_file_transition(const char *s, const char *t, const char *c, const char *d, - const char *filename) { +int sepol_nametrans(const char *s, const char *t, const char *c, const char *d, const char *o) { type_datum_t *src, *tgt, *def; class_datum_t *cls; @@ -498,13 +449,13 @@ int add_file_transition(const char *s, const char *t, const char *c, const char trans_key.stype = src->s.value; trans_key.ttype = tgt->s.value; trans_key.tclass = cls->s.value; - trans_key.name = (char *) filename; + trans_key.name = (char *) o; filename_trans_datum_t *trans_datum; trans_datum = hashtab_search(policydb->p_types.table, (hashtab_key_t) &trans_key); if (trans_datum == NULL) { - trans_datum = cmalloc(sizeof(*trans_datum)); + trans_datum = xcalloc(sizeof(*trans_datum), 1); hashtab_insert(policydb->filename_trans, (hashtab_key_t) &trans_key, trans_datum); } @@ -634,3 +585,42 @@ int add_xperm_rule(const char *s, const char *t, const char *c, const char *rang return add_xperm_rule_auto(src, tgt, cls, low, high, effect, n); } + +int add_type_rule(const char *s, const char *t, const char *c, const char *d, int effect) { + type_datum_t *src, *tgt, *def; + class_datum_t *cls; + + avtab_key_t key; + avtab_datum_t *av; + + src = hashtab_search(policydb->p_types.table, s); + if (src == NULL) { + LOGW("source type %s does not exist\n", s); + return 1; + } + tgt = hashtab_search(policydb->p_types.table, t); + if (tgt == NULL) { + LOGW("target type %s does not exist\n", t); + return 1; + } + cls = hashtab_search(policydb->p_classes.table, c); + if (cls == NULL) { + LOGW("class %s does not exist\n", c); + return 1; + } + def = hashtab_search(policydb->p_types.table, d); + if (def == NULL) { + LOGW("default type %s does not exist\n", d); + return 1; + } + + key.source_type = src->s.value; + key.target_type = tgt->s.value; + key.target_class = cls->s.value; + key.specified = effect; + + av = &get_avtab_node(&key, NULL)->datum; + av->data = def->s.value; + + return 0; +} diff --git a/native/jni/magiskpolicy/sepolicy.h b/native/jni/magiskpolicy/sepolicy.h index b69a3b583..a306bc2bd 100644 --- a/native/jni/magiskpolicy/sepolicy.h +++ b/native/jni/magiskpolicy/sepolicy.h @@ -21,12 +21,12 @@ extern policydb_t *policydb; // sepolicy manipulation functions int create_domain(const char *d); int set_domain_state(const char *s, int state); -int add_transition(const char *s, const char *t, const char *c, const char *d); int add_file_transition(const char *s, const char *t, const char *c, const char *d, - const char *filename); + const char *o); int add_typeattribute(const char *domainS, const char *attr); int add_rule(const char *s, const char *t, const char *c, const char *p, int effect, int n); int add_xperm_rule(const char *s, const char *t, const char *c, const char *range, int effect, int n); +int add_type_rule(const char *s, const char *t, const char *c, const char *d, int effect); #ifdef __cplusplus };