diff --git a/main.c b/main.c index 450beb192..6130e2d03 100644 --- a/main.c +++ b/main.c @@ -1,119 +1,122 @@ #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"); + fprintf(stderr, "%s [--live] [--minimal] [--load ] [--save ] [policystatement...]\n\n", arg0); + 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, "\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, minimal = 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}, - {"minimal", 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, "minimal") == 0) - minimal = 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]); +// 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; + vec_init(&source); + vec_init(&target); + vec_init(&permission); + tok = strtok(statement, " "); + while (tok != NULL) { + if (tok[0] == '{') { + if (in_bracket || state == 2) return 1; + in_bracket = 1; + if (tok[1]) { + ++tok; + continue; } + } else if (tok[strlen(tok) - 1] == '}') { + if (!in_bracket || state == 2) 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 = NULL; + class = tok; + break; + case 3: + temp = &permission; + break; + default: + return 1; + } + vec_push_back(temp, tok); + } + if (!in_bracket) ++state; + tok = strtok(NULL, " "); + } + if (state != 4) return 1; + for(int i = 0; i < source.size; ++i) + for (int j = 0; j < target.size; ++j) + for (int k = 0; k < permission.size; ++k) + switch (action) { + case 0: + allow(source.data[i], target.data[j], class, permission.data[k]); + break; + case 1: + deny(source.data[i], target.data[j], class, permission.data[k]); + break; + case 2: + auditallow(source.data[i], target.data[j], class, permission.data[k]); + break; + case 3: + auditdeny(source.data[i], target.data[j], class, permission.data[k]); + break; + default: + return 1; + } + vec_destroy(&source); + vec_destroy(&target); + vec_destroy(&permission); + return 0; +} + +int main(int argc, char *argv[]) { + char *infile = NULL, *outfile, *tok, cpy[ARG_MAX]; + int live = 0, minimal = 0; + struct vector rules; + + vec_init(&rules); + + if (argc < 2) usage(argv[0]); + for (int i = 1; i < argc; ++i) { + if (argv[i][0] == '-' && argv[i][1] == '-') { + if (strcmp(argv[i], "--live") == 0) + live = 1; + else if (strcmp(argv[i], "--minimal") == 0) + minimal = 1; + else if (strcmp(argv[i], "--load") == 0) { + if (i + 1 >= argc) usage(argv[0]); + infile = argv[i + 1]; + i += 1; + } else if (strcmp(argv[i], "--save") == 0) { + if (i + 1 >= argc) usage(argv[0]); + outfile = argv[i + 1]; + i += 1; + } else + usage(argv[0]); + } else + vec_push_back(&rules, argv[i]); } - // Use builtin rules if nothing specified - if (!minimal && !source && !target && !class && !perm && !permissive && !fcon && !attr &&!filetrans && !exists) - builtin = 1; - - // Overwrite original if not specified - if(!outfile) - outfile = infile; + policydb_t policydb; + struct policy_file pf; + sidtab_t sidtab; // Use current policy if not specified if(!infile) @@ -132,114 +135,53 @@ int main(int argc, char **argv) { policy = &policydb; - if (builtin) { - su_rules(); - } - else if (minimal) { - min_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; + if (!minimal && rules.size == 0) su_rules(); + if (minimal) min_rules(); - 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; - } + 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], " "); + if (strcmp(tok, "allow") == 0) { + if (parse_pattern_1(0, rules.data[i] + strlen(tok) + 1)) + printf("Syntax error in \"%s\"\n", cpy); + } else if (strcmp(tok, "deny") == 0) { + if (parse_pattern_1(1, rules.data[i] + strlen(tok) + 1)) + printf("Syntax error in \"%s\"\n", cpy); + } else if (strcmp(tok, "auditallow") == 0) { + if (parse_pattern_1(2, rules.data[i] + strlen(tok) + 1)) + printf("Syntax error in \"%s\"\n", cpy); + } else if (strcmp(tok, "auditdeny") == 0) { + if (parse_pattern_1(3, rules.data[i] + strlen(tok) + 1)) + printf("Syntax error in \"%s\"\n", cpy); } } - if (live) { - if (live_patch()) { - fprintf(stderr, "Could not load new policy into kernel\n"); - return 1; - } - } - + vec_destroy(&rules); + + if (live) + outfile = "/sys/fs/selinux/load"; + if (outfile) { - fp = fopen(outfile, "w"); - if (!fp) { - fprintf(stderr, "Could not open outfile\n"); + int fd, ret; + void *data = NULL; + size_t len; + policydb_to_image(NULL, policy, &data, &len); + if (data == NULL) fprintf(stderr, "Error!"); + + fd = open(outfile, O_RDWR | O_CREAT); + if (fd < 0) { + fprintf(stderr, "Can't open '%s': %s\n", + outfile, strerror(errno)); 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"); + ret = write(fd, data, len); + close(fd); + if (ret < 0) { + fprintf(stderr, "Could not write policy to %s\n", + outfile); return 1; } - fclose(fp); } policydb_destroy(&policydb); diff --git a/rules.c b/rules.c index a320554be..b40778ad4 100644 --- a/rules.c +++ b/rules.c @@ -115,14 +115,14 @@ void otherToSU() { allow(ALL, "su", "process", "sigchld"); // uNetworkL0 - add_type("su", "netdomain"); - add_type("su", "bluetoothdomain"); + attradd("su", "netdomain"); + attradd("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"); + attradd("surfaceflinger", "mlstrustedsubject"); // suMiscL6 if (exists("audioserver")) diff --git a/sepolicy-inject.h b/sepolicy-inject.h index 06da0c023..b97ed64f9 100644 --- a/sepolicy-inject.h +++ b/sepolicy-inject.h @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include #include @@ -28,7 +30,7 @@ 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_typeattribute(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(); @@ -43,6 +45,16 @@ void enforce(char *s); void attradd(char *s, char *a); int exists(char *source); +// Vector of char* +struct vector { + size_t size; + size_t cap; + char **data; +}; +void vec_init(struct vector *v); +void vec_push_back(struct vector *v, char* s); +void vec_destroy(struct vector *v); + // Built in rules void su_rules(); void min_rules(); diff --git a/sepolicy.c b/sepolicy.c index 877b65e57..1d855c851 100644 --- a/sepolicy.c +++ b/sepolicy.c @@ -395,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) { +int add_typeattribute(char *domainS, char *typeS) { type_datum_t *domain; domain = hashtab_search(policy->p_types.table, domainS); diff --git a/utils.c b/utils.c index f02b6006c..601c3c440 100644 --- a/utils.c +++ b/utils.c @@ -15,6 +15,28 @@ static void set_domain(char* s, int value) { } } +void vec_init(struct vector *v) { + v->size = 0; + v->cap = 1; + v->data = (char**) malloc(sizeof(char*)); +} + +void vec_push_back(struct vector *v, char* s) { + if (v == NULL) return; + if (v->size == v->cap) { + v->cap *= 2; + v->data = (char**) realloc(v->data, sizeof(char*) * v->cap); + } + v->data[v->size] = s; + ++v->size; +} + +void vec_destroy(struct vector *v) { + v->size = 0; + v->cap = 0; + free(v->data); +} + void allow(char *s, char *t, char *c, char *p) { add_rule(s, t, c, p, AVTAB_ALLOWED, 0); } @@ -40,7 +62,7 @@ void enforce(char *s) { } void attradd(char *s, char *a) { - add_type(s, a); + add_typeattribute(s, a); } int exists(char* source) {