Add parser for all commands and complete usage

This commit is contained in:
topjohnwu 2017-02-04 06:36:15 +08:00
parent 10bf497cda
commit 0e35350160
5 changed files with 283 additions and 95 deletions

191
main.c
View File

@ -2,12 +2,30 @@
static void usage(char *arg0) {
fprintf(stderr, "%s [--live] [--minimal] [--load <infile>] [--save <outfile>] [policystatement...]\n\n", arg0);
fprintf(stderr, " --live: directly load patched policy to device\n");
fprintf(stderr, " --minimal: minimal patches for boot image to let Magisk live patch on boot\n\n");
fprintf(stderr, "Supported policy statements:\n\n");
fprintf(stderr, "\"allow source-class target-class permission-class permission\"\n");
fprintf(stderr, "\"deny source-class target-class permission-class permission\"\n");
fprintf(stderr, "\"permissive class\"\n");
fprintf(stderr, "\"enforcing class\"\n");
fprintf(stderr, "\"attradd class attribute\"\n");
fprintf(stderr, "\"allow #source-class #target-class permission-class #permission\"\n");
fprintf(stderr, "\"deny #source-class #target-class permission-class #permission\"\n");
fprintf(stderr, "\"create #class\"\n");
fprintf(stderr, "\"permissive #class\"\n");
fprintf(stderr, "\"enforcing #class\"\n");
fprintf(stderr, "\"attradd #class #attribute\"\n");
fprintf(stderr, "\"typetrans source-class target-class permission-class default-class (optional: object_name)\"\n");
fprintf(stderr, "\nsource-class and target-class can be replaced with attributes (will patch the whole group)");
fprintf(stderr, "Sections (except typetrans) can be replaced with \'*\'; it'll try to patch every possible matches\n");
fprintf(stderr, "Sections marked with \'#\' can be replaced with collections in curly brackets\n");
fprintf(stderr, "e.g.: allow { source1 source2 } { target1 target2 } permission-class { permission1 permission2 }\n");
fprintf(stderr, "Will be expanded to:\n");
fprintf(stderr,
"allow source1 target1 permission-class permission1\n\
allow source1 target1 permission-class permission2\n\
allow source1 target2 permission-class permission1\n\
allow source1 target2 permission-class permission2\n\
allow source2 target1 permission-class permission1\n\
allow source2 target1 permission-class permission2\n\
allow source2 target2 permission-class permission1\n\
allow source2 target2 permission-class permission2\n");
fprintf(stderr, "\n");
exit(1);
}
@ -15,12 +33,12 @@ static void usage(char *arg0) {
// Pattern 1: action { source } { target } class { permission }
static int parse_pattern_1(int action, char* statement) {
int state = 0, in_bracket = 0;
char *tok, *class;
struct vector source, target, permission, *temp;
char *tok, *class, *saveptr;
vector source, target, permission, *temp;
vec_init(&source);
vec_init(&target);
vec_init(&permission);
tok = strtok(statement, " ");
tok = strtok_r(statement, " ", &saveptr);
while (tok != NULL) {
if (tok[0] == '{') {
if (in_bracket || state == 2) return 1;
@ -58,7 +76,7 @@ static int parse_pattern_1(int action, char* statement) {
vec_push_back(temp, tok);
}
if (!in_bracket) ++state;
tok = strtok(NULL, " ");
tok = strtok_r(NULL, " ", &saveptr);
}
if (state != 4) return 1;
for(int i = 0; i < source.size; ++i)
@ -66,16 +84,20 @@ static int parse_pattern_1(int action, char* statement) {
for (int k = 0; k < permission.size; ++k)
switch (action) {
case 0:
allow(source.data[i], target.data[j], class, permission.data[k]);
if (allow(source.data[i], target.data[j], class, permission.data[k]))
fprintf(stderr, "Error in: allow %s %s %s %s\n", source.data[i], target.data[j], class, permission.data[k]);
break;
case 1:
deny(source.data[i], target.data[j], class, permission.data[k]);
if (deny(source.data[i], target.data[j], class, permission.data[k]))
fprintf(stderr, "Error in: deny %s %s %s %s\n", source.data[i], target.data[j], class, permission.data[k]);
break;
case 2:
auditallow(source.data[i], target.data[j], class, permission.data[k]);
if (auditallow(source.data[i], target.data[j], class, permission.data[k]))
fprintf(stderr, "Error in: auditallow %s %s %s %s\n", source.data[i], target.data[j], class, permission.data[k]);
break;
case 3:
auditdeny(source.data[i], target.data[j], class, permission.data[k]);
if (auditdeny(source.data[i], target.data[j], class, permission.data[k]))
fprintf(stderr, "Error in: auditdeny %s %s %s %s\n", source.data[i], target.data[j], class, permission.data[k]);
break;
default:
return 1;
@ -86,8 +108,130 @@ static int parse_pattern_1(int action, char* statement) {
return 0;
}
// Pattern 2: action { class } { attribute }
int parse_pattern_2(int action, char* statement) {
int state = 0, in_bracket = 0;
char *tok, *saveptr;
vector class, attribute, *temp;
vec_init(&class);
vec_init(&attribute);
tok = strtok_r(statement, " ", &saveptr);
while (tok != NULL) {
if (tok[0] == '{') {
if (in_bracket) return 1;
in_bracket = 1;
if (tok[1]) {
++tok;
continue;
}
} else if (tok[strlen(tok) - 1] == '}') {
if (!in_bracket) 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 = &class;
break;
case 1:
temp = &attribute;
break;
default:
return 1;
}
vec_push_back(temp, tok);
}
if (!in_bracket) ++state;
tok = strtok_r(NULL, " ", &saveptr);
}
if (state != 2) return 1;
for(int i = 0; i < class.size; ++i)
for (int j = 0; j < attribute.size; ++j)
switch (action) {
case 0:
if (attradd(class.data[i], attribute.data[j]))
fprintf(stderr, "Error in: attradd %s %s\n", class.data[i], attribute.data[j]);
break;
default:
return 1;
}
vec_destroy(&class);
vec_destroy(&attribute);
return 0;
}
// Pattern 3: action { type }
int parse_pattern_3(int action, char* statement) {
char *tok, *saveptr;
vector classes;
vec_init(&classes);
tok = strtok_r(statement, " {}", &saveptr);
while (tok != NULL) {
if (tok[0] == '*') tok = ALL;
vec_push_back(&classes, tok);
tok = strtok_r(NULL, " {}", &saveptr);
}
for (int i = 0; i < classes.size; ++i) {
switch (action) {
case 0:
if (create(classes.data[i]))
fprintf(stderr, "Error in: create %s", classes.data[i]);
break;
case 1:
if (permissive(classes.data[i]))
fprintf(stderr, "Error in: permissive %s", classes.data[i]);
break;
case 2:
if (enforce(classes.data[i]))
fprintf(stderr, "Error in: enforce %s", classes.data[i]);
break;
}
}
vec_destroy(&classes);
return 0;
}
// Pattern 4: action source target class default (filename)
int parse_pattern_4(int action, char* statement) {
int state = 0;
char *tok, *saveptr;
char *source, *target, *class, *def, *filename = NULL;
tok = strtok_r(statement, " ", &saveptr);
while (tok != NULL) {
switch(state) {
case 0:
source = tok;
break;
case 1:
target = tok;
break;
case 2:
class = tok;
break;
case 3:
def = tok;
break;
case 4:
filename = tok;
break;
default:
return 1;
}
tok = strtok_r(NULL, " ", &saveptr);
++state;
}
if (state < 4) return 1;
if (typetrans(source, target, class, def, filename))
fprintf(stderr, "Error in: typetrans %s %s %s %s %s\n", source, target, class, def, filename ? filename : "");
return 0;
}
int main(int argc, char *argv[]) {
char *infile = NULL, *outfile, *tok, cpy[ARG_MAX];
char *infile = NULL, *outfile, *tok, *saveptr, cpy[ARG_MAX];
int live = 0, minimal = 0;
struct vector rules;
@ -141,7 +285,7 @@ int main(int argc, char *argv[]) {
for (int i = 0; i < rules.size; ++i) {
// Since strtok will modify the origin string, copy the policy for error messages
strcpy(cpy, rules.data[i]);
tok = strtok(rules.data[i], " ");
tok = strtok_r(rules.data[i], " ", &saveptr);
if (strcmp(tok, "allow") == 0) {
if (parse_pattern_1(0, rules.data[i] + strlen(tok) + 1))
printf("Syntax error in \"%s\"\n", cpy);
@ -154,6 +298,23 @@ int main(int argc, char *argv[]) {
} else if (strcmp(tok, "auditdeny") == 0) {
if (parse_pattern_1(3, rules.data[i] + strlen(tok) + 1))
printf("Syntax error in \"%s\"\n", cpy);
} else if (strcmp(tok, "attradd") == 0) {
if (parse_pattern_2(0, rules.data[i] + strlen(tok) + 1))
printf("Syntax error in \"%s\"\n", cpy);
} else if (strcmp(tok, "create") == 0) {
if (parse_pattern_3(0, rules.data[i] + strlen(tok) + 1))
printf("Syntax error in \"%s\"\n", cpy);
} else if (strcmp(tok, "permissive") == 0) {
if (parse_pattern_3(1, rules.data[i] + strlen(tok) + 1))
printf("Syntax error in \"%s\"\n", cpy);
} else if (strcmp(tok, "enforce") == 0) {
if (parse_pattern_3(2, rules.data[i] + strlen(tok) + 1))
printf("Syntax error in \"%s\"\n", cpy);
} else if (strcmp(tok, "typetrans") == 0) {
if (parse_pattern_4(0, rules.data[i] + strlen(tok) + 1))
printf("Syntax error in \"%s\"\n", cpy);
} else {
usage(argv[0]);
}
}

10
rules.c
View File

@ -136,15 +136,19 @@ void su_rules() {
samsung();
// Create domains if they don't exist
if (!exists("su"))
create("su");
permissive("su");
if (!exists("su_device"))
create("su_device");
enforce("su_device");
// Patch su to everything
allow("su", ALL, ALL, ALL);
// Autotransition su's socket to su_device
add_transition("su", "device", "su_device", "file");
add_transition("su", "device", "su_device", "dir");
add_transition("su", "device", "file", "su_device");
add_transition("su", "device", "dir", "su_device");
allow("su_device", "tmpfs", "filesystem", "associate");
// Transition from untrusted_app to su_client
@ -176,6 +180,8 @@ void su_rules() {
// Minimal to run Magisk script before live patching
void min_rules() {
if (!exists("su"))
create("su");
permissive("su");
permissive("init");

View File

@ -32,22 +32,23 @@ policydb_t *policy;
// sepolicy manipulation functions
int load_policy(char *filename, policydb_t *policydb, struct policy_file *pf);
void create_domain(char *d);
int create_domain(char *d);
int set_domain_state(char* s, int state);
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_typeattribute(char *domainS, char *typeS);
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_typerule(char *s, char *targetAttribute, char **minusses, char *c, char *p, int effect, int not);
// 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 allow(char *s, char *t, char *c, char *p);
int deny(char *s, char *t, char *c, char *p);
int auditallow(char *s, char *t, char *c, char *p);
int auditdeny(char *s, char *t, char *c, char *p);
int typetrans(char *s, char *t, char *c, char *d, char *o);
int create(char *s);
int permissive(char *s);
int enforce(char *s);
int attradd(char *s, char *a);
int exists(char *source);
// Vector of char*

View File

@ -12,10 +12,10 @@ static void *cmalloc(size_t s) {
static int get_attr(char *type, int value) {
type_datum_t *attr = hashtab_search(policy->p_types.table, type);
if (!attr)
exit(1);
return 1;
if (attr->flavor != TYPE_ATTRIB)
exit(1);
return 1;
return !! ebitmap_get_bit(&policy->attr_type_map[attr->s.value-1], value-1);
//return !! ebitmap_get_bit(&policy->type_attr_map[value-1], attr->s.value-1);
@ -24,10 +24,10 @@ static int get_attr(char *type, int value) {
static int get_attr_id(char *type) {
type_datum_t *attr = hashtab_search(policy->p_types.table, type);
if (!attr)
exit(1);
return 1;
if (attr->flavor != TYPE_ATTRIB)
exit(1);
return 1;
return attr->s.value;
}
@ -35,15 +35,15 @@ static int get_attr_id(char *type) {
static int set_attr(char *type, int value) {
type_datum_t *attr = hashtab_search(policy->p_types.table, type);
if (!attr)
exit(1);
return 1;
if (attr->flavor != TYPE_ATTRIB)
exit(1);
return 1;
if(ebitmap_set_bit(&policy->type_attr_map[value-1], attr->s.value-1, 1))
exit(1);
return 1;
if(ebitmap_set_bit(&policy->attr_type_map[attr->s.value-1], value-1, 1))
exit(1);
return 1;
return 0;
}
@ -179,10 +179,10 @@ int load_policy(char *filename, policydb_t *policydb, struct policy_file *pf) {
return 0;
}
void create_domain(char *d) {
int create_domain(char *d) {
symtab_datum_t *src = hashtab_search(policy->p_types.table, d);
if(src)
return;
return 1;
type_datum_t *typdatum = (type_datum_t *) malloc(sizeof(type_datum_t));
type_datum_init(typdatum);
@ -193,9 +193,8 @@ void create_domain(char *d) {
int r = symtab_insert(policy, SYM_TYPES, strdup(d), typdatum, SCOPE_DECL, 1, &value);
typdatum->s.value = value;
fprintf(stderr, "source type %s does not exist: %d,%d\n", d, r, value);
if (ebitmap_set_bit(&policy->global->branch_list->declared.scope[SYM_TYPES], value - 1, 1)) {
exit(1);
return 1;
}
policy->type_attr_map = realloc(policy->type_attr_map, sizeof(ebitmap_t)*policy->p_types.nprim);
@ -215,52 +214,62 @@ void create_domain(char *d) {
src = hashtab_search(policy->p_types.table, d);
if(!src)
exit(1);
return 1;
extern int policydb_index_decls(policydb_t * p);
if(policydb_index_decls(policy))
exit(1);
return 1;
if(policydb_index_classes(policy))
exit(1);
return 1;
if(policydb_index_others(NULL, policy, 0))
exit(1);
return 1;
set_attr("domain", value);
return set_attr("domain", value);
}
int set_domain_state(char* s, int state) {
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);
hashtab_ptr_t cur;
if (s == NULL) {
hashtab_for_each(policy->p_types.table, &cur) {
type = cur->datum;
if (ebitmap_set_bit(&policy->permissive_map, type->s.value, state)) {
fprintf(stderr, "Could not set bit in permissive map\n");
return 1;
}
}
} else {
type = hashtab_search(policy->p_types.table, s);
if (type == NULL) {
fprintf(stderr, "type %s does not exist\n", s);
return 1;
}
if (ebitmap_set_bit(&policy->permissive_map, type->s.value, state)) {
fprintf(stderr, "Could not set bit in permissive map\n");
return 1;
}
}
if (ebitmap_set_bit(&policy->permissive_map, type->s.value, state)) {
fprintf(stderr, "Could not set bit in permissive map\n");
return 1;
}
return 0;
}
int add_transition(char *srcS, char *origS, char *tgtS, char *c) {
type_datum_t *src, *tgt, *orig;
int add_transition(char *s, char *t, char *c, char *d) {
type_datum_t *src, *tgt, *def;
class_datum_t *cls;
avtab_datum_t *av;
avtab_key_t key;
src = hashtab_search(policy->p_types.table, srcS);
src = hashtab_search(policy->p_types.table, s);
if (src == NULL) {
fprintf(stderr, "source type %s does not exist\n", srcS);
fprintf(stderr, "source type %s does not exist\n", s);
return 1;
}
tgt = hashtab_search(policy->p_types.table, tgtS);
tgt = hashtab_search(policy->p_types.table, t);
if (tgt == NULL) {
fprintf(stderr, "target type %s does not exist\n", tgtS);
fprintf(stderr, "target type %s does not exist\n", t);
return 1;
}
cls = hashtab_search(policy->p_classes.table, c);
@ -268,21 +277,21 @@ int add_transition(char *srcS, char *origS, char *tgtS, char *c) {
fprintf(stderr, "class %s does not exist\n", c);
return 1;
}
orig = hashtab_search(policy->p_types.table, origS);
if (cls == NULL) {
fprintf(stderr, "class %s does not exist\n", origS);
def = hashtab_search(policy->p_types.table, d);
if (def == NULL) {
fprintf(stderr, "default type %s does not exist\n", d);
return 1;
}
key.source_type = src->s.value;
key.target_type = orig->s.value;
key.target_type = tgt->s.value;
key.target_class = cls->s.value;
key.specified = AVTAB_TRANSITION;
av = avtab_search(&policy->te_avtab, &key);
if (av == NULL) {
av = cmalloc(sizeof(*av));
av->data = tgt->s.value;
av->data = def->s.value;
int ret = avtab_insert(&policy->te_avtab, &key, av);
if (ret) {
fprintf(stderr, "Error inserting into avtab\n");
@ -290,24 +299,24 @@ int add_transition(char *srcS, char *origS, char *tgtS, char *c) {
}
} else {
fprintf(stderr, "Warning, rule already defined! Won't override.\n");
fprintf(stderr, "Previous value = %d, wanted value = %d\n", av->data, tgt->s.value);
fprintf(stderr, "Previous value = %d, wanted value = %d\n", av->data, def->s.value);
}
return 0;
}
int add_file_transition(char *srcS, char *origS, char *tgtS, char *c, char* filename) {
type_datum_t *src, *tgt, *orig;
int add_file_transition(char *s, char *t, char *c, char *d, char* filename) {
type_datum_t *src, *tgt, *def;
class_datum_t *cls;
src = hashtab_search(policy->p_types.table, srcS);
src = hashtab_search(policy->p_types.table, s);
if (src == NULL) {
fprintf(stderr, "source type %s does not exist\n", srcS);
fprintf(stderr, "source type %s does not exist\n", s);
return 1;
}
tgt = hashtab_search(policy->p_types.table, tgtS);
tgt = hashtab_search(policy->p_types.table, t);
if (tgt == NULL) {
fprintf(stderr, "target type %s does not exist\n", tgtS);
fprintf(stderr, "target type %s does not exist\n", t);
return 1;
}
cls = hashtab_search(policy->p_classes.table, c);
@ -315,17 +324,17 @@ int add_file_transition(char *srcS, char *origS, char *tgtS, char *c, char* file
fprintf(stderr, "class %s does not exist\n", c);
return 1;
}
orig = hashtab_search(policy->p_types.table, origS);
if (cls == NULL) {
fprintf(stderr, "class %s does not exist\n", origS);
def = hashtab_search(policy->p_types.table, d);
if (def == NULL) {
fprintf(stderr, "default type %s does not exist\n", d);
return 1;
}
filename_trans_t *new_transition = cmalloc(sizeof(*new_transition));
new_transition->stype = src->s.value;
new_transition->ttype = orig->s.value;
new_transition->ttype = tgt->s.value;
new_transition->tclass = cls->s.value;
new_transition->otype = tgt->s.value;
new_transition->otype = def->s.value;
new_transition->name = strdup(filename);
new_transition->next = policy->filename_trans;
@ -334,7 +343,7 @@ int add_file_transition(char *srcS, char *origS, char *tgtS, char *c, char* file
return 0;
}
int add_typeattribute(char *domainS, char *typeS) {
int add_typeattribute(char *domainS, char *attr) {
type_datum_t *domain;
domain = hashtab_search(policy->p_types.table, domainS);
@ -343,9 +352,9 @@ int add_typeattribute(char *domainS, char *typeS) {
return 1;
}
set_attr(typeS, domain->s.value);
set_attr(attr, domain->s.value);
int typeId = get_attr_id(typeS);
int typeId = get_attr_id(attr);
//Now let's update all constraints!
//(kernel doesn't support (yet?) type_names rules)
for(int i=0; i<policy->p_classes.nprim; ++i) {

39
utils.c
View File

@ -22,32 +22,43 @@ void vec_destroy(vector *v) {
free(v->data);
}
void allow(char *s, char *t, char *c, char *p) {
add_rule(s, t, c, p, AVTAB_ALLOWED, 0);
int allow(char *s, char *t, char *c, char *p) {
return 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);
int deny(char *s, char *t, char *c, char *p) {
return 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);
int auditallow(char *s, char *t, char *c, char *p) {
return 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);
int auditdeny(char *s, char *t, char *c, char *p) {
return add_rule(s, t, c, p, AVTAB_AUDITDENY, 0);
}
void permissive(char *s) {
set_domain_state(s, 1);
int typetrans(char *s, char *t, char *c, char *d, char *o) {
if (o == NULL)
return add_transition(s, t, c, d);
else
return add_file_transition(s, t, c, d, o);
}
void enforce(char *s) {
set_domain_state(s, 0);
int permissive(char *s) {
return set_domain_state(s, 1);
}
void attradd(char *s, char *a) {
add_typeattribute(s, a);
int enforce(char *s) {
return set_domain_state(s, 0);
}
int create(char *s) {
return create_domain(s);
}
int attradd(char *s, char *a) {
return add_typeattribute(s, a);
}
int exists(char* source) {