Update magiskpolicy

- Generalize avtab node extraction and insertion
- Add new supported rules: type_change, type_member
- Update help message with official policy language
This commit is contained in:
topjohnwu 2018-11-29 03:46:29 -05:00
parent a9f265a591
commit 3b071116ac
5 changed files with 227 additions and 171 deletions

View File

@ -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);

View File

@ -14,18 +14,20 @@
static const char *type_msg_1 =
"Type 1:\n"
"\"<action> source-class target-class permission-class permission\"\n"
"Action: allow, deny, auditallow, auditdeny\n";
"\"<rule_name> source_type target_type class perm_set\"\n"
"Rules: allow, deny, auditallow, auditdeny\n";
static const char *type_msg_2 =
"Type 2:\n"
"\"<action> source-class target-class permission-class ioctl range\"\n"
"Action: allowxperm, auditallowxperm, dontauditxperm\n";
"\"<rule_name> 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"
"\"<action> class\"\n"
"Action: create, permissive, enforcing\n";
"\"<rule_name> 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";
"\"<rule_name> 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 \"<action> [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 \"<rule_name> [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()); }
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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
};