2
0
mirror of https://gitlab.com/apparmor/apparmor synced 2025-08-30 13:58:22 +00:00

Merge parser: add support for prompt rules

This adds support for prompt rules and the beginning of support for extended permissions. Currently extended permissions are only used if a prompt rule is used in policy.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1305
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
This commit is contained in:
John Johansen
2024-08-14 23:34:29 +00:00
40 changed files with 1375 additions and 244 deletions

View File

@@ -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
@@ -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;
}

View File

@@ -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()
{

View File

@@ -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)
{
@@ -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))

View File

@@ -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);
@@ -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;
}

View File

@@ -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) {
@@ -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;

View File

@@ -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);

View File

@@ -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

View File

@@ -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,
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(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, perm32_t perms, perm32_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";
@@ -189,16 +192,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, optflags const &opts,
bool filedfa)
CHFA *aare_rules::create_chfa(int *min_match_len,
vector <aa_perms> &perms_table,
optflags const &opts, bool filedfa,
bool extended_perms, bool prompt)
{
char *buffer = NULL;
/* finish constructing the expr tree from the different permission
* set nodes */
PermExprMap::iterator i = expr_map.begin();
@@ -247,7 +250,7 @@ void *aare_rules::create_dfa(size_t *size, int *min_match_len, optflags const &o
}
}
stringstream stream;
CHFA *chfa = NULL;
try {
DFA dfa(root, opts, filedfa);
if (opts.dump & DUMP_DFA_UNIQ_PERMS)
@@ -304,10 +307,45 @@ 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);
//cerr << "Checking extended perms " << extended_perms << "\n";
if (extended_perms) {
//cerr << "creating permstable\n";
dfa.compute_perms_table(perms_table, prompt);
}
chfa = new CHFA(dfa, eq, opts, extended_perms, prompt);
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 <aa_perms> &perms_table,
optflags const &opts, bool filedfa,
bool extended_perms, bool prompt)
{
char *buffer = NULL;
stringstream stream;
try {
CHFA *chfa = create_chfa(min_match_len, perms_table,
opts, filedfa, extended_perms,
prompt);
if (!chfa) {
*size = 0;
return NULL;
}
chfa->flex_table(stream);
delete (chfa);
}
catch(int error) {
*size = 0;
@@ -323,5 +361,85 @@ void *aare_rules::create_dfa(size_t *size, int *min_match_len, optflags const &o
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 <aa_perms> &perms_table,
optflags const &opts,
bool extended_perms, bool prompt)
{
int file_min_len;
vector <aa_perms> file_perms;
CHFA *file_chfa;
try {
file_chfa = file_rules->create_chfa(&file_min_len,
file_perms, opts,
true, extended_perms, prompt);
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, prompt);
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, prompt,
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;
}

View File

@@ -21,22 +21,28 @@
#ifndef __LIBAA_RE_RULES_H
#define __LIBAA_RE_RULES_H
#include <vector>
#include <stdint.h>
#include "../common_optarg.h"
#include "apparmor_re.h"
#include "chfa.h"
#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;
@@ -44,7 +50,7 @@ public:
}
return exact_match;
}
return deny;
return true; // mode < rhs.mode
}
};
@@ -65,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
@@ -101,13 +109,26 @@ 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,
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(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);
void *create_dfa(size_t *size, int *min_match_len, optflags const &opts,
bool filedfa);
CHFA *create_chfa(int *min_match_len,
vector <aa_perms> &perms_table,
optflags const &opts, bool filedfa,
bool extended_perms, bool prompt);
void *create_dfablob(size_t *size, int *min_match_len,
vector <aa_perms> &perms_table,
optflags const &opts,
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 <aa_perms> &perms_table,
optflags const &opts,
bool extended_perms, bool prompt);
};
#endif /* __LIBAA_RE_RULES_H */

View File

@@ -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<pair<size_t, size_t> > &free_list,
@@ -46,11 +47,15 @@ void CHFA::init_free_list(vector<pair<size_t, size_t> > &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<transchar, transchar> &eq, optflags const &opts):
eq(eq)
CHFA::CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts,
bool permindex, bool prompt): eq(eq)
{
if (opts.dump & DUMP_DFA_TRANS_PROGRESS)
fprintf(stderr, "Compressing HFA:\r");
@@ -101,18 +106,29 @@ CHFA::CHFA(DFA &dfa, map<transchar, transchar> &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) {
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],
accept3,
prompt);
dfa.start->map_perms_to_accept(accept[1],
accept2[1],
accept3,
prompt);
}
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);
start = dfa.start;
insert_state(free_list, dfa.start, dfa);
accept[1] = 0;
accept2[1] = 0;
num.insert(make_pair(dfa.start, num.size()));
int count = 2;
@@ -120,9 +136,15 @@ CHFA::CHFA(DFA &dfa, map<transchar, transchar> &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);
accept[num.size()] = (*i)->perms.allow;
accept2[num.size()] = PACK_AUDIT_CTL((*i)->perms.audit, (*i)->perms.quiet & (*i)->perms.deny);
if (permindex)
accept[num.size()] = (*i)->idx;
else
(*i)->map_perms_to_accept(accept[num.size()],
accept2[num.size()],
accept3,
prompt);
num.insert(make_pair(*i, num.size()));
}
if (opts.dump & (DUMP_DFA_TRANS_PROGRESS)) {
@@ -137,9 +159,15 @@ CHFA::CHFA(DFA &dfa, map<transchar, transchar> &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);
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);
if (permindex)
accept[num.size()] = i->second->idx;
else
i->second->map_perms_to_accept(accept[num.size()],
accept2[num.size()],
accept3,
prompt);
num.insert(make_pair(i->second, num.size()));
}
if (opts.dump & (DUMP_DFA_TRANS_PROGRESS)) {
@@ -426,7 +454,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 +465,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());
@@ -446,3 +476,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, bool prompt,
vector <aa_perms> &policy_perms,
vector <aa_perms> &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<const State *, size_t>::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];
}

View File

@@ -16,7 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
* 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
@@ -25,6 +25,7 @@
#include <vector>
#include "hfa.h"
#include "../perms.h"
#define BASE32_FLAGS 0xff000000
#define DiffEncodeBit32 0x80000000
@@ -37,7 +38,9 @@ class CHFA {
typedef vector<pair<const State *, size_t> > DefaultBase;
typedef vector<pair<const State *, const State *> > NextCheck;
public:
CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts);
CHFA(void);
CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts,
bool permindex, bool prompt);
void dump(ostream & os);
void flex_table(ostream &os);
void init_free_list(vector<pair<size_t, size_t> > &free_list,
@@ -46,12 +49,17 @@ class CHFA {
StateTrans &cases);
void insert_state(vector<pair<size_t, size_t> > &free_list,
State *state, DFA &dfa);
void weld_file_to_policy(CHFA &file_chfa, size_t &new_start,
bool accept_idx, bool prompt,
vector <aa_perms> &policy_perms,
vector <aa_perms> &file_perms);
private:
vector<uint32_t> accept;
vector<uint32_t> accept2;
DefaultBase default_base;
NextCheck next_check;
const State *start;
map<const State *, size_t> num;
map<transchar, transchar> eq;
transchar max_eq;

View File

@@ -41,6 +41,7 @@
#include <stdint.h>
#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,12 +906,18 @@ 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;
}
};
class PromptMatchFlag: public MatchFlag {
public:
PromptMatchFlag(perm32_t prompt, perm32_t audit): MatchFlag(prompt, audit) {}
};
/* Traverse the syntax tree depth-first in an iterator-like manner. */
class depth_first_traversal {
stack<Node *>pos;

View File

@@ -31,11 +31,12 @@
#include <iostream>
#include <fstream>
#include <string.h>
#include <stdint.h>
#include "expr-tree.h"
#include "hfa.h"
#include "policy_compat.h"
#include "../immunix.h"
#include "../perms.h"
ostream &operator<<(ostream &os, const CacheStats &cache)
{
@@ -537,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 */
@@ -644,10 +646,13 @@ int DFA::apply_and_clear_deny(void)
return c;
}
typedef pair<uint64_t,uint64_t> uint128_t;
/* minimize the number of dfa states */
void DFA::minimize(optflags const &opts)
{
map<pair<uint64_t, size_t>, Partition *> perm_map;
map<pair<uint128_t, size_t>, Partition *> perm_map;
list<Partition *> partitions;
/* Set up the initial partitions
@@ -664,16 +669,18 @@ 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<uint64_t, size_t> group = make_pair(permtype, hash);
map<pair<uint64_t, size_t>, Partition *>::iterator p = perm_map.find(group);
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<uint128_t, size_t> group = make_pair(permtype, hash);
map<pair<uint128_t, size_t>, Partition *>::iterator p = perm_map.find(group);
if (p == perm_map.end()) {
Partition *part = new Partition();
part->push_back(*i);
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;
@@ -1075,8 +1082,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";
@@ -1300,6 +1309,46 @@ void DFA::apply_equivalence_classes(map<transchar, transchar> &eq)
}
}
void DFA::compute_perms_table_ent(State *state, size_t pos,
vector <aa_perms> &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, prompt);
if (filedfa) {
state->idx = pos * 2;
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, accept3);
}
}
void DFA::compute_perms_table(vector <aa_perms> &perms_table, bool prompt)
{
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, 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, prompt);
pos++;
}
}
#if 0
typedef set <ImportantNode *>AcceptNodes;
map<ImportantNode *, AcceptNodes> dominance(DFA & dfa)
@@ -1329,7 +1378,7 @@ map<ImportantNode *, AcceptNodes> 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));
@@ -1343,8 +1392,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_audit = 0;
perm32_t exact_match_allow = 0;
perm32_t exact_match_prompt = 0;
perm32_t exact_audit = 0;
perms.clear();
@@ -1359,26 +1409,31 @@ 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<PromptMatchFlag *>(match)) {
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;
}
}
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) {
@@ -1399,6 +1454,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");

View File

@@ -27,11 +27,15 @@
#include <list>
#include <map>
#include <vector>
#include <iostream>
#include <assert.h>
#include <stdint.h>
#include "expr-tree.h"
#include "policy_compat.h"
#include "../rule.h"
extern int prompt_compat_mode;
#define DiffEncodeFlag 1
@@ -49,16 +53,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;
@@ -95,6 +103,7 @@ public:
allow = (allow | (rhs.allow & ~ALL_AA_EXEC_TYPE));
else
allow |= rhs.allow;
prompt |= rhs.prompt;
audit |= rhs.audit;
quiet = (quiet | rhs.quiet);
@@ -112,6 +121,7 @@ public:
{
if (deny) {
allow &= ~deny;
prompt &= ~deny;
quiet &= deny;
deny = 0;
return !is_accept();
@@ -125,12 +135,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;
perm32_t allow, deny, prompt, audit, quiet, exact;
};
int accept_perms(NodeVec *state, perms_t &perms, bool filedfa);
@@ -198,7 +210,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;
@@ -248,9 +260,20 @@ 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(perm32_t &accept1, perm32_t &accept2,
perm32_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;
}
int label;
int flags;
int idx;
perms_t perms;
StateTrans trans;
State *otherwise;
@@ -298,7 +321,6 @@ public:
}
};
/* Transitions in the DFA. */
class DFA {
void dump_node_to_dfa(void);
@@ -341,6 +363,12 @@ public:
map<transchar, transchar> equivalence_classes(optflags const &flags);
void apply_equivalence_classes(map<transchar, transchar> &eq);
void compute_perms_table_ent(State *state, size_t pos,
vector <aa_perms> &perms_table,
bool prompt);
void compute_perms_table(vector <aa_perms> &perms_table,
bool prompt);
unsigned int diffcount;
int oob_range;
int max_range;

View File

@@ -0,0 +1,218 @@
/*
* 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 <stdint.h>
#include <iostream>
#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 */
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) (((accept1) & 0x7f) | \
((accept1) & 0x80000000))
#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) \
(dfa_map_xindex(accept1 & 0x3fff))
#define dfa_other_allow(accept1) ((((accept1) >> 14) & \
0x7f) | \
((accept1) & 0x80000000))
#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) \
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,
uint32_t accept3)
{
struct aa_perms perms = { };
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));
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;
}
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));
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));
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;
}
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,
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);
perms.prompt = dfa_user_allow(accept3);
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));
// 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.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))
// perms.quiet |= map_xbits(dfa_other_xbits(dfa, state));
return perms;
}

View File

@@ -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, 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 */

View File

@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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);

View File

@@ -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);
@@ -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;
}

View File

@@ -25,7 +25,7 @@
#include <iostream>
#include <sstream>
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),
@@ -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;
}
}

View File

@@ -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);

View File

@@ -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<std::ostringstream> copy_streams_list(std::list<std::ostringstream> &s
bool network_rule::gen_ip_conds(Profile &prof, std::list<std::ostringstream> &streams, ip_conds &entry, bool is_peer, bool is_cmd)
{
std::string buf;
perms_t cond_perms;
perm32_t cond_perms;
std::list<std::ostringstream> ip_streams;
for (auto &oss : streams) {
@@ -697,7 +697,7 @@ bool network_rule::gen_ip_conds(Profile &prof, std::list<std::ostringstream> &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<std::ostringstream> &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;

View File

@@ -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();

View File

@@ -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;
@@ -324,6 +324,7 @@ do { \
/* The parser fills this variable in automatically */
#define PROFILE_NAME_VARIABLE "profile_name"
/* from parser_common.c */
extern uint32_t policy_version;
extern uint32_t parser_abi_version;
@@ -359,6 +360,10 @@ 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;
extern int conf_verbose;
extern int conf_quiet;
extern int names_only;
@@ -374,6 +379,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)
@@ -449,12 +458,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);

View File

@@ -87,6 +87,10 @@ 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 = PROMPT_COMPAT_UNKNOWN;
int conf_verbose = 0;
int conf_quiet = 0;
int names_only = 0;
@@ -166,3 +170,65 @@ 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_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;
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_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))
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_FLAG:
fprintf(f, "flag");
break;
case PROMPT_COMPAT_PERMSV2:
fprintf(f, "permsv2");
break;
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);
}
}

View File

@@ -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 <aa_perms> &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 <aa_perms> &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, "\000", 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,42 @@ 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 (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);
}
/* 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);
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);
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);
}

View File

@@ -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,30 @@ 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_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);
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);
@@ -1544,6 +1572,20 @@ 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");
}
kernel_supports_permstable32_v1 = aa_features_supports(*features, "policy/permstable32_version/0x000001");
if (kernel_supports_permstable32_v1) {
//fprintf(stderr, "kernel supports prompt_v1\n");
}
/* set default prompt_compat_mode to the best that is supported */
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;

View File

@@ -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},
@@ -565,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);
@@ -583,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) {
@@ -741,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);
@@ -752,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);
@@ -812,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, ""))
@@ -975,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;

View File

@@ -240,6 +240,13 @@ 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;
else if (prompt_compat_mode == PROMPT_COMPAT_FLAG && profile->uses_prompt_rules)
profile->flags.mode = MODE_PROMPT;
return error;
}

View File

@@ -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;
}
@@ -569,7 +572,13 @@ 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
*
* 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, false, false);
delete rules;
if (!prof->xmatch)
return FALSE;
@@ -580,7 +589,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.
@@ -635,14 +644,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;
@@ -667,7 +676,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)) {
@@ -718,13 +727,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;
@@ -733,7 +742,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;
}
@@ -767,10 +776,17 @@ 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 && prompt_compat_mode != PROMPT_COMPAT_PERMSV1) {
int xmatch_len = 0;
prof->dfa.dfa = prof->dfa.rules->create_dfa(&prof->dfa.size,
&xmatch_len, parseopts, true);
//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,
prof->uses_prompt_rules && (prompt_compat_mode == PROMPT_COMPAT_PERMSV2),
prof->uses_prompt_rules);
delete prof->dfa.rules;
prof->dfa.rules = NULL;
if (!prof->dfa.dfa)
@@ -967,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)
@@ -984,6 +1074,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)
{
@@ -999,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 */
@@ -1009,42 +1099,76 @@ 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;
}
if (prof->policy.rules->rule_count > 0) {
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) {
// add null dfa
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, RULE_DENY, AA_MAY_READ, 0, parseopts))
goto out;
}
int xmatch_len = 0;
prof->policy.dfa = prof->policy.rules->create_dfa(&prof->policy.size,
&xmatch_len, parseopts, false);
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,
prof->uses_prompt_rules);
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
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,
prof->uses_prompt_rules && (prompt_compat_mode == PROMPT_COMPAT_PERMSV2),
prof->uses_prompt_rules);
delete prof->policy.rules;
prof->policy.rules = NULL;

View File

@@ -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);
@@ -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
@@ -212,7 +213,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;
@@ -222,6 +223,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;
@@ -267,7 +269,7 @@ static void abi_features(char *filename, bool search);
%type <id> opt_id_or_var
%type <boolean> opt_subset_flag
%type <audit> opt_audit_flag
%type <boolean> opt_owner_flag
%type <owner> opt_owner_flag
%type <boolean> opt_profile_flag
%type <boolean> opt_flags
%type <rule_mode> opt_rule_mode
@@ -627,13 +629,14 @@ 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; }
| TOK_DENY { $$ = RULE_DENY; }
| TOK_PROMPT { $$ = RULE_PROMPT; }
opt_prefix: opt_audit_flag opt_rule_mode opt_owner_flag
{
@@ -676,8 +679,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_SPECIFIED ? "owner " : "");
list_for_each_safe($3->entries, entry, tmp) {
const char *error;
entry->next = NULL;
@@ -743,8 +749,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) {
@@ -759,8 +765,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;
@@ -1553,7 +1559,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;
@@ -1661,7 +1667,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);
@@ -1702,7 +1708,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"));
@@ -1800,4 +1806,3 @@ static void abi_features(char *filename, bool search)
}
};

117
parser/perms.h Normal file
View File

@@ -0,0 +1,117 @@
/*
* 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
/* 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 <stdint.h>
#include <sys/apparmor.h>
/* 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 */
#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 */
#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
typedef uint32_t perm32_t;
struct aa_perms {
perm32_t allow;
perm32_t deny; /* explicit deny, or conflict if allow also set */
perm32_t subtree; /* allow perm on full subtree only when allow is set */
perm32_t cond; /* set only when ~allow and ~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 */
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;
uint32_t tag; /* tag string index, if present */
uint32_t label; /* label string index, if present */
};
#endif /* __AA_PERM_H */

View File

@@ -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)
@@ -269,11 +271,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);

View File

@@ -15,6 +15,7 @@
#define __AA_PROFILE_H
#include <set>
#include <vector>
#include <string>
#include <iostream>
@@ -24,6 +25,8 @@
#include "libapparmor_re/aare_rules.h"
#include "network.h"
#include "signal.h"
#include "immunix.h"
#include "perms.h"
class Profile;
@@ -146,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 {
@@ -233,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;
@@ -336,12 +344,14 @@ struct dfa_stuff {
aare_rules *rules;
void *dfa;
size_t size;
size_t file_start; /* special start in welded dfa */
vector <aa_perms> perms_table;
dfa_stuff(void): rules(NULL), dfa(NULL), size(0) { }
};
class Profile {
public:
bool uses_prompt_rules;
char *ns;
char *name;
char *attachment;
@@ -349,7 +359,7 @@ public:
void *xmatch;
size_t xmatch_size;
int xmatch_len;
vector <aa_perms> xmatch_perms_table;
struct cond_entry_list xattrs;
/* char *sub_name; */ /* subdomain name or NULL */
@@ -375,6 +385,7 @@ public:
Profile(void)
{
uses_prompt_rules = false;
ns = name = attachment = NULL;
altnames = NULL;
xmatch = NULL;

View File

@@ -24,7 +24,7 @@
#include <string>
#include <sstream>
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) {
@@ -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;
}

View File

@@ -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);
@@ -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;
}

View File

@@ -22,10 +22,19 @@
#include <list>
#include <ostream>
#include "perms.h"
#include "policydb.h"
using namespace std;
#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;
#define RULE_NOT_SUPPORTED 0
@@ -151,9 +160,10 @@ std::ostream &operator<<(std::ostream &os, rule_t &rule);
typedef std::list<rule_t *> 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;
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
@@ -165,7 +175,7 @@ class prefixes {
public:
audit_t audit;
rule_mode_t rule_mode;
int owner;
owner_t owner;
ostream &dump(ostream &os)
{
@@ -183,6 +193,13 @@ public:
}
switch (rule_mode) {
case RULE_ALLOW:
if (output)
os << " ";
os << "allow";
output = true;
break;
case RULE_DENY:
if (output)
os << " ";
@@ -190,15 +207,32 @@ public:
os << "deny";
output = true;
break;
case RULE_PROMPT:
if (output)
os << " ";
os << "prompt";
output = true;
break;
default:
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)
@@ -216,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;
}
@@ -228,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;
}
@@ -241,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;
@@ -271,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;
@@ -393,7 +429,7 @@ public:
return os;
}
perms_t perms, saved;
perm32_t perms, saved;
};
// alternate perms rule class that only does dedup instead of perms merging
@@ -418,7 +454,7 @@ public:
return os;
}
perms_t perms;
perm32_t perms;
};

View File

@@ -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) {
@@ -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;
}

View File

@@ -32,7 +32,7 @@
typedef set<int> 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,13 +41,13 @@ 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);
};
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;
}

View File

@@ -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) {
@@ -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;
}

View File

@@ -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()
{
};