mirror of
https://gitlab.com/apparmor/apparmor.git
synced 2025-03-04 08:24:42 +01:00
Add Audit control to AppArmor through, the use of audit and deny
key words. Deny is also used to subtract permissions from the profiles permission set. the audit key word can be prepended to any file, network, or capability rule, to force a selective audit when that rule is matched. Audit permissions accumulate just like standard permissions. eg. audit /bin/foo rw, will force an audit message when the file /bin/foo is opened for read or write. audit /etc/shadow w, /etc/shadow r, will force an audit message when /etc/shadow is opened for writing. The audit message is per permission bit so only opening the file for read access will not, force an audit message. audit can also be used in block form instead of prepending audit to every rule. audit { /bin/foo rw, /etc/shadow w, } /etc/shadow r, # don't audit r access to /etc/shadow the deny key word can be prepended to file, network and capability rules, to result in a denial of permissions when matching that rule. The deny rule specifically does 3 things - it gives AppArmor the ability to remember what has been denied so that the tools don't prompt for what has been denied in previous profiling sessions. - it subtracts globally from the allowed permissions. Deny permissions accumulate in the the deny set just as allow permissions accumulate then, the deny set is subtracted from the allow set. - it quiets known rejects. The default audit behavior of deny rules is to quiet known rejects so that audit logs are not flooded with already known rejects. To have known rejects logged prepend the audit keyword to the deny rule. Deny rules do not have a block form. eg. deny /foo/bar rw, audit deny /etc/shadow w, audit { deny owner /blah w, deny other /foo w, deny /etc/shadow w, }
This commit is contained in:
parent
36ad7de2c5
commit
a3c0753b89
8 changed files with 308 additions and 108 deletions
|
@ -845,21 +845,27 @@ DFA::~DFA()
|
|||
|
||||
class MatchFlag : public AcceptNode {
|
||||
public:
|
||||
MatchFlag(uint32_t flag) : flag(flag) {}
|
||||
MatchFlag(uint32_t flag, uint32_t audit) : flag(flag), audit(audit) {}
|
||||
ostream& dump(ostream& os)
|
||||
{
|
||||
return os << '<' << flag << '>';
|
||||
}
|
||||
|
||||
uint32_t flag;
|
||||
uint32_t audit;
|
||||
};
|
||||
|
||||
class ExactMatchFlag : public MatchFlag {
|
||||
public:
|
||||
ExactMatchFlag(uint32_t flag) : MatchFlag(flag) {}
|
||||
ExactMatchFlag(uint32_t flag, uint32_t audit) : MatchFlag(flag, audit) {}
|
||||
};
|
||||
|
||||
uint32_t accept_perms(State *state);
|
||||
class DenyMatchFlag : public MatchFlag {
|
||||
public:
|
||||
DenyMatchFlag(uint32_t flag, uint32_t quiet) : MatchFlag(flag, quiet) {}
|
||||
};
|
||||
|
||||
uint32_t accept_perms(State *state, uint32_t *audit_ctl);
|
||||
|
||||
/**
|
||||
* verify that there are no conflicting X permissions on the dfa
|
||||
|
@ -869,7 +875,7 @@ uint32_t accept_perms(State *state);
|
|||
State *DFA::verify_perms(void)
|
||||
{
|
||||
for (States::iterator i = states.begin(); i != states.end(); i++) {
|
||||
uint32_t accept = accept_perms(*i);
|
||||
uint32_t accept = accept_perms(*i, NULL);
|
||||
if (*i == start || accept) {
|
||||
if (accept & AA_ERROR_BIT)
|
||||
return *i;
|
||||
|
@ -884,13 +890,14 @@ State *DFA::verify_perms(void)
|
|||
void DFA::dump(ostream& os)
|
||||
{
|
||||
for (States::iterator i = states.begin(); i != states.end(); i++) {
|
||||
uint32_t accept = accept_perms(*i);
|
||||
uint32_t accept, audit;
|
||||
accept = accept_perms(*i, &audit);
|
||||
if (*i == start || accept) {
|
||||
os << **i;
|
||||
if (*i == start)
|
||||
os << " <==";
|
||||
if (accept) {
|
||||
os << " (0x" << hex << accept << dec << ')';
|
||||
os << " (0x" << hex << accept << " " << audit << dec << ')';
|
||||
}
|
||||
os << endl;
|
||||
}
|
||||
|
@ -923,7 +930,7 @@ void DFA::dump_dot_graph(ostream& os)
|
|||
if (*i == start) {
|
||||
os << "\t\tstyle=bold" << endl;
|
||||
}
|
||||
uint32_t perms = accept_perms(*i);
|
||||
uint32_t perms = accept_perms(*i, NULL);
|
||||
if (perms) {
|
||||
os << "\t\tlabel=\"" << **i << "\\n("
|
||||
<< perms << ")\"" << endl;
|
||||
|
@ -1096,6 +1103,7 @@ public:
|
|||
|
||||
private:
|
||||
vector<uint32_t> accept;
|
||||
vector<uint32_t> accept2;
|
||||
DefaultBase default_base;
|
||||
NextCheck next_check;
|
||||
map<const State *, size_t> num;
|
||||
|
@ -1142,8 +1150,12 @@ TransitionTable::TransitionTable(DFA& dfa, map<uchar, uchar>& eq)
|
|||
}
|
||||
|
||||
accept.resize(dfa.states.size());
|
||||
for (States::iterator i = dfa.states.begin(); i != dfa.states.end(); i++)
|
||||
accept[num[*i]] = accept_perms(*i);
|
||||
accept2.resize(dfa.states.size());
|
||||
for (States::iterator i = dfa.states.begin(); i != dfa.states.end(); i++) {
|
||||
uint32_t audit_ctl;
|
||||
accept[num[*i]] = accept_perms(*i, &audit_ctl);
|
||||
accept2[num[*i]] = audit_ctl;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1397,6 +1409,7 @@ void TransitionTable::flex_table(ostream& os, const char *name)
|
|||
th.th_hsize = htonl(hsize);
|
||||
th.th_ssize = htonl(hsize +
|
||||
flex_table_size(accept.begin(), accept.end()) +
|
||||
flex_table_size(accept2.begin(), accept2.end()) +
|
||||
(eq.size() ?
|
||||
flex_table_size(equiv_vec.begin(), equiv_vec.end()) : 0) +
|
||||
flex_table_size(base_vec.begin(), base_vec.end()) +
|
||||
|
@ -1409,6 +1422,7 @@ void TransitionTable::flex_table(ostream& os, const char *name)
|
|||
|
||||
|
||||
write_flex_table(os, YYTD_ID_ACCEPT, accept.begin(), accept.end());
|
||||
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());
|
||||
write_flex_table(os, YYTD_ID_BASE, base_vec.begin(), base_vec.end());
|
||||
|
@ -1503,41 +1517,66 @@ static inline int diff_qualifiers(uint32_t perm1, uint32_t perm2)
|
|||
* have any exact matches, then they override the execute and safe
|
||||
* execute flags.
|
||||
*/
|
||||
uint32_t accept_perms(State *state)
|
||||
uint32_t accept_perms(State *state, uint32_t *audit_ctl)
|
||||
{
|
||||
uint32_t perms = 0, exact_match_perms = 0;
|
||||
uint32_t perms = 0, exact_match_perms = 0, audit = 0, exact_audit = 0,
|
||||
quiet = 0, deny = 0;
|
||||
|
||||
for (State::iterator i = state->begin(); i != state->end(); i++) {
|
||||
MatchFlag *match;
|
||||
if (!(match= dynamic_cast<MatchFlag *>(*i)))
|
||||
continue;
|
||||
if (dynamic_cast<ExactMatchFlag *>(match)) {
|
||||
/* exact match only ever happens with x */
|
||||
if (!is_merged_x_consistent(exact_match_perms,
|
||||
match->flag))
|
||||
exact_match_perms |= AA_ERROR_BIT;
|
||||
exact_match_perms |= match->flag;
|
||||
exact_audit |= match->audit;
|
||||
} else if (dynamic_cast<DenyMatchFlag *>(match)) {
|
||||
deny |= match->flag;
|
||||
quiet |= match->audit;
|
||||
} else {
|
||||
if (!is_merged_x_consistent(perms, match->flag))
|
||||
perms |= AA_ERROR_BIT;
|
||||
perms |= match->flag;
|
||||
audit |= match->audit;
|
||||
}
|
||||
}
|
||||
|
||||
//if (audit || quiet)
|
||||
//fprintf(stderr, "perms: 0x%x, audit: 0x%x exact: 0x%x eaud: 0x%x deny: 0x%x quiet: 0x%x\n", perms, audit, exact_match_perms, exact_audit, deny, quiet);
|
||||
|
||||
perms |= exact_match_perms &
|
||||
~(AA_USER_EXEC_TYPE | AA_OTHER_EXEC_TYPE);
|
||||
|
||||
if (exact_match_perms & AA_USER_EXEC_TYPE)
|
||||
if (exact_match_perms & AA_USER_EXEC_TYPE) {
|
||||
perms = (exact_match_perms & AA_USER_EXEC_TYPE) |
|
||||
(perms & ~AA_USER_EXEC_TYPE);
|
||||
|
||||
if (exact_match_perms & AA_OTHER_EXEC_TYPE)
|
||||
audit = (exact_audit & AA_USER_EXEC_TYPE) |
|
||||
(audit & ~ AA_USER_EXEC_TYPE);
|
||||
}
|
||||
if (exact_match_perms & AA_OTHER_EXEC_TYPE) {
|
||||
perms = (exact_match_perms & AA_OTHER_EXEC_TYPE) |
|
||||
(perms & ~AA_OTHER_EXEC_TYPE);
|
||||
audit = (exact_audit & AA_OTHER_EXEC_TYPE) |
|
||||
(audit & ~AA_OTHER_EXEC_TYPE);
|
||||
}
|
||||
if (perms & AA_USER_EXEC & deny)
|
||||
perms &= ~AA_USER_EXEC_TYPE;
|
||||
|
||||
if (perms & AA_ERROR_BIT) {
|
||||
fprintf(stderr, "error bit 0x%x\n", perms);
|
||||
exit(255);
|
||||
}
|
||||
if (perms & AA_OTHER_EXEC & deny)
|
||||
perms &= ~AA_OTHER_EXEC_TYPE;
|
||||
|
||||
perms &= ~deny;
|
||||
|
||||
if (audit_ctl)
|
||||
*audit_ctl = PACK_AUDIT_CTL(audit, quiet & deny);
|
||||
|
||||
// if (perms & AA_ERROR_BIT) {
|
||||
// fprintf(stderr, "error bit 0x%x\n", perms);
|
||||
// exit(255);
|
||||
//}
|
||||
|
||||
//if (perms & AA_EXEC_BITS)
|
||||
//fprintf(stderr, "accept perm: 0x%x\n", perms);
|
||||
|
@ -1548,17 +1587,20 @@ uint32_t accept_perms(State *state)
|
|||
return perms;
|
||||
}
|
||||
|
||||
extern "C" int aare_add_rule(aare_ruleset_t *rules, char *rule, uint32_t perms)
|
||||
extern "C" int aare_add_rule(aare_ruleset_t *rules, char *rule, int deny,
|
||||
uint32_t perms, uint32_t audit)
|
||||
{
|
||||
return aare_add_rule_vec(rules, perms, 1, &rule);
|
||||
return aare_add_rule_vec(rules, deny, perms, audit, 1, &rule);
|
||||
}
|
||||
|
||||
extern "C" int aare_add_rule_vec(aare_ruleset_t *rules, uint32_t perms,
|
||||
extern "C" int aare_add_rule_vec(aare_ruleset_t *rules, int deny,
|
||||
uint32_t perms, uint32_t audit,
|
||||
int count, char **rulev)
|
||||
{
|
||||
static MatchFlag *match_flags[sizeof(perms) * 8 - 1];
|
||||
static MatchFlag *exec_match_flags[64 * 2]; /* mods + unsafe *u::o*/
|
||||
static ExactMatchFlag *exact_match_flags[64 * 2]; /* mods + unsafe *u::o*/
|
||||
static MatchFlag *match_flags[2][sizeof(perms) * 8 - 1];
|
||||
static DenyMatchFlag *deny_flags[2][sizeof(perms) * 8 - 1];
|
||||
static MatchFlag *exec_match_flags[2][(AA_EXEC_COUNT << 1) * 2]; /* mods + unsafe *u::o*/
|
||||
static ExactMatchFlag *exact_match_flags[2][(AA_EXEC_COUNT << 1) * 2];/* mods + unsafe *u::o*/
|
||||
Node *tree = NULL, *accept;
|
||||
int exact_match;
|
||||
|
||||
|
@ -1595,58 +1637,73 @@ extern "C" int aare_add_rule_vec(aare_ruleset_t *rules, uint32_t perms,
|
|||
if (rules->reverse)
|
||||
flip_tree(tree);
|
||||
|
||||
#define ALL_EXEC_TYPE (AA_USER_EXEC_TYPE | AA_OTHER_EXEC_TYPE)
|
||||
|
||||
/* 0x3f == 5 bits x mods + 1 bit unsafe mask, after shift */
|
||||
#define EXTRACT_X_INDEX(perm, shift) (((perm) >> (shift + 8)) & 0x3f)
|
||||
|
||||
if (perms & ALL_EXEC_TYPE && (!perms & AA_EXEC_BITS))
|
||||
fprintf(stderr, "adding X rule without MAY_EXEC: 0x%x %s\n", perms, rulev[0]);
|
||||
//if (perms & ALL_AA_EXEC_TYPE && (!perms & AA_EXEC_BITS))
|
||||
// fprintf(stderr, "adding X rule without MAY_EXEC: 0x%x %s\n", perms, rulev[0]);
|
||||
|
||||
//if (perms & ALL_EXEC_TYPE)
|
||||
// fprintf(stderr, "adding X rule %s 0x%x\n", rulev[0], perms);
|
||||
|
||||
//if (audit)
|
||||
//fprintf(stderr, "adding rule with audit bits set: 0x%x %s\n", audit, rulev[0]);
|
||||
|
||||
/* the permissions set is assumed to be non-empty if any audit
|
||||
* bits are specified */
|
||||
accept = NULL;
|
||||
for (unsigned int n = 0; perms && n < (sizeof(perms) * 8) - 1; n++) {
|
||||
uint32_t mask = 1 << n;
|
||||
|
||||
if (perms & mask) {
|
||||
int ai = audit & mask ? 1 : 0;
|
||||
perms &= ~mask;
|
||||
|
||||
Node *flag;
|
||||
if (mask & AA_EXEC_BITS) {
|
||||
if (mask & ALL_AA_EXEC_TYPE)
|
||||
/* these cases are covered by EXEC_BITS */
|
||||
continue;
|
||||
if (deny) {
|
||||
if (deny_flags[ai][n]) {
|
||||
flag = deny_flags[ai][n]->dup();
|
||||
} else {
|
||||
//fprintf(stderr, "Adding deny ai %d mask 0x%x audit 0x%x\n", ai, mask, audit & mask);
|
||||
deny_flags[ai][n] = new DenyMatchFlag(mask, audit&mask);
|
||||
flag = deny_flags[ai][n];
|
||||
}
|
||||
} else if (mask & AA_EXEC_BITS) {
|
||||
uint32_t eperm = 0;
|
||||
uint32_t index = 0;
|
||||
if (mask & AA_USER_EXEC_TYPE) {
|
||||
if (mask & AA_USER_EXEC) {
|
||||
eperm = mask | (perms & AA_USER_EXEC_TYPE);
|
||||
index = EXTRACT_X_INDEX(eperm, AA_USER_SHIFT);
|
||||
} else {
|
||||
eperm = mask | (perms & AA_OTHER_EXEC_TYPE);
|
||||
index = EXTRACT_X_INDEX(eperm, AA_OTHER_SHIFT) + 16;
|
||||
index = EXTRACT_X_INDEX(eperm, AA_OTHER_SHIFT) + (AA_EXEC_COUNT << 1);
|
||||
}
|
||||
//fprintf(stderr, "index %d eperm 0x%x\n", index, eperm);
|
||||
if (exact_match) {
|
||||
if (exact_match_flags[index]) {
|
||||
flag = exact_match_flags[index]->dup();
|
||||
if (exact_match_flags[ai][index]) {
|
||||
flag = exact_match_flags[ai][index]->dup();
|
||||
} else {
|
||||
exact_match_flags[index] = new ExactMatchFlag(eperm);
|
||||
flag = exact_match_flags[index];
|
||||
exact_match_flags[ai][index] = new ExactMatchFlag(eperm, audit&mask);
|
||||
flag = exact_match_flags[ai][index];
|
||||
}
|
||||
} else {
|
||||
if (exec_match_flags[index]) {
|
||||
flag = exec_match_flags[index]->dup();
|
||||
if (exec_match_flags[ai][index]) {
|
||||
flag = exec_match_flags[ai][index]->dup();
|
||||
} else {
|
||||
exec_match_flags[index] = new MatchFlag(eperm);
|
||||
flag = exec_match_flags[index];
|
||||
exec_match_flags[ai][index] = new MatchFlag(eperm, audit&mask);
|
||||
flag = exec_match_flags[ai][index];
|
||||
}
|
||||
}
|
||||
} else if (mask & ALL_EXEC_TYPE) {
|
||||
/* these cases are covered by EXEC_BITS */
|
||||
continue;
|
||||
} else {
|
||||
if (match_flags[n]) {
|
||||
flag = match_flags[n]->dup();
|
||||
if (match_flags[ai][n]) {
|
||||
flag = match_flags[ai][n]->dup();
|
||||
} else {
|
||||
match_flags[n] = new MatchFlag(mask);
|
||||
flag = match_flags[n];
|
||||
match_flags[ai][n] = new MatchFlag(mask, audit&mask);
|
||||
flag = match_flags[ai][n];
|
||||
}
|
||||
}
|
||||
if (accept)
|
||||
|
|
|
@ -42,6 +42,7 @@ struct cod_entry {
|
|||
struct codomain *codomain; /* Special codomain defined
|
||||
* just for this executable */
|
||||
int mode; /* mode is 'or' of AA_* bits */
|
||||
int audit; /* audit flags for mode */
|
||||
int deny; /* TRUE or FALSE */
|
||||
|
||||
int subset;
|
||||
|
@ -72,8 +73,15 @@ struct codomain {
|
|||
struct flagval flags;
|
||||
|
||||
unsigned int capabilities;
|
||||
unsigned int audit_caps;
|
||||
unsigned int deny_caps;
|
||||
unsigned int quiet_caps;
|
||||
|
||||
unsigned int *network_allowed; /* array of type masks
|
||||
* indexed by AF_FAMILY */
|
||||
unsigned int *audit_network;
|
||||
unsigned int *deny_network;
|
||||
unsigned int *quiet_network;
|
||||
|
||||
struct cod_entry *entries;
|
||||
void *hat_table;
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
#define SD_STR_LEN (sizeof(u16))
|
||||
|
||||
#define SUBDOMAIN_INTERFACE_VERSION 2
|
||||
#define SUBDOMAIN_INTERFACE_DFA_VERSION 3
|
||||
#define SUBDOMAIN_INTERFACE_DFA_VERSION 4
|
||||
|
||||
int sd_serialize_codomain(int option, struct codomain *cod);
|
||||
|
||||
|
@ -206,7 +206,7 @@ struct __sdserialize {
|
|||
|
||||
sd_serialize *alloc_sd_serial(void)
|
||||
{
|
||||
sd_serialize *p = malloc(sizeof(sd_serialize));
|
||||
sd_serialize *p = calloc(1, sizeof(sd_serialize));
|
||||
if (!p)
|
||||
return NULL;
|
||||
p->buffer = malloc(BUFFERINC);
|
||||
|
@ -529,6 +529,7 @@ int sd_serialize_profile(sd_serialize *p, struct codomain *profile,
|
|||
int flattened)
|
||||
{
|
||||
struct cod_entry *entry;
|
||||
u32 allowed_caps;
|
||||
|
||||
if (!sd_write_struct(p, "profile"))
|
||||
return 0;
|
||||
|
@ -560,7 +561,12 @@ int sd_serialize_profile(sd_serialize *p, struct codomain *profile,
|
|||
return 0;
|
||||
if (!sd_write_structend(p))
|
||||
return 0;
|
||||
if (!sd_write32(p, profile->capabilities))
|
||||
allowed_caps = profile->capabilities & ~profile->deny_caps;
|
||||
if (!sd_write32(p, allowed_caps))
|
||||
return 0;
|
||||
if (!sd_write32(p, allowed_caps & profile->audit_caps))
|
||||
return 0;
|
||||
if (!sd_write32(p, profile->deny_caps & profile->quiet_caps))
|
||||
return 0;
|
||||
|
||||
if (profile->network_allowed) {
|
||||
|
@ -568,7 +574,13 @@ int sd_serialize_profile(sd_serialize *p, struct codomain *profile,
|
|||
if (!sd_write_array(p, "net_allowed_af", AF_MAX))
|
||||
return 0;
|
||||
for (i = 0; i < AF_MAX; i++) {
|
||||
if (!sd_write16(p, profile->network_allowed[i]))
|
||||
u16 allowed = profile->network_allowed[i] &
|
||||
~profile->deny_network[i];
|
||||
if (!sd_write16(p, allowed))
|
||||
return 0;
|
||||
if (!sd_write16(p, allowed & profile->audit_network[i]))
|
||||
return 0;
|
||||
if (!sd_write16(p, profile->deny_network[i] & profile->quiet_network[i]))
|
||||
return 0;
|
||||
}
|
||||
if (!sd_write_arrayend(p))
|
||||
|
|
|
@ -53,7 +53,7 @@ COLON :
|
|||
END_OF_RULE [,]
|
||||
SEPERATOR {UP}
|
||||
RANGE -
|
||||
MODE_CHARS ([RrWwaLlMmk])|([Pp][Xx])|([Uu][Xx])|([Ii][Xx])|([Pp][Ii][Xx])
|
||||
MODE_CHARS ([RrWwaLlMmkXx])|([Pp][Xx])|([Uu][Xx])|([Ii][Xx])|([Pp][Ii][Xx])
|
||||
MODES {MODE_CHARS}+
|
||||
WS [[:blank:]]
|
||||
NUMBER [[:digit:]]+
|
||||
|
|
|
@ -64,6 +64,9 @@ static int file_comp(const void *c1, const void *c2)
|
|||
if (res)
|
||||
return res;
|
||||
|
||||
if ((*e1)->deny != (*e2)->deny)
|
||||
return (*e1)->deny < (*e2)->deny ? -1 : 1;
|
||||
|
||||
return strcmp((*e1)->name, (*e2)->name);
|
||||
}
|
||||
|
||||
|
@ -105,7 +108,10 @@ static int process_file_entries(struct codomain *cod)
|
|||
cod->name, cur->name);
|
||||
return 0;
|
||||
}
|
||||
//if (next->audit)
|
||||
//fprintf(stderr, "warning: merging rule 0x%x %s\n", next->audit, next->name);
|
||||
cur->mode |= next->mode;
|
||||
cur->audit |= next->audit;
|
||||
free(next->name);
|
||||
if (next->link_name)
|
||||
free(next->link_name);
|
||||
|
|
|
@ -62,7 +62,11 @@ static struct keyword_table keyword_table[] = {
|
|||
{"unsafe", TOK_UNSAFE},
|
||||
{"link", TOK_LINK},
|
||||
{"owner", TOK_OWNER},
|
||||
{"user", TOK_OWNER},
|
||||
{"other", TOK_OTHER},
|
||||
{"subset", TOK_SUBSET},
|
||||
{"audit", TOK_AUDIT},
|
||||
{"deny", TOK_DENY},
|
||||
/* terminate */
|
||||
{NULL, 0}
|
||||
};
|
||||
|
@ -520,8 +524,11 @@ reeval:
|
|||
break;
|
||||
|
||||
case COD_EXEC_CHAR:
|
||||
PDEBUG("Parsing mode: found %s EXEC\n", mode_desc);
|
||||
yyerror(_("Invalid mode, 'x' must be preceded by exec qualifier 'i', 'p', or 'u'"));
|
||||
/* this is valid for deny rules, and named transitions
|
||||
* but invalid for regular x transitions
|
||||
* sort it out later.
|
||||
*/
|
||||
mode |= AA_MAY_EXEC;
|
||||
break;
|
||||
|
||||
/* error cases */
|
||||
|
@ -572,7 +579,7 @@ struct cod_entry *new_entry(char *namespace, char *id, int mode, char *link_id)
|
|||
{
|
||||
struct cod_entry *entry = NULL;
|
||||
|
||||
entry = (struct cod_entry *)malloc(sizeof(struct cod_entry));
|
||||
entry = (struct cod_entry *)calloc(1, sizeof(struct cod_entry));
|
||||
if (!entry)
|
||||
return NULL;
|
||||
|
||||
|
@ -580,6 +587,7 @@ struct cod_entry *new_entry(char *namespace, char *id, int mode, char *link_id)
|
|||
entry->name = id;
|
||||
entry->link_name = link_id;
|
||||
entry->mode = mode;
|
||||
entry->audit = 0;
|
||||
entry->deny = FALSE;
|
||||
|
||||
entry->pattern_type = ePatternInvalid;
|
||||
|
@ -596,7 +604,7 @@ struct cod_entry *copy_cod_entry(struct cod_entry *orig)
|
|||
{
|
||||
struct cod_entry *entry = NULL;
|
||||
|
||||
entry = (struct cod_entry *)malloc(sizeof(struct cod_entry));
|
||||
entry = (struct cod_entry *)calloc(1, sizeof(struct cod_entry));
|
||||
if (!entry)
|
||||
return NULL;
|
||||
|
||||
|
|
|
@ -503,8 +503,21 @@ static int process_dfa_entry(aare_ruleset_t *dfarules, struct cod_entry *entry)
|
|||
AA_EXEC_INHERIT)
|
||||
entry->mode |= AA_EXEC_MMAP << AA_USER_SHIFT;
|
||||
|
||||
if (!aare_add_rule(dfarules, tbuf, entry->mode))
|
||||
return FALSE;
|
||||
/* the link bit on the first pair entry should not get masked
|
||||
* out by a deny rule, as both pieces of the link pair must
|
||||
* match. audit info for the link is carried on the second
|
||||
* entry of the pair
|
||||
*/
|
||||
if (entry->deny && (entry->mode & AA_LINK_BITS)) {
|
||||
if (!aare_add_rule(dfarules, tbuf, entry->deny,
|
||||
entry->mode & ~AA_LINK_BITS,
|
||||
entry->audit & ~AA_LINK_BITS))
|
||||
return FALSE;
|
||||
} else {
|
||||
if (!aare_add_rule(dfarules, tbuf, entry->deny, entry->mode,
|
||||
entry->audit))
|
||||
return FALSE;
|
||||
}
|
||||
if (entry->mode & (AA_LINK_BITS)) {
|
||||
/* add the pair rule */
|
||||
char lbuf[PATH_MAX + 8];
|
||||
|
@ -522,7 +535,7 @@ static int process_dfa_entry(aare_ruleset_t *dfarules, struct cod_entry *entry)
|
|||
perms |= LINK_TO_LINK_SUBSET(perms);
|
||||
vec[1] = "/[^/].*";
|
||||
}
|
||||
if (!aare_add_rule_vec(dfarules, perms, 2, vec))
|
||||
if (!aare_add_rule_vec(dfarules, entry->deny, perms, entry->audit & AA_LINK_BITS, 2, vec))
|
||||
return FALSE;
|
||||
}
|
||||
if (entry->mode & AA_CHANGE_PROFILE) {
|
||||
|
@ -530,10 +543,10 @@ static int process_dfa_entry(aare_ruleset_t *dfarules, struct cod_entry *entry)
|
|||
char *vec[2];
|
||||
vec[0] = entry->namespace;
|
||||
vec[1] = entry->name;
|
||||
if (!aare_add_rule_vec(dfarules, AA_CHANGE_PROFILE, 2, vec))
|
||||
if (!aare_add_rule_vec(dfarules, 0, AA_CHANGE_PROFILE, 0, 2, vec))
|
||||
return FALSE;
|
||||
} else {
|
||||
if (!aare_add_rule(dfarules, entry->name, AA_CHANGE_PROFILE))
|
||||
if (!aare_add_rule(dfarules, entry->name, 0, AA_CHANGE_PROFILE, 0))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,7 +95,10 @@ struct cod_entry *do_file_rule(char *namespace, char *id, int mode,
|
|||
%token TOK_COLON
|
||||
%token TOK_LINK
|
||||
%token TOK_OWNER
|
||||
%token TOK_OTHER
|
||||
%token TOK_SUBSET
|
||||
%token TOK_AUDIT
|
||||
%token TOK_DENY
|
||||
|
||||
/* capabilities */
|
||||
%token TOK_CAPABILITY
|
||||
|
@ -136,8 +139,6 @@ struct cod_entry *do_file_rule(char *namespace, char *id, int mode,
|
|||
%type <cod> cond_rule
|
||||
%type <network_entry> network_rule
|
||||
%type <user_entry> rule
|
||||
%type <user_entry> owner_rule
|
||||
%type <user_entry> owner_rules
|
||||
%type <flags> flags
|
||||
%type <flags> flagvals
|
||||
%type <flags> flagval
|
||||
|
@ -152,6 +153,8 @@ struct cod_entry *do_file_rule(char *namespace, char *id, int mode,
|
|||
%type <boolean> expr
|
||||
%type <id> id_or_var
|
||||
%type <boolean> opt_subset_flag
|
||||
%type <boolean> opt_audit_flag
|
||||
%type <boolean> opt_owner_flag
|
||||
%%
|
||||
|
||||
|
||||
|
@ -291,7 +294,7 @@ varassign: TOK_BOOL_VAR TOK_EQUALS TOK_VALUE
|
|||
|
||||
valuelist: TOK_VALUE
|
||||
{
|
||||
struct value_list *new = malloc(sizeof(struct value_list));
|
||||
struct value_list *new = calloc(1, sizeof(struct value_list));
|
||||
if (!new)
|
||||
yyerror(_("Memory allocation error."));
|
||||
PDEBUG("Matched: value (%s)\n", $1);
|
||||
|
@ -303,7 +306,7 @@ valuelist: TOK_VALUE
|
|||
|
||||
valuelist: valuelist TOK_VALUE
|
||||
{
|
||||
struct value_list *new = malloc(sizeof(struct value_list));
|
||||
struct value_list *new = calloc(1, sizeof(struct value_list));
|
||||
if (!new)
|
||||
yyerror(_("Memory allocation error."));
|
||||
PDEBUG("Matched: value (%s)\n", $1);
|
||||
|
@ -361,6 +364,13 @@ flagval: TOK_FLAG_ID
|
|||
opt_subset_flag: { /* nothing */ $$ = 0; }
|
||||
| TOK_SUBSET { $$ = 1; }
|
||||
|
||||
opt_audit_flag: { /* nothing */ $$ = 0; }
|
||||
| TOK_AUDIT { $$ = 1; };
|
||||
|
||||
opt_owner_flag: { /* nothing */ $$ = 0; }
|
||||
| TOK_OWNER { $$ = 1; };
|
||||
| TOK_OTHER { $$ = 2; };
|
||||
|
||||
rules: { /* nothing */
|
||||
struct codomain *cod = NULL;
|
||||
cod = (struct codomain *) calloc(1, sizeof(struct codomain));
|
||||
|
@ -371,50 +381,151 @@ rules: { /* nothing */
|
|||
$$ = cod;
|
||||
};
|
||||
|
||||
rules: rules rule
|
||||
/* can't fold TOK_DENY in as opt_deny_flag as it messes up the generated
|
||||
* parser, even though it shouldn't
|
||||
*/
|
||||
rules: rules opt_audit_flag TOK_DENY opt_owner_flag rule
|
||||
{
|
||||
PDEBUG("matched: rules rule\n");
|
||||
PDEBUG("rules rule: (%s)\n", $2->name);
|
||||
if (!$2)
|
||||
PDEBUG("rules rule: (%s)\n", $5->name);
|
||||
if (!$5)
|
||||
yyerror(_("Assert: `rule' returned NULL."));
|
||||
add_entry_to_policy($1, $2);
|
||||
$5->deny = 1;
|
||||
if (($5->mode & AA_EXEC_BITS) && ($5->mode & ALL_AA_EXEC_TYPE))
|
||||
yyerror(_("Invalid mode, in deny rules 'x' must not be preceded by exec qualifier 'i', 'p', or 'u'"));
|
||||
|
||||
if ($4 == 1)
|
||||
$5->mode &= (AA_USER_PERMS | AA_SHARED_PERMS);
|
||||
else if ($4 == 2)
|
||||
$5->mode &= (AA_OTHER_PERMS | AA_SHARED_PERMS);
|
||||
/* only set audit ctl quieting if the rule is not audited */
|
||||
if (!$2)
|
||||
$5->audit = $5->mode & ~ALL_AA_EXEC_TYPE;
|
||||
|
||||
add_entry_to_policy($1, $5);
|
||||
$$ = $1;
|
||||
};
|
||||
|
||||
rules: rules TOK_OWNER owner_rule
|
||||
rules: rules opt_audit_flag opt_owner_flag rule
|
||||
{
|
||||
PDEBUG("matched: rules rule\n");
|
||||
PDEBUG("rules rule: (%s)\n", $4->name);
|
||||
if (!$4)
|
||||
yyerror(_("Assert: `rule' returned NULL."));
|
||||
if (($4->mode & AA_EXEC_BITS) && !($4->mode & ALL_AA_EXEC_TYPE))
|
||||
yyerror(_("Invalid mode, 'x' must be preceded by exec qualifier 'i', 'p', or 'u'"));
|
||||
|
||||
if ($3 == 1)
|
||||
$4->mode &= (AA_USER_PERMS | AA_SHARED_PERMS);
|
||||
else if ($3 == 2)
|
||||
$4->mode &= (AA_OTHER_PERMS | AA_SHARED_PERMS);
|
||||
if ($2)
|
||||
$4->audit = $4->mode & ~ALL_AA_EXEC_TYPE;
|
||||
|
||||
add_entry_to_policy($1, $4);
|
||||
$$ = $1;
|
||||
};
|
||||
|
||||
rules: rules opt_audit_flag opt_owner_flag TOK_OPEN rules TOK_CLOSE
|
||||
{
|
||||
struct cod_entry *entry, *tmp;
|
||||
|
||||
PDEBUG("matched: rules owner_rules\n");
|
||||
PDEBUG("rules owner_rules: (%s)\n", $3->name);
|
||||
if ($3) {
|
||||
list_for_each_safe($3, entry, tmp) {
|
||||
entry->next = NULL;
|
||||
add_entry_to_policy($1, entry);
|
||||
PDEBUG("matched: audit block\n");
|
||||
list_for_each_safe($5->entries, entry, tmp) {
|
||||
entry->next = NULL;
|
||||
if (entry->mode & AA_EXEC_BITS) {
|
||||
if (entry->deny &&
|
||||
(entry->mode & ALL_AA_EXEC_TYPE))
|
||||
yyerror(_("Invalid mode, in deny rules 'x' must not be preceded by exec qualifier 'i', 'p', or 'u'"));
|
||||
else if (!entry->deny &&
|
||||
!(entry->mode & ALL_AA_EXEC_TYPE))
|
||||
yyerror(_("Invalid mode, 'x' must be preceded by exec qualifier 'i', 'p', or 'u'"));
|
||||
}
|
||||
if ($3 == 1)
|
||||
entry->mode &= (AA_USER_PERMS | AA_SHARED_PERMS);
|
||||
else if ($3 == 2)
|
||||
entry->mode &= (AA_OTHER_PERMS | AA_SHARED_PERMS);
|
||||
|
||||
if ($2 && !entry->deny)
|
||||
entry->audit = entry->mode & ~ALL_AA_EXEC_TYPE;
|
||||
else if (!$2 && entry->deny)
|
||||
entry->audit = entry->mode & ~ALL_AA_EXEC_TYPE;
|
||||
add_entry_to_policy($1, entry);
|
||||
}
|
||||
$5->entries = NULL;
|
||||
// fix me transfer rules and free sub codomain
|
||||
free_policy($5);
|
||||
$$ = $1;
|
||||
};
|
||||
|
||||
rules: rules network_rule
|
||||
rules: rules opt_audit_flag TOK_DENY network_rule
|
||||
{
|
||||
struct aa_network_entry *entry, *tmp;
|
||||
|
||||
PDEBUG("Matched: network rule\n");
|
||||
if (!$2)
|
||||
if (!$4)
|
||||
yyerror(_("Assert: `network_rule' return invalid protocol."));
|
||||
if (!$1->network_allowed) {
|
||||
$1->network_allowed = calloc(AF_MAX,
|
||||
sizeof(unsigned int));
|
||||
if (!$1->network_allowed)
|
||||
$1->audit_network = calloc(AF_MAX,
|
||||
sizeof(unsigned int));
|
||||
$1->deny_network = calloc(AF_MAX,
|
||||
sizeof(unsigned int));
|
||||
$1->quiet_network = calloc(AF_MAX,
|
||||
sizeof(unsigned int));
|
||||
if (!$1->network_allowed || !$1->audit_network ||
|
||||
!$1->deny_network || !$1->quiet_network)
|
||||
yyerror(_("Memory allocation error."));
|
||||
}
|
||||
list_for_each_safe($2, entry, tmp) {
|
||||
list_for_each_safe($4, entry, tmp) {
|
||||
if (entry->type > SOCK_PACKET) {
|
||||
/* setting mask instead of a bit */
|
||||
$1->deny_network[entry->family] |= entry->type;
|
||||
if (!$2)
|
||||
$1->quiet_network[entry->family] |= entry->type;
|
||||
|
||||
} else {
|
||||
$1->deny_network[entry->family] |= 1 << entry->type;
|
||||
if (!$2)
|
||||
$1->quiet_network[entry->family] |= 1 << entry->type;
|
||||
}
|
||||
free(entry);
|
||||
}
|
||||
|
||||
$$ = $1
|
||||
}
|
||||
|
||||
rules: rules opt_audit_flag network_rule
|
||||
{
|
||||
struct aa_network_entry *entry, *tmp;
|
||||
|
||||
PDEBUG("Matched: network rule\n");
|
||||
if (!$3)
|
||||
yyerror(_("Assert: `network_rule' return invalid protocol."));
|
||||
if (!$1->network_allowed) {
|
||||
$1->network_allowed = calloc(AF_MAX,
|
||||
sizeof(unsigned int));
|
||||
$1->audit_network = calloc(AF_MAX,
|
||||
sizeof(unsigned int));
|
||||
$1->deny_network = calloc(AF_MAX,
|
||||
sizeof(unsigned int));
|
||||
$1->quiet_network = calloc(AF_MAX,
|
||||
sizeof(unsigned int));
|
||||
if (!$1->network_allowed || !$1->audit_network ||
|
||||
!$1->deny_network || !$1->quiet_network)
|
||||
yyerror(_("Memory allocation error."));
|
||||
}
|
||||
list_for_each_safe($3, entry, tmp) {
|
||||
if (entry->type > SOCK_PACKET) {
|
||||
/* setting mask instead of a bit */
|
||||
$1->network_allowed[entry->family] |= entry->type;
|
||||
if ($2)
|
||||
$1->audit_network[entry->family] |= entry->type;
|
||||
|
||||
} else {
|
||||
$1->network_allowed[entry->family] |= 1 << entry->type;
|
||||
if ($2)
|
||||
$1->audit_network[entry->family] |= 1 << entry->type;
|
||||
}
|
||||
free(entry);
|
||||
}
|
||||
|
@ -432,9 +543,19 @@ rules: rules change_profile
|
|||
$$ = $1;
|
||||
};
|
||||
|
||||
rules: rules capability
|
||||
rules: rules opt_audit_flag TOK_DENY capability
|
||||
{
|
||||
$1->capabilities = $1->capabilities | $2;
|
||||
$1->deny_caps |= $4;
|
||||
if (!$2)
|
||||
$1->quiet_caps |= $4;
|
||||
$$ = $1;
|
||||
};
|
||||
|
||||
rules: rules opt_audit_flag capability
|
||||
{
|
||||
$1->capabilities |= $3;
|
||||
if ($2)
|
||||
$1->audit_caps |= $3;
|
||||
$$ = $1;
|
||||
};
|
||||
|
||||
|
@ -536,31 +657,6 @@ expr: TOK_DEFINED TOK_BOOL_VAR
|
|||
id_or_var: TOK_ID { $$ = $1; }
|
||||
id_or_var: TOK_SET_VAR { $$ = $1; };
|
||||
|
||||
owner_rule: TOK_OPEN owner_rules TOK_CLOSE
|
||||
{
|
||||
$$ = $2;
|
||||
};
|
||||
|
||||
owner_rule: rule
|
||||
{
|
||||
/* mask mode to owner permissions */
|
||||
if ($1) {
|
||||
$1->mode &= (AA_USER_PERMS | AA_SHARED_PERMS);
|
||||
}
|
||||
$$ = $1;
|
||||
};
|
||||
|
||||
owner_rules: { $$ = NULL; };
|
||||
|
||||
owner_rules: owner_rules rule
|
||||
{
|
||||
if ($2) {
|
||||
$2->mode &= (AA_USER_PERMS | AA_SHARED_PERMS);
|
||||
$2->next = $1;
|
||||
}
|
||||
$$ = $2;
|
||||
};
|
||||
|
||||
rule: id_or_var file_mode TOK_END_OF_RULE
|
||||
{
|
||||
$$ = do_file_rule(NULL, $1, $2, NULL);
|
||||
|
@ -680,7 +776,7 @@ hat_start: TOK_SEP {}
|
|||
file_mode: TOK_MODE
|
||||
{
|
||||
/* A single TOK_MODE maps to the same permission in all
|
||||
* of user:group:other */
|
||||
* of user::other */
|
||||
$$ = parse_mode($1);
|
||||
free($1);
|
||||
}
|
||||
|
@ -709,7 +805,7 @@ change_profile: TOK_CHANGE_PROFILE TOK_ID TOK_COLON TOK_ID TOK_END_OF_RULE
|
|||
|
||||
capability: TOK_CAPABILITY caps TOK_END_OF_RULE
|
||||
{
|
||||
$$ = $2;
|
||||
$$ = $2;
|
||||
};
|
||||
|
||||
caps: caps TOK_ID
|
||||
|
|
Loading…
Add table
Reference in a new issue