From db66b360641acbf9cd1f785ebaebc1ae836008fe Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 3 Apr 2023 21:39:03 -0700 Subject: [PATCH 01/17] parser: move perm to accept mapping into State Let the state deal with permission mappings and what to do if outputting an index. Signed-off-by: John Johansen --- parser/libapparmor_re/aare_rules.cc | 2 +- parser/libapparmor_re/chfa.cc | 30 ++++++++++++++++++----------- parser/libapparmor_re/chfa.h | 3 ++- parser/libapparmor_re/hfa.h | 5 +++++ 4 files changed, 27 insertions(+), 13 deletions(-) diff --git a/parser/libapparmor_re/aare_rules.cc b/parser/libapparmor_re/aare_rules.cc index 410953cc8..2223906f7 100644 --- a/parser/libapparmor_re/aare_rules.cc +++ b/parser/libapparmor_re/aare_rules.cc @@ -304,7 +304,7 @@ void *aare_rules::create_dfa(size_t *size, int *min_match_len, optflags const &o dfa.dump_diff_encode(cerr); } - CHFA chfa(dfa, eq, opts); + CHFA chfa(dfa, eq, opts, false); if (opts.dump & DUMP_DFA_TRANS_TABLE) chfa.dump(cerr); chfa.flex_table(stream); diff --git a/parser/libapparmor_re/chfa.cc b/parser/libapparmor_re/chfa.cc index 205c697c2..a29d858fc 100644 --- a/parser/libapparmor_re/chfa.cc +++ b/parser/libapparmor_re/chfa.cc @@ -46,11 +46,15 @@ void CHFA::init_free_list(vector > &free_list, free_list[free_list.size() - 1].second = 0; } + /** * new Construct the transition table. + * + * TODO: split dfaflags into separate control and dump so we can fold in + * permtable index flag */ -CHFA::CHFA(DFA &dfa, map &eq, optflags const &opts): - eq(eq) +CHFA::CHFA(DFA &dfa, map &eq, optflags const &opts, + bool permindex): eq(eq) { if (opts.dump & DUMP_DFA_TRANS_PROGRESS) fprintf(stderr, "Compressing HFA:\r"); @@ -101,18 +105,20 @@ CHFA::CHFA(DFA &dfa, map &eq, optflags const &opts): num.insert(make_pair(dfa.nonmatching, num.size())); accept.resize(max(dfa.states.size(), (size_t) 2)); - accept2.resize(max(dfa.states.size(), (size_t) 2)); + if (!permindex) { + accept2.resize(max(dfa.states.size(), (size_t) 2)); + accept2[0] = 0; + accept2[1] = 0; + } next_check.resize(max(optimal, (size_t) dfa.max_range)); free_list.resize(next_check.size()); accept[0] = 0; - accept2[0] = 0; first_free = 1; init_free_list(free_list, 0, 1); insert_state(free_list, dfa.start, dfa); accept[1] = 0; - accept2[1] = 0; num.insert(make_pair(dfa.start, num.size())); int count = 2; @@ -121,8 +127,8 @@ CHFA::CHFA(DFA &dfa, map &eq, optflags const &opts): for (Partition::iterator i = dfa.states.begin(); i != dfa.states.end(); i++) { if (*i != dfa.nonmatching && *i != dfa.start) { insert_state(free_list, *i, dfa); - accept[num.size()] = (*i)->perms.allow; - accept2[num.size()] = PACK_AUDIT_CTL((*i)->perms.audit, (*i)->perms.quiet & (*i)->perms.deny); + (*i)->map_perms_to_accept(accept[num.size()], + accept2[num.size()]); num.insert(make_pair(*i, num.size())); } if (opts.dump & (DUMP_DFA_TRANS_PROGRESS)) { @@ -138,8 +144,8 @@ CHFA::CHFA(DFA &dfa, map &eq, optflags const &opts): if (i->second != dfa.nonmatching && i->second != dfa.start) { insert_state(free_list, i->second, dfa); - accept[num.size()] = i->second->perms.allow; - accept2[num.size()] = PACK_AUDIT_CTL(i->second->perms.audit, i->second->perms.quiet & i->second->perms.deny); + i->second->map_perms_to_accept(accept[num.size()], + accept2[num.size()]); num.insert(make_pair(i->second, num.size())); } if (opts.dump & (DUMP_DFA_TRANS_PROGRESS)) { @@ -426,7 +432,7 @@ void CHFA::flex_table(ostream &os) th.th_hsize = htonl(hsize); th.th_ssize = htonl(hsize + flex_table_size(accept.begin(), accept.end()) + - flex_table_size(accept2.begin(), accept2.end()) + + (accept2.size() ? flex_table_size(accept2.begin(), accept2.end()) : 0) + (eq.size() ? flex_table_size(equiv_vec.begin(), equiv_vec.end()) : 0) + flex_table_size(base_vec.begin(), base_vec.end()) + flex_table_size(default_vec.begin(), default_vec.end()) + @@ -437,7 +443,9 @@ void CHFA::flex_table(ostream &os) os << fill64(sizeof(th) + sizeof(th_version)); write_flex_table(os, YYTD_ID_ACCEPT, accept.begin(), accept.end()); - write_flex_table(os, YYTD_ID_ACCEPT2, accept2.begin(), accept2.end()); + if (accept2.size()) + write_flex_table(os, YYTD_ID_ACCEPT2, accept2.begin(), + accept2.end()); if (eq.size()) write_flex_table(os, YYTD_ID_EC, equiv_vec.begin(), equiv_vec.end()); diff --git a/parser/libapparmor_re/chfa.h b/parser/libapparmor_re/chfa.h index 7d6a6f4af..3976f413e 100644 --- a/parser/libapparmor_re/chfa.h +++ b/parser/libapparmor_re/chfa.h @@ -37,7 +37,8 @@ class CHFA { typedef vector > DefaultBase; typedef vector > NextCheck; public: - CHFA(DFA &dfa, map &eq, optflags const &opts); + CHFA(DFA &dfa, map &eq, optflags const &opts, + bool permindex); void dump(ostream & os); void flex_table(ostream &os); void init_free_list(vector > &free_list, diff --git a/parser/libapparmor_re/hfa.h b/parser/libapparmor_re/hfa.h index 185d34e30..51d02c7a8 100644 --- a/parser/libapparmor_re/hfa.h +++ b/parser/libapparmor_re/hfa.h @@ -248,6 +248,11 @@ public: void flatten_relative(State *, int upper_bound); int apply_and_clear_deny(void) { return perms.apply_and_clear_deny(); } + void map_perms_to_accept(uint32_t &accept1, uint32_t &accept2) + { + accept1 = perms.allow; + accept2 = PACK_AUDIT_CTL(perms.audit, perms.quiet & perms.deny); + } int label; int flags; From c86f8f06dda30953b7a003435c01dd85c8125372 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Thu, 18 Jun 2020 04:06:42 -0700 Subject: [PATCH 02/17] parser: add non-functional prompt parsing Add the ability to parse the prompt qualifier but do not provide functionality because the backend does not currently support prompt permissions. Signed-off-by: John Johansen --- parser/parser_misc.c | 1 + parser/parser_yacc.y | 9 +++++++-- parser/rule.h | 16 +++++++++++++++- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/parser/parser_misc.c b/parser/parser_misc.c index d66c990d7..5582ff9fb 100644 --- a/parser/parser_misc.c +++ b/parser/parser_misc.c @@ -97,6 +97,7 @@ static struct keyword_table keyword_table[] = { {"audit", TOK_AUDIT}, {"deny", TOK_DENY}, {"allow", TOK_ALLOW}, + {"prompt", TOK_PROMPT}, {"set", TOK_SET}, {"rlimit", TOK_RLIMIT}, {"alias", TOK_ALIAS}, diff --git a/parser/parser_yacc.y b/parser/parser_yacc.y index b225fb5d0..10aca3227 100644 --- a/parser/parser_yacc.y +++ b/parser/parser_yacc.y @@ -115,6 +115,7 @@ static void abi_features(char *filename, bool search); %token TOK_AUDIT %token TOK_DENY %token TOK_ALLOW +%token TOK_PROMPT %token TOK_PROFILE %token TOK_SET %token TOK_ALIAS @@ -632,6 +633,7 @@ opt_owner_flag: { /* nothing */ $$ = 0; } opt_rule_mode: { /* nothing */ $$ = RULE_UNSPECIFIED; } | TOK_ALLOW { $$ = RULE_ALLOW; } | TOK_DENY { $$ = RULE_DENY; } + | TOK_PROMPT { $$ = RULE_PROMPT; } opt_prefix: opt_audit_flag opt_rule_mode opt_owner_flag { @@ -674,8 +676,11 @@ rules: rules opt_prefix block { struct cod_entry *entry, *tmp; - PDEBUG("matched: %s%s%sblock\n", $2.audit == AUDIT_FORCE ? "audit " : "", - $2.rule_mode == RULE_DENY ? "deny " : "", $2.owner ? "owner " : ""); + PDEBUG("matched: %s%s%sblock\n", + $2.audit == AUDIT_FORCE ? "audit " : "", + $2.rule_mode == RULE_DENY ? "deny " : "", + $2.rule_mode == RULE_PROMPT ? "prompt " : "", + $2.owner ? "owner " : ""); list_for_each_safe($3->entries, entry, tmp) { const char *error; entry->next = NULL; diff --git a/parser/rule.h b/parser/rule.h index 05dbed13d..a7234c778 100644 --- a/parser/rule.h +++ b/parser/rule.h @@ -153,7 +153,7 @@ typedef std::list RuleList; /* Not classes so they can be used in the bison front end */ typedef uint32_t perms_t; typedef enum { AUDIT_UNSPECIFIED, AUDIT_FORCE, AUDIT_QUIET } audit_t; -typedef enum { RULE_UNSPECIFIED, RULE_ALLOW, RULE_DENY } rule_mode_t; +typedef enum { RULE_UNSPECIFIED, RULE_ALLOW, RULE_DENY, RULE_PROMPT } rule_mode_t; /* NOTE: we can not have a constructor for class prefixes. This is * because it will break bison, and we would need to transition to @@ -183,6 +183,13 @@ public: } switch (rule_mode) { + case RULE_ALLOW: + if (output) + os << " "; + + os << "allow"; + output = true; + break; case RULE_DENY: if (output) os << " "; @@ -190,6 +197,13 @@ public: os << "deny"; output = true; break; + case RULE_PROMPT: + if (output) + os << " "; + + os << "prompt"; + output = true; + break; default: break; } From e29f5ce5f313d551bac567bf88994697e9f86723 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Thu, 18 Jun 2020 05:49:20 -0700 Subject: [PATCH 03/17] parser: if extended perms are supported by the kernel build a permstable If extended permissions are supported use them. We need to build a permission table and set the accept state of the chfa up as an index into the table. For now map the front end permission layout into the old format and then convert that to the perms table just as the kernel does. Signed-off-by: John Johansen --- parser/libapparmor_re/Makefile | 6 +- parser/libapparmor_re/aare_rules.cc | 13 +- parser/libapparmor_re/aare_rules.h | 10 +- parser/libapparmor_re/chfa.cc | 27 ++-- parser/libapparmor_re/chfa.h | 2 +- parser/libapparmor_re/hfa.cc | 41 ++++- parser/libapparmor_re/hfa.h | 10 +- parser/libapparmor_re/policy_compat.cc | 215 +++++++++++++++++++++++++ parser/libapparmor_re/policy_compat.h | 25 +++ parser/parser.h | 1 + parser/parser_common.c | 1 + parser/parser_interface.c | 91 +++++++++-- parser/parser_main.c | 4 + parser/parser_regex.c | 11 +- parser/perms.h | 104 ++++++++++++ parser/profile.h | 7 +- 16 files changed, 530 insertions(+), 38 deletions(-) create mode 100644 parser/libapparmor_re/policy_compat.cc create mode 100644 parser/libapparmor_re/policy_compat.h create mode 100644 parser/perms.h diff --git a/parser/libapparmor_re/Makefile b/parser/libapparmor_re/Makefile index 4cf11a6a9..620dd297e 100644 --- a/parser/libapparmor_re/Makefile +++ b/parser/libapparmor_re/Makefile @@ -22,17 +22,19 @@ all : ${TARGET} UNITTESTS = tst_parse -libapparmor_re.a: parse.o expr-tree.o hfa.o chfa.o aare_rules.o +libapparmor_re.a: parse.o expr-tree.o hfa.o chfa.o aare_rules.o policy_compat.o ${AR} ${ARFLAGS} $@ $^ expr-tree.o: expr-tree.cc expr-tree.h -hfa.o: hfa.cc apparmor_re.h hfa.h ../immunix.h +hfa.o: hfa.cc apparmor_re.h hfa.h ../immunix.h policy_compat.h aare_rules.o: aare_rules.cc aare_rules.h apparmor_re.h expr-tree.h hfa.h chfa.h parse.h ../immunix.h chfa.o: chfa.cc chfa.h ../immunix.h +policy_compat.o: policy_compat.cc policy_compat.h ../perms.h ../immunix.h + parse.o : parse.cc apparmor_re.h expr-tree.h parse.cc : parse.y parse.h flex-tables.h ../immunix.h diff --git a/parser/libapparmor_re/aare_rules.cc b/parser/libapparmor_re/aare_rules.cc index 2223906f7..f48d858fb 100644 --- a/parser/libapparmor_re/aare_rules.cc +++ b/parser/libapparmor_re/aare_rules.cc @@ -194,8 +194,10 @@ bool aare_rules::append_rule(const char *rule, bool oob, bool with_perm, * else NULL on failure, @min_match_len set to the shortest string * that can match the dfa for determining xmatch priority. */ -void *aare_rules::create_dfa(size_t *size, int *min_match_len, optflags const &opts, - bool filedfa) +void *aare_rules::create_dfa(size_t *size, int *min_match_len, + vector &perms_table, + optflags const &opts, + bool filedfa, bool extended_perms) { char *buffer = NULL; @@ -304,7 +306,12 @@ void *aare_rules::create_dfa(size_t *size, int *min_match_len, optflags const &o dfa.dump_diff_encode(cerr); } - CHFA chfa(dfa, eq, opts, false); + //cerr << "Checking extended perms " << extended_perms << "\n"; + if (extended_perms) { + //cerr << "creating permstable\n"; + dfa.compute_perms_table(perms_table); + } + CHFA chfa(dfa, eq, opts, extended_perms); if (opts.dump & DUMP_DFA_TRANS_TABLE) chfa.dump(cerr); chfa.flex_table(stream); diff --git a/parser/libapparmor_re/aare_rules.h b/parser/libapparmor_re/aare_rules.h index 71087b887..5e9104036 100644 --- a/parser/libapparmor_re/aare_rules.h +++ b/parser/libapparmor_re/aare_rules.h @@ -21,11 +21,15 @@ #ifndef __LIBAA_RE_RULES_H #define __LIBAA_RE_RULES_H +#include + #include #include "../common_optarg.h" #include "apparmor_re.h" #include "expr-tree.h" +#include "../immunix.h" +#include "../perms.h" class UniquePerm { public: @@ -106,8 +110,10 @@ class aare_rules { bool add_rule_vec(int deny, uint32_t perms, uint32_t audit, int count, const char **rulev, optflags const &opts, bool oob); bool append_rule(const char *rule, bool oob, bool with_perm, optflags const &opts); - void *create_dfa(size_t *size, int *min_match_len, optflags const &opts, - bool filedfa); + void *create_dfa(size_t *size, int *min_match_len, + vector &perms_table, + optflags const &opts, + bool filedfa, bool extended_perms); }; #endif /* __LIBAA_RE_RULES_H */ diff --git a/parser/libapparmor_re/chfa.cc b/parser/libapparmor_re/chfa.cc index a29d858fc..f5aa97929 100644 --- a/parser/libapparmor_re/chfa.cc +++ b/parser/libapparmor_re/chfa.cc @@ -105,20 +105,23 @@ CHFA::CHFA(DFA &dfa, map &eq, optflags const &opts, num.insert(make_pair(dfa.nonmatching, num.size())); accept.resize(max(dfa.states.size(), (size_t) 2)); - if (!permindex) { + if (permindex) { + accept[0] = dfa.nonmatching->idx; + accept[1] = dfa.start->idx; + } else { accept2.resize(max(dfa.states.size(), (size_t) 2)); - accept2[0] = 0; - accept2[1] = 0; + dfa.nonmatching->map_perms_to_accept(accept[0], + accept2[0]); + dfa.start->map_perms_to_accept(accept[1], + accept2[1]); } next_check.resize(max(optimal, (size_t) dfa.max_range)); free_list.resize(next_check.size()); - accept[0] = 0; first_free = 1; init_free_list(free_list, 0, 1); insert_state(free_list, dfa.start, dfa); - accept[1] = 0; num.insert(make_pair(dfa.start, num.size())); int count = 2; @@ -127,8 +130,11 @@ CHFA::CHFA(DFA &dfa, map &eq, optflags const &opts, for (Partition::iterator i = dfa.states.begin(); i != dfa.states.end(); i++) { if (*i != dfa.nonmatching && *i != dfa.start) { insert_state(free_list, *i, dfa); - (*i)->map_perms_to_accept(accept[num.size()], - accept2[num.size()]); + if (permindex) + accept[num.size()] = (*i)->idx; + else + (*i)->map_perms_to_accept(accept[num.size()], + accept2[num.size()]); num.insert(make_pair(*i, num.size())); } if (opts.dump & (DUMP_DFA_TRANS_PROGRESS)) { @@ -144,8 +150,11 @@ CHFA::CHFA(DFA &dfa, map &eq, optflags const &opts, if (i->second != dfa.nonmatching && i->second != dfa.start) { insert_state(free_list, i->second, dfa); - i->second->map_perms_to_accept(accept[num.size()], - accept2[num.size()]); + if (permindex) + accept[num.size()] = i->second->idx; + else + i->second->map_perms_to_accept(accept[num.size()], + accept2[num.size()]); num.insert(make_pair(i->second, num.size())); } if (opts.dump & (DUMP_DFA_TRANS_PROGRESS)) { diff --git a/parser/libapparmor_re/chfa.h b/parser/libapparmor_re/chfa.h index 3976f413e..b1028add9 100644 --- a/parser/libapparmor_re/chfa.h +++ b/parser/libapparmor_re/chfa.h @@ -16,7 +16,7 @@ * along with this program. If not, see . * * - * Create a compressed hfa (chfa) from and hfa + * Create a compressed hfa (chfa) from an hfa */ #ifndef __LIBAA_RE_CHFA_H #define __LIBAA_RE_CHFA_H diff --git a/parser/libapparmor_re/hfa.cc b/parser/libapparmor_re/hfa.cc index 9c2f54dd3..323f3236a 100644 --- a/parser/libapparmor_re/hfa.cc +++ b/parser/libapparmor_re/hfa.cc @@ -34,8 +34,9 @@ #include "expr-tree.h" #include "hfa.h" +#include "policy_compat.h" #include "../immunix.h" - +#include "../perms.h" ostream &operator<<(ostream &os, const CacheStats &cache) { @@ -1300,6 +1301,44 @@ void DFA::apply_equivalence_classes(map &eq) } } +void DFA::compute_perms_table_ent(State *state, size_t pos, + vector &perms_table) +{ + uint32_t accept1, accept2; + + state->map_perms_to_accept(accept1, accept2); + if (filedfa) { + state->idx = pos * 2; + perms_table[pos*2] = compute_fperms_user(accept1, accept2); + perms_table[pos*2 + 1] = compute_fperms_other(accept1, accept2); + } else { + state->idx = pos; + perms_table[pos] = compute_perms_entry(accept1, accept2); + } +} + +void DFA::compute_perms_table(vector &perms_table) +{ + size_t mult = filedfa ? 2 : 1; + size_t pos = 2; + + assert(states.size() >= 2); + perms_table.resize(states.size() * mult); + + // nonmatching and start need to be 0 and 1 so handle outside of loop + if (filedfa) + compute_perms_table_ent(nonmatching, 0, perms_table); + compute_perms_table_ent(start, 1, perms_table); + + for (Partition::iterator i = states.begin(); i != states.end(); i++) { + if (*i == nonmatching || *i == start) + continue; + compute_perms_table_ent(*i, pos, perms_table); + pos++; + } +} + + #if 0 typedef set AcceptNodes; map dominance(DFA & dfa) diff --git a/parser/libapparmor_re/hfa.h b/parser/libapparmor_re/hfa.h index 51d02c7a8..530c0c086 100644 --- a/parser/libapparmor_re/hfa.h +++ b/parser/libapparmor_re/hfa.h @@ -32,6 +32,7 @@ #include #include "expr-tree.h" +#include "policy_compat.h" #define DiffEncodeFlag 1 @@ -198,7 +199,7 @@ struct DiffDag { class State { public: State(int l, ProtoState &n, State *other, bool filedfa): - label(l), flags(0), perms(), trans() + label(l), flags(0), idx(0), perms(), trans() { int error; @@ -256,6 +257,7 @@ public: int label; int flags; + int idx; perms_t perms; StateTrans trans; State *otherwise; @@ -303,7 +305,6 @@ public: } }; - /* Transitions in the DFA. */ class DFA { void dump_node_to_dfa(void); @@ -346,6 +347,10 @@ public: map equivalence_classes(optflags const &flags); void apply_equivalence_classes(map &eq); + void compute_perms_table_ent(State *state, size_t pos, + vector &perms_table); + void compute_perms_table(vector &perms_table); + unsigned int diffcount; int oob_range; int max_range; @@ -354,6 +359,7 @@ public: Node *root; State *nonmatching, *start; Partition states; + //vector perms_table; bool filedfa; }; diff --git a/parser/libapparmor_re/policy_compat.cc b/parser/libapparmor_re/policy_compat.cc new file mode 100644 index 000000000..8213109a8 --- /dev/null +++ b/parser/libapparmor_re/policy_compat.cc @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2022 + * Canonical, Ltd. (All rights reserved) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, contact Novell, Inc. or Canonical + * Ltd. + */ +/* + * This is a set of functions to provide convertion from old style permission + * mappings, to new style kernel mappings. It is based on the kernel to + * as the kernel needs this for backwards compatibility. This allows the + * userspace to convert to the new permission mapping without reworking + * the internal dfa permission tracking. + * + * In the future this code will be converted to go the reverse direction + * i.e. new mappings into old, which the parser will need for backwards + * compat with old kernels. + */ + +#include +#include + +#include "policy_compat.h" +#include "../perms.h" + + +/* remap old accept table embedded permissions to separate permission table */ +static uint32_t dfa_map_xindex(uint16_t mask) +{ + uint16_t old_index = (mask >> 10) & 0xf; + uint32_t index = 0; + + if (mask & 0x100) + index |= AA_X_UNSAFE; + if (mask & 0x200) + index |= AA_X_INHERIT; + if (mask & 0x80) + index |= AA_X_UNCONFINED; + + if (old_index == 1) { + index |= AA_X_UNCONFINED; + } else if (old_index == 2) { + index |= AA_X_NAME; + } else if (old_index == 3) { + index |= AA_X_NAME | AA_X_CHILD; + } else if (old_index) { + index |= AA_X_TABLE; + index |= old_index - 4; + } + + return index; +} + +/* + * map old dfa inline permissions to new format + */ +#define dfa_user_allow(accept1, accept2) (((accept1) & 0x7f) | \ + ((accept1) & 0x80000000)) +#define dfa_user_xbits(accept1, accept2) (((accept1) >> 7) & 0x7f) +#define dfa_user_audit(accept1, accept2) ((accept2) & 0x7f) +#define dfa_user_quiet(accept1, accept2) (((accept2) >> 7) & 0x7f) +#define dfa_user_xindex(accept1, accept2) \ + (dfa_map_xindex(accept1 & 0x3fff)) + +#define dfa_other_allow(accept1, accept2) ((((accept1) >> 14) & \ + 0x7f) | \ + ((accept1) & 0x80000000)) +#define dfa_other_xbits(accept1, accept2) \ + ((((accept1) >> 7) >> 14) & 0x7f) +#define dfa_other_audit(accept1, accept2) (((accept2) >> 14) & 0x7f) +#define dfa_other_quiet(accept1, accept2) \ + ((((accept2) >> 7) >> 14) & 0x7f) +#define dfa_other_xindex(accept1, accept2) \ + dfa_map_xindex((accept1 >> 14) & 0x3fff) + +/** + * map_old_perms - map old file perms layout to the new layout + * @old: permission set in old mapping + * + * Returns: new permission mapping + */ +static uint32_t map_old_perms(uint32_t old) +{ + uint32_t perm = old & 0xf; + + if (old & AA_MAY_READ) + perm |= AA_MAY_GETATTR | AA_MAY_OPEN; + if (old & AA_MAY_WRITE) + perm |= AA_MAY_SETATTR | AA_MAY_CREATE | AA_MAY_DELETE | + AA_MAY_CHMOD | AA_MAY_CHOWN | AA_MAY_OPEN; + if (old & 0x10) + perm |= AA_MAY_LINK; + /* the old mapping lock and link_subset flags where overlaid + * and use was determined by part of a pair that they were in + */ + if (old & 0x20) + perm |= AA_MAY_LOCK | AA_LINK_SUBSET; + if (old & 0x40) /* AA_EXEC_MMAP */ + perm |= AA_EXEC_MMAP; + + return perm; +} + +static void compute_fperms_allow(struct aa_perms *perms, uint32_t accept1) +{ + perms->allow |= AA_MAY_GETATTR; + + /* change_profile wasn't determined by ownership in old mapping */ + if (accept1 & 0x80000000) + perms->allow |= AA_MAY_CHANGE_PROFILE; + if (accept1 & 0x40000000) + perms->allow |= AA_MAY_ONEXEC; +} + +struct aa_perms compute_fperms_user(uint32_t accept1, uint32_t accept2) +{ + struct aa_perms perms = { }; + + perms.allow = map_old_perms(dfa_user_allow(accept1, accept2)); + perms.audit = map_old_perms(dfa_user_audit(accept1, accept2)); + perms.quiet = map_old_perms(dfa_user_quiet(accept1, accept2)); + perms.xindex = dfa_user_xindex(accept1, accept2); + + compute_fperms_allow(&perms, accept1); + // prompt being carried as audit need to change + perms.allow &= ~perms.prompt; + if (perms.allow & perms.prompt) { + //std::cerr << "user allow & prompt\n"; + } + return perms; +} + +struct aa_perms compute_fperms_other(uint32_t accept1, uint32_t accept2) +{ + struct aa_perms perms = { }; + + perms.allow = map_old_perms(dfa_other_allow(accept1, accept2)); + perms.audit = map_old_perms(dfa_other_audit(accept1, accept2)); + perms.quiet = map_old_perms(dfa_other_quiet(accept1, accept2)); + perms.xindex = dfa_other_xindex(accept1, accept2); + + compute_fperms_allow(&perms, accept1); + // prompt being carried as audit need to change + perms.allow &= ~perms.prompt; + if (perms.allow & perms.prompt) { + std::cerr << "other allow & prompt\n"; + } + return perms; +} + +static uint32_t map_other(uint32_t x) +{ + return ((x & 0x3) << 8) | /* SETATTR/GETATTR */ + ((x & 0x1c) << 18) | /* ACCEPT/BIND/LISTEN */ + ((x & 0x60) << 19); /* SETOPT/GETOPT */ +} + +static uint32_t map_xbits(uint32_t x) +{ + return ((x & 0x1) << 7) | + ((x & 0x7e) << 9); +} + +struct aa_perms compute_perms_entry(uint32_t accept1, uint32_t accept2) +// don't need to worry about version internally within the parser +// uint32_t version) +{ + struct aa_perms perms = { }; + + perms.allow = dfa_user_allow(accept1, accept2); + perms.audit = dfa_user_audit(accept1, accept2); + perms.quiet = dfa_user_quiet(accept1, accept2); + + /* + * This mapping is convulated due to history. + * v1-v4: only file perms, which are handled by compute_fperms + * v5: added policydb which dropped user conditional to gain new + * perm bits, but had to map around the xbits because the + * userspace compiler was still munging them. + * v9: adds using the xbits in policydb because the compiler now + * supports treating policydb permission bits different. + * Unfortunately there is no way to force auditing on the + * perms represented by the xbits + */ + perms.allow |= map_other(dfa_other_allow(accept1, accept2)); + // v9 encoding never rolled out. AA_MAY_LOCK needed to fix + // non fs unix locking see kernel commit + // 1cf26c3d2c4c apparmor: fix apparmor mediating locking non-fs unix sockets + //if (VERSION_LE(version, v8)) + perms.allow |= AA_MAY_LOCK; + //else + // perms.allow |= map_xbits(dfa_user_xbits(dfa, state)); + + /* + * for v5-v9 perm mapping in the policydb, the other set is used + * to extend the general perm set + */ + perms.audit |= map_other(dfa_other_audit(accept1, accept2)); + perms.quiet |= map_other(dfa_other_quiet(accept1, accept2)); + //if (VERSION_GT(version, v8)) + // perms.quiet |= map_xbits(dfa_other_xbits(dfa, state)); + + return perms; +} + diff --git a/parser/libapparmor_re/policy_compat.h b/parser/libapparmor_re/policy_compat.h new file mode 100644 index 000000000..f19c14b20 --- /dev/null +++ b/parser/libapparmor_re/policy_compat.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2022 + * Canonical, Ltd. (All rights reserved) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, contact Novell, Inc. or Canonical + * Ltd. + */ +#ifndef __AA_POLICY_COMPAT_H +#define __AA_POLICY_COMPAT_H + +struct aa_perms compute_fperms_user(uint32_t accept1, uint32_t accept2); +struct aa_perms compute_fperms_other(uint32_t accept1, uint32_t accept2); +struct aa_perms compute_perms_entry(uint32_t accept1, uint32_t accept2); + +#endif /* __AA_POLICY_COMPAT_H */ diff --git a/parser/parser.h b/parser/parser.h index 0722e5609..27bac1849 100644 --- a/parser/parser.h +++ b/parser/parser.h @@ -359,6 +359,7 @@ extern int features_supports_flag_interruptible; extern int features_supports_flag_signal; extern int features_supports_flag_error; extern int kernel_supports_oob; +extern int kernel_supports_permstable32; extern int conf_verbose; extern int conf_quiet; extern int names_only; diff --git a/parser/parser_common.c b/parser/parser_common.c index b43a4a075..b041fa05c 100644 --- a/parser/parser_common.c +++ b/parser/parser_common.c @@ -87,6 +87,7 @@ int features_supports_flag_interruptible = 0; int features_supports_flag_signal = 0; int features_supports_flag_error = 0; int kernel_supports_oob = 0; /* out of band transitions */ +int kernel_supports_permstable32 = 0; /* extended permissions */ int conf_verbose = 0; int conf_quiet = 0; int names_only = 0; diff --git a/parser/parser_interface.c b/parser/parser_interface.c index 647902be4..dca49b224 100644 --- a/parser/parser_interface.c +++ b/parser/parser_interface.c @@ -323,10 +323,49 @@ static inline void sd_write_listend(std::ostringstream &buf) sd_write8(buf, SD_LISTEND); } -void sd_serialize_dfa(std::ostringstream &buf, void *dfa, size_t size) +void sd_serialize_perm(std::ostringstream &buf, aa_perms &perms) { - if (dfa) + sd_write_uint32(buf, 0); /* reserved */ + sd_write_uint32(buf, perms.allow); + sd_write_uint32(buf, perms.deny); + sd_write_uint32(buf, perms.subtree); + sd_write_uint32(buf, perms.cond); + sd_write_uint32(buf, perms.kill); + sd_write_uint32(buf, perms.complain); + sd_write_uint32(buf, perms.prompt); + sd_write_uint32(buf, perms.audit); + sd_write_uint32(buf, perms.quiet); + sd_write_uint32(buf, perms.hide); + sd_write_uint32(buf, perms.xindex); + sd_write_uint32(buf, perms.tag); + sd_write_uint32(buf, perms.label); +} + +void sd_serialize_permstable(std::ostringstream &buf, vector &perms_table) +{ + sd_write_struct(buf, "perms"); + sd_write_name(buf, "version"); + sd_write_uint32(buf, 1); + sd_write_array(buf, NULL, perms_table.size()); + for (size_t i = 0; i < perms_table.size(); i++) { + sd_serialize_perm(buf, perms_table[i]); + } + sd_write_arrayend(buf); + sd_write_structend(buf); +} + +void sd_serialize_dfa(std::ostringstream &buf, void *dfa, size_t size, + vector &perms_table) +{ + if (dfa) { + if (kernel_supports_permstable32 && perms_table.size() > 0) { + //fprintf(stderr, "writing perms table %d\n", size); + sd_serialize_permstable(buf, perms_table); + } else { + //fprintf(stderr, "skipping permtable32 %d, size %d\n", kernel_supports_permstable32, perms_table.size()); + } sd_write_aligned_blob(buf, dfa, size, "aadfa"); + } } void sd_serialize_rlimits(std::ostringstream &buf, struct aa_rlimits *limits) @@ -344,10 +383,13 @@ void sd_serialize_rlimits(std::ostringstream &buf, struct aa_rlimits *limits) sd_write_structend(buf); } -void sd_serialize_xtable(std::ostringstream &buf, char **table) +void sd_serialize_xtable(std::ostringstream &buf, char **table, + size_t min_size) { - int count; - if (!table[4]) + size_t count; + size_t size; + + if (!table[4] && min_size == 0) return; sd_write_struct(buf, "xtable"); count = 0; @@ -356,9 +398,11 @@ void sd_serialize_xtable(std::ostringstream &buf, char **table) count++; } - sd_write_array(buf, NULL, count); - for (int i = 4; i < count + 4; i++) { - int len = strlen(table[i]) + 1; + size = max(min_size, count); + + sd_write_array(buf, NULL, size); + for (size_t i = 4; i < count + 4; i++) { + size_t len = strlen(table[i]) + 1; /* if its a namespace make sure the second : is overwritten * with 0, so that the namespace and name are \0 separated @@ -369,6 +413,14 @@ void sd_serialize_xtable(std::ostringstream &buf, char **table) } sd_write_strn(buf, table[i], len, NULL); } + if (min_size > count) { + //fprintf(stderr, "Adding padding to xtable count %lu, min %lu\n", count, min_size); + for (; count < min_size; count++) { + /* fill with null strings */ + sd_write_strn(buf, "", 1, NULL); + } + } + sd_write_arrayend(buf); sd_write_structend(buf); } @@ -411,7 +463,7 @@ void sd_serialize_profile(std::ostringstream &buf, Profile *profile, /* only emit this if current kernel at least supports "create" */ if (perms_create) { if (profile->xmatch) { - sd_serialize_dfa(buf, profile->xmatch, profile->xmatch_size); + sd_serialize_dfa(buf, profile->xmatch, profile->xmatch_size, profile->xmatch_perms_table); sd_write_uint32(buf, profile->xmatch_len); } } @@ -491,14 +543,27 @@ void sd_serialize_profile(std::ostringstream &buf, Profile *profile, if (profile->policy.dfa) { sd_write_struct(buf, "policydb"); - sd_serialize_dfa(buf, profile->policy.dfa, profile->policy.size); + sd_serialize_dfa(buf, profile->policy.dfa, profile->policy.size, + profile->policy.perms_table); + if (profile->policy.dfa) { + // fprintf(stderr, "profile %s: policy xtable\n", profile->name); + // TODO: this is dummy exec make dependent on V1 + sd_serialize_xtable(buf, profile->exec_table, + //??? work around + profile->policy.perms_table.size()); + } sd_write_structend(buf); } /* either have a single dfa or lists of different entry types */ - sd_serialize_dfa(buf, profile->dfa.dfa, profile->dfa.size); - sd_serialize_xtable(buf, profile->exec_table); - + sd_serialize_dfa(buf, profile->dfa.dfa, profile->dfa.size, + profile->dfa.perms_table); + if (profile->dfa.dfa) { + // fprintf(stderr, "profile %s: dfa xtable\n", profile->name); + sd_serialize_xtable(buf, profile->exec_table, + //??? work around + profile->dfa.perms_table.size()); + } sd_write_structend(buf); } diff --git a/parser/parser_main.c b/parser/parser_main.c index 0adb8a563..4186c7269 100644 --- a/parser/parser_main.c +++ b/parser/parser_main.c @@ -1544,6 +1544,10 @@ static bool get_kernel_features(struct aa_features **features) else if (aa_features_supports(*features, "policy/versions/v6")) kernel_abi_version = 6; + kernel_supports_permstable32 = aa_features_supports(*features, "policy/permstable32"); + if (kernel_supports_permstable32) { + //fprintf(stderr, "kernel supports prompt\n"); + } if (!kernel_supports_diff_encode) /* clear diff_encode because it is not supported */ parseopts.control &= ~CONTROL_DFA_DIFF_ENCODE; diff --git a/parser/parser_regex.c b/parser/parser_regex.c index 1af5eaf58..de38c7773 100644 --- a/parser/parser_regex.c +++ b/parser/parser_regex.c @@ -569,7 +569,11 @@ static int process_profile_name_xmatch(Profile *prof) } } build: - prof->xmatch = rules->create_dfa(&prof->xmatch_size, &prof->xmatch_len, parseopts, true); + /* xmatch doesn't use file dfa exec mode bits NOT the owner + * conditional and for just MAY_EXEC can be processed as + * none file perms + */ + prof->xmatch = rules->create_dfa(&prof->xmatch_size, &prof->xmatch_len, prof->xmatch_perms_table, parseopts, false, kernel_supports_permstable32); delete rules; if (!prof->xmatch) return FALSE; @@ -769,8 +773,9 @@ int process_profile_regex(Profile *prof) if (prof->dfa.rules->rule_count > 0) { int xmatch_len = 0; + //fprintf(stderr, "Creating file DFA %d\n", kernel_supports_permstable32); prof->dfa.dfa = prof->dfa.rules->create_dfa(&prof->dfa.size, - &xmatch_len, parseopts, true); + &xmatch_len, prof->dfa.perms_table, parseopts, true, kernel_supports_permstable32); delete prof->dfa.rules; prof->dfa.rules = NULL; if (!prof->dfa.dfa) @@ -1044,7 +1049,7 @@ int process_profile_policydb(Profile *prof) if (prof->policy.rules->rule_count > 0) { int xmatch_len = 0; prof->policy.dfa = prof->policy.rules->create_dfa(&prof->policy.size, - &xmatch_len, parseopts, false); + &xmatch_len, prof->policy.perms_table, parseopts, false, kernel_supports_permstable32); delete prof->policy.rules; prof->policy.rules = NULL; diff --git a/parser/perms.h b/parser/perms.h new file mode 100644 index 000000000..2759b7225 --- /dev/null +++ b/parser/perms.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2022 + * Canonical, Ltd. (All rights reserved) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, contact Novell, Inc. or Canonical + * Ltd. + */ +#ifndef __AA_PERM_H +#define __AA_PERM_H + +#include + +/* same as in immunix.h - make it so they can both be included or used alone */ +#ifndef AA_MAY_EXEC +#define AA_MAY_EXEC 1 +#define AA_MAY_WRITE 2 +#define AA_MAY_READ 4 +#define AA_MAY_APPEND 8 +#endif + +#ifndef AA_MAY_CREATE +// these are in apparmor.h +#define AA_MAY_CREATE 0x0010 +#define AA_MAY_DELETE 0x0020 +#define AA_MAY_OPEN 0x0040 +#define AA_MAY_RENAME 0x0080 /* pair */ + +#define AA_MAY_SETATTR 0x0100 /* meta write */ +#define AA_MAY_GETATTR 0x0200 /* meta read */ +#define AA_MAY_SETCRED 0x0400 /* security cred/attr */ +#define AA_MAY_GETCRED 0x0800 + +#define AA_MAY_CHMOD 0x1000 /* pair */ +#define AA_MAY_CHOWN 0x2000 /* pair */ +#define AA_MAY_CHGRP 0x4000 /* pair */ +#define AA_MAY_LOCK 0x8000 /* LINK_SUBSET overlaid */ + +#define AA_EXEC_MMAP 0x00010000 +#define AA_MAY_MPROT 0x00020000 /* extend conditions */ +#define AA_MAY_LINK 0x00040000 /* pair */ +#endif +#define AA_MAY_SNAPSHOT 0x00080000 /* pair */ + +#define AA_MAY_DELEGATE +#define AA_CONT_MATCH 0x08000000 + +#define AA_MAY_STACK 0x10000000 +#define AA_MAY_ONEXEC 0x20000000 /* either stack or change_profile */ +#define AA_MAY_CHANGE_PROFILE 0x40000000 +#define AA_MAY_CHANGEHAT 0x80000000 + +#define AA_LINK_SUBSET AA_MAY_LOCK /* overlaid */ + + +/* + * The xindex is broken into 3 parts + * - index - an index into either the exec name table or the variable table + * - exec type - which determines how the executable name and index are used + * - flags - which modify how the destination name is applied + */ +#define AA_X_INDEX_MASK AA_INDEX_MASK + +#define AA_X_TYPE_MASK 0x0c000000 +#define AA_X_NONE AA_INDEX_NONE +#define AA_X_NAME 0x04000000 /* use executable name px */ +#define AA_X_TABLE 0x08000000 /* use a specified name ->n# */ + +#define AA_X_UNSAFE 0x10000000 +#define AA_X_CHILD 0x20000000 +#define AA_X_INHERIT 0x40000000 +#define AA_X_UNCONFINED 0x80000000 + +struct aa_perms { + uint32_t allow; + uint32_t deny; /* explicit deny, or conflict if allow also set */ + + uint32_t subtree; /* allow perm on full subtree only when allow is set */ + uint32_t cond; /* set only when ~allow and ~deny */ + + uint32_t kill; /* set only when ~allow | deny */ + uint32_t complain; /* accumulates only used when ~allow & ~deny */ + uint32_t prompt; /* accumulates only used when ~allow & ~deny */ + + uint32_t audit; /* set only when allow is set */ + uint32_t quiet; /* set only when ~allow | deny */ + uint32_t hide; /* set only when ~allow | deny */ + + + uint32_t xindex; + uint32_t tag; /* tag string index, if present */ + uint32_t label; /* label string index, if present */ +}; + +#endif /* __AA_PERM_H */ diff --git a/parser/profile.h b/parser/profile.h index 8286208d8..fa4ceadb9 100644 --- a/parser/profile.h +++ b/parser/profile.h @@ -15,6 +15,7 @@ #define __AA_PROFILE_H #include +#include #include #include @@ -24,6 +25,8 @@ #include "libapparmor_re/aare_rules.h" #include "network.h" #include "signal.h" +#include "immunix.h" +#include "perms.h" class Profile; @@ -336,7 +339,7 @@ struct dfa_stuff { aare_rules *rules; void *dfa; size_t size; - + vector perms_table; dfa_stuff(void): rules(NULL), dfa(NULL), size(0) { } }; @@ -349,7 +352,7 @@ public: void *xmatch; size_t xmatch_size; int xmatch_len; - + vector xmatch_perms_table; struct cond_entry_list xattrs; /* char *sub_name; */ /* subdomain name or NULL */ From 2e18cb9aed9c6f34b10231e57c630ed44095c727 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Wed, 2 Aug 2023 02:07:36 -0700 Subject: [PATCH 04/17] parser: rename rules.h perms_t to perm32_t There are two distinct declarations of perms_t. rule.h: typedef uint32_t perms_t hfa.h: class perms_t these definitions clash when the front end and backend share more info. To avoid this rename rule.h to perm32_t, and move the definition into perms.h and use it in struct aa_perms. Signed-off-by: John Johansen --- parser/af_unix.cc | 8 ++++---- parser/af_unix.h | 4 ++-- parser/dbus.cc | 4 ++-- parser/dbus.h | 4 ++-- parser/io_uring.cc | 2 +- parser/io_uring.h | 2 +- parser/mount.cc | 8 ++++---- parser/mount.h | 2 +- parser/mqueue.cc | 4 ++-- parser/mqueue.h | 4 ++-- parser/network.cc | 10 +++++----- parser/network.h | 9 +++++---- parser/parser.h | 8 ++++---- parser/parser_misc.c | 18 +++++++++--------- parser/parser_regex.c | 2 +- parser/parser_yacc.y | 12 ++++++------ parser/perms.h | 27 +++++++++++++++++---------- parser/profile.cc | 4 ++-- parser/ptrace.cc | 4 ++-- parser/ptrace.h | 4 ++-- parser/rule.h | 6 +++--- parser/signal.cc | 4 ++-- parser/signal.h | 4 ++-- parser/userns.cc | 2 +- parser/userns.h | 2 +- 25 files changed, 83 insertions(+), 75 deletions(-) diff --git a/parser/af_unix.cc b/parser/af_unix.cc index b1fc38c14..4e3b97077 100644 --- a/parser/af_unix.cc +++ b/parser/af_unix.cc @@ -33,7 +33,7 @@ /* See unix(7) for autobind address definition */ #define autobind_address_pattern "\\x00[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]"; -int parse_unix_perms(const char *str_perms, perms_t *perms, int fail) +int parse_unix_perms(const char *str_perms, perm32_t *perms, int fail) { return parse_X_perms("unix", AA_VALID_NET_PERMS, str_perms, perms, fail); } @@ -113,7 +113,7 @@ unix_rule::unix_rule(unsigned int type_p, audit_t audit_p, rule_mode_t rule_mode downgrade = false; } -unix_rule::unix_rule(perms_t perms_p, struct cond_entry *conds, +unix_rule::unix_rule(perm32_t perms_p, struct cond_entry *conds, struct cond_entry *peer_conds): af_rule(AF_UNIX), addr(NULL), peer_addr(NULL) { @@ -191,7 +191,7 @@ static void writeu16(std::ostringstream &o, int v) #define CMD_OPT 4 void unix_rule::downgrade_rule(Profile &prof) { - perms_t mask = (perms_t) -1; + perm32_t mask = (perm32_t) -1; if (!prof.net.allow && !prof.net.alloc_net_table()) yyerror(_("Memory allocation error.")); @@ -318,7 +318,7 @@ int unix_rule::gen_policy_re(Profile &prof) std::ostringstream buffer; std::string buf; - perms_t mask = perms; + perm32_t mask = perms; /* always generate a downgraded rule. This doesn't change generated * policy size and allows the binary policy to be loaded against diff --git a/parser/af_unix.h b/parser/af_unix.h index 03dbfdc64..3441263e9 100644 --- a/parser/af_unix.h +++ b/parser/af_unix.h @@ -24,7 +24,7 @@ #include "profile.h" #include "af_rule.h" -int parse_unix_perms(const char *str_mode, perms_t *perms, int fail); +int parse_unix_perms(const char *str_mode, perm32_t *perms, int fail); class unix_rule: public af_rule { void write_to_prot(std::ostringstream &buffer); @@ -39,7 +39,7 @@ public: bool downgrade = true; unix_rule(unsigned int type_p, audit_t audit_p, rule_mode_t rule_mode_p); - unix_rule(perms_t perms, struct cond_entry *conds, + unix_rule(perm32_t perms, struct cond_entry *conds, struct cond_entry *peer_conds); virtual ~unix_rule() { diff --git a/parser/dbus.cc b/parser/dbus.cc index 0371f66c1..fc028de6c 100644 --- a/parser/dbus.cc +++ b/parser/dbus.cc @@ -30,7 +30,7 @@ #include "dbus.h" -int parse_dbus_perms(const char *str_perms, perms_t *perms, int fail) +int parse_dbus_perms(const char *str_perms, perm32_t *perms, int fail) { return parse_X_perms("DBus", AA_VALID_DBUS_PERMS, str_perms, perms, fail); } @@ -66,7 +66,7 @@ void dbus_rule::move_conditionals(struct cond_entry *conds) } } -dbus_rule::dbus_rule(perms_t perms_p, struct cond_entry *conds, +dbus_rule::dbus_rule(perm32_t perms_p, struct cond_entry *conds, struct cond_entry *peer_conds): perms_rule_t(AA_CLASS_DBUS), bus(NULL), name(NULL), peer_label(NULL), path(NULL), interface(NULL), member(NULL) { diff --git a/parser/dbus.h b/parser/dbus.h index a273bffe5..852755687 100644 --- a/parser/dbus.h +++ b/parser/dbus.h @@ -23,7 +23,7 @@ #include "rule.h" #include "profile.h" -extern int parse_dbus_perms(const char *str_mode, perms_t *mode, int fail); +extern int parse_dbus_perms(const char *str_mode, perm32_t *mode, int fail); class dbus_rule: public perms_rule_t { void move_conditionals(struct cond_entry *conds); @@ -40,7 +40,7 @@ public: char *interface; char *member; - dbus_rule(perms_t perms_p, struct cond_entry *conds, + dbus_rule(perm32_t perms_p, struct cond_entry *conds, struct cond_entry *peer_conds); virtual ~dbus_rule() { free(bus); diff --git a/parser/io_uring.cc b/parser/io_uring.cc index ec3af65bf..3425ea36c 100644 --- a/parser/io_uring.cc +++ b/parser/io_uring.cc @@ -47,7 +47,7 @@ void io_uring_rule::move_conditionals(struct cond_entry *conds) } } -io_uring_rule::io_uring_rule(perms_t perms_p, struct cond_entry *conds, struct cond_entry *ring_conds): +io_uring_rule::io_uring_rule(perm32_t perms_p, struct cond_entry *conds, struct cond_entry *ring_conds): perms_rule_t(AA_CLASS_IO_URING), label(NULL) { if (perms_p) { diff --git a/parser/io_uring.h b/parser/io_uring.h index 7299e16b0..b1d094424 100644 --- a/parser/io_uring.h +++ b/parser/io_uring.h @@ -31,7 +31,7 @@ class io_uring_rule: public perms_rule_t { public: char *label; - io_uring_rule(perms_t perms, struct cond_entry *conds, struct cond_entry *ring_conds); + io_uring_rule(perm32_t perms, struct cond_entry *conds, struct cond_entry *ring_conds); virtual ~io_uring_rule() { free(label); diff --git a/parser/mount.cc b/parser/mount.cc index c3af39a81..31b43ef6d 100644 --- a/parser/mount.cc +++ b/parser/mount.cc @@ -478,7 +478,7 @@ static void process_one_option(struct cond_entry *&opts, unsigned int &flags, mnt_rule::mnt_rule(struct cond_entry *src_conds, char *device_p, struct cond_entry *dst_conds unused, char *mnt_point_p, - perms_t perms_p): + perm32_t perms_p): perms_rule_t(AA_CLASS_MOUNT), mnt_point(mnt_point_p), device(device_p), trans(NULL), opts(NULL), flagsv(0), opt_flagsv(0) @@ -784,7 +784,7 @@ int mnt_rule::gen_policy_remount(Profile &prof, int &count, vec[3] = flagsbuf; - perms_t tmpperms, tmpaudit; + perm32_t tmpperms, tmpaudit; if (opts) { tmpperms = AA_MATCH_CONT; tmpaudit = 0; @@ -993,7 +993,7 @@ int mnt_rule::gen_policy_new_mount(Profile &prof, int &count, goto fail; vec[3] = flagsbuf; - perms_t tmpperms, tmpaudit; + perm32_t tmpperms, tmpaudit; if (opts) { tmpperms = AA_MATCH_CONT; tmpaudit = 0; @@ -1141,7 +1141,7 @@ fail: void mnt_rule::post_parse_profile(Profile &prof) { if (trans) { - perms_t perms = 0; + perm32_t perms = 0; int n = add_entry_to_x_table(&prof, trans); if (!n) { PERROR("Profile %s has too many specified profile transitions.\n", prof.name); diff --git a/parser/mount.h b/parser/mount.h index fa1794f87..8767a404e 100644 --- a/parser/mount.h +++ b/parser/mount.h @@ -152,7 +152,7 @@ public: mnt_rule(struct cond_entry *src_conds, char *device_p, struct cond_entry *dst_conds unused, char *mnt_point_p, - perms_t perms_p); + perm32_t perms_p); virtual ~mnt_rule() { free_value_list(opts); diff --git a/parser/mqueue.cc b/parser/mqueue.cc index 3cff674f1..4d91011ef 100644 --- a/parser/mqueue.cc +++ b/parser/mqueue.cc @@ -25,7 +25,7 @@ #include #include -int parse_mqueue_perms(const char *str_perms, perms_t *perms, int fail) +int parse_mqueue_perms(const char *str_perms, perm32_t *perms, int fail) { return parse_X_perms("mqueue", AA_VALID_MQUEUE_PERMS, str_perms, perms, fail); } @@ -86,7 +86,7 @@ void mqueue_rule::move_conditionals(struct cond_entry *conds) } } -mqueue_rule::mqueue_rule(perms_t perms_p, struct cond_entry *conds, char *qname_p): +mqueue_rule::mqueue_rule(perm32_t perms_p, struct cond_entry *conds, char *qname_p): // mqueue uses multiple classes, arbitrary choice to represent group // withing the AST perms_rule_t(AA_CLASS_POSIX_MQUEUE), diff --git a/parser/mqueue.h b/parser/mqueue.h index 0b37b0704..ebfa5636e 100644 --- a/parser/mqueue.h +++ b/parser/mqueue.h @@ -84,7 +84,7 @@ static inline uint32_t map_mqueue_perms(uint32_t mask) ((mask & (AA_MQUEUE_GETATTR | AA_MQUEUE_SETATTR)) << (AA_OTHER_SHIFT - 8)); } -int parse_mqueue_perms(const char *str_perms, perms_t *perms, int fail); +int parse_mqueue_perms(const char *str_perms, perm32_t *perms, int fail); class mqueue_rule: public perms_rule_t { void move_conditionals(struct cond_entry *conds); @@ -93,7 +93,7 @@ public: char *qname; char *label; - mqueue_rule(perms_t perms, struct cond_entry *conds, char *qname = NULL); + mqueue_rule(perm32_t perms, struct cond_entry *conds, char *qname = NULL); virtual ~mqueue_rule() { free(qname); diff --git a/parser/network.cc b/parser/network.cc index c22bfb08e..939f2112f 100644 --- a/parser/network.cc +++ b/parser/network.cc @@ -29,7 +29,7 @@ #define ALL_TYPES 0x43e -int parse_net_perms(const char *str_mode, perms_t *mode, int fail) +int parse_net_perms(const char *str_mode, perm32_t *mode, int fail) { return parse_X_perms("net", AA_VALID_NET_PERMS, str_mode, mode, fail); } @@ -401,7 +401,7 @@ void network_rule::set_netperm(unsigned int family, unsigned int type, unsigned network_perms[family].second |= protocol; } -network_rule::network_rule(perms_t perms_p, struct cond_entry *conds, +network_rule::network_rule(perm32_t perms_p, struct cond_entry *conds, struct cond_entry *peer_conds): dedup_perms_rule_t(AA_CLASS_NETV8), label(NULL) { @@ -441,7 +441,7 @@ network_rule::network_rule(perms_t perms_p, struct cond_entry *conds, } } -network_rule::network_rule(perms_t perms_p, const char *family, const char *type, +network_rule::network_rule(perm32_t perms_p, const char *family, const char *type, const char *protocol, struct cond_entry *conds, struct cond_entry *peer_conds): dedup_perms_rule_t(AA_CLASS_NETV8), label(NULL) @@ -494,7 +494,7 @@ network_rule::network_rule(perms_t perms_p, const char *family, const char *type } } -network_rule::network_rule(perms_t perms_p, unsigned int family, unsigned int type): +network_rule::network_rule(perm32_t perms_p, unsigned int family, unsigned int type): dedup_perms_rule_t(AA_CLASS_NETV8), label(NULL) { network_map[family].push_back({ family, type, 0xFFFFFFFF }); @@ -653,7 +653,7 @@ std::list copy_streams_list(std::list &s bool network_rule::gen_ip_conds(Profile &prof, std::list &streams, ip_conds &entry, bool is_peer, bool is_cmd) { std::string buf; - perms_t cond_perms; + perm32_t cond_perms; std::list ip_streams; for (auto &oss : streams) { diff --git a/parser/network.h b/parser/network.h index d9fa18144..cb396c9f1 100644 --- a/parser/network.h +++ b/parser/network.h @@ -107,8 +107,9 @@ static inline uint32_t map_perms(uint32_t mask) ((mask & (AA_NET_SETOPT | AA_NET_GETOPT)) >> 5); /* 5 + (AA_OTHER_SHIFT - 24) */ }; -int parse_net_perms(const char *str_mode, perms_t *perms, int fail); + size_t get_af_max(); +int parse_net_perms(const char *str_mode, perm32_t *perms, int fail); int net_find_type_val(const char *type); const char *net_find_type_name(int type); const char *net_find_af_name(unsigned int af); @@ -158,12 +159,12 @@ public: * static elements to maintain compatibility with * AA_CLASS_NET */ network_rule(): dedup_perms_rule_t(AA_CLASS_NETV8), label(NULL) { } - network_rule(perms_t perms_p, struct cond_entry *conds, + network_rule(perm32_t perms_p, struct cond_entry *conds, struct cond_entry *peer_conds); - network_rule(perms_t perms_p, const char *family, const char *type, + network_rule(perm32_t perms_p, const char *family, const char *type, const char *protocol, struct cond_entry *conds, struct cond_entry *peer_conds); - network_rule(perms_t perms_p, unsigned int family, unsigned int type); + network_rule(perm32_t perms_p, unsigned int family, unsigned int type); virtual ~network_rule() { peer.free_conds(); diff --git a/parser/parser.h b/parser/parser.h index 27bac1849..885c85d45 100644 --- a/parser/parser.h +++ b/parser/parser.h @@ -122,7 +122,7 @@ struct cod_entry { char *nt_name; Profile *prof; /* Special profile defined * just for this executable */ - perms_t perms; /* perms is 'or' of AA_* bits */ + perm32_t perms; /* perms is 'or' of AA_* bits */ audit_t audit; rule_mode_t rule_mode; @@ -450,12 +450,12 @@ extern char *processunquoted(const char *string, int len); extern int get_keyword_token(const char *keyword); extern int get_rlimit(const char *name); extern char *process_var(const char *var); -extern perms_t parse_perms(const char *permstr); -extern int parse_X_perms(const char *X, int valid, const char *str_perms, perms_t *perms, int fail); +extern perm32_t parse_perms(const char *permstr); +extern int parse_X_perms(const char *X, int valid, const char *str_perms, perm32_t *perms, int fail); bool label_contains_ns(const char *label); bool parse_label(bool *_stack, char **_ns, char **_name, const char *label, bool yyerr); -extern struct cod_entry *new_entry(char *id, perms_t perms, char *link_id); +extern struct cod_entry *new_entry(char *id, perm32_t perms, char *link_id); /* returns -1 if value != true or false, otherwise 0 == false, 1 == true */ extern int str_to_boolean(const char* str); diff --git a/parser/parser_misc.c b/parser/parser_misc.c index 5582ff9fb..124e8b7a2 100644 --- a/parser/parser_misc.c +++ b/parser/parser_misc.c @@ -566,12 +566,12 @@ void warn_uppercase(void) } } -static perms_t parse_sub_perms(const char *str_perms, const char *perms_desc unused) +static perm32_t parse_sub_perms(const char *str_perms, const char *perms_desc unused) { #define IS_DIFF_QUAL(perms, q) (((perms) & AA_MAY_EXEC) && (((perms) & AA_EXEC_TYPE) != ((q) & AA_EXEC_TYPE))) - perms_t perms = 0; + perm32_t perms = 0; const char *p; PDEBUG("Parsing perms: %s\n", str_perms); @@ -584,7 +584,7 @@ static perms_t parse_sub_perms(const char *str_perms, const char *perms_desc unu char thisc = *p; char next = *(p + 1); char lower; - perms_t tperms = 0; + perm32_t tperms = 0; reeval: switch (thisc) { @@ -742,9 +742,9 @@ reeval: return perms; } -perms_t parse_perms(const char *str_perms) +perm32_t parse_perms(const char *str_perms) { - perms_t tmp, perms = 0; + perm32_t tmp, perms = 0; tmp = parse_sub_perms(str_perms, ""); perms = SHIFT_PERMS(tmp, AA_USER_SHIFT); perms |= SHIFT_PERMS(tmp, AA_OTHER_SHIFT); @@ -753,9 +753,9 @@ perms_t parse_perms(const char *str_perms) return perms; } -static int parse_X_sub_perms(const char *X, const char *str_perms, perms_t *result, int fail, const char *perms_desc unused) +static int parse_X_sub_perms(const char *X, const char *str_perms, perm32_t *result, int fail, const char *perms_desc unused) { - perms_t perms = 0; + perm32_t perms = 0; const char *p; PDEBUG("Parsing %s perms: %s\n", X, str_perms); @@ -813,7 +813,7 @@ reeval: return 1; } -int parse_X_perms(const char *X, int valid, const char *str_perms, perms_t *perms, int fail) +int parse_X_perms(const char *X, int valid, const char *str_perms, perm32_t *perms, int fail) { *perms = 0; if (!parse_X_sub_perms(X, str_perms, perms, fail, "")) @@ -976,7 +976,7 @@ alloc_fail: return false; } -struct cod_entry *new_entry(char *id, perms_t perms, char *link_id) +struct cod_entry *new_entry(char *id, perm32_t perms, char *link_id) { struct cod_entry *entry = NULL; diff --git a/parser/parser_regex.c b/parser/parser_regex.c index de38c7773..65c34f0e4 100644 --- a/parser/parser_regex.c +++ b/parser/parser_regex.c @@ -584,7 +584,7 @@ build: static int warn_change_profile = 1; -static bool is_change_profile_perms(perms_t perms) +static bool is_change_profile_perms(perm32_t perms) { /** * A change_profile entry will have the AA_CHANGE_PROFILE bit set. diff --git a/parser/parser_yacc.y b/parser/parser_yacc.y index 10aca3227..c957bd5e1 100644 --- a/parser/parser_yacc.y +++ b/parser/parser_yacc.y @@ -63,10 +63,10 @@ int parser_token = 0; -struct cod_entry *do_file_rule(char *id, perms_t perms, char *link_id, char *nt); +struct cod_entry *do_file_rule(char *id, perm32_t perms, char *link_id, char *nt); mnt_rule *do_mnt_rule(struct cond_entry *src_conds, char *src, struct cond_entry *dst_conds, char *dst, - perms_t perms); + perm32_t perms); mnt_rule *do_pivot_rule(struct cond_entry *old, char *root, char *transition); static void abi_features(char *filename, bool search); @@ -212,7 +212,7 @@ static void abi_features(char *filename, bool search); prefix_rule_t *prefix_entry; flagvals flags; - perms_t fperms; + perm32_t fperms; uint64_t cap; unsigned int allowed_protocol; char *set_var; @@ -1562,7 +1562,7 @@ file_perms: TOK_MODE change_profile: TOK_CHANGE_PROFILE opt_exec_mode opt_id opt_named_transition TOK_END_OF_RULE { struct cod_entry *entry; - perms_t perms = AA_CHANGE_PROFILE; + perm32_t perms = AA_CHANGE_PROFILE; int exec_mode = $2; char *exec = $3; char *target = $4; @@ -1670,7 +1670,7 @@ void yyerror(const char *msg, ...) exit(1); } -struct cod_entry *do_file_rule(char *id, perms_t perms, char *link_id, char *nt) +struct cod_entry *do_file_rule(char *id, perm32_t perms, char *link_id, char *nt) { struct cod_entry *entry; PDEBUG("Matched: tok_id (%s) tok_perms (0x%x)\n", id, perms); @@ -1711,7 +1711,7 @@ int verify_mnt_conds(struct cond_entry *conds, int src) mnt_rule *do_mnt_rule(struct cond_entry *src_conds, char *src, struct cond_entry *dst_conds, char *dst, - perms_t perms) + perm32_t perms) { if (verify_mnt_conds(src_conds, MNT_SRC_OPT) != 0) yyerror(_("bad mount rule")); diff --git a/parser/perms.h b/parser/perms.h index 2759b7225..f1ac7b4b3 100644 --- a/parser/perms.h +++ b/parser/perms.h @@ -19,6 +19,7 @@ #define __AA_PERM_H #include +#include /* same as in immunix.h - make it so they can both be included or used alone */ #ifndef AA_MAY_EXEC @@ -42,11 +43,15 @@ #define AA_MAY_CHMOD 0x1000 /* pair */ #define AA_MAY_CHOWN 0x2000 /* pair */ +#endif #define AA_MAY_CHGRP 0x4000 /* pair */ +#ifndef AA_MAY_CREATE #define AA_MAY_LOCK 0x8000 /* LINK_SUBSET overlaid */ #define AA_EXEC_MMAP 0x00010000 +#endif #define AA_MAY_MPROT 0x00020000 /* extend conditions */ +#ifndef AA_MAY_CREATE #define AA_MAY_LINK 0x00040000 /* pair */ #endif #define AA_MAY_SNAPSHOT 0x00080000 /* pair */ @@ -80,20 +85,22 @@ #define AA_X_INHERIT 0x40000000 #define AA_X_UNCONFINED 0x80000000 +typedef uint32_t perm32_t; + struct aa_perms { - uint32_t allow; - uint32_t deny; /* explicit deny, or conflict if allow also set */ + perm32_t allow; + perm32_t deny; /* explicit deny, or conflict if allow also set */ - uint32_t subtree; /* allow perm on full subtree only when allow is set */ - uint32_t cond; /* set only when ~allow and ~deny */ + perm32_t subtree; /* allow perm on full subtree only when allow is set */ + perm32_t cond; /* set only when ~allow and ~deny */ - uint32_t kill; /* set only when ~allow | deny */ - uint32_t complain; /* accumulates only used when ~allow & ~deny */ - uint32_t prompt; /* accumulates only used when ~allow & ~deny */ + perm32_t kill; /* set only when ~allow | deny */ + perm32_t complain; /* accumulates only used when ~allow & ~deny */ + perm32_t prompt; /* accumulates only used when ~allow & ~deny */ - uint32_t audit; /* set only when allow is set */ - uint32_t quiet; /* set only when ~allow | deny */ - uint32_t hide; /* set only when ~allow | deny */ + perm32_t audit; /* set only when allow is set */ + perm32_t quiet; /* set only when ~allow | deny */ + perm32_t hide; /* set only when ~allow | deny */ uint32_t xindex; diff --git a/parser/profile.cc b/parser/profile.cc index 3844c2fbf..5c96e65a2 100644 --- a/parser/profile.cc +++ b/parser/profile.cc @@ -269,11 +269,11 @@ static bool add_proc_access(Profile *prof, const char *rule) void post_process_file_entries(Profile *prof) { struct cod_entry *entry; - perms_t cp_perms = 0; + perm32_t cp_perms = 0; list_for_each(prof->entries, entry) { if (entry->nt_name) { - perms_t perms = 0; + perm32_t perms = 0; int n = add_named_transition(prof, entry); if (!n) { PERROR("Profile %s has too many specified profile transitions.\n", prof->name); diff --git a/parser/ptrace.cc b/parser/ptrace.cc index 3729b7606..3a4bbf690 100644 --- a/parser/ptrace.cc +++ b/parser/ptrace.cc @@ -24,7 +24,7 @@ #include #include -int parse_ptrace_perms(const char *str_perms, perms_t *perms, int fail) +int parse_ptrace_perms(const char *str_perms, perm32_t *perms, int fail) { return parse_X_perms("ptrace", AA_VALID_PTRACE_PERMS, str_perms, perms, fail); } @@ -47,7 +47,7 @@ void ptrace_rule::move_conditionals(struct cond_entry *conds) } } -ptrace_rule::ptrace_rule(perms_t perms_p, struct cond_entry *conds): +ptrace_rule::ptrace_rule(perm32_t perms_p, struct cond_entry *conds): perms_rule_t(AA_CLASS_PTRACE), peer_label(NULL) { if (perms_p) { diff --git a/parser/ptrace.h b/parser/ptrace.h index b129c5795..bbe7b8638 100644 --- a/parser/ptrace.h +++ b/parser/ptrace.h @@ -27,14 +27,14 @@ #define AA_VALID_PTRACE_PERMS (AA_MAY_READ | AA_MAY_TRACE | AA_MAY_READBY | \ AA_MAY_TRACEDBY) -int parse_ptrace_perms(const char *str_perms, perms_t *perms, int fail); +int parse_ptrace_perms(const char *str_perms, perm32_t *perms, int fail); class ptrace_rule: public perms_rule_t { void move_conditionals(struct cond_entry *conds); public: char *peer_label; - ptrace_rule(perms_t perms, struct cond_entry *conds); + ptrace_rule(perm32_t perms, struct cond_entry *conds); virtual ~ptrace_rule() { free(peer_label); diff --git a/parser/rule.h b/parser/rule.h index a7234c778..3d2d2946f 100644 --- a/parser/rule.h +++ b/parser/rule.h @@ -22,6 +22,7 @@ #include #include +#include "perms.h" #include "policydb.h" using namespace std; @@ -151,7 +152,6 @@ std::ostream &operator<<(std::ostream &os, rule_t &rule); typedef std::list RuleList; /* Not classes so they can be used in the bison front end */ -typedef uint32_t perms_t; typedef enum { AUDIT_UNSPECIFIED, AUDIT_FORCE, AUDIT_QUIET } audit_t; typedef enum { RULE_UNSPECIFIED, RULE_ALLOW, RULE_DENY, RULE_PROMPT } rule_mode_t; @@ -407,7 +407,7 @@ public: return os; } - perms_t perms, saved; + perm32_t perms, saved; }; // alternate perms rule class that only does dedup instead of perms merging @@ -432,7 +432,7 @@ public: return os; } - perms_t perms; + perm32_t perms; }; diff --git a/parser/signal.cc b/parser/signal.cc index 15fc5a17a..b2eda5ac2 100644 --- a/parser/signal.cc +++ b/parser/signal.cc @@ -116,7 +116,7 @@ static const char *const sig_names[MAXMAPPED_SIG + 1] = { }; -int parse_signal_perms(const char *str_perms, perms_t *perms, int fail) +int parse_signal_perms(const char *str_perms, perm32_t *perms, int fail) { return parse_X_perms("signal", AA_VALID_SIGNAL_PERMS, str_perms, perms, fail); } @@ -173,7 +173,7 @@ void signal_rule::move_conditionals(struct cond_entry *conds) } } -signal_rule::signal_rule(perms_t perms_p, struct cond_entry *conds): +signal_rule::signal_rule(perm32_t perms_p, struct cond_entry *conds): perms_rule_t(AA_CLASS_SIGNAL), signals(), peer_label(NULL) { if (perms_p) { diff --git a/parser/signal.h b/parser/signal.h index 4cb4411f9..d3295a4a9 100644 --- a/parser/signal.h +++ b/parser/signal.h @@ -32,7 +32,7 @@ typedef set Signals; int find_signal_mapping(const char *sig); -int parse_signal_perms(const char *str_perms, perms_t *perms, int fail); +int parse_signal_perms(const char *str_perms, perm32_t *perms, int fail); class signal_rule: public perms_rule_t { void extract_sigs(struct value_list **list); @@ -41,7 +41,7 @@ public: Signals signals; char *peer_label; - signal_rule(perms_t perms, struct cond_entry *conds); + signal_rule(perm32_t perms, struct cond_entry *conds); virtual ~signal_rule() { signals.clear(); free(peer_label); diff --git a/parser/userns.cc b/parser/userns.cc index f70f8e84e..cbef5e580 100644 --- a/parser/userns.cc +++ b/parser/userns.cc @@ -40,7 +40,7 @@ void userns_rule::move_conditionals(struct cond_entry *conds) } } -userns_rule::userns_rule(perms_t perms_p, struct cond_entry *conds): +userns_rule::userns_rule(perm32_t perms_p, struct cond_entry *conds): perms_rule_t(AA_CLASS_NS) { if (perms_p) { diff --git a/parser/userns.h b/parser/userns.h index 9d17fc203..8c1364aa9 100644 --- a/parser/userns.h +++ b/parser/userns.h @@ -26,7 +26,7 @@ class userns_rule: public perms_rule_t { void move_conditionals(struct cond_entry *conds); public: - userns_rule(perms_t perms, struct cond_entry *conds); + userns_rule(perm32_t perms, struct cond_entry *conds); virtual ~userns_rule() { }; From e4890e6ba184dd51392c3f2a622af91187080901 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Thu, 20 Apr 2023 08:31:12 -0700 Subject: [PATCH 05/17] parser: Add work around for buggy permstable32 v1 of permstable32 has some broken verification checks. By using two copies of a merged dfa and an xtable the same size of the permstable we can work around the issue. Signed-off-by: John Johansen --- parser/libapparmor_re/aare_rules.cc | 129 +++++++++++++++++++++++++--- parser/libapparmor_re/aare_rules.h | 13 ++- parser/libapparmor_re/chfa.cc | 114 ++++++++++++++++++++++++ parser/libapparmor_re/chfa.h | 8 ++ parser/libapparmor_re/hfa.h | 2 +- parser/parser.h | 1 + parser/parser_common.c | 1 + parser/parser_interface.c | 35 +++++--- parser/parser_main.c | 6 +- parser/parser_regex.c | 55 ++++++++++-- parser/profile.h | 1 + 11 files changed, 334 insertions(+), 31 deletions(-) diff --git a/parser/libapparmor_re/aare_rules.cc b/parser/libapparmor_re/aare_rules.cc index f48d858fb..75883c7e7 100644 --- a/parser/libapparmor_re/aare_rules.cc +++ b/parser/libapparmor_re/aare_rules.cc @@ -189,18 +189,16 @@ bool aare_rules::append_rule(const char *rule, bool oob, bool with_perm, return true; } -/* create a dfa from the ruleset +/* create a chfa from the ruleset * returns: buffer contain dfa tables, @size set to the size of the tables * else NULL on failure, @min_match_len set to the shortest string * that can match the dfa for determining xmatch priority. */ -void *aare_rules::create_dfa(size_t *size, int *min_match_len, - vector &perms_table, - optflags const &opts, - bool filedfa, bool extended_perms) +CHFA *aare_rules::create_chfa(int *min_match_len, + vector &perms_table, + optflags const &opts, + bool filedfa, bool extended_perms) { - char *buffer = NULL; - /* finish constructing the expr tree from the different permission * set nodes */ PermExprMap::iterator i = expr_map.begin(); @@ -249,7 +247,7 @@ void *aare_rules::create_dfa(size_t *size, int *min_match_len, } } - stringstream stream; + CHFA *chfa = NULL; try { DFA dfa(root, opts, filedfa); if (opts.dump & DUMP_DFA_UNIQ_PERMS) @@ -311,10 +309,39 @@ void *aare_rules::create_dfa(size_t *size, int *min_match_len, //cerr << "creating permstable\n"; dfa.compute_perms_table(perms_table); } - CHFA chfa(dfa, eq, opts, extended_perms); + chfa = new CHFA(dfa, eq, opts, extended_perms); if (opts.dump & DUMP_DFA_TRANS_TABLE) - chfa.dump(cerr); - chfa.flex_table(stream); + chfa->dump(cerr); + } + catch(int error) { + return NULL; + } + + return chfa; +} + +/* create a dfa from the ruleset + * returns: buffer contain dfa tables, @size set to the size of the tables + * else NULL on failure, @min_match_len set to the shortest string + * that can match the dfa for determining xmatch priority. + */ +void *aare_rules::create_dfablob(size_t *size, int *min_match_len, + vector &perms_table, + optflags const &opts, bool filedfa, + bool extended_perms) +{ + char *buffer = NULL; + stringstream stream; + + try { + CHFA *chfa = create_chfa(min_match_len, perms_table, + opts, filedfa, extended_perms); + if (!chfa) { + *size = 0; + return NULL; + } + chfa->flex_table(stream); + delete (chfa); } catch(int error) { *size = 0; @@ -330,5 +357,85 @@ void *aare_rules::create_dfa(size_t *size, int *min_match_len, if (!buffer) return NULL; buf->sgetn(buffer, *size); + + return buffer; +} + + +/* create a dfa from the ruleset + * returns: buffer contain dfa tables, @size set to the size of the tables + * else NULL on failure, @min_match_len set to the shortest string + * that can match the dfa for determining xmatch priority. + */ +void *aare_rules::create_welded_dfablob(aare_rules *file_rules, + size_t *size, int *min_match_len, + size_t *new_start, + vector &perms_table, + optflags const &opts, + bool extended_perms) +{ + int file_min_len; + vector file_perms; + CHFA *file_chfa; + try { + file_chfa = file_rules->create_chfa(&file_min_len, + file_perms, opts, + true, extended_perms); + if (!file_chfa) { + *size = 0; + return NULL; + } + } + catch(int error) { + *size = 0; + return NULL; + } + + CHFA *policy_chfa; + try { + policy_chfa = create_chfa(min_match_len, + perms_table, opts, + false, extended_perms); + if (!policy_chfa) { + delete file_chfa; + *size = 0; + return NULL; + } + } + catch(int error) { + delete file_chfa; + *size = 0; + return NULL; + } + + stringstream stream; + try { + policy_chfa->weld_file_to_policy(*file_chfa, *new_start, + extended_perms, + perms_table, file_perms); + policy_chfa->flex_table(stream); + } + catch(int error) { + delete (file_chfa); + delete (policy_chfa); + *size = 0; + return NULL; + } + delete file_chfa; + delete policy_chfa; + + /* write blob to buffer */ + stringbuf *buf = stream.rdbuf(); + + buf->pubseekpos(0); + *size = buf->in_avail(); + if (file_min_len < *min_match_len) + *min_match_len = file_min_len; + + char *buffer = (char *)malloc(*size); + if (!buffer) + return NULL; + buf->sgetn(buffer, *size); + return buffer; } diff --git a/parser/libapparmor_re/aare_rules.h b/parser/libapparmor_re/aare_rules.h index 5e9104036..8a22afb89 100644 --- a/parser/libapparmor_re/aare_rules.h +++ b/parser/libapparmor_re/aare_rules.h @@ -27,6 +27,7 @@ #include "../common_optarg.h" #include "apparmor_re.h" +#include "chfa.h" #include "expr-tree.h" #include "../immunix.h" #include "../perms.h" @@ -110,10 +111,20 @@ class aare_rules { bool add_rule_vec(int deny, uint32_t perms, uint32_t audit, int count, const char **rulev, optflags const &opts, bool oob); bool append_rule(const char *rule, bool oob, bool with_perm, optflags const &opts); - void *create_dfa(size_t *size, int *min_match_len, + CHFA *create_chfa(int *min_match_len, + vector &perms_table, + optflags const &opts, bool filedfa, + bool extended_perms); + void *create_dfablob(size_t *size, int *min_match_len, vector &perms_table, optflags const &opts, bool filedfa, bool extended_perms); + void *create_welded_dfablob(aare_rules *file_rules, + size_t *size, int *min_match_len, + size_t *new_start, + vector &perms_table, + optflags const &opts, + bool extended_perms); }; #endif /* __LIBAA_RE_RULES_H */ diff --git a/parser/libapparmor_re/chfa.cc b/parser/libapparmor_re/chfa.cc index f5aa97929..64bfdbc8a 100644 --- a/parser/libapparmor_re/chfa.cc +++ b/parser/libapparmor_re/chfa.cc @@ -32,6 +32,7 @@ #include "hfa.h" #include "chfa.h" #include "../immunix.h" +#include "../policydb.h" #include "flex-tables.h" void CHFA::init_free_list(vector > &free_list, @@ -121,6 +122,7 @@ CHFA::CHFA(DFA &dfa, map &eq, optflags const &opts, first_free = 1; init_free_list(free_list, 0, 1); + start = dfa.start; insert_state(free_list, dfa.start, dfa); num.insert(make_pair(dfa.start, num.size())); @@ -463,3 +465,115 @@ void CHFA::flex_table(ostream &os) write_flex_table(os, YYTD_ID_NXT, next_vec.begin(), next_vec.end()); write_flex_table(os, YYTD_ID_CHK, check_vec.begin(), check_vec.end()); } + +/* + * @file_chfa: chfa to add on to the policy chfa + * @new_start: new start state for where the @file_dfa is in the new chfa + * + * Make a new chfa that is a combination of policy and file chfas. It + * assumes policy is built with AA_CLASS_FILE support transition. The + * resultant chfa will have file states and indexes offset except for + * start and null states. + * + * NOTE: + * - modifies chfa + * requires: + * - no ec + * - policy chfa has transitions state[start].next[AA_CLASS_FILE] + * - policy perms table is build if using permstable + + */ +void CHFA::weld_file_to_policy(CHFA &file_chfa, size_t &new_start, + bool accept_idx, + vector &policy_perms, + vector &file_perms) +{ + // doesn't support remapping eq classes yet + if (eq.size() > 0 || file_chfa.eq.size() > 0) + throw 1; + + size_t old_base_size = default_base.size(); + size_t old_next_size = next_check.size(); + + const State *nonmatching = default_base[0].first; + //const State *start = default_base[1].first; + const State *file_nonmatching = file_chfa.default_base[0].first; + + // renumber states from file_dfa by appending to policy dfa + num.insert(make_pair(file_nonmatching, 0)); // remap to policy nonmatching + for (map::iterator i = file_chfa.num.begin(); i != file_chfa.num.end() ; i++) { + if (i->first == file_nonmatching) + continue; + num.insert(make_pair(i->first, i->second + old_base_size)); + } + + // handle default and base table expansion, and setup renumbering + // while we remap file_nonmatch within the table, we still keep its + // slot. + bool first = true; + for (DefaultBase::iterator i = file_chfa.default_base.begin(); i != file_chfa.default_base.end(); i++) { + const State *def; + size_t base; + if (first) { + first = false; + // remap file_nonmatch to nonmatch + def = nonmatching; + base = 0; + } else { + def = i->first; + base = i->second + old_next_size; + } + default_base.push_back(make_pair(def, base)); + } + + // mapping for these are handled by num[] + for (NextCheck::iterator i = file_chfa.next_check.begin(); i != file_chfa.next_check.end(); i++) { + next_check.push_back(*i); + } + + // append file perms to policy perms, and rework permsidx if needed + if (accept_idx) { + // policy idx double + // file + doubled offset + // Requires: policy perms table, so we can double and + // update indexes + // * file perm idx to start on even idx + // * policy perms table size to double and entries + // to repeat + assert(accept.size() == old_base_size); + accept.resize(accept.size() + file_chfa.accept.size()); + size_t size = policy_perms.size(); + policy_perms.resize(size*2 + file_perms.size()); + // shift and double the policy perms + for (size_t i = size - 1; size >= 0; i--) { + policy_perms[i*2] = policy_perms[i]; + policy_perms[i*2 + 1] = policy_perms[i]; + } + // update policy accept idx for the new shifted perms table + for (size_t i = 0; i < old_base_size; i++) { + accept[i] = accept[i]*2; + } + // copy over file perms + for (size_t i = 0; i < file_perms.size(); i++) { + policy_perms[size*2 + i] = file_perms[i]; + } + // shift file accept indexs + for (size_t i = 0; i < file_chfa.accept.size(); i++) { + accept[old_base_size + i] = file_chfa.accept[i] + size*2; + } + } else { + // perms are stored in accept just append the perms + size_t size = accept.size(); + accept.resize(size + file_chfa.accept.size()); + accept2.resize(size + file_chfa.accept.size()); + for (size_t i = 0; i < file_chfa.accept.size(); i++) { + accept[size + i] = file_chfa.accept[i]; + accept2[size + i] = file_chfa.accept2[i]; + } + } + + // Rework transition state[start].next[AA_CLASS_FILE] + next_check[default_base[1].second + AA_CLASS_FILE].first = file_chfa.start; + + new_start = num[file_chfa.start]; +} diff --git a/parser/libapparmor_re/chfa.h b/parser/libapparmor_re/chfa.h index b1028add9..a8aaa585a 100644 --- a/parser/libapparmor_re/chfa.h +++ b/parser/libapparmor_re/chfa.h @@ -25,6 +25,7 @@ #include #include "hfa.h" +#include "../perms.h" #define BASE32_FLAGS 0xff000000 #define DiffEncodeBit32 0x80000000 @@ -37,8 +38,10 @@ class CHFA { typedef vector > DefaultBase; typedef vector > NextCheck; public: + CHFA(void); CHFA(DFA &dfa, map &eq, optflags const &opts, bool permindex); + void dump(ostream & os); void flex_table(ostream &os); void init_free_list(vector > &free_list, @@ -47,12 +50,17 @@ class CHFA { StateTrans &cases); void insert_state(vector > &free_list, State *state, DFA &dfa); + void weld_file_to_policy(CHFA &file_chfa, size_t &new_start, + bool accept_idx, + vector &policy_perms, + vector &file_perms); private: vector accept; vector accept2; DefaultBase default_base; NextCheck next_check; + const State *start; map num; map eq; transchar max_eq; diff --git a/parser/libapparmor_re/hfa.h b/parser/libapparmor_re/hfa.h index 530c0c086..575b23cc8 100644 --- a/parser/libapparmor_re/hfa.h +++ b/parser/libapparmor_re/hfa.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -359,7 +360,6 @@ public: Node *root; State *nonmatching, *start; Partition states; - //vector perms_table; bool filedfa; }; diff --git a/parser/parser.h b/parser/parser.h index 885c85d45..979e67889 100644 --- a/parser/parser.h +++ b/parser/parser.h @@ -360,6 +360,7 @@ extern int features_supports_flag_signal; extern int features_supports_flag_error; extern int kernel_supports_oob; extern int kernel_supports_permstable32; +extern int kernel_supports_permstable32_v1; extern int conf_verbose; extern int conf_quiet; extern int names_only; diff --git a/parser/parser_common.c b/parser/parser_common.c index b041fa05c..1dc1640f0 100644 --- a/parser/parser_common.c +++ b/parser/parser_common.c @@ -88,6 +88,7 @@ int features_supports_flag_signal = 0; int features_supports_flag_error = 0; int kernel_supports_oob = 0; /* out of band transitions */ int kernel_supports_permstable32 = 0; /* extended permissions */ +int kernel_supports_permstable32_v1 = 0; /* extended permissions */ int conf_verbose = 0; int conf_quiet = 0; int names_only = 0; diff --git a/parser/parser_interface.c b/parser/parser_interface.c index dca49b224..c9fdd7870 100644 --- a/parser/parser_interface.c +++ b/parser/parser_interface.c @@ -417,7 +417,7 @@ void sd_serialize_xtable(std::ostringstream &buf, char **table, //fprintf(stderr, "Adding padding to xtable count %lu, min %lu\n", count, min_size); for (; count < min_size; count++) { /* fill with null strings */ - sd_write_strn(buf, "", 1, NULL); + sd_write_strn(buf, "\000", 1, NULL); } } @@ -549,20 +549,35 @@ void sd_serialize_profile(std::ostringstream &buf, Profile *profile, // fprintf(stderr, "profile %s: policy xtable\n", profile->name); // TODO: this is dummy exec make dependent on V1 sd_serialize_xtable(buf, profile->exec_table, - //??? work around - profile->policy.perms_table.size()); + kernel_supports_permstable32_v1 ? + profile->policy.perms_table.size() : 0); } sd_write_structend(buf); } /* either have a single dfa or lists of different entry types */ - sd_serialize_dfa(buf, profile->dfa.dfa, profile->dfa.size, - profile->dfa.perms_table); - if (profile->dfa.dfa) { - // fprintf(stderr, "profile %s: dfa xtable\n", profile->name); - sd_serialize_xtable(buf, profile->exec_table, - //??? work around - profile->dfa.perms_table.size()); + if (kernel_supports_permstable32_v1) { + /* special compat mode to work around verification problem */ + sd_serialize_dfa(buf, profile->policy.dfa, profile->policy.size, + profile->policy.perms_table); + sd_write_name(buf, "dfa_start"); + sd_write_uint32(buf, profile->policy.file_start); + if (profile->policy.dfa) { + // fprintf(stderr, "profile %s: policy xtable\n", profile->name); + // TODO: this is dummy exec make dependent on V1 + sd_serialize_xtable(buf, profile->exec_table, + //permstable32_v1 workaround + profile->policy.perms_table.size()); + } + } else { + sd_serialize_dfa(buf, profile->dfa.dfa, profile->dfa.size, + profile->dfa.perms_table); + if (profile->dfa.dfa) { + // fprintf(stderr, "profile %s: dfa xtable\n", profile->name); + sd_serialize_xtable(buf, profile->exec_table, + //??? work around + profile->dfa.perms_table.size()); + } } sd_write_structend(buf); } diff --git a/parser/parser_main.c b/parser/parser_main.c index 4186c7269..0f51fc62e 100644 --- a/parser/parser_main.c +++ b/parser/parser_main.c @@ -1546,7 +1546,11 @@ static bool get_kernel_features(struct aa_features **features) kernel_supports_permstable32 = aa_features_supports(*features, "policy/permstable32"); if (kernel_supports_permstable32) { - //fprintf(stderr, "kernel supports prompt\n"); + fprintf(stderr, "kernel supports prompt\n"); + } + kernel_supports_permstable32_v1 = aa_features_supports(*features, "policy/permstable32/1"); + if (kernel_supports_permstable32_v1) { + fprintf(stderr, "kernel supports prompt\n"); } if (!kernel_supports_diff_encode) /* clear diff_encode because it is not supported */ diff --git a/parser/parser_regex.c b/parser/parser_regex.c index 65c34f0e4..a1c208de4 100644 --- a/parser/parser_regex.c +++ b/parser/parser_regex.c @@ -572,8 +572,11 @@ build: /* xmatch doesn't use file dfa exec mode bits NOT the owner * conditional and for just MAY_EXEC can be processed as * none file perms + * + * we don't need to build xmatch for buggy permstable32_v1 + * so don't */ - prof->xmatch = rules->create_dfa(&prof->xmatch_size, &prof->xmatch_len, prof->xmatch_perms_table, parseopts, false, kernel_supports_permstable32); + prof->xmatch = rules->create_dfablob(&prof->xmatch_size, &prof->xmatch_len, prof->xmatch_perms_table, parseopts, false, kernel_supports_permstable32 && !kernel_supports_permstable32_v1); delete rules; if (!prof->xmatch) return FALSE; @@ -771,11 +774,16 @@ int process_profile_regex(Profile *prof) if (!post_process_entries(prof)) goto out; - if (prof->dfa.rules->rule_count > 0) { + /* under permstable32_v1 we weld file and policydb together, so + * don't create the file blob here + */ + if (prof->dfa.rules->rule_count > 0 && !kernel_supports_permstable32_v1) { int xmatch_len = 0; //fprintf(stderr, "Creating file DFA %d\n", kernel_supports_permstable32); - prof->dfa.dfa = prof->dfa.rules->create_dfa(&prof->dfa.size, - &xmatch_len, prof->dfa.perms_table, parseopts, true, kernel_supports_permstable32); + prof->dfa.dfa = prof->dfa.rules->create_dfablob(&prof->dfa.size, + &xmatch_len, prof->dfa.perms_table, + parseopts, true, + kernel_supports_permstable32); delete prof->dfa.rules; prof->dfa.rules = NULL; if (!prof->dfa.dfa) @@ -989,6 +997,7 @@ static const char *mediates_ns = CLASS_STR(AA_CLASS_NS); static const char *mediates_posix_mqueue = CLASS_STR(AA_CLASS_POSIX_MQUEUE); static const char *mediates_sysv_mqueue = CLASS_STR(AA_CLASS_SYSV_MQUEUE); static const char *mediates_io_uring = CLASS_STR(AA_CLASS_IO_URING); +static const char *deny_file = ".*"; int process_profile_policydb(Profile *prof) { @@ -1046,10 +1055,42 @@ int process_profile_policydb(Profile *prof) goto out; } - if (prof->policy.rules->rule_count > 0) { + if (kernel_supports_permstable32_v1) { + // MUST have file and policy + // This requires file rule processing happen first + if (!prof->dfa.rules->rule_count) { + // add null dfa + if (!prof->dfa.rules->add_rule(deny_file, true, AA_MAY_READ, 0, parseopts)) + goto out; + } + if (!prof->policy.rules->rule_count) { + if (!prof->policy.rules->add_rule(mediates_file, true, AA_MAY_READ, 0, parseopts)) + goto out; + } int xmatch_len = 0; - prof->policy.dfa = prof->policy.rules->create_dfa(&prof->policy.size, - &xmatch_len, prof->policy.perms_table, parseopts, false, kernel_supports_permstable32); + prof->policy.dfa = prof->policy.rules->create_welded_dfablob( + prof->dfa.rules, + &prof->policy.size, + &xmatch_len, + &prof->policy.file_start, + prof->policy.perms_table, parseopts, + kernel_supports_permstable32_v1); + delete prof->policy.rules; + delete prof->dfa.rules; + prof->policy.rules = NULL; + prof->dfa.rules = NULL; + if (!prof->policy.dfa) + goto out; + } else if (prof->policy.rules->rule_count > 0 && + // yes not needed as covered above, just making sure + // this doesn't get messed up in the future + !kernel_supports_permstable32_v1) { + int xmatch_len = 0; + prof->policy.dfa = prof->policy.rules->create_dfablob(&prof->policy.size, + &xmatch_len, + prof->policy.perms_table, + parseopts, false, + kernel_supports_permstable32); delete prof->policy.rules; prof->policy.rules = NULL; diff --git a/parser/profile.h b/parser/profile.h index fa4ceadb9..59bb16475 100644 --- a/parser/profile.h +++ b/parser/profile.h @@ -339,6 +339,7 @@ struct dfa_stuff { aare_rules *rules; void *dfa; size_t size; + size_t file_start; /* special start in welded dfa */ vector perms_table; dfa_stuff(void): rules(NULL), dfa(NULL), size(0) { } }; From 48b727b88abf446c5f535f010b35956416891736 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Thu, 6 Apr 2023 01:28:31 -0700 Subject: [PATCH 06/17] parser: frontend carry use of prompt rules flag on profile add a flag to make it easy to check if a profile uses prompt rules. Signed-off-by: John Johansen --- parser/profile.cc | 2 ++ parser/profile.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/parser/profile.cc b/parser/profile.cc index 5c96e65a2..71f423b0f 100644 --- a/parser/profile.cc +++ b/parser/profile.cc @@ -161,6 +161,8 @@ void add_entry_to_policy(Profile *prof, struct cod_entry *entry) { entry->next = prof->entries; prof->entries = entry; + if (entry->rule_mode == RULE_PROMPT) + prof->uses_prompt_rules = true; } static int add_named_transition(Profile *prof, struct cod_entry *entry) diff --git a/parser/profile.h b/parser/profile.h index 59bb16475..0e8b67b15 100644 --- a/parser/profile.h +++ b/parser/profile.h @@ -346,6 +346,7 @@ struct dfa_stuff { class Profile { public: + bool uses_prompt_rules; char *ns; char *name; char *attachment; @@ -379,6 +380,7 @@ public: Profile(void) { + uses_prompt_rules = false; ns = name = attachment = NULL; altnames = NULL; xmatch = NULL; From 5c2bd207207c0f57f9daaa55a3fef6ccac10ac40 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Sun, 23 Apr 2023 19:03:38 -0700 Subject: [PATCH 07/17] parser: pass rule mode prompt through to backend Signed-off-by: John Johansen --- parser/af_unix.cc | 20 ++-- parser/dbus.cc | 6 +- parser/io_uring.cc | 4 +- parser/libapparmor_re/aare_rules.cc | 13 ++- parser/libapparmor_re/aare_rules.h | 22 +++-- parser/libapparmor_re/expr-tree.h | 6 ++ parser/libapparmor_re/hfa.cc | 25 +++-- parser/libapparmor_re/hfa.h | 19 +++- parser/libapparmor_re/policy_compat.cc | 47 +++++----- parser/libapparmor_re/policy_compat.h | 6 +- parser/mount.cc | 18 ++-- parser/mqueue.cc | 8 +- parser/network.cc | 12 +-- parser/parser_regex.c | 122 ++++++++++++++++++++----- parser/ptrace.cc | 5 +- parser/signal.cc | 5 +- parser/userns.cc | 6 +- 17 files changed, 227 insertions(+), 117 deletions(-) diff --git a/parser/af_unix.cc b/parser/af_unix.cc index 4e3b97077..a098ee7f3 100644 --- a/parser/af_unix.cc +++ b/parser/af_unix.cc @@ -344,7 +344,7 @@ int unix_rule::gen_policy_re(Profile &prof) write_to_prot(buffer); if ((mask & AA_NET_CREATE) && !has_peer_conds()) { buf = buffer.str(); - if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, + if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode, map_perms(AA_NET_CREATE), map_perms(audit == AUDIT_FORCE ? AA_NET_CREATE : 0), parseopts)) @@ -369,7 +369,7 @@ int unix_rule::gen_policy_re(Profile &prof) tmp << "\\x00"; buf = tmp.str(); - if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, + if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode, map_perms(AA_NET_BIND), map_perms(audit == AUDIT_FORCE ? AA_NET_BIND : 0), parseopts)) @@ -394,7 +394,7 @@ int unix_rule::gen_policy_re(Profile &prof) AA_LOCAL_NET_PERMS & ~AA_LOCAL_NET_CMD; if (mask & local_mask) { buf = buffer.str(); - if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, + if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode, map_perms(mask & local_mask), map_perms(audit == AUDIT_FORCE ? mask & local_mask : 0), parseopts)) @@ -408,7 +408,7 @@ int unix_rule::gen_policy_re(Profile &prof) /* TODO: backlog conditional: for now match anything*/ tmp << ".."; buf = tmp.str(); - if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, + if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode, map_perms(AA_NET_LISTEN), map_perms(audit == AUDIT_FORCE ? AA_NET_LISTEN : 0), parseopts)) @@ -421,10 +421,12 @@ int unix_rule::gen_policy_re(Profile &prof) /* TODO: sockopt conditional: for now match anything */ tmp << ".."; buf = tmp.str(); - if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, - map_perms(mask & AA_NET_OPT), - map_perms(audit == AUDIT_FORCE ? AA_NET_OPT : 0), - parseopts)) + if (!prof.policy.rules->add_rule(buf.c_str(), + rule_mode, + map_perms(mask & AA_NET_OPT), + map_perms(audit == AUDIT_FORCE ? + AA_NET_OPT : 0), + parseopts)) goto fail; } mask &= ~AA_LOCAL_NET_PERMS | AA_NET_ACCEPT; @@ -442,7 +444,7 @@ int unix_rule::gen_policy_re(Profile &prof) goto fail; buf = buffer.str(); - if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, map_perms(perms & AA_PEER_NET_PERMS), map_perms(audit == AUDIT_FORCE ? perms & AA_PEER_NET_PERMS : 0), parseopts)) + if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode, map_perms(perms & AA_PEER_NET_PERMS), map_perms(audit == AUDIT_FORCE ? perms & AA_PEER_NET_PERMS : 0), parseopts)) goto fail; } diff --git a/parser/dbus.cc b/parser/dbus.cc index fc028de6c..163d8c396 100644 --- a/parser/dbus.cc +++ b/parser/dbus.cc @@ -274,20 +274,20 @@ int dbus_rule::gen_policy_re(Profile &prof) } if (perms & AA_DBUS_BIND) { - if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms & AA_DBUS_BIND, + if (!prof.policy.rules->add_rule_vec(rule_mode, perms & AA_DBUS_BIND, audit == AUDIT_FORCE ? perms & AA_DBUS_BIND : 0, 2, vec, parseopts, false)) goto fail; } if (perms & (AA_DBUS_SEND | AA_DBUS_RECEIVE)) { - if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, + if (!prof.policy.rules->add_rule_vec(rule_mode, perms & (AA_DBUS_SEND | AA_DBUS_RECEIVE), audit == AUDIT_FORCE ? perms & (AA_DBUS_SEND | AA_DBUS_RECEIVE) : 0, 6, vec, parseopts, false)) goto fail; } if (perms & AA_DBUS_EAVESDROP) { - if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, + if (!prof.policy.rules->add_rule_vec(rule_mode, perms & AA_DBUS_EAVESDROP, audit == AUDIT_FORCE ? perms & AA_DBUS_EAVESDROP : 0, 1, vec, parseopts, false)) diff --git a/parser/io_uring.cc b/parser/io_uring.cc index 3425ea36c..687b6d08c 100644 --- a/parser/io_uring.cc +++ b/parser/io_uring.cc @@ -122,14 +122,14 @@ int io_uring_rule::gen_policy_re(Profile &prof) } if (perms & AA_VALID_IO_URING_PERMS) { - if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, perms, + if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode, perms, audit == AUDIT_FORCE ? perms : 0, parseopts)) goto fail; if (perms & AA_IO_URING_OVERRIDE_CREDS) { buf = buffer.str(); /* update buf to have label */ - if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, + if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode, perms, audit == AUDIT_FORCE ? perms : 0, parseopts)) goto fail; diff --git a/parser/libapparmor_re/aare_rules.cc b/parser/libapparmor_re/aare_rules.cc index 75883c7e7..08e8e6fb9 100644 --- a/parser/libapparmor_re/aare_rules.cc +++ b/parser/libapparmor_re/aare_rules.cc @@ -44,10 +44,10 @@ aare_rules::~aare_rules(void) expr_map.clear(); } -bool aare_rules::add_rule(const char *rule, int deny, uint32_t perms, +bool aare_rules::add_rule(const char *rule, rule_mode_t mode, uint32_t perms, uint32_t audit, optflags const &opts) { - return add_rule_vec(deny, perms, audit, 1, &rule, opts, false); + return add_rule_vec(mode, perms, audit, 1, &rule, opts, false); } void aare_rules::add_to_rules(Node *tree, Node *perms) @@ -71,7 +71,7 @@ static Node *cat_with_oob_separator(Node *l, Node *r) return new CatNode(new CatNode(l, new CharNode(transchar(-1, true))), r); } -bool aare_rules::add_rule_vec(int deny, uint32_t perms, uint32_t audit, +bool aare_rules::add_rule_vec(rule_mode_t mode, uint32_t perms, uint32_t audit, int count, const char **rulev, optflags const &opts, bool oob) { @@ -107,7 +107,7 @@ bool aare_rules::add_rule_vec(int deny, uint32_t perms, uint32_t audit, if (reverse) flip_tree(tree); - accept = unique_perms.insert(deny, perms, audit, exact_match); + accept = unique_perms.insert(mode, perms, audit, exact_match); if (opts.dump & DUMP_DFA_RULE_EXPR) { const char *separator; @@ -123,8 +123,11 @@ bool aare_rules::add_rule_vec(int deny, uint32_t perms, uint32_t audit, } cerr << " -> "; tree->dump(cerr); - if (deny) + // TODO: split out from prefixes class + if (mode == RULE_DENY) cerr << " deny"; + else if (mode == RULE_PROMPT) + cerr << " prompt"; cerr << " (0x" << hex << perms <<"/" << audit << dec << ")"; accept->dump(cerr); cerr << "\n\n"; diff --git a/parser/libapparmor_re/aare_rules.h b/parser/libapparmor_re/aare_rules.h index 8a22afb89..ca24c7eb2 100644 --- a/parser/libapparmor_re/aare_rules.h +++ b/parser/libapparmor_re/aare_rules.h @@ -31,17 +31,18 @@ #include "expr-tree.h" #include "../immunix.h" #include "../perms.h" +#include "../rule.h" class UniquePerm { public: - bool deny; + rule_mode_t mode; bool exact_match; uint32_t perms; uint32_t audit; bool operator<(UniquePerm const &rhs)const { - if (deny == rhs.deny) { + if (mode >= rhs.mode) { if (exact_match == rhs.exact_match) { if (perms == rhs.perms) return audit < rhs.audit; @@ -49,7 +50,7 @@ public: } return exact_match; } - return deny; + return true; // mode < rhs.mode } }; @@ -70,15 +71,17 @@ public: nodes.clear(); } - Node *insert(bool deny, uint32_t perms, uint32_t audit, + Node *insert(rule_mode_t mode, uint32_t perms, uint32_t audit, bool exact_match) { - UniquePerm tmp = { deny, exact_match, perms, audit }; + UniquePerm tmp = { mode, exact_match, perms, audit }; iterator res = nodes.find(tmp); if (res == nodes.end()) { Node *node; - if (deny) + if (mode == RULE_DENY) node = new DenyMatchFlag(perms, audit); + else if (mode == RULE_PROMPT) + node = new PromptMatchFlag(perms, audit); else if (exact_match) node = new ExactMatchFlag(perms, audit); else @@ -106,10 +109,11 @@ class aare_rules { aare_rules(int reverse): root(NULL), unique_perms(), expr_map(), reverse(reverse), rule_count(0) { }; ~aare_rules(); - bool add_rule(const char *rule, int deny, uint32_t perms, + bool add_rule(const char *rule, rule_mode_t mode, uint32_t perms, uint32_t audit, optflags const &opts); - bool add_rule_vec(int deny, uint32_t perms, uint32_t audit, int count, - const char **rulev, optflags const &opts, bool oob); + bool add_rule_vec(rule_mode_t mode, uint32_t perms, uint32_t audit, + int count, const char **rulev, optflags const &opts, + bool oob); bool append_rule(const char *rule, bool oob, bool with_perm, optflags const &opts); CHFA *create_chfa(int *min_match_len, vector &perms_table, diff --git a/parser/libapparmor_re/expr-tree.h b/parser/libapparmor_re/expr-tree.h index 95d68f8c7..8341b4ff9 100644 --- a/parser/libapparmor_re/expr-tree.h +++ b/parser/libapparmor_re/expr-tree.h @@ -911,6 +911,12 @@ public: } }; +class PromptMatchFlag: public MatchFlag { +public: + PromptMatchFlag(uint32_t prompt, uint32_t audit): MatchFlag(prompt, audit) {} +}; + + /* Traverse the syntax tree depth-first in an iterator-like manner. */ class depth_first_traversal { stackpos; diff --git a/parser/libapparmor_re/hfa.cc b/parser/libapparmor_re/hfa.cc index 323f3236a..75e43e36a 100644 --- a/parser/libapparmor_re/hfa.cc +++ b/parser/libapparmor_re/hfa.cc @@ -1076,8 +1076,10 @@ void DFA::dump(ostream & os) for (Partition::iterator i = states.begin(); i != states.end(); i++) { if (*i == start || (*i)->perms.is_accept()) { os << **i; - if (*i == start) - os << " <== (allow/deny/audit/quiet)"; + if (*i == start) { + os << " <== "; + (*i)->perms.dump_header(os); + } if ((*i)->perms.is_accept()) (*i)->perms.dump(os); os << "\n"; @@ -1304,16 +1306,17 @@ void DFA::apply_equivalence_classes(map &eq) void DFA::compute_perms_table_ent(State *state, size_t pos, vector &perms_table) { - uint32_t accept1, accept2; + uint32_t accept1, accept2, accept3; - state->map_perms_to_accept(accept1, accept2); + // until front end doesn't map the way it does + state->map_perms_to_accept(accept1, accept2, accept3); if (filedfa) { state->idx = pos * 2; - perms_table[pos*2] = compute_fperms_user(accept1, accept2); - perms_table[pos*2 + 1] = compute_fperms_other(accept1, accept2); + perms_table[pos*2] = compute_fperms_user(accept1, accept2, accept3); + perms_table[pos*2 + 1] = compute_fperms_other(accept1, accept2, accept3); } else { state->idx = pos; - perms_table[pos] = compute_perms_entry(accept1, accept2); + perms_table[pos] = compute_perms_entry(accept1, accept2, accept3); } } @@ -1383,6 +1386,7 @@ int accept_perms(NodeVec *state, perms_t &perms, bool filedfa) { int error = 0; uint32_t exact_match_allow = 0; + uint32_t exact_match_prompt = 0; uint32_t exact_audit = 0; perms.clear(); @@ -1405,6 +1409,9 @@ int accept_perms(NodeVec *state, perms_t &perms, bool filedfa) } else if (match->is_type(NODE_TYPE_DENYMATCHFLAG)) { perms.deny |= match->flag; perms.quiet |= match->audit; + } else if (dynamic_cast(match)) { + perms.prompt |= match->flag; + perms.audit |= match->audit; } else { if (filedfa && !is_merged_x_consistent(perms.allow, match->flag)) error = 1; @@ -1415,9 +1422,11 @@ int accept_perms(NodeVec *state, perms_t &perms, bool filedfa) if (filedfa) { perms.allow |= exact_match_allow & ~(ALL_AA_EXEC_TYPE); + perms.prompt |= exact_match_prompt & ~(ALL_AA_EXEC_TYPE); perms.audit |= exact_audit & ~(ALL_AA_EXEC_TYPE); } else { perms.allow |= exact_match_allow; + perms.prompt |= exact_match_prompt; perms.audit |= exact_audit; } if (exact_match_allow & AA_USER_EXEC) { @@ -1438,6 +1447,8 @@ int accept_perms(NodeVec *state, perms_t &perms, bool filedfa) perms.allow &= ~perms.deny; perms.quiet &= perms.deny; + perms.prompt &= ~perms.deny; + perms.prompt &= ~perms.allow; if (error) fprintf(stderr, "profile has merged rule with conflicting x modifiers\n"); diff --git a/parser/libapparmor_re/hfa.h b/parser/libapparmor_re/hfa.h index 575b23cc8..2c5ab15d6 100644 --- a/parser/libapparmor_re/hfa.h +++ b/parser/libapparmor_re/hfa.h @@ -51,16 +51,20 @@ class perms_t { public: perms_t(void): allow(0), deny(0), audit(0), quiet(0), exact(0) { }; - bool is_accept(void) { return (allow | audit | quiet); } + bool is_accept(void) { return (allow | prompt | audit | quiet); } + void dump_header(ostream &os) + { + os << "(allow/deny/prompt/audit/quiet)"; + } void dump(ostream &os) { os << " (0x " << hex - << allow << "/" << deny << "/" << audit << "/" << quiet + << allow << "/" << deny << "/" << "/" << prompt << "/" << audit << "/" << quiet << ')' << dec; } - void clear(void) { allow = deny = audit = quiet = 0; } + void clear(void) { allow = deny = prompt = audit = quiet = 0; } void add(perms_t &rhs, bool filedfa) { deny |= rhs.deny; @@ -97,6 +101,7 @@ public: allow = (allow | (rhs.allow & ~ALL_AA_EXEC_TYPE)); else allow |= rhs.allow; + prompt |= rhs.prompt; audit |= rhs.audit; quiet = (quiet | rhs.quiet); @@ -114,6 +119,7 @@ public: { if (deny) { allow &= ~deny; + prompt &= ~deny; quiet &= deny; deny = 0; return !is_accept(); @@ -127,12 +133,14 @@ public: return allow < rhs.allow; if (deny < rhs.deny) return deny < rhs.deny; + if (prompt < rhs.prompt) + return prompt < rhs.prompt; if (audit < rhs.audit) return audit < rhs.audit; return quiet < rhs.quiet; } - uint32_t allow, deny, audit, quiet, exact; + uint32_t allow, deny, prompt, audit, quiet, exact; }; int accept_perms(NodeVec *state, perms_t &perms, bool filedfa); @@ -250,10 +258,11 @@ public: void flatten_relative(State *, int upper_bound); int apply_and_clear_deny(void) { return perms.apply_and_clear_deny(); } - void map_perms_to_accept(uint32_t &accept1, uint32_t &accept2) + void map_perms_to_accept(uint32_t &accept1, uint32_t &accept2, uint32_t &accept3) { accept1 = perms.allow; accept2 = PACK_AUDIT_CTL(perms.audit, perms.quiet & perms.deny); + accept3 = perms.prompt; } int label; diff --git a/parser/libapparmor_re/policy_compat.cc b/parser/libapparmor_re/policy_compat.cc index 8213109a8..5b8106647 100644 --- a/parser/libapparmor_re/policy_compat.cc +++ b/parser/libapparmor_re/policy_compat.cc @@ -64,23 +64,23 @@ static uint32_t dfa_map_xindex(uint16_t mask) /* * map old dfa inline permissions to new format */ -#define dfa_user_allow(accept1, accept2) (((accept1) & 0x7f) | \ +#define dfa_user_allow(accept1) (((accept1) & 0x7f) | \ ((accept1) & 0x80000000)) -#define dfa_user_xbits(accept1, accept2) (((accept1) >> 7) & 0x7f) +#define dfa_user_xbits(accept1) (((accept1) >> 7) & 0x7f) #define dfa_user_audit(accept1, accept2) ((accept2) & 0x7f) #define dfa_user_quiet(accept1, accept2) (((accept2) >> 7) & 0x7f) -#define dfa_user_xindex(accept1, accept2) \ +#define dfa_user_xindex(accept1) \ (dfa_map_xindex(accept1 & 0x3fff)) -#define dfa_other_allow(accept1, accept2) ((((accept1) >> 14) & \ +#define dfa_other_allow(accept1) ((((accept1) >> 14) & \ 0x7f) | \ ((accept1) & 0x80000000)) -#define dfa_other_xbits(accept1, accept2) \ +#define dfa_other_xbits(accept1) \ ((((accept1) >> 7) >> 14) & 0x7f) #define dfa_other_audit(accept1, accept2) (((accept2) >> 14) & 0x7f) #define dfa_other_quiet(accept1, accept2) \ ((((accept2) >> 7) >> 14) & 0x7f) -#define dfa_other_xindex(accept1, accept2) \ +#define dfa_other_xindex(accept1) \ dfa_map_xindex((accept1 >> 14) & 0x3fff) /** @@ -122,39 +122,33 @@ static void compute_fperms_allow(struct aa_perms *perms, uint32_t accept1) perms->allow |= AA_MAY_ONEXEC; } -struct aa_perms compute_fperms_user(uint32_t accept1, uint32_t accept2) +struct aa_perms compute_fperms_user(uint32_t accept1, uint32_t accept2, + uint32_t accept3) { struct aa_perms perms = { }; - perms.allow = map_old_perms(dfa_user_allow(accept1, accept2)); + perms.allow = map_old_perms(dfa_user_allow(accept1)); + perms.prompt = map_old_perms(dfa_user_allow(accept3)); perms.audit = map_old_perms(dfa_user_audit(accept1, accept2)); perms.quiet = map_old_perms(dfa_user_quiet(accept1, accept2)); - perms.xindex = dfa_user_xindex(accept1, accept2); + perms.xindex = dfa_user_xindex(accept1); compute_fperms_allow(&perms, accept1); - // prompt being carried as audit need to change - perms.allow &= ~perms.prompt; - if (perms.allow & perms.prompt) { - //std::cerr << "user allow & prompt\n"; - } return perms; } -struct aa_perms compute_fperms_other(uint32_t accept1, uint32_t accept2) +struct aa_perms compute_fperms_other(uint32_t accept1, uint32_t accept2, + uint32_t accept3) { struct aa_perms perms = { }; - perms.allow = map_old_perms(dfa_other_allow(accept1, accept2)); + perms.allow = map_old_perms(dfa_other_allow(accept1)); + perms.prompt = map_old_perms(dfa_other_allow(accept3)); perms.audit = map_old_perms(dfa_other_audit(accept1, accept2)); perms.quiet = map_old_perms(dfa_other_quiet(accept1, accept2)); - perms.xindex = dfa_other_xindex(accept1, accept2); + perms.xindex = dfa_other_xindex(accept1); compute_fperms_allow(&perms, accept1); - // prompt being carried as audit need to change - perms.allow &= ~perms.prompt; - if (perms.allow & perms.prompt) { - std::cerr << "other allow & prompt\n"; - } return perms; } @@ -171,13 +165,15 @@ static uint32_t map_xbits(uint32_t x) ((x & 0x7e) << 9); } -struct aa_perms compute_perms_entry(uint32_t accept1, uint32_t accept2) +struct aa_perms compute_perms_entry(uint32_t accept1, uint32_t accept2, + uint32_t accept3) // don't need to worry about version internally within the parser // uint32_t version) { struct aa_perms perms = { }; - perms.allow = dfa_user_allow(accept1, accept2); + perms.allow = dfa_user_allow(accept1); + perms.prompt = dfa_user_allow(accept3); perms.audit = dfa_user_audit(accept1, accept2); perms.quiet = dfa_user_quiet(accept1, accept2); @@ -192,7 +188,7 @@ struct aa_perms compute_perms_entry(uint32_t accept1, uint32_t accept2) * Unfortunately there is no way to force auditing on the * perms represented by the xbits */ - perms.allow |= map_other(dfa_other_allow(accept1, accept2)); + perms.allow |= map_other(dfa_other_allow(accept1)); // v9 encoding never rolled out. AA_MAY_LOCK needed to fix // non fs unix locking see kernel commit // 1cf26c3d2c4c apparmor: fix apparmor mediating locking non-fs unix sockets @@ -205,6 +201,7 @@ struct aa_perms compute_perms_entry(uint32_t accept1, uint32_t accept2) * for v5-v9 perm mapping in the policydb, the other set is used * to extend the general perm set */ + perms.prompt |= map_other(dfa_other_allow(accept3)); perms.audit |= map_other(dfa_other_audit(accept1, accept2)); perms.quiet |= map_other(dfa_other_quiet(accept1, accept2)); //if (VERSION_GT(version, v8)) diff --git a/parser/libapparmor_re/policy_compat.h b/parser/libapparmor_re/policy_compat.h index f19c14b20..7563c41bf 100644 --- a/parser/libapparmor_re/policy_compat.h +++ b/parser/libapparmor_re/policy_compat.h @@ -18,8 +18,8 @@ #ifndef __AA_POLICY_COMPAT_H #define __AA_POLICY_COMPAT_H -struct aa_perms compute_fperms_user(uint32_t accept1, uint32_t accept2); -struct aa_perms compute_fperms_other(uint32_t accept1, uint32_t accept2); -struct aa_perms compute_perms_entry(uint32_t accept1, uint32_t accept2); +struct aa_perms compute_fperms_user(uint32_t accept1, uint32_t accept2, uint32_t accept3); +struct aa_perms compute_fperms_other(uint32_t accept1, uint32_t accept2, uint32_t accept3); +struct aa_perms compute_perms_entry(uint32_t accept1, uint32_t accept2, uint32_t accept3); #endif /* __AA_POLICY_COMPAT_H */ diff --git a/parser/mount.cc b/parser/mount.cc index 31b43ef6d..bbd2bab12 100644 --- a/parser/mount.cc +++ b/parser/mount.cc @@ -797,7 +797,7 @@ int mnt_rule::gen_policy_remount(Profile &prof, int &count, * if a data match is required this only has AA_MATCH_CONT perms * else it has full perms */ - if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, tmpperms, tmpaudit, 4, + if (!prof.policy.rules->add_rule_vec(rule_mode, tmpperms, tmpaudit, 4, vec, parseopts, false)) goto fail; count++; @@ -808,7 +808,7 @@ int mnt_rule::gen_policy_remount(Profile &prof, int &count, if (!build_mnt_opts(optsbuf, opts)) goto fail; vec[4] = optsbuf.c_str(); - if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, + if (!prof.policy.rules->add_rule_vec(rule_mode, perms, (audit == AUDIT_FORCE ? perms : 0), 5, vec, parseopts, false)) goto fail; @@ -850,7 +850,7 @@ int mnt_rule::gen_policy_bind_mount(Profile &prof, int &count, opt_flags & MS_BIND_FLAGS)) goto fail; vec[3] = flagsbuf; - if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, + if (!prof.policy.rules->add_rule_vec(rule_mode, perms, audit == AUDIT_FORCE ? perms : 0, 4, vec, parseopts, false)) goto fail; @@ -907,7 +907,7 @@ int mnt_rule::gen_policy_change_mount_type(Profile &prof, int &count, opt_flags & MS_MAKE_FLAGS)) goto fail; vec[3] = flagsbuf; - if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, + if (!prof.policy.rules->add_rule_vec(rule_mode, perms, audit == AUDIT_FORCE ? perms : 0, 4, vec, parseopts, false)) goto fail; @@ -950,7 +950,7 @@ int mnt_rule::gen_policy_move_mount(Profile &prof, int &count, opt_flags & MS_MOVE_FLAGS)) goto fail; vec[3] = flagsbuf; - if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, + if (!prof.policy.rules->add_rule_vec(rule_mode, perms, audit == AUDIT_FORCE ? perms : 0, 4, vec, parseopts, false)) goto fail; @@ -1002,7 +1002,7 @@ int mnt_rule::gen_policy_new_mount(Profile &prof, int &count, tmpaudit = audit == AUDIT_FORCE ? perms : 0; } /* rule for match without required data || data MATCH_CONT */ - if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, tmpperms, tmpaudit, 4, + if (!prof.policy.rules->add_rule_vec(rule_mode, tmpperms, tmpaudit, 4, vec, parseopts, false)) goto fail; count++; @@ -1013,7 +1013,7 @@ int mnt_rule::gen_policy_new_mount(Profile &prof, int &count, if (!build_mnt_opts(optsbuf, opts)) goto fail; vec[4] = optsbuf.c_str(); - if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, + if (!prof.policy.rules->add_rule_vec(rule_mode, perms, audit == AUDIT_FORCE ? perms : 0, 5, vec, parseopts, false)) goto fail; @@ -1105,7 +1105,7 @@ int mnt_rule::gen_policy_re(Profile &prof) if (!convert_entry(mntbuf, mnt_point)) goto fail; vec[0] = mntbuf.c_str(); - if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, + if (!prof.policy.rules->add_rule_vec(rule_mode, perms, (audit == AUDIT_FORCE ? perms : 0), 1, vec, parseopts, false)) goto fail; @@ -1120,7 +1120,7 @@ int mnt_rule::gen_policy_re(Profile &prof) if (!clear_and_convert_entry(devbuf, device)) goto fail; vec[1] = devbuf.c_str(); - if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, + if (!prof.policy.rules->add_rule_vec(rule_mode, perms, (audit == AUDIT_FORCE ? perms : 0), 2, vec, parseopts, false)) goto fail; diff --git a/parser/mqueue.cc b/parser/mqueue.cc index 4d91011ef..8166110c3 100644 --- a/parser/mqueue.cc +++ b/parser/mqueue.cc @@ -231,10 +231,10 @@ int mqueue_rule::gen_policy_re(Profile &prof) /* store perms at name match so label doesn't need * to be checked */ - if (!label && !prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, map_mqueue_perms(perms), audit == AUDIT_FORCE ? map_mqueue_perms(perms) : 0, 1, vec, parseopts, false)) + if (!label && !prof.policy.rules->add_rule_vec(rule_mode, map_mqueue_perms(perms), audit == AUDIT_FORCE ? map_mqueue_perms(perms) : 0, 1, vec, parseopts, false)) goto fail; /* also provide label match with perm */ - if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, map_mqueue_perms(perms), audit == AUDIT_FORCE ? map_mqueue_perms(perms) : 0, size, vec, parseopts, false)) + if (!prof.policy.rules->add_rule_vec(rule_mode, map_mqueue_perms(perms), audit == AUDIT_FORCE ? map_mqueue_perms(perms) : 0, size, vec, parseopts, false)) goto fail; } } @@ -266,10 +266,10 @@ int mqueue_rule::gen_policy_re(Profile &prof) } if (perms & AA_VALID_SYSV_MQ_PERMS) { - if (!label && !prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, map_mqueue_perms(perms), audit == AUDIT_FORCE ? map_mqueue_perms(perms) : 0, 1, vec, parseopts, false)) + if (!label && !prof.policy.rules->add_rule_vec(rule_mode, map_mqueue_perms(perms), audit == AUDIT_FORCE ? map_mqueue_perms(perms) : 0, 1, vec, parseopts, false)) goto fail; /* also provide label match with perm */ - if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, map_mqueue_perms(perms), audit == AUDIT_FORCE ? map_mqueue_perms(perms) : 0, size, vec, parseopts, false)) + if (!prof.policy.rules->add_rule_vec(rule_mode, map_mqueue_perms(perms), audit == AUDIT_FORCE ? map_mqueue_perms(perms) : 0, size, vec, parseopts, false)) goto fail; } } diff --git a/parser/network.cc b/parser/network.cc index 939f2112f..55bf17170 100644 --- a/parser/network.cc +++ b/parser/network.cc @@ -697,7 +697,7 @@ bool network_rule::gen_ip_conds(Profile &prof, std::list &st buf = oss.str(); /* AA_CONT_MATCH mapping (cond_perms) only applies to perms, not audit */ - if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, cond_perms, + if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode, cond_perms, dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms) : 0, parseopts)) return false; @@ -710,7 +710,7 @@ bool network_rule::gen_ip_conds(Profile &prof, std::list &st oss << "\\x00"; /* null transition */ buf = oss.str(); - if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, cond_perms, + if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode, cond_perms, dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms) : 0, parseopts)) return false; @@ -735,7 +735,7 @@ bool network_rule::gen_net_rule(Profile &prof, u16 family, unsigned int type_mas if (!features_supports_inet || (family != AF_INET && family != AF_INET6)) { buf = buffer.str(); - if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, map_perms(perms), + if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode, map_perms(perms), dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms) : 0, parseopts)) return false; @@ -745,7 +745,7 @@ bool network_rule::gen_net_rule(Profile &prof, u16 family, unsigned int type_mas buf = buffer.str(); /* create perms need to be generated excluding the rest of the perms */ if (perms & AA_NET_CREATE) { - if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, map_perms(perms & AA_NET_CREATE) | (AA_CONT_MATCH << 1), + if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode, map_perms(perms & AA_NET_CREATE) | (AA_CONT_MATCH << 1), dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms & AA_NET_CREATE) : 0, parseopts)) return false; @@ -797,7 +797,7 @@ bool network_rule::gen_net_rule(Profile &prof, u16 family, unsigned int type_mas /* length of queue allowed - not used for now */ listen_buffer << ".."; buf = listen_buffer.str(); - if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, map_perms(perms), + if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode, map_perms(perms), dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms) : 0, parseopts)) return false; @@ -816,7 +816,7 @@ bool network_rule::gen_net_rule(Profile &prof, u16 family, unsigned int type_mas /* socket mapping - not used for now */ opt_buffer << ".."; buf = opt_buffer.str(); - if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, map_perms(perms), + if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode, map_perms(perms), dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms) : 0, parseopts)) return false; diff --git a/parser/parser_regex.c b/parser/parser_regex.c index a1c208de4..b6600266d 100644 --- a/parser/parser_regex.c +++ b/parser/parser_regex.c @@ -507,7 +507,8 @@ static int process_profile_name_xmatch(Profile *prof) aare_rules *rules = new aare_rules(); if (!rules) return FALSE; - if (!rules->add_rule(tbuf.c_str(), 0, AA_MAY_EXEC, 0, parseopts)) { + if (!rules->add_rule(tbuf.c_str(), RULE_ALLOW, + AA_MAY_EXEC, 0, parseopts)) { delete rules; return FALSE; } @@ -520,7 +521,9 @@ static int process_profile_name_xmatch(Profile *prof) ptype = convert_aaregex_to_pcre(alt->name, 0, glob_default, tbuf, &len); - if (!rules->add_rule(tbuf.c_str(), 0, AA_MAY_EXEC, 0, parseopts)) { + if (!rules->add_rule(tbuf.c_str(), + RULE_ALLOW, AA_MAY_EXEC, + 0, parseopts)) { delete rules; return FALSE; } @@ -642,14 +645,14 @@ static int process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry) if (entry->rule_mode == RULE_DENY) { if ((entry->perms & ~AA_LINK_BITS) && !is_change_profile_perms(entry->perms) && - !dfarules->add_rule(tbuf.c_str(), entry->rule_mode == RULE_DENY, + !dfarules->add_rule(tbuf.c_str(), entry->rule_mode, entry->perms & ~(AA_LINK_BITS | AA_CHANGE_PROFILE), entry->audit == AUDIT_FORCE ? entry->perms & ~(AA_LINK_BITS | AA_CHANGE_PROFILE) : 0, parseopts)) return FALSE; } else if (!is_change_profile_perms(entry->perms)) { if (!dfarules->add_rule(tbuf.c_str(), - entry->rule_mode == RULE_DENY, entry->perms, + entry->rule_mode, entry->perms, entry->audit == AUDIT_FORCE ? entry->perms : 0, parseopts)) return FALSE; @@ -674,7 +677,7 @@ static int process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry) perms |= LINK_TO_LINK_SUBSET(perms); vec[1] = "/[^/].*"; } - if (!dfarules->add_rule_vec(entry->rule_mode == RULE_DENY, perms, entry->audit == AUDIT_FORCE ? perms & AA_LINK_BITS : 0, 2, vec, parseopts, false)) + if (!dfarules->add_rule_vec(entry->rule_mode, perms, entry->audit == AUDIT_FORCE ? perms & AA_LINK_BITS : 0, 2, vec, parseopts, false)) return FALSE; } if (is_change_profile_perms(entry->perms)) { @@ -725,13 +728,13 @@ static int process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry) } /* regular change_profile rule */ - if (!dfarules->add_rule_vec(entry->rule_mode == RULE_DENY, + if (!dfarules->add_rule_vec(entry->rule_mode, AA_CHANGE_PROFILE | onexec_perms, 0, index - 1, &vec[1], parseopts, false)) return FALSE; /* onexec rules - both rules are needed for onexec */ - if (!dfarules->add_rule_vec(entry->rule_mode == RULE_DENY, onexec_perms, + if (!dfarules->add_rule_vec(entry->rule_mode, onexec_perms, 0, 1, vec, parseopts, false)) return FALSE; @@ -740,7 +743,7 @@ static int process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry) * unsafe exec transitions */ onexec_perms |= (entry->perms & (AA_EXEC_BITS | ALL_AA_EXEC_UNSAFE)); - if (!dfarules->add_rule_vec(entry->rule_mode == RULE_DENY, onexec_perms, + if (!dfarules->add_rule_vec(entry->rule_mode, onexec_perms, 0, index, vec, parseopts, false)) return FALSE; } @@ -980,6 +983,80 @@ int post_process_policydb_ents(Profile *prof) return TRUE; } + +static bool gen_net_rule(Profile *prof, u16 family, unsigned int type_mask, + bool audit, rule_mode_t rmode) { + std::ostringstream buffer; + std::string buf; + + buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << AA_CLASS_NETV8; + buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << ((family & 0xff00) >> 8); + buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << (family & 0xff); + if (type_mask > 0xffff) { + buffer << ".."; + } else { + buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << ((type_mask & 0xff00) >> 8); + buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << (type_mask & 0xff); + } + buf = buffer.str(); + if (!prof->policy.rules->add_rule(buf.c_str(), rmode, map_perms(AA_VALID_NET_PERMS), + audit ? map_perms(AA_VALID_NET_PERMS) : 0, + parseopts)) + return false; + + return true; +} + +static bool gen_af_rules(Profile *prof, u16 family, unsigned int type_mask, + unsigned int audit_mask, rule_mode_t rmode) +{ + if (type_mask > 0xffff && audit_mask > 0xffff) { + /* instead of generating multiple rules wild card type */ + return gen_net_rule(prof, family, type_mask, audit_mask, rmode); + } else { + int t; + /* generate rules for types that are set */ + for (t = 0; t < 16; t++) { + if (type_mask & (1 << t)) { + if (!gen_net_rule(prof, family, t, + audit_mask & (1 << t), + rmode)) + return false; + } + } + } + + return true; +} + +bool post_process_policydb_net(Profile *prof) +{ + u16 af; + + /* no network rules defined so we don't have generate them */ + if (!prof->net.allow) + return true; + + /* generate rules if the af has something set */ + for (af = AF_UNSPEC; af < get_af_max(); af++) { + if (prof->net.allow[af] || + prof->net.deny[af] || + prof->net.audit[af] || + prof->net.quiet[af]) { + if (!gen_af_rules(prof, af, prof->net.allow[af], + prof->net.audit[af], + { RULE_ALLOW})) + return false; + if (!gen_af_rules(prof, af, prof->net.deny[af], + prof->net.quiet[af], + { RULE_DENY})) + return false; + } + } + + return true; +} + #define MAKE_STR(X) #X #define CLASS_STR(X) "\\d" MAKE_STR(X) #define MAKE_SUB_STR(X) "\\000" MAKE_STR(X) @@ -1013,9 +1090,8 @@ int process_profile_policydb(Profile *prof) /* insert entries to show indicate what compiler/policy expects * to be supported */ - if (features_supports_userns && - !prof->policy.rules->add_rule(mediates_ns, 0, AA_MAY_READ, 0, parseopts)) + !prof->policy.rules->add_rule(mediates_ns, RULE_ALLOW, AA_MAY_READ, 0, parseopts)) goto out; /* don't add mediated classes to unconfined profiles */ @@ -1023,35 +1099,35 @@ int process_profile_policydb(Profile *prof) prof->flags.mode != MODE_DEFAULT_ALLOW) { /* note: this activates fs based unix domain sockets mediation on connect */ if (kernel_abi_version > 5 && - !prof->policy.rules->add_rule(mediates_file, 0, AA_MAY_READ, 0, parseopts)) + !prof->policy.rules->add_rule(mediates_file, RULE_ALLOW, AA_MAY_READ, 0, parseopts)) goto out; if (features_supports_mount && - !prof->policy.rules->add_rule(mediates_mount, 0, AA_MAY_READ, 0, parseopts)) + !prof->policy.rules->add_rule(mediates_mount, RULE_ALLOW, AA_MAY_READ, 0, parseopts)) goto out; if (features_supports_dbus && - !prof->policy.rules->add_rule(mediates_dbus, 0, AA_MAY_READ, 0, parseopts)) + !prof->policy.rules->add_rule(mediates_dbus, RULE_ALLOW, AA_MAY_READ, 0, parseopts)) goto out; if (features_supports_signal && - !prof->policy.rules->add_rule(mediates_signal, 0, AA_MAY_READ, 0, parseopts)) + !prof->policy.rules->add_rule(mediates_signal, RULE_ALLOW, AA_MAY_READ, 0, parseopts)) goto out; if (features_supports_ptrace && - !prof->policy.rules->add_rule(mediates_ptrace, 0, AA_MAY_READ, 0, parseopts)) + !prof->policy.rules->add_rule(mediates_ptrace, RULE_ALLOW, AA_MAY_READ, 0, parseopts)) goto out; if (features_supports_networkv8 && - !prof->policy.rules->add_rule(mediates_netv8, 0, AA_MAY_READ, 0, parseopts)) + !prof->policy.rules->add_rule(mediates_netv8, RULE_ALLOW, AA_MAY_READ, 0, parseopts)) goto out; if (features_supports_unix && - (!prof->policy.rules->add_rule(mediates_extended_net, 0, AA_MAY_READ, 0, parseopts) || - !prof->policy.rules->add_rule(mediates_net_unix, 0, AA_MAY_READ, 0, parseopts))) + (!prof->policy.rules->add_rule(mediates_extended_net, RULE_ALLOW, AA_MAY_READ, 0, parseopts) || + !prof->policy.rules->add_rule(mediates_net_unix, RULE_ALLOW, AA_MAY_READ, 0, parseopts))) goto out; if (features_supports_posix_mqueue && - !prof->policy.rules->add_rule(mediates_posix_mqueue, 0, AA_MAY_READ, 0, parseopts)) + !prof->policy.rules->add_rule(mediates_posix_mqueue, RULE_ALLOW, AA_MAY_READ, 0, parseopts)) goto out; if (features_supports_sysv_mqueue && - !prof->policy.rules->add_rule(mediates_sysv_mqueue, 0, AA_MAY_READ, 0, parseopts)) + !prof->policy.rules->add_rule(mediates_sysv_mqueue, RULE_ALLOW, AA_MAY_READ, 0, parseopts)) goto out; if (features_supports_io_uring && - !prof->policy.rules->add_rule(mediates_io_uring, 0, AA_MAY_READ, 0, parseopts)) + !prof->policy.rules->add_rule(mediates_io_uring, RULE_ALLOW, AA_MAY_READ, 0, parseopts)) goto out; } @@ -1060,11 +1136,11 @@ int process_profile_policydb(Profile *prof) // This requires file rule processing happen first if (!prof->dfa.rules->rule_count) { // add null dfa - if (!prof->dfa.rules->add_rule(deny_file, true, AA_MAY_READ, 0, parseopts)) + if (!prof->dfa.rules->add_rule(deny_file, RULE_DENY, AA_MAY_READ, 0, parseopts)) goto out; } if (!prof->policy.rules->rule_count) { - if (!prof->policy.rules->add_rule(mediates_file, true, AA_MAY_READ, 0, parseopts)) + if (!prof->policy.rules->add_rule(mediates_file, RULE_DENY, AA_MAY_READ, 0, parseopts)) goto out; } int xmatch_len = 0; diff --git a/parser/ptrace.cc b/parser/ptrace.cc index 3a4bbf690..9627f84b4 100644 --- a/parser/ptrace.cc +++ b/parser/ptrace.cc @@ -133,8 +133,9 @@ int ptrace_rule::gen_policy_re(Profile &prof) buf = buffer.str(); if (perms & AA_VALID_PTRACE_PERMS) { - if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, - parseopts)) + if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode, perms, + audit == AUDIT_FORCE ? perms : 0, + parseopts)) goto fail; } diff --git a/parser/signal.cc b/parser/signal.cc index b2eda5ac2..a161c275a 100644 --- a/parser/signal.cc +++ b/parser/signal.cc @@ -316,8 +316,9 @@ int signal_rule::gen_policy_re(Profile &prof) buf = buffer.str(); if (perms & (AA_MAY_SEND | AA_MAY_RECEIVE)) { - if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, - parseopts)) + if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode, + perms, audit == AUDIT_FORCE ? perms : 0, + parseopts)) goto fail; } diff --git a/parser/userns.cc b/parser/userns.cc index cbef5e580..96a60c649 100644 --- a/parser/userns.cc +++ b/parser/userns.cc @@ -95,9 +95,9 @@ int userns_rule::gen_policy_re(Profile &prof) buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << AA_CLASS_NS; buf = buffer.str(); if (perms & AA_VALID_USERNS_PERMS) { - if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, perms, - audit == AUDIT_FORCE ? perms : 0, - parseopts)) + if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode, perms, + audit == AUDIT_FORCE ? perms : 0, + parseopts)) goto fail; } From 1d0d1fd0c293de091d656abbed294a6ecd440d9a Mon Sep 17 00:00:00 2001 From: John Johansen Date: Sun, 23 Apr 2023 11:56:00 -0700 Subject: [PATCH 08/17] parser: and prompt-compat control flag Allow contronling which prompt compat mode fallback is used. Signed-off-by: John Johansen --- parser/parser.h | 9 ++++++++ parser/parser_common.c | 43 +++++++++++++++++++++++++++++++++++++++ parser/parser_interface.c | 4 ++-- parser/parser_main.c | 27 ++++++++++++++++++++++++ parser/parser_regex.c | 13 ++++++------ 5 files changed, 87 insertions(+), 9 deletions(-) diff --git a/parser/parser.h b/parser/parser.h index 979e67889..6695def7b 100644 --- a/parser/parser.h +++ b/parser/parser.h @@ -324,6 +324,10 @@ do { \ /* The parser fills this variable in automatically */ #define PROFILE_NAME_VARIABLE "profile_name" +#define PROMPT_COMPAT_IGNORE 0 +#define PROMPT_COMPAT_PERMSV2 1 +#define PROMPT_COMPAT_PERMSV1 2 + /* from parser_common.c */ extern uint32_t policy_version; extern uint32_t parser_abi_version; @@ -361,6 +365,7 @@ extern int features_supports_flag_error; extern int kernel_supports_oob; extern int kernel_supports_permstable32; extern int kernel_supports_permstable32_v1; +extern int prompt_compat_mode; extern int conf_verbose; extern int conf_quiet; extern int names_only; @@ -376,6 +381,10 @@ extern IncludeCache_t *g_includecache; extern void pwarnf(bool werr, const char *fmt, ...) __attribute__((__format__(__printf__, 2, 3))); extern void common_warn_once(const char *name, const char *msg, const char **warned_name); +bool prompt_compat_mode_supported(int mode); +int default_prompt_compat_mode(); +void print_prompt_compat_mode(FILE *f); + #define pwarn(F, args...) do { if (parseopts.warn & (F)) pwarnf((parseopts.Werror & (F)), ## args); } while (0) diff --git a/parser/parser_common.c b/parser/parser_common.c index 1dc1640f0..3eb7b6ab9 100644 --- a/parser/parser_common.c +++ b/parser/parser_common.c @@ -89,6 +89,7 @@ int features_supports_flag_error = 0; int kernel_supports_oob = 0; /* out of band transitions */ int kernel_supports_permstable32 = 0; /* extended permissions */ int kernel_supports_permstable32_v1 = 0; /* extended permissions */ +int prompt_compat_mode = 0; int conf_verbose = 0; int conf_quiet = 0; int names_only = 0; @@ -168,3 +169,45 @@ void common_warn_once(const char *name, const char *msg, const char **warned_nam if (parseopts.Werror & WARN_RULE_NOT_ENFORCED) exit(1); } + +bool prompt_compat_mode_supported(int mode) +{ + if (mode == PROMPT_COMPAT_PERMSV2 && + (kernel_supports_permstable32 && !kernel_supports_permstable32_v1)) + return true; + else if (mode == PROMPT_COMPAT_PERMSV1 && + (kernel_supports_permstable32_v1)) + return true; + else if (mode == PROMPT_COMPAT_IGNORE) + return true; + + return false; +} + +int default_prompt_compat_mode() +{ + if (prompt_compat_mode_supported(PROMPT_COMPAT_PERMSV2)) + return PROMPT_COMPAT_PERMSV2; + if (prompt_compat_mode_supported(PROMPT_COMPAT_PERMSV1)) + return PROMPT_COMPAT_PERMSV1; + if (prompt_compat_mode_supported(PROMPT_COMPAT_IGNORE)) + return PROMPT_COMPAT_IGNORE; + return PROMPT_COMPAT_IGNORE; +} + +void print_prompt_compat_mode(FILE *f) +{ + switch (prompt_compat_mode) { + case PROMPT_COMPAT_IGNORE: + fprintf(f, "ignore"); + break; + case PROMPT_COMPAT_PERMSV2: + fprintf(f, "permsv2"); + break; + case PROMPT_COMPAT_PERMSV1: + fprintf(f, "permsv1"); + break; + default: + fprintf(f, "Unknown prompt compat mode '%d'", prompt_compat_mode); + } +} diff --git a/parser/parser_interface.c b/parser/parser_interface.c index c9fdd7870..f4abe5bf7 100644 --- a/parser/parser_interface.c +++ b/parser/parser_interface.c @@ -549,14 +549,14 @@ void sd_serialize_profile(std::ostringstream &buf, Profile *profile, // fprintf(stderr, "profile %s: policy xtable\n", profile->name); // TODO: this is dummy exec make dependent on V1 sd_serialize_xtable(buf, profile->exec_table, - kernel_supports_permstable32_v1 ? + profile->uses_prompt_rules && prompt_compat_mode == PROMPT_COMPAT_PERMSV1 ? profile->policy.perms_table.size() : 0); } sd_write_structend(buf); } /* either have a single dfa or lists of different entry types */ - if (kernel_supports_permstable32_v1) { + if (profile->uses_prompt_rules && prompt_compat_mode == PROMPT_COMPAT_PERMSV1) { /* special compat mode to work around verification problem */ sd_serialize_dfa(buf, profile->policy.dfa, profile->policy.size, profile->policy.perms_table); diff --git a/parser/parser_main.c b/parser/parser_main.c index 0f51fc62e..d578c1ff5 100644 --- a/parser/parser_main.c +++ b/parser/parser_main.c @@ -137,6 +137,8 @@ static const char *config_file = "/etc/apparmor/parser.conf"; #define EARLY_ARG_CONFIG_FILE 142 #define ARG_WERROR 143 #define ARG_ESTIMATED_COMPILE_SIZE 144 +#define ARG_PROMPT_COMPAT 145 +#define ARG_PRINT_PROMPT_COMPAT 146 /* Make sure to update BOTH the short and long_options */ static const char *short_options = "ad::f:h::rRVvI:b:BCD:NSm:M:qQn:XKTWkL:O:po:j:"; @@ -192,6 +194,8 @@ struct option long_options[] = { {"override-policy-abi", 1, 0, ARG_OVERRIDE_POLICY_ABI}, /* no short option */ {"config-file", 1, 0, EARLY_ARG_CONFIG_FILE}, /* early option, no short option */ {"estimated-compile-size", 1, 0, ARG_ESTIMATED_COMPILE_SIZE}, /* no short option, not in help */ + {"prompt-compat", 1, 0, ARG_PROMPT_COMPAT}, /* no short option */ + {"print-prompt-compat", 1, 0, ARG_PRINT_PROMPT_COMPAT}, /* no short option */ {NULL, 0, 0, 0}, }; @@ -789,6 +793,26 @@ static int process_arg(int c, char *optarg) estimated_job_size = tmp * mult; } break; + case ARG_PROMPT_COMPAT: + if (strcmp(optarg, "permsv2") == 0) { + prompt_compat_mode = PROMPT_COMPAT_PERMSV1; + } else if (strcmp(optarg, "permsv1") == 0) { + prompt_compat_mode = PROMPT_COMPAT_PERMSV1; + } else if (strcmp(optarg, "default") == 0) { + prompt_compat_mode = default_prompt_compat_mode(); + } else if (strcmp(optarg, "ignore") == 0) { + prompt_compat_mode = PROMPT_COMPAT_IGNORE; + } else { + PERROR("%s: Invalid --prompt-compat option '%s'\n", + progname, optarg); + exit(1); + } + break; + case ARG_PRINT_PROMPT_COMPAT: + fprintf(stderr, "Prompt compat mode: "); + print_prompt_compat_mode(stderr); + fprintf(stderr, "\n"); + break; default: /* 'unrecognized option' error message gets printed by getopt_long() */ exit(1); @@ -1552,6 +1576,9 @@ static bool get_kernel_features(struct aa_features **features) if (kernel_supports_permstable32_v1) { fprintf(stderr, "kernel supports prompt\n"); } + + /* set default prompt_compat_mode to the best that is supported */ + prompt_compat_mode = default_prompt_compat_mode(); if (!kernel_supports_diff_encode) /* clear diff_encode because it is not supported */ parseopts.control &= ~CONTROL_DFA_DIFF_ENCODE; diff --git a/parser/parser_regex.c b/parser/parser_regex.c index b6600266d..968527603 100644 --- a/parser/parser_regex.c +++ b/parser/parser_regex.c @@ -576,8 +576,7 @@ build: * conditional and for just MAY_EXEC can be processed as * none file perms * - * we don't need to build xmatch for buggy permstable32_v1 - * so don't + * we don't need to build xmatch for permstable32, so don't */ prof->xmatch = rules->create_dfablob(&prof->xmatch_size, &prof->xmatch_len, prof->xmatch_perms_table, parseopts, false, kernel_supports_permstable32 && !kernel_supports_permstable32_v1); delete rules; @@ -780,13 +779,13 @@ int process_profile_regex(Profile *prof) /* under permstable32_v1 we weld file and policydb together, so * don't create the file blob here */ - if (prof->dfa.rules->rule_count > 0 && !kernel_supports_permstable32_v1) { + if (prof->dfa.rules->rule_count > 0 && prompt_compat_mode != PROMPT_COMPAT_PERMSV1) { int xmatch_len = 0; //fprintf(stderr, "Creating file DFA %d\n", kernel_supports_permstable32); prof->dfa.dfa = prof->dfa.rules->create_dfablob(&prof->dfa.size, &xmatch_len, prof->dfa.perms_table, parseopts, true, - kernel_supports_permstable32); + prof->uses_prompt_rules && kernel_supports_permstable32); delete prof->dfa.rules; prof->dfa.rules = NULL; if (!prof->dfa.dfa) @@ -1131,7 +1130,7 @@ int process_profile_policydb(Profile *prof) goto out; } - if (kernel_supports_permstable32_v1) { + if (prompt_compat_mode == PROMPT_COMPAT_PERMSV1) { // MUST have file and policy // This requires file rule processing happen first if (!prof->dfa.rules->rule_count) { @@ -1160,13 +1159,13 @@ int process_profile_policydb(Profile *prof) } else if (prof->policy.rules->rule_count > 0 && // yes not needed as covered above, just making sure // this doesn't get messed up in the future - !kernel_supports_permstable32_v1) { + prompt_compat_mode != PROMPT_COMPAT_PERMSV1) { int xmatch_len = 0; prof->policy.dfa = prof->policy.rules->create_dfablob(&prof->policy.size, &xmatch_len, prof->policy.perms_table, parseopts, false, - kernel_supports_permstable32); + prof->uses_prompt_rules && kernel_supports_permstable32); delete prof->policy.rules; prof->policy.rules = NULL; From b4384d53e12c549cccd2722285ec11f145c26a85 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Sun, 23 Apr 2023 16:04:23 -0700 Subject: [PATCH 09/17] parser: Add prompt dev compat support Support mapping rule prompt via the audit bits in pre permtable32 kernels. Signed-off-by: John Johansen --- parser/parser.h | 4 +++- parser/parser_common.c | 9 +++++++++ parser/parser_main.c | 1 + parser/parser_policy.c | 4 ++++ parser/profile.h | 5 +++++ 5 files changed, 22 insertions(+), 1 deletion(-) diff --git a/parser/parser.h b/parser/parser.h index 6695def7b..636ad92ee 100644 --- a/parser/parser.h +++ b/parser/parser.h @@ -326,7 +326,8 @@ do { \ #define PROMPT_COMPAT_IGNORE 0 #define PROMPT_COMPAT_PERMSV2 1 -#define PROMPT_COMPAT_PERMSV1 2 +#define PROMPT_COMPAT_DEV 2 +#define PROMPT_COMPAT_PERMSV1 3 /* from parser_common.c */ extern uint32_t policy_version; @@ -363,6 +364,7 @@ extern int features_supports_flag_interruptible; extern int features_supports_flag_signal; extern int features_supports_flag_error; extern int kernel_supports_oob; +extern int kernel_supports_promptdev; extern int kernel_supports_permstable32; extern int kernel_supports_permstable32_v1; extern int prompt_compat_mode; diff --git a/parser/parser_common.c b/parser/parser_common.c index 3eb7b6ab9..d86b7fbe5 100644 --- a/parser/parser_common.c +++ b/parser/parser_common.c @@ -87,6 +87,7 @@ int features_supports_flag_interruptible = 0; int features_supports_flag_signal = 0; int features_supports_flag_error = 0; int kernel_supports_oob = 0; /* out of band transitions */ +int kernel_supports_promptdev = 0; /* prompt via audit perms */ int kernel_supports_permstable32 = 0; /* extended permissions */ int kernel_supports_permstable32_v1 = 0; /* extended permissions */ int prompt_compat_mode = 0; @@ -175,6 +176,9 @@ bool prompt_compat_mode_supported(int mode) if (mode == PROMPT_COMPAT_PERMSV2 && (kernel_supports_permstable32 && !kernel_supports_permstable32_v1)) return true; + else if (mode == PROMPT_COMPAT_DEV && + kernel_supports_promptdev) + return true; else if (mode == PROMPT_COMPAT_PERMSV1 && (kernel_supports_permstable32_v1)) return true; @@ -188,6 +192,8 @@ int default_prompt_compat_mode() { if (prompt_compat_mode_supported(PROMPT_COMPAT_PERMSV2)) return PROMPT_COMPAT_PERMSV2; + if (prompt_compat_mode_supported(PROMPT_COMPAT_DEV)) + return PROMPT_COMPAT_DEV; if (prompt_compat_mode_supported(PROMPT_COMPAT_PERMSV1)) return PROMPT_COMPAT_PERMSV1; if (prompt_compat_mode_supported(PROMPT_COMPAT_IGNORE)) @@ -207,6 +213,9 @@ void print_prompt_compat_mode(FILE *f) case PROMPT_COMPAT_PERMSV1: fprintf(f, "permsv1"); break; + case PROMPT_COMPAT_DEV: + fprintf(stderr, "dev"); + break; default: fprintf(f, "Unknown prompt compat mode '%d'", prompt_compat_mode); } diff --git a/parser/parser_main.c b/parser/parser_main.c index d578c1ff5..35f47530e 100644 --- a/parser/parser_main.c +++ b/parser/parser_main.c @@ -1568,6 +1568,7 @@ static bool get_kernel_features(struct aa_features **features) else if (aa_features_supports(*features, "policy/versions/v6")) kernel_abi_version = 6; + kernel_supports_promptdev = aa_features_supports(*features, "policy/perms_compatprompt"); kernel_supports_permstable32 = aa_features_supports(*features, "policy/permstable32"); if (kernel_supports_permstable32) { fprintf(stderr, "kernel supports prompt\n"); diff --git a/parser/parser_policy.c b/parser/parser_policy.c index 67d9f3b0d..365974f07 100644 --- a/parser/parser_policy.c +++ b/parser/parser_policy.c @@ -240,6 +240,10 @@ int post_process_profile(Profile *profile, int debug_only) } error = post_process_policy_list(profile->hat_table, debug_only); + + if (prompt_compat_mode == PROMPT_COMPAT_DEV && profile->uses_prompt_rules) + profile->flags.flags |= FLAG_PROMPT_COMPAT; + return error; } diff --git a/parser/profile.h b/parser/profile.h index 0e8b67b15..2c13be17b 100644 --- a/parser/profile.h +++ b/parser/profile.h @@ -149,6 +149,7 @@ static const char *find_error_name_mapping(int code) #define FLAG_DEBUG1 2 #define FLAG_DEBUG2 4 #define FLAG_INTERRUPTIBLE 8 +#define FLAG_PROMPT_COMPAT 0x10 /* sigh, used in parse union so needs trivial constructors. */ class flagvals { @@ -236,6 +237,10 @@ public: os << ", kill.signal=" << signal; if (error) os << ", error=" << find_error_name_mapping(error); + + if (flags & FLAG_PROMPT_COMPAT) + os << ", prompt_dev"; + os << "\n"; return os; From 2510698f636f753de96a0f12822b18a98f4b757e Mon Sep 17 00:00:00 2001 From: John Johansen Date: Sun, 23 Apr 2023 19:52:38 -0700 Subject: [PATCH 10/17] parser: make minimization sets take prompt into account Signed-off-by: John Johansen --- parser/libapparmor_re/hfa.cc | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/parser/libapparmor_re/hfa.cc b/parser/libapparmor_re/hfa.cc index 75e43e36a..7e05d67ab 100644 --- a/parser/libapparmor_re/hfa.cc +++ b/parser/libapparmor_re/hfa.cc @@ -538,6 +538,7 @@ void DFA::dump_uniq_perms(const char *s) << i->deny << " audit:" << i->audit << " quiet:" << i->quiet << dec << "\n"; } + //TODO: add prompt } /* Remove dead or unreachable states */ @@ -645,10 +646,13 @@ int DFA::apply_and_clear_deny(void) return c; } + +typedef __uint128_t uint128_t; + /* minimize the number of dfa states */ void DFA::minimize(optflags const &opts) { - map, Partition *> perm_map; + map, Partition *> perm_map; list partitions; /* Set up the initial partitions @@ -665,9 +669,9 @@ void DFA::minimize(optflags const &opts) int final_accept = 0; for (Partition::iterator i = states.begin(); i != states.end(); i++) { size_t hash = 0; - uint64_t permtype = ((uint64_t) (PACK_AUDIT_CTL((*i)->perms.audit, (*i)->perms.quiet & (*i)->perms.deny)) << 32) | (uint64_t) (*i)->perms.allow; - pair group = make_pair(permtype, hash); - map, Partition *>::iterator p = perm_map.find(group); + uint128_t permtype = ((uint128_t) (PACK_AUDIT_CTL((*i)->perms.audit, (*i)->perms.quiet & (*i)->perms.deny)) << 32) | (uint128_t) (*i)->perms.allow | ((uint128_t) (*i)->perms.prompt << 64); + pair group = make_pair(permtype, hash); + map, Partition *>::iterator p = perm_map.find(group); if (p == perm_map.end()) { Partition *part = new Partition(); part->push_back(*i); From 5bd2271189c33e2fcd8551f37f364fb963a2256e Mon Sep 17 00:00:00 2001 From: John Johansen Date: Sun, 23 Apr 2023 20:27:51 -0700 Subject: [PATCH 11/17] pass prompt info down into the backend for mapping mapping for PROMPT_DEV needs to know that we should prompt --- parser/libapparmor_re/aare_rules.cc | 21 +++++++++++---------- parser/libapparmor_re/aare_rules.h | 6 +++--- parser/libapparmor_re/chfa.cc | 23 +++++++++++++++++------ parser/libapparmor_re/chfa.h | 5 ++--- parser/libapparmor_re/hfa.cc | 13 +++++++------ parser/libapparmor_re/hfa.h | 14 +++++++++++--- parser/parser.h | 4 ---- parser/parser_regex.c | 11 +++++++---- parser/rule.h | 6 ++++++ 9 files changed, 64 insertions(+), 39 deletions(-) diff --git a/parser/libapparmor_re/aare_rules.cc b/parser/libapparmor_re/aare_rules.cc index 08e8e6fb9..4dcbc4cc9 100644 --- a/parser/libapparmor_re/aare_rules.cc +++ b/parser/libapparmor_re/aare_rules.cc @@ -199,8 +199,8 @@ bool aare_rules::append_rule(const char *rule, bool oob, bool with_perm, */ CHFA *aare_rules::create_chfa(int *min_match_len, vector &perms_table, - optflags const &opts, - bool filedfa, bool extended_perms) + optflags const &opts, bool filedfa, + bool extended_perms, bool prompt) { /* finish constructing the expr tree from the different permission * set nodes */ @@ -310,9 +310,9 @@ CHFA *aare_rules::create_chfa(int *min_match_len, //cerr << "Checking extended perms " << extended_perms << "\n"; if (extended_perms) { //cerr << "creating permstable\n"; - dfa.compute_perms_table(perms_table); + dfa.compute_perms_table(perms_table, prompt); } - chfa = new CHFA(dfa, eq, opts, extended_perms); + chfa = new CHFA(dfa, eq, opts, extended_perms, prompt); if (opts.dump & DUMP_DFA_TRANS_TABLE) chfa->dump(cerr); } @@ -331,14 +331,15 @@ CHFA *aare_rules::create_chfa(int *min_match_len, void *aare_rules::create_dfablob(size_t *size, int *min_match_len, vector &perms_table, optflags const &opts, bool filedfa, - bool extended_perms) + bool extended_perms, bool prompt) { char *buffer = NULL; stringstream stream; try { CHFA *chfa = create_chfa(min_match_len, perms_table, - opts, filedfa, extended_perms); + opts, filedfa, extended_perms, + prompt); if (!chfa) { *size = 0; return NULL; @@ -375,7 +376,7 @@ void *aare_rules::create_welded_dfablob(aare_rules *file_rules, size_t *new_start, vector &perms_table, optflags const &opts, - bool extended_perms) + bool extended_perms, bool prompt) { int file_min_len; vector file_perms; @@ -383,7 +384,7 @@ void *aare_rules::create_welded_dfablob(aare_rules *file_rules, try { file_chfa = file_rules->create_chfa(&file_min_len, file_perms, opts, - true, extended_perms); + true, extended_perms, prompt); if (!file_chfa) { *size = 0; return NULL; @@ -398,7 +399,7 @@ void *aare_rules::create_welded_dfablob(aare_rules *file_rules, try { policy_chfa = create_chfa(min_match_len, perms_table, opts, - false, extended_perms); + false, extended_perms, prompt); if (!policy_chfa) { delete file_chfa; *size = 0; @@ -414,7 +415,7 @@ void *aare_rules::create_welded_dfablob(aare_rules *file_rules, stringstream stream; try { policy_chfa->weld_file_to_policy(*file_chfa, *new_start, - extended_perms, + extended_perms, prompt, perms_table, file_perms); policy_chfa->flex_table(stream); } diff --git a/parser/libapparmor_re/aare_rules.h b/parser/libapparmor_re/aare_rules.h index ca24c7eb2..7cc163380 100644 --- a/parser/libapparmor_re/aare_rules.h +++ b/parser/libapparmor_re/aare_rules.h @@ -118,17 +118,17 @@ class aare_rules { CHFA *create_chfa(int *min_match_len, vector &perms_table, optflags const &opts, bool filedfa, - bool extended_perms); + bool extended_perms, bool prompt); void *create_dfablob(size_t *size, int *min_match_len, vector &perms_table, optflags const &opts, - bool filedfa, bool extended_perms); + bool filedfa, bool extended_perms, bool prompt); void *create_welded_dfablob(aare_rules *file_rules, size_t *size, int *min_match_len, size_t *new_start, vector &perms_table, optflags const &opts, - bool extended_perms); + bool extended_perms, bool prompt); }; #endif /* __LIBAA_RE_RULES_H */ diff --git a/parser/libapparmor_re/chfa.cc b/parser/libapparmor_re/chfa.cc index 64bfdbc8a..7a94b9f43 100644 --- a/parser/libapparmor_re/chfa.cc +++ b/parser/libapparmor_re/chfa.cc @@ -55,7 +55,7 @@ void CHFA::init_free_list(vector > &free_list, * permtable index flag */ CHFA::CHFA(DFA &dfa, map &eq, optflags const &opts, - bool permindex): eq(eq) + bool permindex, bool prompt): eq(eq) { if (opts.dump & DUMP_DFA_TRANS_PROGRESS) fprintf(stderr, "Compressing HFA:\r"); @@ -110,11 +110,16 @@ CHFA::CHFA(DFA &dfa, map &eq, optflags const &opts, accept[0] = dfa.nonmatching->idx; accept[1] = dfa.start->idx; } else { + uint32_t accept3; accept2.resize(max(dfa.states.size(), (size_t) 2)); dfa.nonmatching->map_perms_to_accept(accept[0], - accept2[0]); + accept2[0], + accept3, + prompt); dfa.start->map_perms_to_accept(accept[1], - accept2[1]); + accept2[1], + accept3, + prompt); } next_check.resize(max(optimal, (size_t) dfa.max_range)); free_list.resize(next_check.size()); @@ -131,12 +136,15 @@ CHFA::CHFA(DFA &dfa, map &eq, optflags const &opts, if (!(opts.control & CONTROL_DFA_TRANS_HIGH)) { for (Partition::iterator i = dfa.states.begin(); i != dfa.states.end(); i++) { if (*i != dfa.nonmatching && *i != dfa.start) { + uint32_t accept3; insert_state(free_list, *i, dfa); if (permindex) accept[num.size()] = (*i)->idx; else (*i)->map_perms_to_accept(accept[num.size()], - accept2[num.size()]); + accept2[num.size()], + accept3, + prompt); num.insert(make_pair(*i, num.size())); } if (opts.dump & (DUMP_DFA_TRANS_PROGRESS)) { @@ -151,12 +159,15 @@ CHFA::CHFA(DFA &dfa, map &eq, optflags const &opts, i != order.end(); i++) { if (i->second != dfa.nonmatching && i->second != dfa.start) { + uint32_t accept3; insert_state(free_list, i->second, dfa); if (permindex) accept[num.size()] = i->second->idx; else i->second->map_perms_to_accept(accept[num.size()], - accept2[num.size()]); + accept2[num.size()], + accept3, + prompt); num.insert(make_pair(i->second, num.size())); } if (opts.dump & (DUMP_DFA_TRANS_PROGRESS)) { @@ -484,7 +495,7 @@ void CHFA::flex_table(ostream &os) */ void CHFA::weld_file_to_policy(CHFA &file_chfa, size_t &new_start, - bool accept_idx, + bool accept_idx, bool prompt, vector &policy_perms, vector &file_perms) { diff --git a/parser/libapparmor_re/chfa.h b/parser/libapparmor_re/chfa.h index a8aaa585a..4fd7933ca 100644 --- a/parser/libapparmor_re/chfa.h +++ b/parser/libapparmor_re/chfa.h @@ -40,8 +40,7 @@ class CHFA { public: CHFA(void); CHFA(DFA &dfa, map &eq, optflags const &opts, - bool permindex); - + bool permindex, bool prompt); void dump(ostream & os); void flex_table(ostream &os); void init_free_list(vector > &free_list, @@ -51,7 +50,7 @@ class CHFA { void insert_state(vector > &free_list, State *state, DFA &dfa); void weld_file_to_policy(CHFA &file_chfa, size_t &new_start, - bool accept_idx, + bool accept_idx, bool prompt, vector &policy_perms, vector &file_perms); diff --git a/parser/libapparmor_re/hfa.cc b/parser/libapparmor_re/hfa.cc index 7e05d67ab..f9cee068d 100644 --- a/parser/libapparmor_re/hfa.cc +++ b/parser/libapparmor_re/hfa.cc @@ -1308,12 +1308,13 @@ void DFA::apply_equivalence_classes(map &eq) } void DFA::compute_perms_table_ent(State *state, size_t pos, - vector &perms_table) + vector &perms_table, + bool prompt) { uint32_t accept1, accept2, accept3; // until front end doesn't map the way it does - state->map_perms_to_accept(accept1, accept2, accept3); + state->map_perms_to_accept(accept1, accept2, accept3, prompt); if (filedfa) { state->idx = pos * 2; perms_table[pos*2] = compute_fperms_user(accept1, accept2, accept3); @@ -1324,7 +1325,7 @@ void DFA::compute_perms_table_ent(State *state, size_t pos, } } -void DFA::compute_perms_table(vector &perms_table) +void DFA::compute_perms_table(vector &perms_table, bool prompt) { size_t mult = filedfa ? 2 : 1; size_t pos = 2; @@ -1334,13 +1335,13 @@ void DFA::compute_perms_table(vector &perms_table) // nonmatching and start need to be 0 and 1 so handle outside of loop if (filedfa) - compute_perms_table_ent(nonmatching, 0, perms_table); - compute_perms_table_ent(start, 1, perms_table); + compute_perms_table_ent(nonmatching, 0, perms_table, prompt); + compute_perms_table_ent(start, 1, perms_table, prompt); for (Partition::iterator i = states.begin(); i != states.end(); i++) { if (*i == nonmatching || *i == start) continue; - compute_perms_table_ent(*i, pos, perms_table); + compute_perms_table_ent(*i, pos, perms_table, prompt); pos++; } } diff --git a/parser/libapparmor_re/hfa.h b/parser/libapparmor_re/hfa.h index 2c5ab15d6..1b3b69335 100644 --- a/parser/libapparmor_re/hfa.h +++ b/parser/libapparmor_re/hfa.h @@ -34,6 +34,8 @@ #include "expr-tree.h" #include "policy_compat.h" +#include "../rule.h" +extern int prompt_compat_mode; #define DiffEncodeFlag 1 @@ -258,9 +260,13 @@ public: void flatten_relative(State *, int upper_bound); int apply_and_clear_deny(void) { return perms.apply_and_clear_deny(); } - void map_perms_to_accept(uint32_t &accept1, uint32_t &accept2, uint32_t &accept3) + void map_perms_to_accept(uint32_t &accept1, uint32_t &accept2, + uint32_t &accept3, bool prompt) { accept1 = perms.allow; + if (prompt && prompt_compat_mode == PROMPT_COMPAT_DEV) + accept2 = PACK_AUDIT_CTL(perms.prompt, perms.quiet & perms.deny); + else accept2 = PACK_AUDIT_CTL(perms.audit, perms.quiet & perms.deny); accept3 = perms.prompt; } @@ -358,8 +364,10 @@ public: void apply_equivalence_classes(map &eq); void compute_perms_table_ent(State *state, size_t pos, - vector &perms_table); - void compute_perms_table(vector &perms_table); + vector &perms_table, + bool prompt); + void compute_perms_table(vector &perms_table, + bool prompt); unsigned int diffcount; int oob_range; diff --git a/parser/parser.h b/parser/parser.h index 636ad92ee..30e45c33b 100644 --- a/parser/parser.h +++ b/parser/parser.h @@ -324,10 +324,6 @@ do { \ /* The parser fills this variable in automatically */ #define PROFILE_NAME_VARIABLE "profile_name" -#define PROMPT_COMPAT_IGNORE 0 -#define PROMPT_COMPAT_PERMSV2 1 -#define PROMPT_COMPAT_DEV 2 -#define PROMPT_COMPAT_PERMSV1 3 /* from parser_common.c */ extern uint32_t policy_version; diff --git a/parser/parser_regex.c b/parser/parser_regex.c index 968527603..3e0873b8d 100644 --- a/parser/parser_regex.c +++ b/parser/parser_regex.c @@ -578,7 +578,7 @@ build: * * we don't need to build xmatch for permstable32, so don't */ - prof->xmatch = rules->create_dfablob(&prof->xmatch_size, &prof->xmatch_len, prof->xmatch_perms_table, parseopts, false, kernel_supports_permstable32 && !kernel_supports_permstable32_v1); + prof->xmatch = rules->create_dfablob(&prof->xmatch_size, &prof->xmatch_len, prof->xmatch_perms_table, parseopts, false, false, false); delete rules; if (!prof->xmatch) return FALSE; @@ -785,7 +785,8 @@ int process_profile_regex(Profile *prof) prof->dfa.dfa = prof->dfa.rules->create_dfablob(&prof->dfa.size, &xmatch_len, prof->dfa.perms_table, parseopts, true, - prof->uses_prompt_rules && kernel_supports_permstable32); + prof->uses_prompt_rules && kernel_supports_permstable32, + prof->uses_prompt_rules); delete prof->dfa.rules; prof->dfa.rules = NULL; if (!prof->dfa.dfa) @@ -1149,7 +1150,8 @@ int process_profile_policydb(Profile *prof) &xmatch_len, &prof->policy.file_start, prof->policy.perms_table, parseopts, - kernel_supports_permstable32_v1); + kernel_supports_permstable32_v1, + prof->uses_prompt_rules); delete prof->policy.rules; delete prof->dfa.rules; prof->policy.rules = NULL; @@ -1165,7 +1167,8 @@ int process_profile_policydb(Profile *prof) &xmatch_len, prof->policy.perms_table, parseopts, false, - prof->uses_prompt_rules && kernel_supports_permstable32); + prof->uses_prompt_rules && kernel_supports_permstable32, + prof->uses_prompt_rules); delete prof->policy.rules; prof->policy.rules = NULL; diff --git a/parser/rule.h b/parser/rule.h index 3d2d2946f..27468cdac 100644 --- a/parser/rule.h +++ b/parser/rule.h @@ -27,6 +27,12 @@ using namespace std; +#define PROMPT_COMPAT_IGNORE 0 +#define PROMPT_COMPAT_PERMSV2 1 +#define PROMPT_COMPAT_DEV 2 +#define PROMPT_COMPAT_PERMSV1 3 + + class Profile; #define RULE_NOT_SUPPORTED 0 From 89673d0c5e712bac638298d519ab0e74363473aa Mon Sep 17 00:00:00 2001 From: John Johansen Date: Sun, 23 Apr 2023 21:14:18 -0700 Subject: [PATCH 12/17] parser: don't set xbits when using permstable32_v1 The use of xbits can not pass verification so we need to leave them off this makes the profile a leaf profile. Signed-off-by: John Johansen --- parser/libapparmor_re/policy_compat.cc | 10 ++++++++-- parser/parser_common.c | 14 +++++++++++++- parser/parser_main.c | 16 +++++++++++----- parser/parser_policy.c | 3 +++ parser/parser_regex.c | 4 ++-- parser/rule.h | 10 ++++++---- 6 files changed, 43 insertions(+), 14 deletions(-) diff --git a/parser/libapparmor_re/policy_compat.cc b/parser/libapparmor_re/policy_compat.cc index 5b8106647..58e11bad3 100644 --- a/parser/libapparmor_re/policy_compat.cc +++ b/parser/libapparmor_re/policy_compat.cc @@ -32,6 +32,8 @@ #include "policy_compat.h" #include "../perms.h" +#include "../rule.h" +extern int prompt_compat_mode; /* remap old accept table embedded permissions to separate permission table */ @@ -131,9 +133,11 @@ struct aa_perms compute_fperms_user(uint32_t accept1, uint32_t accept2, perms.prompt = map_old_perms(dfa_user_allow(accept3)); perms.audit = map_old_perms(dfa_user_audit(accept1, accept2)); perms.quiet = map_old_perms(dfa_user_quiet(accept1, accept2)); - perms.xindex = dfa_user_xindex(accept1); + if (prompt_compat_mode != PROMPT_COMPAT_PERMSV1) + perms.xindex = dfa_user_xindex(accept1); compute_fperms_allow(&perms, accept1); + perms.prompt &= ~(perms.allow | perms.deny); return perms; } @@ -146,9 +150,11 @@ struct aa_perms compute_fperms_other(uint32_t accept1, uint32_t accept2, perms.prompt = map_old_perms(dfa_other_allow(accept3)); perms.audit = map_old_perms(dfa_other_audit(accept1, accept2)); perms.quiet = map_old_perms(dfa_other_quiet(accept1, accept2)); - perms.xindex = dfa_other_xindex(accept1); + if (prompt_compat_mode != PROMPT_COMPAT_PERMSV1) + perms.xindex = dfa_other_xindex(accept1); compute_fperms_allow(&perms, accept1); + perms.prompt &= ~(perms.allow | perms.deny); return perms; } diff --git a/parser/parser_common.c b/parser/parser_common.c index d86b7fbe5..e924f0cfe 100644 --- a/parser/parser_common.c +++ b/parser/parser_common.c @@ -90,7 +90,7 @@ int kernel_supports_oob = 0; /* out of band transitions */ int kernel_supports_promptdev = 0; /* prompt via audit perms */ int kernel_supports_permstable32 = 0; /* extended permissions */ int kernel_supports_permstable32_v1 = 0; /* extended permissions */ -int prompt_compat_mode = 0; +int prompt_compat_mode = PROMPT_COMPAT_UNKNOWN; int conf_verbose = 0; int conf_quiet = 0; int names_only = 0; @@ -176,12 +176,19 @@ bool prompt_compat_mode_supported(int mode) if (mode == PROMPT_COMPAT_PERMSV2 && (kernel_supports_permstable32 && !kernel_supports_permstable32_v1)) return true; + /* else if (mode == PROMPT_COMPAT_DEV && kernel_supports_promptdev) return true; + */ + else if (mode == PROMPT_COMPAT_FLAG && + kernel_supports_permstable32) + return true; + /* else if (mode == PROMPT_COMPAT_PERMSV1 && (kernel_supports_permstable32_v1)) return true; + */ else if (mode == PROMPT_COMPAT_IGNORE) return true; @@ -194,6 +201,8 @@ int default_prompt_compat_mode() return PROMPT_COMPAT_PERMSV2; if (prompt_compat_mode_supported(PROMPT_COMPAT_DEV)) return PROMPT_COMPAT_DEV; + if (prompt_compat_mode_supported(PROMPT_COMPAT_FLAG)) + return PROMPT_COMPAT_FLAG; if (prompt_compat_mode_supported(PROMPT_COMPAT_PERMSV1)) return PROMPT_COMPAT_PERMSV1; if (prompt_compat_mode_supported(PROMPT_COMPAT_IGNORE)) @@ -207,6 +216,9 @@ void print_prompt_compat_mode(FILE *f) case PROMPT_COMPAT_IGNORE: fprintf(f, "ignore"); break; + case PROMPT_COMPAT_FLAG: + fprintf(f, "flag"); + break; case PROMPT_COMPAT_PERMSV2: fprintf(f, "permsv2"); break; diff --git a/parser/parser_main.c b/parser/parser_main.c index 35f47530e..d6ff5477d 100644 --- a/parser/parser_main.c +++ b/parser/parser_main.c @@ -795,13 +795,17 @@ static int process_arg(int c, char *optarg) break; case ARG_PROMPT_COMPAT: if (strcmp(optarg, "permsv2") == 0) { - prompt_compat_mode = PROMPT_COMPAT_PERMSV1; + prompt_compat_mode = PROMPT_COMPAT_PERMSV2; } else if (strcmp(optarg, "permsv1") == 0) { prompt_compat_mode = PROMPT_COMPAT_PERMSV1; } else if (strcmp(optarg, "default") == 0) { prompt_compat_mode = default_prompt_compat_mode(); + } else if (strcmp(optarg, "dev") == 0) { + prompt_compat_mode = PROMPT_COMPAT_DEV; } else if (strcmp(optarg, "ignore") == 0) { prompt_compat_mode = PROMPT_COMPAT_IGNORE; + } else if (strcmp(optarg, "flag") == 0) { + prompt_compat_mode = PROMPT_COMPAT_FLAG; } else { PERROR("%s: Invalid --prompt-compat option '%s'\n", progname, optarg); @@ -1571,15 +1575,17 @@ static bool get_kernel_features(struct aa_features **features) kernel_supports_promptdev = aa_features_supports(*features, "policy/perms_compatprompt"); kernel_supports_permstable32 = aa_features_supports(*features, "policy/permstable32"); if (kernel_supports_permstable32) { - fprintf(stderr, "kernel supports prompt\n"); + //fprintf(stderr, "kernel supports prompt\n"); } - kernel_supports_permstable32_v1 = aa_features_supports(*features, "policy/permstable32/1"); + kernel_supports_permstable32_v1 = aa_features_supports(*features, "policy/permstable32_version/0x000001"); if (kernel_supports_permstable32_v1) { - fprintf(stderr, "kernel supports prompt\n"); + //fprintf(stderr, "kernel supports prompt_v1\n"); } /* set default prompt_compat_mode to the best that is supported */ - prompt_compat_mode = default_prompt_compat_mode(); + if (prompt_compat_mode == PROMPT_COMPAT_UNKNOWN) { + prompt_compat_mode = default_prompt_compat_mode(); + } if (!kernel_supports_diff_encode) /* clear diff_encode because it is not supported */ parseopts.control &= ~CONTROL_DFA_DIFF_ENCODE; diff --git a/parser/parser_policy.c b/parser/parser_policy.c index 365974f07..facb1d173 100644 --- a/parser/parser_policy.c +++ b/parser/parser_policy.c @@ -244,6 +244,9 @@ int post_process_profile(Profile *profile, int debug_only) if (prompt_compat_mode == PROMPT_COMPAT_DEV && profile->uses_prompt_rules) profile->flags.flags |= FLAG_PROMPT_COMPAT; + else if (prompt_compat_mode == PROMPT_COMPAT_FLAG && profile->uses_prompt_rules) + profile->flags.mode = MODE_PROMPT; + return error; } diff --git a/parser/parser_regex.c b/parser/parser_regex.c index 3e0873b8d..c347a1360 100644 --- a/parser/parser_regex.c +++ b/parser/parser_regex.c @@ -785,7 +785,7 @@ int process_profile_regex(Profile *prof) prof->dfa.dfa = prof->dfa.rules->create_dfablob(&prof->dfa.size, &xmatch_len, prof->dfa.perms_table, parseopts, true, - prof->uses_prompt_rules && kernel_supports_permstable32, + prof->uses_prompt_rules && (prompt_compat_mode == PROMPT_COMPAT_PERMSV2), prof->uses_prompt_rules); delete prof->dfa.rules; prof->dfa.rules = NULL; @@ -1167,7 +1167,7 @@ int process_profile_policydb(Profile *prof) &xmatch_len, prof->policy.perms_table, parseopts, false, - prof->uses_prompt_rules && kernel_supports_permstable32, + prof->uses_prompt_rules && (prompt_compat_mode == PROMPT_COMPAT_PERMSV2), prof->uses_prompt_rules); delete prof->policy.rules; diff --git a/parser/rule.h b/parser/rule.h index 27468cdac..1def6b418 100644 --- a/parser/rule.h +++ b/parser/rule.h @@ -27,10 +27,12 @@ using namespace std; -#define PROMPT_COMPAT_IGNORE 0 -#define PROMPT_COMPAT_PERMSV2 1 -#define PROMPT_COMPAT_DEV 2 -#define PROMPT_COMPAT_PERMSV1 3 +#define PROMPT_COMPAT_UNKNOWN 0 +#define PROMPT_COMPAT_IGNORE 1 +#define PROMPT_COMPAT_PERMSV2 2 +#define PROMPT_COMPAT_DEV 3 +#define PROMPT_COMPAT_FLAG 4 +#define PROMPT_COMPAT_PERMSV1 5 class Profile; From 07155e8e8309d84524601c48e8059ea5921c667f Mon Sep 17 00:00:00 2001 From: John Johansen Date: Thu, 3 Aug 2023 20:51:26 -0700 Subject: [PATCH 13/17] parser: add note of what perms.h is perms.h contains policy uapi for extended perms v2/v3 add a note about what it is Signed-off-by: John Johansen --- parser/perms.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/parser/perms.h b/parser/perms.h index f1ac7b4b3..ab92632eb 100644 --- a/parser/perms.h +++ b/parser/perms.h @@ -18,6 +18,12 @@ #ifndef __AA_PERM_H #define __AA_PERM_H +/* this represents permissions as used as part of the state machine in + * the kernel. + * It is possible this will get further mapped for compatibility with + * older versions + */ + #include #include From 4264338bed12e44497a915233f8e5f35b5016bee Mon Sep 17 00:00:00 2001 From: John Johansen Date: Thu, 3 Aug 2023 23:21:05 -0700 Subject: [PATCH 14/17] convert owner to an enum provide better type checking and semantics to the owner conditional Signed-off-by: John Johansen --- parser/dbus.h | 2 +- parser/mount.h | 2 +- parser/parser_yacc.y | 20 ++++++++++---------- parser/ptrace.h | 2 +- parser/rule.h | 28 +++++++++++++++++++++------- parser/signal.h | 2 +- 6 files changed, 35 insertions(+), 21 deletions(-) diff --git a/parser/dbus.h b/parser/dbus.h index 852755687..9d978d97d 100644 --- a/parser/dbus.h +++ b/parser/dbus.h @@ -51,7 +51,7 @@ public: free(member); }; virtual bool valid_prefix(const prefixes &p, const char *&error) { - if (p.owner) { + if (p.owner != OWNER_UNSPECIFIED) { error = "owner prefix not allowed on dbus rules"; return false; } diff --git a/parser/mount.h b/parser/mount.h index 8767a404e..e6bdd01b5 100644 --- a/parser/mount.h +++ b/parser/mount.h @@ -163,7 +163,7 @@ public: } virtual bool valid_prefix(const prefixes &p, const char *&error) { - if (p.owner) { + if (p.owner != OWNER_UNSPECIFIED) { error = "owner prefix not allowed on mount rules"; return false; } diff --git a/parser/parser_yacc.y b/parser/parser_yacc.y index c957bd5e1..e4fd875e2 100644 --- a/parser/parser_yacc.y +++ b/parser/parser_yacc.y @@ -222,6 +222,7 @@ static void abi_features(char *filename, bool search); struct cond_entry *cond_entry; struct cond_entry_list cond_entry_list; int boolean; + owner_t owner; struct prefixes prefix; IncludeCache_t *includecache; audit_t audit; @@ -266,7 +267,7 @@ static void abi_features(char *filename, bool search); %type opt_id_or_var %type opt_subset_flag %type opt_audit_flag -%type opt_owner_flag +%type opt_owner_flag %type opt_profile_flag %type opt_flags %type opt_rule_mode @@ -626,9 +627,9 @@ opt_subset_flag: { /* nothing */ $$ = false; } opt_audit_flag: { /* nothing */ $$ = AUDIT_UNSPECIFIED; } | TOK_AUDIT { $$ = AUDIT_FORCE; }; -opt_owner_flag: { /* nothing */ $$ = 0; } - | TOK_OWNER { $$ = 1; }; - | TOK_OTHER { $$ = 2; }; +opt_owner_flag: { /* nothing */ $$ = OWNER_UNSPECIFIED; } + | TOK_OWNER { $$ = OWNER_SPECIFIED; }; + | TOK_OTHER { $$ = OWNER_NOT; }; opt_rule_mode: { /* nothing */ $$ = RULE_UNSPECIFIED; } | TOK_ALLOW { $$ = RULE_ALLOW; } @@ -680,7 +681,7 @@ rules: rules opt_prefix block $2.audit == AUDIT_FORCE ? "audit " : "", $2.rule_mode == RULE_DENY ? "deny " : "", $2.rule_mode == RULE_PROMPT ? "prompt " : "", - $2.owner ? "owner " : ""); + $2.owner == OWNER_SPECIFIED ? "owner " : ""); list_for_each_safe($3->entries, entry, tmp) { const char *error; entry->next = NULL; @@ -746,8 +747,8 @@ rules: rules opt_prefix change_profile PDEBUG("rules change_profile: (%s)\n", $3->name); if (!$3) yyerror(_("Assert: `change_profile' returned NULL.")); - if ($2.owner) - yyerror(_("owner prefix not allowed on unix rules")); + if ($2.owner != OWNER_UNSPECIFIED) + yyerror(_("owner conditional not allowed on unix rules")); if (($2.rule_mode == RULE_DENY) && $2.audit == AUDIT_FORCE) { $3->rule_mode = RULE_DENY; } else if ($2.rule_mode == RULE_DENY) { @@ -762,8 +763,8 @@ rules: rules opt_prefix change_profile rules: rules opt_prefix capability { - if ($2.owner) - yyerror(_("owner prefix not allowed on capability rules")); + if ($2.owner != OWNER_UNSPECIFIED) + yyerror(_("owner conditional not allowed on capability rules")); if ($2.rule_mode == RULE_DENY && $2.audit == AUDIT_FORCE) { $1->caps.deny |= $3; @@ -1809,4 +1810,3 @@ static void abi_features(char *filename, bool search) } }; - diff --git a/parser/ptrace.h b/parser/ptrace.h index bbe7b8638..3b76507d5 100644 --- a/parser/ptrace.h +++ b/parser/ptrace.h @@ -45,7 +45,7 @@ public: virtual int gen_policy_re(Profile &prof); virtual bool valid_prefix(const prefixes &p, const char *&error) { - if (p.owner) { + if (p.owner != OWNER_UNSPECIFIED) { error = "owner prefix not allowed on ptrace rules"; return false; } diff --git a/parser/rule.h b/parser/rule.h index 1def6b418..1192b270a 100644 --- a/parser/rule.h +++ b/parser/rule.h @@ -162,6 +162,8 @@ typedef std::list RuleList; /* Not classes so they can be used in the bison front end */ typedef enum { AUDIT_UNSPECIFIED, AUDIT_FORCE, AUDIT_QUIET } audit_t; typedef enum { RULE_UNSPECIFIED, RULE_ALLOW, RULE_DENY, RULE_PROMPT } rule_mode_t; +typedef enum { OWNER_UNSPECIFIED, OWNER_SPECIFIED, OWNER_NOT } owner_t; + /* NOTE: we can not have a constructor for class prefixes. This is * because it will break bison, and we would need to transition to @@ -173,7 +175,7 @@ class prefixes { public: audit_t audit; rule_mode_t rule_mode; - int owner; + owner_t owner; ostream &dump(ostream &os) { @@ -216,11 +218,21 @@ public: break; } - if (owner) { + switch (owner) { + case OWNER_SPECIFIED: if (output) os << " "; os << "owner"; output = true; + break; + case OWNER_NOT: + if (output) + os << " "; + os << "!owner"; + output = true; + break; + default: + break; } if (output) @@ -238,9 +250,9 @@ public: return -1; if ((uint) rule_mode > (uint) rhs.rule_mode) return 1; - if (owner < rhs.owner) + if ((uint) owner < (uint) rhs.owner) return -1; - if (owner > rhs.owner) + if ((uint) owner > (uint) rhs.owner) return 1; return 0; } @@ -250,7 +262,7 @@ public: return true; if ((uint) rule_mode < (uint) rhs.rule_mode) return true; - if (owner < rhs.owner) + if ((uint) owner < (uint) rhs.owner) return true; return false; } @@ -263,7 +275,7 @@ public: /* Must construct prefix here see note on prefixes */ audit = AUDIT_UNSPECIFIED; rule_mode = RULE_UNSPECIFIED; - owner = 0; + owner = OWNER_UNSPECIFIED; }; virtual bool valid_prefix(const prefixes &p, const char *&error) = 0; @@ -293,13 +305,15 @@ public: /* owner !owner conflicts */ if (p.owner) { - if (owner && owner != p.owner) { + if (owner != OWNER_UNSPECIFIED && + owner != p.owner) { error = "conflicting owner prefix"; return false; } owner = p.owner; } + /* TODO: MOVE this ! */ /* does the prefix imply a modifier */ if (p.rule_mode == RULE_DENY && p.audit == AUDIT_FORCE) { rule_mode = RULE_DENY; diff --git a/parser/signal.h b/parser/signal.h index d3295a4a9..a670eb2c3 100644 --- a/parser/signal.h +++ b/parser/signal.h @@ -47,7 +47,7 @@ public: free(peer_label); }; virtual bool valid_prefix(const prefixes &p, const char *&error) { - if (p.owner) { + if (p.owner != OWNER_UNSPECIFIED) { error = "owner prefix not allowed on signal rules"; return false; } From 373c095b3e061c2c4452e9e0c9e728cad76c1035 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Fri, 4 Aug 2023 01:49:10 -0700 Subject: [PATCH 15/17] parser: switch backend to perm32_t for permission bits switch permission bits to use perm32_t type. This is just annotating the code as it is no different than uint32_t at this time. We do not convert the accept values as they may be mapped permission bits or they may be and index value. Signed-off-by: John Johansen --- parser/libapparmor_re/aare_rules.cc | 6 +++--- parser/libapparmor_re/aare_rules.h | 6 +++--- parser/libapparmor_re/expr-tree.h | 15 ++++++++------- parser/libapparmor_re/hfa.cc | 20 ++++++++++---------- parser/libapparmor_re/hfa.h | 6 +++--- 5 files changed, 27 insertions(+), 26 deletions(-) diff --git a/parser/libapparmor_re/aare_rules.cc b/parser/libapparmor_re/aare_rules.cc index 4dcbc4cc9..f86f9968c 100644 --- a/parser/libapparmor_re/aare_rules.cc +++ b/parser/libapparmor_re/aare_rules.cc @@ -44,8 +44,8 @@ aare_rules::~aare_rules(void) expr_map.clear(); } -bool aare_rules::add_rule(const char *rule, rule_mode_t mode, uint32_t perms, - uint32_t audit, optflags const &opts) +bool aare_rules::add_rule(const char *rule, rule_mode_t mode, perm32_t perms, + perm32_t audit, optflags const &opts) { return add_rule_vec(mode, perms, audit, 1, &rule, opts, false); } @@ -71,7 +71,7 @@ static Node *cat_with_oob_separator(Node *l, Node *r) return new CatNode(new CatNode(l, new CharNode(transchar(-1, true))), r); } -bool aare_rules::add_rule_vec(rule_mode_t mode, uint32_t perms, uint32_t audit, +bool aare_rules::add_rule_vec(rule_mode_t mode, perm32_t perms, perm32_t audit, int count, const char **rulev, optflags const &opts, bool oob) { diff --git a/parser/libapparmor_re/aare_rules.h b/parser/libapparmor_re/aare_rules.h index 7cc163380..a35ffd9e9 100644 --- a/parser/libapparmor_re/aare_rules.h +++ b/parser/libapparmor_re/aare_rules.h @@ -109,9 +109,9 @@ class aare_rules { aare_rules(int reverse): root(NULL), unique_perms(), expr_map(), reverse(reverse), rule_count(0) { }; ~aare_rules(); - bool add_rule(const char *rule, rule_mode_t mode, uint32_t perms, - uint32_t audit, optflags const &opts); - bool add_rule_vec(rule_mode_t mode, uint32_t perms, uint32_t audit, + bool add_rule(const char *rule, rule_mode_t mode, perm32_t perms, + perm32_t audit, optflags const &opts); + bool add_rule_vec(rule_mode_t mode, perm32_t perms, perm32_t audit, int count, const char **rulev, optflags const &opts, bool oob); bool append_rule(const char *rule, bool oob, bool with_perm, optflags const &opts); diff --git a/parser/libapparmor_re/expr-tree.h b/parser/libapparmor_re/expr-tree.h index 8341b4ff9..1a674539e 100644 --- a/parser/libapparmor_re/expr-tree.h +++ b/parser/libapparmor_re/expr-tree.h @@ -41,6 +41,7 @@ #include +#include "../perms.h" #include "apparmor_re.h" using namespace std; @@ -885,19 +886,19 @@ public: class MatchFlag: public AcceptNode { public: - MatchFlag(uint32_t flag, uint32_t audit): flag(flag), audit(audit) + MatchFlag(perm32_t perms, perm32_t audit): perms(perms), audit(audit) { type_flags |= NODE_TYPE_MATCHFLAG; } - ostream &dump(ostream &os) { return os << "< 0x" << hex << flag << '>'; } + ostream &dump(ostream &os) { return os << "< 0x" << hex << perms << '>'; } - uint32_t flag; - uint32_t audit; + perm32_t perms; + perm32_t audit; }; class ExactMatchFlag: public MatchFlag { public: - ExactMatchFlag(uint32_t flag, uint32_t audit): MatchFlag(flag, audit) + ExactMatchFlag(perm32_t perms, perm32_t audit): MatchFlag(perms, audit) { type_flags |= NODE_TYPE_EXACTMATCHFLAG; } @@ -905,7 +906,7 @@ public: class DenyMatchFlag: public MatchFlag { public: - DenyMatchFlag(uint32_t flag, uint32_t quiet): MatchFlag(flag, quiet) + DenyMatchFlag(perm32_t perms, perm32_t quiet): MatchFlag(perms, quiet) { type_flags |= NODE_TYPE_DENYMATCHFLAG; } @@ -913,7 +914,7 @@ public: class PromptMatchFlag: public MatchFlag { public: - PromptMatchFlag(uint32_t prompt, uint32_t audit): MatchFlag(prompt, audit) {} + PromptMatchFlag(perm32_t prompt, perm32_t audit): MatchFlag(prompt, audit) {} }; diff --git a/parser/libapparmor_re/hfa.cc b/parser/libapparmor_re/hfa.cc index f9cee068d..b32bb07cf 100644 --- a/parser/libapparmor_re/hfa.cc +++ b/parser/libapparmor_re/hfa.cc @@ -1376,7 +1376,7 @@ map dominance(DFA & dfa) } #endif -static inline int diff_qualifiers(uint32_t perm1, uint32_t perm2) +static inline int diff_qualifiers(perm32_t perm1, perm32_t perm2) { return ((perm1 & AA_EXEC_TYPE) && (perm2 & AA_EXEC_TYPE) && (perm1 & AA_EXEC_TYPE) != (perm2 & AA_EXEC_TYPE)); @@ -1390,9 +1390,9 @@ static inline int diff_qualifiers(uint32_t perm1, uint32_t perm2) int accept_perms(NodeVec *state, perms_t &perms, bool filedfa) { int error = 0; - uint32_t exact_match_allow = 0; - uint32_t exact_match_prompt = 0; - uint32_t exact_audit = 0; + perm32_t exact_match_allow = 0; + perm32_t exact_match_prompt = 0; + perm32_t exact_audit = 0; perms.clear(); @@ -1407,20 +1407,20 @@ int accept_perms(NodeVec *state, perms_t &perms, bool filedfa) if (match->is_type(NODE_TYPE_EXACTMATCHFLAG)) { /* exact match only ever happens with x */ if (filedfa && !is_merged_x_consistent(exact_match_allow, - match->flag)) + match->perms)) error = 1;; - exact_match_allow |= match->flag; + exact_match_allow |= match->perms; exact_audit |= match->audit; } else if (match->is_type(NODE_TYPE_DENYMATCHFLAG)) { - perms.deny |= match->flag; + perms.deny |= match->perms; perms.quiet |= match->audit; } else if (dynamic_cast(match)) { - perms.prompt |= match->flag; + perms.prompt |= match->perms; perms.audit |= match->audit; } else { - if (filedfa && !is_merged_x_consistent(perms.allow, match->flag)) + if (filedfa && !is_merged_x_consistent(perms.allow, match->perms)) error = 1; - perms.allow |= match->flag; + perms.allow |= match->perms; perms.audit |= match->audit; } } diff --git a/parser/libapparmor_re/hfa.h b/parser/libapparmor_re/hfa.h index 1b3b69335..1aa599266 100644 --- a/parser/libapparmor_re/hfa.h +++ b/parser/libapparmor_re/hfa.h @@ -142,7 +142,7 @@ public: return quiet < rhs.quiet; } - uint32_t allow, deny, prompt, audit, quiet, exact; + perm32_t allow, deny, prompt, audit, quiet, exact; }; int accept_perms(NodeVec *state, perms_t &perms, bool filedfa); @@ -260,8 +260,8 @@ public: void flatten_relative(State *, int upper_bound); int apply_and_clear_deny(void) { return perms.apply_and_clear_deny(); } - void map_perms_to_accept(uint32_t &accept1, uint32_t &accept2, - uint32_t &accept3, bool prompt) + void map_perms_to_accept(perm32_t &accept1, perm32_t &accept2, + perm32_t &accept3, bool prompt) { accept1 = perms.allow; if (prompt && prompt_compat_mode == PROMPT_COMPAT_DEV) From b72cae79cb14acb231af01861ab7d9f8c1dc2c02 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Thu, 29 Feb 2024 17:21:37 -0800 Subject: [PATCH 16/17] parser: support uin128_t key as a pair of uint64_t numbers __uint128 is not supported by gcc on 32 bit architectures so rework the 128 bit map key to be a pair of 64bit numbers. Signed-off-by: John Johansen --- parser/libapparmor_re/hfa.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/parser/libapparmor_re/hfa.cc b/parser/libapparmor_re/hfa.cc index b32bb07cf..e0164c501 100644 --- a/parser/libapparmor_re/hfa.cc +++ b/parser/libapparmor_re/hfa.cc @@ -31,7 +31,7 @@ #include #include #include - +#include #include "expr-tree.h" #include "hfa.h" #include "policy_compat.h" @@ -647,7 +647,7 @@ int DFA::apply_and_clear_deny(void) } -typedef __uint128_t uint128_t; +typedef pair uint128_t; /* minimize the number of dfa states */ void DFA::minimize(optflags const &opts) @@ -669,7 +669,9 @@ void DFA::minimize(optflags const &opts) int final_accept = 0; for (Partition::iterator i = states.begin(); i != states.end(); i++) { size_t hash = 0; - uint128_t permtype = ((uint128_t) (PACK_AUDIT_CTL((*i)->perms.audit, (*i)->perms.quiet & (*i)->perms.deny)) << 32) | (uint128_t) (*i)->perms.allow | ((uint128_t) (*i)->perms.prompt << 64); + uint128_t permtype; + permtype.first = ((uint64_t) (PACK_AUDIT_CTL((*i)->perms.audit, (*i)->perms.quiet & (*i)->perms.deny)) << 32); + permtype.second = (uint64_t) (*i)->perms.allow | ((uint64_t) (*i)->perms.prompt << 32); pair group = make_pair(permtype, hash); map, Partition *>::iterator p = perm_map.find(group); if (p == perm_map.end()) { @@ -678,7 +680,7 @@ void DFA::minimize(optflags const &opts) perm_map.insert(make_pair(group, part)); partitions.push_back(part); (*i)->partition = part; - if (permtype) + if (permtype.first || permtype.second) accept_count++; } else { (*i)->partition = p->second; From d0062b6d4a09eeedf3992f60a2a99241b379dc14 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Thu, 8 Aug 2024 01:44:05 -0700 Subject: [PATCH 17/17] parser: fix protocol error on older kernels caused by additional xtable Older kernels do not support an xtable grouped with the policy dfa. The presence of a policy.dfa does not indicate whether we should create an xtable with the policy dfa. Instead the check should be if the kernel supports the extended permstable32 format. Signed-off-by: John Johansen --- parser/parser_interface.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/parser/parser_interface.c b/parser/parser_interface.c index f4abe5bf7..816fe5cba 100644 --- a/parser/parser_interface.c +++ b/parser/parser_interface.c @@ -545,13 +545,13 @@ void sd_serialize_profile(std::ostringstream &buf, Profile *profile, sd_write_struct(buf, "policydb"); sd_serialize_dfa(buf, profile->policy.dfa, profile->policy.size, profile->policy.perms_table); - if (profile->policy.dfa) { - // fprintf(stderr, "profile %s: policy xtable\n", profile->name); - // TODO: this is dummy exec make dependent on V1 - sd_serialize_xtable(buf, profile->exec_table, - profile->uses_prompt_rules && prompt_compat_mode == PROMPT_COMPAT_PERMSV1 ? - profile->policy.perms_table.size() : 0); - } + if (kernel_supports_permstable32) { + sd_serialize_xtable(buf, profile->exec_table, + profile->uses_prompt_rules && + prompt_compat_mode == PROMPT_COMPAT_PERMSV1 ? + profile->policy.perms_table.size() : 0); + + } sd_write_structend(buf); }