2
* (C) 2006, 2007 Andreas Gruenbacher <agruen@suse.de>
3
* Copyright (c) 2003-2008 Novell, Inc. (All rights reserved)
4
* Copyright 2009-2012 Canonical Ltd.
6
* The libapparmor library is licensed under the terms of the GNU
7
* Lesser General Public License, version 2.1. Please see the file
10
* This library is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU Lesser General Public License for more details.
15
* You should have received a copy of the GNU Lesser General Public License
16
* along with this program. If not, see <http://www.gnu.org/licenses/>.
19
* Wrapper around the dfa to convert aa rules into a dfa
26
#include <ext/stdio_filebuf.h>
30
#include "aare_rules.h"
31
#include "expr-tree.h"
35
#include "../immunix.h"
42
extern "C" aare_ruleset_t *aare_new_ruleset(int reverse)
44
aare_ruleset_t *container = (aare_ruleset_t *) malloc(sizeof(aare_ruleset_t));
48
container->root = NULL;
49
container->reverse = reverse;
54
extern "C" void aare_delete_ruleset(aare_ruleset_t *rules)
58
rules->root->release();
63
extern "C" int aare_add_rule(aare_ruleset_t *rules, char *rule, int deny,
64
uint32_t perms, uint32_t audit, dfaflags_t flags)
66
return aare_add_rule_vec(rules, deny, perms, audit, 1, &rule, flags);
70
#define MATCH_FLAGS_SIZE (sizeof(uint32_t) * 8 - 1)
71
MatchFlag *match_flags[FLAGS_WIDTH][MATCH_FLAGS_SIZE];
72
DenyMatchFlag *deny_flags[FLAGS_WIDTH][MATCH_FLAGS_SIZE];
73
#define EXEC_MATCH_FLAGS_SIZE (AA_EXEC_COUNT *2 * 2 * 2) /* double for each of ix pux, unsafe x bits * u::o */
74
MatchFlag *exec_match_flags[FLAGS_WIDTH][EXEC_MATCH_FLAGS_SIZE]; /* mods + unsafe + ix + pux * u::o */
75
ExactMatchFlag *exact_match_flags[FLAGS_WIDTH][EXEC_MATCH_FLAGS_SIZE]; /* mods + unsafe + ix + pux *u::o */
77
extern "C" void aare_reset_matchflags(void)
80
#define RESET_FLAGS(group, size) { \
81
for (i = 0; i < FLAGS_WIDTH; i++) { \
82
for (j = 0; j < size; j++) { \
83
if ((group)[i][j]) delete (group)[i][j]; \
84
(group)[i][j] = NULL; \
88
RESET_FLAGS(match_flags, MATCH_FLAGS_SIZE);
89
RESET_FLAGS(deny_flags, MATCH_FLAGS_SIZE);
90
RESET_FLAGS(exec_match_flags, EXEC_MATCH_FLAGS_SIZE);
91
RESET_FLAGS(exact_match_flags, EXEC_MATCH_FLAGS_SIZE);
95
extern "C" int aare_add_rule_vec(aare_ruleset_t *rules, int deny,
96
uint32_t perms, uint32_t audit,
97
int count, char **rulev, dfaflags_t flags)
99
Node *tree = NULL, *accept;
101
uint32_t allow = perms;
105
if (regex_parse(&tree, rulev[0]))
107
for (int i = 1; i < count; i++) {
108
Node *subtree = NULL;
109
Node *node = new CharNode(0);
112
tree = new CatNode(tree, node);
113
if (regex_parse(&subtree, rulev[i]))
115
tree = new CatNode(tree, subtree);
119
* Check if we have an expression with or without wildcards. This
120
* determines how exec modifiers are merged in accept_perms() based
121
* on how we split permission bitmasks here.
124
for (depth_first_traversal i(tree); i; i++) {
125
if (dynamic_cast<StarNode *>(*i) ||
126
dynamic_cast<PlusNode *>(*i) ||
127
dynamic_cast<AnyCharNode *>(*i) ||
128
dynamic_cast<CharSetNode *>(*i) ||
129
dynamic_cast<NotCharSetNode *>(*i))
136
/* 0x7f == 4 bits x mods + 1 bit unsafe mask + 1 bit ix, + 1 pux after shift */
137
#define EXTRACT_X_INDEX(perm, shift) (((perm) >> (shift + 7)) & 0x7f)
139
//if (perms & ALL_AA_EXEC_TYPE && (!perms & AA_EXEC_BITS))
140
// fprintf(stderr, "adding X rule without MAY_EXEC: 0x%x %s\n", perms, rulev[0]);
142
//if (perms & ALL_EXEC_TYPE)
143
// fprintf(stderr, "adding X rule %s 0x%x\n", rulev[0], perms);
146
//fprintf(stderr, "adding rule with audit bits set: 0x%x %s\n", audit, rulev[0]);
148
//if (perms & AA_CHANGE_HAT)
149
// fprintf(stderr, "adding change_hat rule %s\n", rulev[0]);
151
/* the permissions set is assumed to be non-empty if any audit
152
* bits are specified */
154
for (unsigned int n = 0; perms && n < (sizeof(perms) * 8); n++) {
155
uint32_t mask = 1 << n;
160
int ai = audit & mask ? 1 : 0;
164
if (mask & ALL_AA_EXEC_TYPE)
165
/* these cases are covered by EXEC_BITS */
168
if (deny_flags[ai][n]) {
169
flag = deny_flags[ai][n];
171
//fprintf(stderr, "Adding deny ai %d mask 0x%x audit 0x%x\n", ai, mask, audit & mask);
172
deny_flags[ai][n] = new DenyMatchFlag(mask, audit & mask);
173
flag = deny_flags[ai][n];
175
} else if (mask & AA_EXEC_BITS) {
178
if (mask & AA_USER_EXEC) {
179
eperm = mask | (perms & AA_USER_EXEC_TYPE);
180
index = EXTRACT_X_INDEX(eperm, AA_USER_SHIFT);
182
eperm = mask | (perms & AA_OTHER_EXEC_TYPE);
183
index = EXTRACT_X_INDEX(eperm, AA_OTHER_SHIFT) + (AA_EXEC_COUNT << 2);
185
//fprintf(stderr, "index %d eperm 0x%x\n", index, eperm);
187
if (exact_match_flags[ai][index]) {
188
flag = exact_match_flags[ai][index];
190
exact_match_flags[ai][index] = new ExactMatchFlag(eperm, audit & mask);
191
flag = exact_match_flags[ai][index];
194
if (exec_match_flags[ai][index]) {
195
flag = exec_match_flags[ai][index];
197
exec_match_flags[ai][index] = new MatchFlag(eperm, audit & mask);
198
flag = exec_match_flags[ai][index];
202
if (match_flags[ai][n]) {
203
flag = match_flags[ai][n];
205
match_flags[ai][n] = new MatchFlag(mask, audit & mask);
206
flag = match_flags[ai][n];
210
accept = new AltNode(accept, flag);
215
if (flags & DFA_DUMP_RULE_EXPR) {
218
for (int i = 1; i < count; i++) {
226
cerr << " (0x" << hex << allow <<"/" << audit << dec << ")";
232
rules->root = new AltNode(rules->root, new CatNode(tree, accept));
234
rules->root = new CatNode(tree, accept);
240
/* create a dfa from the ruleset
241
* returns: buffer contain dfa tables, @size set to the size of the tables
242
* else NULL on failure
244
extern "C" void *aare_create_dfa(aare_ruleset_t *rules, size_t *size,
249
label_nodes(rules->root);
250
if (flags & DFA_DUMP_TREE) {
251
cerr << "\nDFA: Expression Tree\n";
252
rules->root->dump(cerr);
256
if (flags & DFA_CONTROL_TREE_SIMPLE) {
257
rules->root = simplify_tree(rules->root, flags);
259
if (flags & DFA_DUMP_SIMPLE_TREE) {
260
cerr << "\nDFA: Simplified Expression Tree\n";
261
rules->root->dump(cerr);
268
DFA dfa(rules->root, flags);
269
if (flags & DFA_DUMP_UNIQ_PERMS)
270
dfa.dump_uniq_perms("dfa");
272
if (flags & DFA_CONTROL_MINIMIZE) {
275
if (flags & DFA_DUMP_MIN_UNIQ_PERMS)
276
dfa.dump_uniq_perms("minimized dfa");
279
if (flags & DFA_CONTROL_FILTER_DENY &&
280
flags & DFA_CONTROL_MINIMIZE &&
281
dfa.apply_and_clear_deny()) {
282
/* Do a second minimization pass as removal of deny
283
* information has moved some states from accepting
284
* to none accepting partitions
286
* TODO: add this as a tail pass to minimization
287
* so we don't need to do a full second pass
291
if (flags & DFA_DUMP_MIN_UNIQ_PERMS)
292
dfa.dump_uniq_perms("minimized dfa");
295
if (flags & DFA_CONTROL_REMOVE_UNREACHABLE)
296
dfa.remove_unreachable(flags);
298
if (flags & DFA_DUMP_STATES)
301
if (flags & DFA_DUMP_GRAPH)
302
dfa.dump_dot_graph(cerr);
304
map<uchar, uchar> eq;
305
if (flags & DFA_CONTROL_EQUIV) {
306
eq = dfa.equivalence_classes(flags);
307
dfa.apply_equivalence_classes(eq);
309
if (flags & DFA_DUMP_EQUIV) {
310
cerr << "\nDFA equivalence class\n";
311
dump_equivalence_classes(cerr, eq);
313
} else if (flags & DFA_DUMP_EQUIV)
314
cerr << "\nDFA did not generate an equivalence class\n";
316
CHFA chfa(dfa, eq, flags);
317
if (flags & DFA_DUMP_TRANS_TABLE)
319
chfa.flex_table(stream, "");
326
stringbuf *buf = stream.rdbuf();
329
*size = buf->in_avail();
331
buffer = (char *)malloc(*size);
334
buf->sgetn(buffer, *size);