2
* (C) 2006, 2007 Andreas Gruenbacher <agruen@suse.de>
3
* Copyright (c) 2003-2008 Novell, Inc. (All rights reserved)
4
* Copyright 2009-2010 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"
34
#include "compressed_hfa.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;
104
if (regex_parse(&tree, rulev[0]))
106
for (int i = 1; i < count; i++) {
107
Node *subtree = NULL;
108
Node *node = new CharNode(0);
111
tree = new CatNode(tree, node);
112
if (regex_parse(&subtree, rulev[i]))
114
tree = new CatNode(tree, subtree);
118
* Check if we have an expression with or without wildcards. This
119
* determines how exec modifiers are merged in accept_perms() based
120
* on how we split permission bitmasks here.
123
for (depth_first_traversal i(tree); i; i++) {
124
if (dynamic_cast<StarNode *>(*i) ||
125
dynamic_cast<PlusNode *>(*i) ||
126
dynamic_cast<AnyCharNode *>(*i) ||
127
dynamic_cast<CharSetNode *>(*i) ||
128
dynamic_cast<NotCharSetNode *>(*i))
135
/* 0x7f == 4 bits x mods + 1 bit unsafe mask + 1 bit ix, + 1 pux after shift */
136
#define EXTRACT_X_INDEX(perm, shift) (((perm) >> (shift + 7)) & 0x7f)
138
//if (perms & ALL_AA_EXEC_TYPE && (!perms & AA_EXEC_BITS))
139
// fprintf(stderr, "adding X rule without MAY_EXEC: 0x%x %s\n", perms, rulev[0]);
141
//if (perms & ALL_EXEC_TYPE)
142
// fprintf(stderr, "adding X rule %s 0x%x\n", rulev[0], perms);
145
//fprintf(stderr, "adding rule with audit bits set: 0x%x %s\n", audit, rulev[0]);
147
//if (perms & AA_CHANGE_HAT)
148
// fprintf(stderr, "adding change_hat rule %s\n", rulev[0]);
150
/* the permissions set is assumed to be non-empty if any audit
151
* bits are specified */
153
for (unsigned int n = 0; perms && n < (sizeof(perms) * 8); n++) {
154
uint32_t mask = 1 << n;
159
int ai = audit & mask ? 1 : 0;
163
if (mask & ALL_AA_EXEC_TYPE)
164
/* these cases are covered by EXEC_BITS */
167
if (deny_flags[ai][n]) {
168
flag = deny_flags[ai][n];
170
//fprintf(stderr, "Adding deny ai %d mask 0x%x audit 0x%x\n", ai, mask, audit & mask);
171
deny_flags[ai][n] = new DenyMatchFlag(mask, audit & mask);
172
flag = deny_flags[ai][n];
174
} else if (mask & AA_EXEC_BITS) {
177
if (mask & AA_USER_EXEC) {
178
eperm = mask | (perms & AA_USER_EXEC_TYPE);
179
index = EXTRACT_X_INDEX(eperm, AA_USER_SHIFT);
181
eperm = mask | (perms & AA_OTHER_EXEC_TYPE);
182
index = EXTRACT_X_INDEX(eperm, AA_OTHER_SHIFT) + (AA_EXEC_COUNT << 2);
184
//fprintf(stderr, "index %d eperm 0x%x\n", index, eperm);
186
if (exact_match_flags[ai][index]) {
187
flag = exact_match_flags[ai][index];
189
exact_match_flags[ai][index] = new ExactMatchFlag(eperm, audit & mask);
190
flag = exact_match_flags[ai][index];
193
if (exec_match_flags[ai][index]) {
194
flag = exec_match_flags[ai][index];
196
exec_match_flags[ai][index] = new MatchFlag(eperm, audit & mask);
197
flag = exec_match_flags[ai][index];
201
if (match_flags[ai][n]) {
202
flag = match_flags[ai][n];
204
match_flags[ai][n] = new MatchFlag(mask, audit & mask);
205
flag = match_flags[ai][n];
209
accept = new AltNode(accept, flag);
214
if (flags & DFA_DUMP_RULE_EXPR) {
217
for (int i = 1; i < count; i++) {
227
rules->root = new AltNode(rules->root, new CatNode(tree, accept));
229
rules->root = new CatNode(tree, accept);
235
/* create a dfa from the ruleset
236
* returns: buffer contain dfa tables, @size set to the size of the tables
237
* else NULL on failure
239
extern "C" void *aare_create_dfa(aare_ruleset_t *rules, size_t *size,
244
label_nodes(rules->root);
245
if (flags & DFA_DUMP_TREE) {
246
cerr << "\nDFA: Expression Tree\n";
247
rules->root->dump(cerr);
251
if (flags & DFA_CONTROL_TREE_SIMPLE) {
252
rules->root = simplify_tree(rules->root, flags);
254
if (flags & DFA_DUMP_SIMPLE_TREE) {
255
cerr << "\nDFA: Simplified Expression Tree\n";
256
rules->root->dump(cerr);
263
DFA dfa(rules->root, flags);
264
if (flags & DFA_DUMP_UNIQ_PERMS)
265
dfa.dump_uniq_perms("dfa");
267
if (flags & DFA_CONTROL_MINIMIZE) {
270
if (flags & DFA_DUMP_MIN_UNIQ_PERMS)
271
dfa.dump_uniq_perms("minimized dfa");
273
if (flags & DFA_CONTROL_REMOVE_UNREACHABLE)
274
dfa.remove_unreachable(flags);
276
if (flags & DFA_DUMP_STATES)
279
if (flags & DFA_DUMP_GRAPH)
280
dfa.dump_dot_graph(cerr);
282
map<uchar, uchar> eq;
283
if (flags & DFA_CONTROL_EQUIV) {
284
eq = dfa.equivalence_classes(flags);
285
dfa.apply_equivalence_classes(eq);
287
if (flags & DFA_DUMP_EQUIV) {
288
cerr << "\nDFA equivalence class\n";
289
dump_equivalence_classes(cerr, eq);
291
} else if (flags & DFA_DUMP_EQUIV)
292
cerr << "\nDFA did not generate an equivalence class\n";
294
TransitionTable transition_table(dfa, eq, flags);
295
if (flags & DFA_DUMP_TRANS_TABLE)
296
transition_table.dump(cerr);
297
transition_table.flex_table(stream, "");
304
stringbuf *buf = stream.rdbuf();
307
*size = buf->in_avail();
309
buffer = (char *)malloc(*size);
312
buf->sgetn(buffer, *size);