diff --git a/parser/immunix.h b/parser/immunix.h index 77085234f..e9d178fe0 100644 --- a/parser/immunix.h +++ b/parser/immunix.h @@ -32,14 +32,18 @@ #define AA_MAY_LINK (1 << 4) #define AA_MAY_LOCK (1 << 5) #define AA_EXEC_MMAP (1 << 6) +#define AA_EXEC_UNSAFE (1 << 7) +#define AA_EXEC_MOD_0 (1 << 8) +#define AA_EXEC_MOD_1 (1 << 9) #define AA_BASE_PERMS (AA_MAY_EXEC | AA_MAY_WRITE | \ AA_MAY_READ | AA_MAY_APPEND | \ AA_MAY_LINK | AA_MAY_LOCK | \ - AA_EXEC_MMAP) + AA_EXEC_MMAP | AA_EXEC_UNSAFE | \ + AA_EXEC_MOD_0 | AA_EXEC_MOD_1) #define AA_USER_SHIFT 0 -#define AA_GROUP_SHIFT 7 -#define AA_OTHER_SHIFT 14 +#define AA_GROUP_SHIFT 10 +#define AA_OTHER_SHIFT 20 #define AA_USER_PERMS (AA_BASE_PERMS << AA_USER_SHIFT) #define AA_GROUP_PERMS (AA_BASE_PERMS << AA_GROUP_SHIFT) @@ -48,31 +52,34 @@ #define AA_FILE_PERMS (AA_USER_PERMS | AA_GROUP_PERMS | \ AA_OTHER_PERMS) -#define AA_CHANGE_PROFILE (1 << 26) - -#define AA_EXEC_UNSAFE (1 << 27) -#define AA_EXEC_MOD_SHIFT 28 -#define AA_EXEC_MOD_0 (1 << 28) -#define AA_EXEC_MOD_1 (1 << 29) -#define AA_EXEC_MOD_2 (1 << 30) +#define AA_CHANGE_PROFILE (1 << 30) #define AA_ERROR_BIT (1 << 31) +#define AA_SHARED_PERMS (AA_CHANGE_PROFILE | AA_ERROR_BIT) -#define AA_EXEC_MODIFIERS (AA_EXEC_MOD_0 | \ - AA_EXEC_MOD_1 | \ - AA_EXEC_MOD_2) -#define AA_EXEC_UNCONFINED (AA_EXEC_MOD_2) +#define AA_EXEC_MODIFIERS (AA_EXEC_MOD_0 | AA_EXEC_MOD_1) +#define AA_EXEC_TYPE (AA_MAY_EXEC | AA_EXEC_UNSAFE | \ + AA_EXEC_MODIFIERS) + +#define AA_EXEC_UNCONFINED 0 #define AA_EXEC_INHERIT (AA_EXEC_MOD_0) #define AA_EXEC_PROFILE (AA_EXEC_MOD_1) #define AA_EXEC_PROFILE_OR_INHERIT (AA_EXEC_MOD_0 | AA_EXEC_MOD_1) -#define AA_VALID_PERMS (AA_FILE_PERMS | AA_CHANGE_PROFILE | \ - AA_EXEC_UNSAFE | AA_EXEC_MODIFIERS) +#define AA_VALID_PERMS (AA_FILE_PERMS | AA_CHANGE_PROFILE) #define AA_EXEC_BITS ((AA_MAY_EXEC << AA_USER_SHIFT) | \ (AA_MAY_EXEC << AA_GROUP_SHIFT) | \ (AA_MAY_EXEC << AA_OTHER_SHIFT)) +#define ALL_AA_EXEC_UNSAFE ((AA_EXEC_UNSAFE << AA_USER_SHIFT) | \ + (AA_EXEC_UNSAFE << AA_GROUP_SHIFT) | \ + (AA_EXEC_UNSAFE << AA_OTHER_SHIFT)) + +#define AA_USER_EXEC_TYPE (AA_EXEC_TYPE << AA_USER_SHIFT) +#define AA_GROUP_EXEC_TYPE (AA_EXEC_TYPE << AA_GROUP_SHIFT) +#define AA_OTHER_EXEC_TYPE (AA_EXEC_TYPE << AA_OTHER_SHIFT) + #define SHIFT_MODE(MODE, SHIFT) ((((MODE) & AA_BASE_PERMS) << (SHIFT))\ | ((MODE) & ~AA_FILE_PERMS)) #define SHIFT_TO_BASE(MODE, SHIFT) ((((MODE) & AA_FILE_PERMS) >> (SHIFT))\ @@ -113,4 +120,19 @@ enum pattern_t { #define HAS_EXEC_UNSAFE(mode) ((mode) & AA_EXEC_UNSAFE) #define HAS_CHANGE_PROFILE(mode) ((mode) & AA_CHANGE_PROFILE) +static inline int is_merged_x_consistent(int a, int b) +{ + if ((a & AA_USER_EXEC_TYPE) && (b & AA_USER_EXEC_TYPE) && + ((a & AA_USER_EXEC_TYPE) != (b & AA_USER_EXEC_TYPE))) + return 0; + if ((a & AA_GROUP_EXEC_TYPE) && (b & AA_GROUP_EXEC_TYPE) && + ((a & AA_GROUP_EXEC_TYPE) != (b & AA_GROUP_EXEC_TYPE))) + return 0; + if ((a & AA_OTHER_EXEC_TYPE) && (b & AA_OTHER_EXEC_TYPE) && + ((a & AA_OTHER_EXEC_TYPE) != (b & AA_OTHER_EXEC_TYPE))) + return 0; + + return 1; +} + #endif /* ! _IMMUNIX_H */ diff --git a/parser/libapparmor_re/regexp.y b/parser/libapparmor_re/regexp.y index ce69ed94f..cf79327e0 100644 --- a/parser/libapparmor_re/regexp.y +++ b/parser/libapparmor_re/regexp.y @@ -1512,23 +1512,32 @@ uint32_t accept_perms(State *state) if (!(match= dynamic_cast(*i))) continue; if (dynamic_cast(match)) { - if (diff_qualifiers(exact_match_perms, match->flag)) + if (!is_merged_x_consistent(exact_match_perms, + match->flag)) exact_match_perms |= AA_ERROR_BIT; exact_match_perms |= match->flag; } else { - if (diff_qualifiers(perms, match->flag)) + if (!is_merged_x_consistent(perms, match->flag)) perms |= AA_ERROR_BIT; perms |= match->flag; } } - if (exact_match_perms & AA_EXEC_MODIFIERS) - perms = exact_match_perms | (perms & ~AA_EXEC_MODIFIERS); - else { -if (exact_match_perms) -fprintf(stderr, "exact match perms without exec modifiers!!!\n"); - perms |= exact_match_perms; - } + perms |= exact_match_perms & + ~(AA_USER_EXEC_TYPE | AA_GROUP_EXEC_TYPE | AA_OTHER_EXEC_TYPE); + + if (exact_match_perms & AA_USER_EXEC_TYPE) + perms = (exact_match_perms & AA_USER_EXEC_TYPE) | + (perms & ~AA_USER_EXEC_TYPE); + + if (exact_match_perms & AA_GROUP_EXEC_TYPE) + perms = (exact_match_perms & AA_GROUP_EXEC_TYPE) | + (perms & ~AA_GROUP_EXEC_TYPE); + + if (exact_match_perms & AA_OTHER_EXEC_TYPE) + perms = (exact_match_perms & AA_OTHER_EXEC_TYPE) | + (perms & ~AA_OTHER_EXEC_TYPE); + if (perms & AA_ERROR_BIT) { fprintf(stderr, "error bit 0x%x\n", perms); exit(255); @@ -1542,7 +1551,7 @@ fprintf(stderr, "exact match perms without exec modifiers!!!\n"); extern "C" int aare_add_rule(aare_ruleset_t *rules, char *rule, uint32_t perms) { - static MatchFlag *match_flags[sizeof(perms) * 8 - 4 + 8]; + static MatchFlag *match_flags[sizeof(perms) * 8 - 1]; static MatchFlag *exec_match_flags[8 * 3]; static ExactMatchFlag *exact_match_flags[8 * 3]; Node *tree, *accept; @@ -1553,8 +1562,6 @@ extern "C" int aare_add_rule(aare_ruleset_t *rules, char *rule, uint32_t perms) if (regexp_parse(&tree, rule)) return 0; - if ((perms & AA_EXEC_BITS) && !(perms & AA_EXEC_MODIFIERS)) - fprintf(stderr, "Rule with exec bits and not exec modifiers\n\t 0x%x %s\n", perms, rule); /* * Check if we have an expression with or without wildcards. This * determines how exec modifiers are merged in accept_perms() based @@ -1573,36 +1580,51 @@ extern "C" int aare_add_rule(aare_ruleset_t *rules, char *rule, uint32_t perms) if (rules->reverse) flip_tree(tree); +#define ALL_EXEC_TYPE (AA_USER_EXEC_TYPE | AA_GROUP_EXEC_TYPE | \ + AA_OTHER_EXEC_TYPE) +#define EXTRACT_X_INDEX(perm, shift) (((perm) >> (shift + 7)) & 0x7) + +if (perms & ALL_EXEC_TYPE && (!perms & AA_EXEC_BITS)) + fprintf(stderr, "adding X rule without MAY_EXEC: 0x%x %s\n", perms, rule); accept = NULL; - for (unsigned int n = 0; perms && n < (sizeof(perms) * 8) - 4; n++) { + for (unsigned int n = 0; perms && n < (sizeof(perms) * 8) - 1; n++) { uint32_t mask = 1 << n; if (perms & mask) { perms &= ~mask; Node *flag; - if ((mask & AA_EXEC_BITS) && (perms & AA_EXEC_MODIFIERS)) { - int index = (perms & AA_EXEC_MODIFIERS) >> AA_EXEC_MOD_SHIFT; - if (mask & (AA_MAY_EXEC << AA_GROUP_SHIFT)) - index += 8; - else if (mask & (AA_MAY_EXEC << AA_OTHER_SHIFT)) - index += 16; - + if (mask & AA_EXEC_BITS) { + uint32_t eperm = 0; + uint32_t index = 0; + if (mask & (AA_MAY_EXEC << AA_USER_SHIFT)) { + eperm = mask | perms & AA_USER_EXEC_TYPE; + index = EXTRACT_X_INDEX(perms, AA_USER_SHIFT); + } else if (mask & (AA_MAY_EXEC << AA_GROUP_SHIFT)) { + eperm = mask | perms & AA_GROUP_EXEC_TYPE; + index = EXTRACT_X_INDEX(perms, AA_GROUP_SHIFT) + 8; + } else { + eperm = mask | perms & AA_OTHER_EXEC_TYPE; + index = EXTRACT_X_INDEX(perms, AA_OTHER_SHIFT) + 16; + } if (exact_match) { if (exact_match_flags[index]) flag = exact_match_flags[index]->dup(); else { - exact_match_flags[index] = new ExactMatchFlag(mask | (perms & AA_EXEC_MODIFIERS)); + exact_match_flags[index] = new ExactMatchFlag(eperm); flag = exact_match_flags[index]; } } else { if (exec_match_flags[index]) flag = exec_match_flags[index]->dup(); else { - exec_match_flags[index] = new MatchFlag(mask | (perms & AA_EXEC_MODIFIERS)); + exec_match_flags[index] = new MatchFlag(eperm); flag = exec_match_flags[index]; } } + } else if (mask & ALL_EXEC_TYPE) { + /* these cases are covered by EXEC_BITS */ + continue; } else { if (match_flags[n]) flag = match_flags[n]->dup(); diff --git a/parser/parser_merge.c b/parser/parser_merge.c index cf95a0949..f1f7f65fb 100644 --- a/parser/parser_merge.c +++ b/parser/parser_merge.c @@ -79,16 +79,12 @@ static int process_file_entries(struct codomain *cod) qsort(table, count, sizeof(struct cod_entry *), file_comp); table[count] = NULL; -#define X_CONFLICT(a, b) \ - (((a) & AA_EXEC_BITS) && ((b) & AA_EXEC_BITS) && \ - (((a) & (AA_EXEC_MODIFIERS | AA_EXEC_UNSAFE)) != \ - ((b) & (AA_EXEC_MODIFIERS | AA_EXEC_UNSAFE)))) /* walk the sorted table merging similar entries */ for (cur = table[0], next = table[1], n = 1; next != NULL; n++, next = table[n]) { if (file_comp(&cur, &next) == 0) { /* check for merged x consistency */ - if (X_CONFLICT(cur->mode, next->mode)) { + if (!is_merged_x_consistent(cur->mode, next->mode)) { PERROR(_("profile %s: has merged rule %s with multiple x modifiers\n"), cod->name, cur->name); return 0; diff --git a/parser/parser_misc.c b/parser/parser_misc.c index b30de73da..87f45150c 100644 --- a/parser/parser_misc.c +++ b/parser/parser_misc.c @@ -560,7 +560,7 @@ out: int parse_mode(const char *str_mode) { const char *next, *pos = str_mode; - int tmp, mode = 0; + int tmp, exec_mods, mode = 0; next = strchr(str_mode, ':'); if (!next) { tmp = parse_sub_mode(str_mode, ""); @@ -572,23 +572,32 @@ int parse_mode(const char *str_mode) return mode; } /* user:group:other */ - if (next > pos) + if (next > pos) { + exec_mods = mode & AA_EXEC_MODIFIERS; mode = SHIFT_MODE(parse_sub_mode(pos, "user"), AA_USER_SHIFT); + } pos = next + 1; next = strchr(pos, ':'); if (next > pos) { tmp = parse_sub_mode(pos, "group"); +/* we can allow different mods per labeling, just not when named transitions + are present. if ((mode & AA_EXEC_BITS) && (tmp & AA_EXEC_BITS) && - (mode & AA_EXEC_MODIFIERS) != (tmp & AA_EXEC_MODIFIERS)) + (exec_mods != (tmp & AA_EXEC_MODIFIERS))) yyerror(_("conflicting x modifiers between user and group permissions.")); +*/ + exec_mods = tmp & AA_EXEC_MODIFIERS; mode |= SHIFT_MODE(tmp, AA_GROUP_SHIFT); } pos = next + 1; if (*pos) { tmp = parse_sub_mode(pos, "other"); +/* allow different x mods per ugo if ((mode & AA_EXEC_BITS) && (tmp & AA_EXEC_BITS) && - (mode & AA_EXEC_MODIFIERS) != (tmp & AA_EXEC_MODIFIERS)) + (exec_mods != (tmp & AA_EXEC_MODIFIERS))) yyerror(_("conflicting x modifiers between other and user:group permissions.")); +*/ + exec_mods = tmp & AA_EXEC_MODIFIERS; mode |= SHIFT_MODE(tmp, AA_OTHER_SHIFT); } if (mode & ~AA_VALID_PERMS) diff --git a/parser/parser_regex.c b/parser/parser_regex.c index a447afd32..1f78883b3 100644 --- a/parser/parser_regex.c +++ b/parser/parser_regex.c @@ -497,14 +497,16 @@ static int process_dfa_entry(aare_ruleset_t *dfarules, struct cod_entry *entry) /* ix implies m but the apparmor module does not add m bit to * dfa states like it does for pcre */ - if ((entry->mode & AA_EXEC_MODIFIERS) == AA_EXEC_INHERIT) { - if (HAS_MAY_EXEC(SHIFT_TO_BASE(entry->mode, AA_OTHER_SHIFT))) - entry->mode |= AA_EXEC_MMAP << AA_OTHER_SHIFT; - if (HAS_MAY_EXEC(SHIFT_TO_BASE(entry->mode, AA_GROUP_SHIFT))) - entry->mode |= AA_EXEC_MMAP << AA_GROUP_SHIFT; - if (HAS_MAY_EXEC(SHIFT_TO_BASE(entry->mode, AA_USER_SHIFT))) - entry->mode |= AA_EXEC_MMAP << AA_USER_SHIFT; - } + if (((entry->mode >> AA_OTHER_SHIFT) & AA_EXEC_MODIFIERS) == + AA_EXEC_INHERIT) + entry->mode |= AA_EXEC_MMAP << AA_OTHER_SHIFT; + if (((entry->mode >> AA_GROUP_SHIFT) & AA_EXEC_MODIFIERS) == + AA_EXEC_INHERIT) + entry->mode |= AA_EXEC_MMAP << AA_GROUP_SHIFT; + if (((entry->mode >> AA_USER_SHIFT) & AA_EXEC_MODIFIERS) == + AA_EXEC_INHERIT) + entry->mode |= AA_EXEC_MMAP << AA_USER_SHIFT; + if (!aare_add_rule(dfarules, tbuf, entry->mode)) ret = FALSE; diff --git a/parser/parser_yacc.y b/parser/parser_yacc.y index 56a3c6a7a..f76a041bd 100644 --- a/parser/parser_yacc.y +++ b/parser/parser_yacc.y @@ -518,14 +518,15 @@ rule: id_or_var file_mode TOK_END_OF_RULE rule: file_mode id_or_var TOK_END_OF_RULE { - $$ = do_file_rule(NULL, $2, $1 & ~AA_EXEC_UNSAFE); + $$ = do_file_rule(NULL, $2, $1 & ~ALL_AA_EXEC_UNSAFE); }; rule: TOK_UNSAFE file_mode id_or_var TOK_END_OF_RULE { + int mode = (($2 & AA_EXEC_BITS) << 7) & ALL_AA_EXEC_UNSAFE; if (!($2 & AA_EXEC_BITS)) yyerror(_("unsafe rule missing exec permissions")); - $$ = do_file_rule(NULL, $3, $2 | AA_EXEC_UNSAFE); + $$ = do_file_rule(NULL, $3, ($2 & ~ALL_AA_EXEC_UNSAFE) | mode); }; rule: id_or_var file_mode id_or_var