mirror of
https://gitlab.com/apparmor/apparmor.git
synced 2025-03-04 08:24:42 +01:00
parser: if extended perms are supported by the kernel build a permstable
If extended permissions are supported use them. We need to build a permission table and set the accept state of the chfa up as an index into the table. For now map the front end permission layout into the old format and then convert that to the perms table just as the kernel does. Signed-off-by: John Johansen <john.johansen@canonical.com>
This commit is contained in:
parent
c86f8f06dd
commit
e29f5ce5f3
16 changed files with 530 additions and 38 deletions
|
@ -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
|
||||
|
|
|
@ -194,8 +194,10 @@ bool aare_rules::append_rule(const char *rule, bool oob, bool with_perm,
|
|||
* else NULL on failure, @min_match_len set to the shortest string
|
||||
* that can match the dfa for determining xmatch priority.
|
||||
*/
|
||||
void *aare_rules::create_dfa(size_t *size, int *min_match_len, optflags const &opts,
|
||||
bool filedfa)
|
||||
void *aare_rules::create_dfa(size_t *size, int *min_match_len,
|
||||
vector <aa_perms> &perms_table,
|
||||
optflags const &opts,
|
||||
bool filedfa, bool extended_perms)
|
||||
{
|
||||
char *buffer = NULL;
|
||||
|
||||
|
@ -304,7 +306,12 @@ void *aare_rules::create_dfa(size_t *size, int *min_match_len, optflags const &o
|
|||
dfa.dump_diff_encode(cerr);
|
||||
}
|
||||
|
||||
CHFA chfa(dfa, eq, opts, false);
|
||||
//cerr << "Checking extended perms " << extended_perms << "\n";
|
||||
if (extended_perms) {
|
||||
//cerr << "creating permstable\n";
|
||||
dfa.compute_perms_table(perms_table);
|
||||
}
|
||||
CHFA chfa(dfa, eq, opts, extended_perms);
|
||||
if (opts.dump & DUMP_DFA_TRANS_TABLE)
|
||||
chfa.dump(cerr);
|
||||
chfa.flex_table(stream);
|
||||
|
|
|
@ -21,11 +21,15 @@
|
|||
#ifndef __LIBAA_RE_RULES_H
|
||||
#define __LIBAA_RE_RULES_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../common_optarg.h"
|
||||
#include "apparmor_re.h"
|
||||
#include "expr-tree.h"
|
||||
#include "../immunix.h"
|
||||
#include "../perms.h"
|
||||
|
||||
class UniquePerm {
|
||||
public:
|
||||
|
@ -106,8 +110,10 @@ class aare_rules {
|
|||
bool add_rule_vec(int deny, uint32_t perms, uint32_t audit, int count,
|
||||
const char **rulev, optflags const &opts, bool oob);
|
||||
bool append_rule(const char *rule, bool oob, bool with_perm, optflags const &opts);
|
||||
void *create_dfa(size_t *size, int *min_match_len, optflags const &opts,
|
||||
bool filedfa);
|
||||
void *create_dfa(size_t *size, int *min_match_len,
|
||||
vector <aa_perms> &perms_table,
|
||||
optflags const &opts,
|
||||
bool filedfa, bool extended_perms);
|
||||
};
|
||||
|
||||
#endif /* __LIBAA_RE_RULES_H */
|
||||
|
|
|
@ -105,20 +105,23 @@ 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));
|
||||
if (!permindex) {
|
||||
if (permindex) {
|
||||
accept[0] = dfa.nonmatching->idx;
|
||||
accept[1] = dfa.start->idx;
|
||||
} else {
|
||||
accept2.resize(max(dfa.states.size(), (size_t) 2));
|
||||
accept2[0] = 0;
|
||||
accept2[1] = 0;
|
||||
dfa.nonmatching->map_perms_to_accept(accept[0],
|
||||
accept2[0]);
|
||||
dfa.start->map_perms_to_accept(accept[1],
|
||||
accept2[1]);
|
||||
}
|
||||
next_check.resize(max(optimal, (size_t) dfa.max_range));
|
||||
free_list.resize(next_check.size());
|
||||
|
||||
accept[0] = 0;
|
||||
first_free = 1;
|
||||
init_free_list(free_list, 0, 1);
|
||||
|
||||
insert_state(free_list, dfa.start, dfa);
|
||||
accept[1] = 0;
|
||||
num.insert(make_pair(dfa.start, num.size()));
|
||||
|
||||
int count = 2;
|
||||
|
@ -127,6 +130,9 @@ CHFA::CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts,
|
|||
for (Partition::iterator i = dfa.states.begin(); i != dfa.states.end(); i++) {
|
||||
if (*i != dfa.nonmatching && *i != dfa.start) {
|
||||
insert_state(free_list, *i, dfa);
|
||||
if (permindex)
|
||||
accept[num.size()] = (*i)->idx;
|
||||
else
|
||||
(*i)->map_perms_to_accept(accept[num.size()],
|
||||
accept2[num.size()]);
|
||||
num.insert(make_pair(*i, num.size()));
|
||||
|
@ -144,6 +150,9 @@ CHFA::CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts,
|
|||
if (i->second != dfa.nonmatching &&
|
||||
i->second != dfa.start) {
|
||||
insert_state(free_list, i->second, dfa);
|
||||
if (permindex)
|
||||
accept[num.size()] = i->second->idx;
|
||||
else
|
||||
i->second->map_perms_to_accept(accept[num.size()],
|
||||
accept2[num.size()]);
|
||||
num.insert(make_pair(i->second, num.size()));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -34,8 +34,9 @@
|
|||
|
||||
#include "expr-tree.h"
|
||||
#include "hfa.h"
|
||||
#include "policy_compat.h"
|
||||
#include "../immunix.h"
|
||||
|
||||
#include "../perms.h"
|
||||
|
||||
ostream &operator<<(ostream &os, const CacheStats &cache)
|
||||
{
|
||||
|
@ -1300,6 +1301,44 @@ void DFA::apply_equivalence_classes(map<transchar, transchar> &eq)
|
|||
}
|
||||
}
|
||||
|
||||
void DFA::compute_perms_table_ent(State *state, size_t pos,
|
||||
vector <aa_perms> &perms_table)
|
||||
{
|
||||
uint32_t accept1, accept2;
|
||||
|
||||
state->map_perms_to_accept(accept1, accept2);
|
||||
if (filedfa) {
|
||||
state->idx = pos * 2;
|
||||
perms_table[pos*2] = compute_fperms_user(accept1, accept2);
|
||||
perms_table[pos*2 + 1] = compute_fperms_other(accept1, accept2);
|
||||
} else {
|
||||
state->idx = pos;
|
||||
perms_table[pos] = compute_perms_entry(accept1, accept2);
|
||||
}
|
||||
}
|
||||
|
||||
void DFA::compute_perms_table(vector <aa_perms> &perms_table)
|
||||
{
|
||||
size_t mult = filedfa ? 2 : 1;
|
||||
size_t pos = 2;
|
||||
|
||||
assert(states.size() >= 2);
|
||||
perms_table.resize(states.size() * mult);
|
||||
|
||||
// nonmatching and start need to be 0 and 1 so handle outside of loop
|
||||
if (filedfa)
|
||||
compute_perms_table_ent(nonmatching, 0, perms_table);
|
||||
compute_perms_table_ent(start, 1, perms_table);
|
||||
|
||||
for (Partition::iterator i = states.begin(); i != states.end(); i++) {
|
||||
if (*i == nonmatching || *i == start)
|
||||
continue;
|
||||
compute_perms_table_ent(*i, pos, perms_table);
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
typedef set <ImportantNode *>AcceptNodes;
|
||||
map<ImportantNode *, AcceptNodes> dominance(DFA & dfa)
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#include "expr-tree.h"
|
||||
#include "policy_compat.h"
|
||||
|
||||
#define DiffEncodeFlag 1
|
||||
|
||||
|
@ -198,7 +199,7 @@ struct DiffDag {
|
|||
class State {
|
||||
public:
|
||||
State(int l, ProtoState &n, State *other, bool filedfa):
|
||||
label(l), flags(0), perms(), trans()
|
||||
label(l), flags(0), idx(0), perms(), trans()
|
||||
{
|
||||
int error;
|
||||
|
||||
|
@ -256,6 +257,7 @@ public:
|
|||
|
||||
int label;
|
||||
int flags;
|
||||
int idx;
|
||||
perms_t perms;
|
||||
StateTrans trans;
|
||||
State *otherwise;
|
||||
|
@ -303,7 +305,6 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
/* Transitions in the DFA. */
|
||||
class DFA {
|
||||
void dump_node_to_dfa(void);
|
||||
|
@ -346,6 +347,10 @@ public:
|
|||
map<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);
|
||||
void compute_perms_table(vector <aa_perms> &perms_table);
|
||||
|
||||
unsigned int diffcount;
|
||||
int oob_range;
|
||||
int max_range;
|
||||
|
@ -354,6 +359,7 @@ public:
|
|||
Node *root;
|
||||
State *nonmatching, *start;
|
||||
Partition states;
|
||||
//vector <aa_perms> perms_table;
|
||||
bool filedfa;
|
||||
};
|
||||
|
||||
|
|
215
parser/libapparmor_re/policy_compat.cc
Normal file
215
parser/libapparmor_re/policy_compat.cc
Normal file
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
* Copyright (c) 2022
|
||||
* Canonical, Ltd. (All rights reserved)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public
|
||||
* License published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, contact Novell, Inc. or Canonical
|
||||
* Ltd.
|
||||
*/
|
||||
/*
|
||||
* This is a set of functions to provide convertion from old style permission
|
||||
* mappings, to new style kernel mappings. It is based on the kernel to
|
||||
* as the kernel needs this for backwards compatibility. This allows the
|
||||
* userspace to convert to the new permission mapping without reworking
|
||||
* the internal dfa permission tracking.
|
||||
*
|
||||
* In the future this code will be converted to go the reverse direction
|
||||
* i.e. new mappings into old, which the parser will need for backwards
|
||||
* compat with old kernels.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <iostream>
|
||||
|
||||
#include "policy_compat.h"
|
||||
#include "../perms.h"
|
||||
|
||||
|
||||
/* remap old accept table embedded permissions to separate permission table */
|
||||
static uint32_t dfa_map_xindex(uint16_t mask)
|
||||
{
|
||||
uint16_t old_index = (mask >> 10) & 0xf;
|
||||
uint32_t index = 0;
|
||||
|
||||
if (mask & 0x100)
|
||||
index |= AA_X_UNSAFE;
|
||||
if (mask & 0x200)
|
||||
index |= AA_X_INHERIT;
|
||||
if (mask & 0x80)
|
||||
index |= AA_X_UNCONFINED;
|
||||
|
||||
if (old_index == 1) {
|
||||
index |= AA_X_UNCONFINED;
|
||||
} else if (old_index == 2) {
|
||||
index |= AA_X_NAME;
|
||||
} else if (old_index == 3) {
|
||||
index |= AA_X_NAME | AA_X_CHILD;
|
||||
} else if (old_index) {
|
||||
index |= AA_X_TABLE;
|
||||
index |= old_index - 4;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/*
|
||||
* map old dfa inline permissions to new format
|
||||
*/
|
||||
#define dfa_user_allow(accept1, accept2) (((accept1) & 0x7f) | \
|
||||
((accept1) & 0x80000000))
|
||||
#define dfa_user_xbits(accept1, accept2) (((accept1) >> 7) & 0x7f)
|
||||
#define dfa_user_audit(accept1, accept2) ((accept2) & 0x7f)
|
||||
#define dfa_user_quiet(accept1, accept2) (((accept2) >> 7) & 0x7f)
|
||||
#define dfa_user_xindex(accept1, accept2) \
|
||||
(dfa_map_xindex(accept1 & 0x3fff))
|
||||
|
||||
#define dfa_other_allow(accept1, accept2) ((((accept1) >> 14) & \
|
||||
0x7f) | \
|
||||
((accept1) & 0x80000000))
|
||||
#define dfa_other_xbits(accept1, accept2) \
|
||||
((((accept1) >> 7) >> 14) & 0x7f)
|
||||
#define dfa_other_audit(accept1, accept2) (((accept2) >> 14) & 0x7f)
|
||||
#define dfa_other_quiet(accept1, accept2) \
|
||||
((((accept2) >> 7) >> 14) & 0x7f)
|
||||
#define dfa_other_xindex(accept1, accept2) \
|
||||
dfa_map_xindex((accept1 >> 14) & 0x3fff)
|
||||
|
||||
/**
|
||||
* map_old_perms - map old file perms layout to the new layout
|
||||
* @old: permission set in old mapping
|
||||
*
|
||||
* Returns: new permission mapping
|
||||
*/
|
||||
static uint32_t map_old_perms(uint32_t old)
|
||||
{
|
||||
uint32_t perm = old & 0xf;
|
||||
|
||||
if (old & AA_MAY_READ)
|
||||
perm |= AA_MAY_GETATTR | AA_MAY_OPEN;
|
||||
if (old & AA_MAY_WRITE)
|
||||
perm |= AA_MAY_SETATTR | AA_MAY_CREATE | AA_MAY_DELETE |
|
||||
AA_MAY_CHMOD | AA_MAY_CHOWN | AA_MAY_OPEN;
|
||||
if (old & 0x10)
|
||||
perm |= AA_MAY_LINK;
|
||||
/* the old mapping lock and link_subset flags where overlaid
|
||||
* and use was determined by part of a pair that they were in
|
||||
*/
|
||||
if (old & 0x20)
|
||||
perm |= AA_MAY_LOCK | AA_LINK_SUBSET;
|
||||
if (old & 0x40) /* AA_EXEC_MMAP */
|
||||
perm |= AA_EXEC_MMAP;
|
||||
|
||||
return perm;
|
||||
}
|
||||
|
||||
static void compute_fperms_allow(struct aa_perms *perms, uint32_t accept1)
|
||||
{
|
||||
perms->allow |= AA_MAY_GETATTR;
|
||||
|
||||
/* change_profile wasn't determined by ownership in old mapping */
|
||||
if (accept1 & 0x80000000)
|
||||
perms->allow |= AA_MAY_CHANGE_PROFILE;
|
||||
if (accept1 & 0x40000000)
|
||||
perms->allow |= AA_MAY_ONEXEC;
|
||||
}
|
||||
|
||||
struct aa_perms compute_fperms_user(uint32_t accept1, uint32_t accept2)
|
||||
{
|
||||
struct aa_perms perms = { };
|
||||
|
||||
perms.allow = map_old_perms(dfa_user_allow(accept1, accept2));
|
||||
perms.audit = map_old_perms(dfa_user_audit(accept1, accept2));
|
||||
perms.quiet = map_old_perms(dfa_user_quiet(accept1, accept2));
|
||||
perms.xindex = dfa_user_xindex(accept1, accept2);
|
||||
|
||||
compute_fperms_allow(&perms, accept1);
|
||||
// prompt being carried as audit need to change
|
||||
perms.allow &= ~perms.prompt;
|
||||
if (perms.allow & perms.prompt) {
|
||||
//std::cerr << "user allow & prompt\n";
|
||||
}
|
||||
return perms;
|
||||
}
|
||||
|
||||
struct aa_perms compute_fperms_other(uint32_t accept1, uint32_t accept2)
|
||||
{
|
||||
struct aa_perms perms = { };
|
||||
|
||||
perms.allow = map_old_perms(dfa_other_allow(accept1, accept2));
|
||||
perms.audit = map_old_perms(dfa_other_audit(accept1, accept2));
|
||||
perms.quiet = map_old_perms(dfa_other_quiet(accept1, accept2));
|
||||
perms.xindex = dfa_other_xindex(accept1, accept2);
|
||||
|
||||
compute_fperms_allow(&perms, accept1);
|
||||
// prompt being carried as audit need to change
|
||||
perms.allow &= ~perms.prompt;
|
||||
if (perms.allow & perms.prompt) {
|
||||
std::cerr << "other allow & prompt\n";
|
||||
}
|
||||
return perms;
|
||||
}
|
||||
|
||||
static uint32_t map_other(uint32_t x)
|
||||
{
|
||||
return ((x & 0x3) << 8) | /* SETATTR/GETATTR */
|
||||
((x & 0x1c) << 18) | /* ACCEPT/BIND/LISTEN */
|
||||
((x & 0x60) << 19); /* SETOPT/GETOPT */
|
||||
}
|
||||
|
||||
static uint32_t map_xbits(uint32_t x)
|
||||
{
|
||||
return ((x & 0x1) << 7) |
|
||||
((x & 0x7e) << 9);
|
||||
}
|
||||
|
||||
struct aa_perms compute_perms_entry(uint32_t accept1, uint32_t accept2)
|
||||
// don't need to worry about version internally within the parser
|
||||
// uint32_t version)
|
||||
{
|
||||
struct aa_perms perms = { };
|
||||
|
||||
perms.allow = dfa_user_allow(accept1, accept2);
|
||||
perms.audit = dfa_user_audit(accept1, accept2);
|
||||
perms.quiet = dfa_user_quiet(accept1, accept2);
|
||||
|
||||
/*
|
||||
* This mapping is convulated due to history.
|
||||
* v1-v4: only file perms, which are handled by compute_fperms
|
||||
* v5: added policydb which dropped user conditional to gain new
|
||||
* perm bits, but had to map around the xbits because the
|
||||
* userspace compiler was still munging them.
|
||||
* v9: adds using the xbits in policydb because the compiler now
|
||||
* supports treating policydb permission bits different.
|
||||
* Unfortunately there is no way to force auditing on the
|
||||
* perms represented by the xbits
|
||||
*/
|
||||
perms.allow |= map_other(dfa_other_allow(accept1, accept2));
|
||||
// v9 encoding never rolled out. AA_MAY_LOCK needed to fix
|
||||
// non fs unix locking see kernel commit
|
||||
// 1cf26c3d2c4c apparmor: fix apparmor mediating locking non-fs unix sockets
|
||||
//if (VERSION_LE(version, v8))
|
||||
perms.allow |= AA_MAY_LOCK;
|
||||
//else
|
||||
// perms.allow |= map_xbits(dfa_user_xbits(dfa, state));
|
||||
|
||||
/*
|
||||
* for v5-v9 perm mapping in the policydb, the other set is used
|
||||
* to extend the general perm set
|
||||
*/
|
||||
perms.audit |= map_other(dfa_other_audit(accept1, accept2));
|
||||
perms.quiet |= map_other(dfa_other_quiet(accept1, accept2));
|
||||
//if (VERSION_GT(version, v8))
|
||||
// perms.quiet |= map_xbits(dfa_other_xbits(dfa, state));
|
||||
|
||||
return perms;
|
||||
}
|
||||
|
25
parser/libapparmor_re/policy_compat.h
Normal file
25
parser/libapparmor_re/policy_compat.h
Normal 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);
|
||||
struct aa_perms compute_fperms_other(uint32_t accept1, uint32_t accept2);
|
||||
struct aa_perms compute_perms_entry(uint32_t accept1, uint32_t accept2);
|
||||
|
||||
#endif /* __AA_POLICY_COMPAT_H */
|
|
@ -359,6 +359,7 @@ extern int features_supports_flag_interruptible;
|
|||
extern int features_supports_flag_signal;
|
||||
extern int features_supports_flag_error;
|
||||
extern int kernel_supports_oob;
|
||||
extern int kernel_supports_permstable32;
|
||||
extern int conf_verbose;
|
||||
extern int conf_quiet;
|
||||
extern int names_only;
|
||||
|
|
|
@ -87,6 +87,7 @@ int features_supports_flag_interruptible = 0;
|
|||
int features_supports_flag_signal = 0;
|
||||
int features_supports_flag_error = 0;
|
||||
int kernel_supports_oob = 0; /* out of band transitions */
|
||||
int kernel_supports_permstable32 = 0; /* extended permissions */
|
||||
int conf_verbose = 0;
|
||||
int conf_quiet = 0;
|
||||
int names_only = 0;
|
||||
|
|
|
@ -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, "", 1, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
sd_write_arrayend(buf);
|
||||
sd_write_structend(buf);
|
||||
}
|
||||
|
@ -411,7 +463,7 @@ void sd_serialize_profile(std::ostringstream &buf, Profile *profile,
|
|||
/* only emit this if current kernel at least supports "create" */
|
||||
if (perms_create) {
|
||||
if (profile->xmatch) {
|
||||
sd_serialize_dfa(buf, profile->xmatch, profile->xmatch_size);
|
||||
sd_serialize_dfa(buf, profile->xmatch, profile->xmatch_size, profile->xmatch_perms_table);
|
||||
sd_write_uint32(buf, profile->xmatch_len);
|
||||
}
|
||||
}
|
||||
|
@ -491,14 +543,27 @@ void sd_serialize_profile(std::ostringstream &buf, Profile *profile,
|
|||
|
||||
if (profile->policy.dfa) {
|
||||
sd_write_struct(buf, "policydb");
|
||||
sd_serialize_dfa(buf, profile->policy.dfa, profile->policy.size);
|
||||
sd_serialize_dfa(buf, profile->policy.dfa, profile->policy.size,
|
||||
profile->policy.perms_table);
|
||||
if (profile->policy.dfa) {
|
||||
// fprintf(stderr, "profile %s: policy xtable\n", profile->name);
|
||||
// TODO: this is dummy exec make dependent on V1
|
||||
sd_serialize_xtable(buf, profile->exec_table,
|
||||
//??? work around
|
||||
profile->policy.perms_table.size());
|
||||
}
|
||||
sd_write_structend(buf);
|
||||
}
|
||||
|
||||
/* either have a single dfa or lists of different entry types */
|
||||
sd_serialize_dfa(buf, profile->dfa.dfa, profile->dfa.size);
|
||||
sd_serialize_xtable(buf, profile->exec_table);
|
||||
|
||||
sd_serialize_dfa(buf, profile->dfa.dfa, profile->dfa.size,
|
||||
profile->dfa.perms_table);
|
||||
if (profile->dfa.dfa) {
|
||||
// fprintf(stderr, "profile %s: dfa xtable\n", profile->name);
|
||||
sd_serialize_xtable(buf, profile->exec_table,
|
||||
//??? work around
|
||||
profile->dfa.perms_table.size());
|
||||
}
|
||||
sd_write_structend(buf);
|
||||
}
|
||||
|
||||
|
|
|
@ -1544,6 +1544,10 @@ static bool get_kernel_features(struct aa_features **features)
|
|||
else if (aa_features_supports(*features, "policy/versions/v6"))
|
||||
kernel_abi_version = 6;
|
||||
|
||||
kernel_supports_permstable32 = aa_features_supports(*features, "policy/permstable32");
|
||||
if (kernel_supports_permstable32) {
|
||||
//fprintf(stderr, "kernel supports prompt\n");
|
||||
}
|
||||
if (!kernel_supports_diff_encode)
|
||||
/* clear diff_encode because it is not supported */
|
||||
parseopts.control &= ~CONTROL_DFA_DIFF_ENCODE;
|
||||
|
|
|
@ -569,7 +569,11 @@ static int process_profile_name_xmatch(Profile *prof)
|
|||
}
|
||||
}
|
||||
build:
|
||||
prof->xmatch = rules->create_dfa(&prof->xmatch_size, &prof->xmatch_len, parseopts, true);
|
||||
/* xmatch doesn't use file dfa exec mode bits NOT the owner
|
||||
* conditional and for just MAY_EXEC can be processed as
|
||||
* none file perms
|
||||
*/
|
||||
prof->xmatch = rules->create_dfa(&prof->xmatch_size, &prof->xmatch_len, prof->xmatch_perms_table, parseopts, false, kernel_supports_permstable32);
|
||||
delete rules;
|
||||
if (!prof->xmatch)
|
||||
return FALSE;
|
||||
|
@ -769,8 +773,9 @@ int process_profile_regex(Profile *prof)
|
|||
|
||||
if (prof->dfa.rules->rule_count > 0) {
|
||||
int xmatch_len = 0;
|
||||
//fprintf(stderr, "Creating file DFA %d\n", kernel_supports_permstable32);
|
||||
prof->dfa.dfa = prof->dfa.rules->create_dfa(&prof->dfa.size,
|
||||
&xmatch_len, parseopts, true);
|
||||
&xmatch_len, prof->dfa.perms_table, parseopts, true, kernel_supports_permstable32);
|
||||
delete prof->dfa.rules;
|
||||
prof->dfa.rules = NULL;
|
||||
if (!prof->dfa.dfa)
|
||||
|
@ -1044,7 +1049,7 @@ int process_profile_policydb(Profile *prof)
|
|||
if (prof->policy.rules->rule_count > 0) {
|
||||
int xmatch_len = 0;
|
||||
prof->policy.dfa = prof->policy.rules->create_dfa(&prof->policy.size,
|
||||
&xmatch_len, parseopts, false);
|
||||
&xmatch_len, prof->policy.perms_table, parseopts, false, kernel_supports_permstable32);
|
||||
delete prof->policy.rules;
|
||||
|
||||
prof->policy.rules = NULL;
|
||||
|
|
104
parser/perms.h
Normal file
104
parser/perms.h
Normal file
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Copyright (c) 2022
|
||||
* Canonical, Ltd. (All rights reserved)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public
|
||||
* License published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, contact Novell, Inc. or Canonical
|
||||
* Ltd.
|
||||
*/
|
||||
#ifndef __AA_PERM_H
|
||||
#define __AA_PERM_H
|
||||
|
||||
#include <stdint.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 */
|
||||
#define AA_MAY_CHGRP 0x4000 /* pair */
|
||||
#define AA_MAY_LOCK 0x8000 /* LINK_SUBSET overlaid */
|
||||
|
||||
#define AA_EXEC_MMAP 0x00010000
|
||||
#define AA_MAY_MPROT 0x00020000 /* extend conditions */
|
||||
#define AA_MAY_LINK 0x00040000 /* pair */
|
||||
#endif
|
||||
#define AA_MAY_SNAPSHOT 0x00080000 /* pair */
|
||||
|
||||
#define AA_MAY_DELEGATE
|
||||
#define AA_CONT_MATCH 0x08000000
|
||||
|
||||
#define AA_MAY_STACK 0x10000000
|
||||
#define AA_MAY_ONEXEC 0x20000000 /* either stack or change_profile */
|
||||
#define AA_MAY_CHANGE_PROFILE 0x40000000
|
||||
#define AA_MAY_CHANGEHAT 0x80000000
|
||||
|
||||
#define AA_LINK_SUBSET AA_MAY_LOCK /* overlaid */
|
||||
|
||||
|
||||
/*
|
||||
* The xindex is broken into 3 parts
|
||||
* - index - an index into either the exec name table or the variable table
|
||||
* - exec type - which determines how the executable name and index are used
|
||||
* - flags - which modify how the destination name is applied
|
||||
*/
|
||||
#define AA_X_INDEX_MASK AA_INDEX_MASK
|
||||
|
||||
#define AA_X_TYPE_MASK 0x0c000000
|
||||
#define AA_X_NONE AA_INDEX_NONE
|
||||
#define AA_X_NAME 0x04000000 /* use executable name px */
|
||||
#define AA_X_TABLE 0x08000000 /* use a specified name ->n# */
|
||||
|
||||
#define AA_X_UNSAFE 0x10000000
|
||||
#define AA_X_CHILD 0x20000000
|
||||
#define AA_X_INHERIT 0x40000000
|
||||
#define AA_X_UNCONFINED 0x80000000
|
||||
|
||||
struct aa_perms {
|
||||
uint32_t allow;
|
||||
uint32_t deny; /* explicit deny, or conflict if allow also set */
|
||||
|
||||
uint32_t subtree; /* allow perm on full subtree only when allow is set */
|
||||
uint32_t cond; /* set only when ~allow and ~deny */
|
||||
|
||||
uint32_t kill; /* set only when ~allow | deny */
|
||||
uint32_t complain; /* accumulates only used when ~allow & ~deny */
|
||||
uint32_t prompt; /* accumulates only used when ~allow & ~deny */
|
||||
|
||||
uint32_t audit; /* set only when allow is set */
|
||||
uint32_t quiet; /* set only when ~allow | deny */
|
||||
uint32_t hide; /* set only when ~allow | deny */
|
||||
|
||||
|
||||
uint32_t xindex;
|
||||
uint32_t tag; /* tag string index, if present */
|
||||
uint32_t label; /* label string index, if present */
|
||||
};
|
||||
|
||||
#endif /* __AA_PERM_H */
|
|
@ -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;
|
||||
|
||||
|
@ -336,7 +339,7 @@ struct dfa_stuff {
|
|||
aare_rules *rules;
|
||||
void *dfa;
|
||||
size_t size;
|
||||
|
||||
vector <aa_perms> perms_table;
|
||||
dfa_stuff(void): rules(NULL), dfa(NULL), size(0) { }
|
||||
};
|
||||
|
||||
|
@ -349,7 +352,7 @@ public:
|
|||
void *xmatch;
|
||||
size_t xmatch_size;
|
||||
int xmatch_len;
|
||||
|
||||
vector <aa_perms> xmatch_perms_table;
|
||||
struct cond_entry_list xattrs;
|
||||
|
||||
/* char *sub_name; */ /* subdomain name or NULL */
|
||||
|
|
Loading…
Add table
Reference in a new issue