~ubuntu-branches/ubuntu/wily/apparmor/wily

« back to all changes in this revision

Viewing changes to parser/libapparmor_re/aare_rules.cc

  • Committer: Bazaar Package Importer
  • Author(s): Kees Cook
  • Date: 2011-08-10 18:12:34 UTC
  • mto: This revision was merged to the branch mainline in revision 9.
  • Revision ID: james.westby@ubuntu.com-20110810181234-b6obckg60cp99crg
Tags: upstream-2.7.0~beta1+bzr1774
ImportĀ upstreamĀ versionĀ 2.7.0~beta1+bzr1774

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
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.
 
5
 *
 
6
 * The libapparmor library is licensed under the terms of the GNU
 
7
 * Lesser General Public License, version 2.1. Please see the file
 
8
 * COPYING.LGPL.
 
9
 *
 
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.
 
14
 *
 
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/>.
 
17
 *
 
18
 *
 
19
 * Wrapper around the dfa to convert aa rules into a dfa
 
20
 */
 
21
 
 
22
#include <ostream>
 
23
#include <iostream>
 
24
#include <fstream>
 
25
#include <sstream>
 
26
#include <ext/stdio_filebuf.h>
 
27
#include <assert.h>
 
28
#include <stdlib.h>
 
29
 
 
30
#include "aare_rules.h"
 
31
#include "expr-tree.h"
 
32
#include "parse.h"
 
33
#include "hfa.h"
 
34
#include "compressed_hfa.h"
 
35
#include "../immunix.h"
 
36
 
 
37
struct aare_ruleset {
 
38
        int reverse;
 
39
        Node *root;
 
40
};
 
41
 
 
42
extern "C" aare_ruleset_t *aare_new_ruleset(int reverse)
 
43
{
 
44
        aare_ruleset_t *container = (aare_ruleset_t *) malloc(sizeof(aare_ruleset_t));
 
45
        if (!container)
 
46
                return NULL;
 
47
 
 
48
        container->root = NULL;
 
49
        container->reverse = reverse;
 
50
 
 
51
        return container;
 
52
}
 
53
 
 
54
extern "C" void aare_delete_ruleset(aare_ruleset_t *rules)
 
55
{
 
56
        if (rules) {
 
57
                if (rules->root)
 
58
                        rules->root->release();
 
59
                free(rules);
 
60
        }
 
61
}
 
62
 
 
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)
 
65
{
 
66
        return aare_add_rule_vec(rules, deny, perms, audit, 1, &rule, flags);
 
67
}
 
68
 
 
69
#define FLAGS_WIDTH 2
 
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 */
 
76
 
 
77
extern "C" void aare_reset_matchflags(void)
 
78
{
 
79
        uint32_t i, j;
 
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; \
 
85
                } \
 
86
        } \
 
87
}
 
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);
 
92
#undef RESET_FLAGS
 
93
}
 
94
 
 
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)
 
98
{
 
99
        Node *tree = NULL, *accept;
 
100
        int exact_match;
 
101
 
 
102
        assert(perms != 0);
 
103
 
 
104
        if (regex_parse(&tree, rulev[0]))
 
105
                return 0;
 
106
        for (int i = 1; i < count; i++) {
 
107
                Node *subtree = NULL;
 
108
                Node *node = new CharNode(0);
 
109
                if (!node)
 
110
                        return 0;
 
111
                tree = new CatNode(tree, node);
 
112
                if (regex_parse(&subtree, rulev[i]))
 
113
                        return 0;
 
114
                tree = new CatNode(tree, subtree);
 
115
        }
 
116
 
 
117
        /*
 
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.
 
121
         */
 
122
        exact_match = 1;
 
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))
 
129
                        exact_match = 0;
 
130
        }
 
131
 
 
132
        if (rules->reverse)
 
133
                flip_tree(tree);
 
134
 
 
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)
 
137
 
 
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]);
 
140
 
 
141
//if (perms & ALL_EXEC_TYPE)
 
142
//    fprintf(stderr, "adding X rule %s 0x%x\n", rulev[0], perms);
 
143
 
 
144
//if (audit)
 
145
//fprintf(stderr, "adding rule with audit bits set: 0x%x %s\n", audit, rulev[0]);
 
146
 
 
147
//if (perms & AA_CHANGE_HAT)
 
148
//    fprintf(stderr, "adding change_hat rule %s\n", rulev[0]);
 
149
 
 
150
/* the permissions set is assumed to be non-empty if any audit
 
151
 * bits are specified */
 
152
        accept = NULL;
 
153
        for (unsigned int n = 0; perms && n < (sizeof(perms) * 8); n++) {
 
154
                uint32_t mask = 1 << n;
 
155
 
 
156
                if (!(perms & mask))
 
157
                        continue;
 
158
 
 
159
                int ai = audit & mask ? 1 : 0;
 
160
                perms &= ~mask;
 
161
 
 
162
                Node *flag;
 
163
                if (mask & ALL_AA_EXEC_TYPE)
 
164
                        /* these cases are covered by EXEC_BITS */
 
165
                        continue;
 
166
                if (deny) {
 
167
                        if (deny_flags[ai][n]) {
 
168
                                flag = deny_flags[ai][n];
 
169
                        } else {
 
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];
 
173
                        }
 
174
                } else if (mask & AA_EXEC_BITS) {
 
175
                        uint32_t eperm = 0;
 
176
                        uint32_t index = 0;
 
177
                        if (mask & AA_USER_EXEC) {
 
178
                                eperm = mask | (perms & AA_USER_EXEC_TYPE);
 
179
                                index = EXTRACT_X_INDEX(eperm, AA_USER_SHIFT);
 
180
                        } else {
 
181
                                eperm = mask | (perms & AA_OTHER_EXEC_TYPE);
 
182
                                index = EXTRACT_X_INDEX(eperm, AA_OTHER_SHIFT) + (AA_EXEC_COUNT << 2);
 
183
                        }
 
184
//fprintf(stderr, "index %d eperm 0x%x\n", index, eperm);
 
185
                        if (exact_match) {
 
186
                                if (exact_match_flags[ai][index]) {
 
187
                                        flag = exact_match_flags[ai][index];
 
188
                                } else {
 
189
                                        exact_match_flags[ai][index] = new ExactMatchFlag(eperm, audit & mask);
 
190
                                        flag = exact_match_flags[ai][index];
 
191
                                }
 
192
                        } else {
 
193
                                if (exec_match_flags[ai][index]) {
 
194
                                        flag = exec_match_flags[ai][index];
 
195
                                } else {
 
196
                                        exec_match_flags[ai][index] = new MatchFlag(eperm, audit & mask);
 
197
                                        flag = exec_match_flags[ai][index];
 
198
                                }
 
199
                        }
 
200
                } else {
 
201
                        if (match_flags[ai][n]) {
 
202
                                flag = match_flags[ai][n];
 
203
                        } else {
 
204
                                match_flags[ai][n] = new MatchFlag(mask, audit & mask);
 
205
                                flag = match_flags[ai][n];
 
206
                        }
 
207
                }
 
208
                if (accept)
 
209
                        accept = new AltNode(accept, flag);
 
210
                else
 
211
                        accept = flag;
 
212
        } /* for ... */
 
213
 
 
214
        if (flags & DFA_DUMP_RULE_EXPR) {
 
215
                cerr << "rule: ";
 
216
                cerr << rulev[0];
 
217
                for (int i = 1; i < count; i++) {
 
218
                        cerr << "\\x00";
 
219
                        cerr << rulev[i];
 
220
                }
 
221
                cerr << "  ->  ";
 
222
                tree->dump(cerr);
 
223
                cerr << "\n\n";
 
224
        }
 
225
 
 
226
        if (rules->root)
 
227
                rules->root = new AltNode(rules->root, new CatNode(tree, accept));
 
228
        else
 
229
                rules->root = new CatNode(tree, accept);
 
230
 
 
231
        return 1;
 
232
 
 
233
}
 
234
 
 
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
 
238
 */
 
239
extern "C" void *aare_create_dfa(aare_ruleset_t *rules, size_t *size,
 
240
                                 dfaflags_t flags)
 
241
{
 
242
        char *buffer = NULL;
 
243
 
 
244
        label_nodes(rules->root);
 
245
        if (flags & DFA_DUMP_TREE) {
 
246
                cerr << "\nDFA: Expression Tree\n";
 
247
                rules->root->dump(cerr);
 
248
                cerr << "\n\n";
 
249
        }
 
250
 
 
251
        if (flags & DFA_CONTROL_TREE_SIMPLE) {
 
252
                rules->root = simplify_tree(rules->root, flags);
 
253
 
 
254
                if (flags & DFA_DUMP_SIMPLE_TREE) {
 
255
                        cerr << "\nDFA: Simplified Expression Tree\n";
 
256
                        rules->root->dump(cerr);
 
257
                        cerr << "\n\n";
 
258
                }
 
259
        }
 
260
 
 
261
        stringstream stream;
 
262
        try {
 
263
                DFA dfa(rules->root, flags);
 
264
                if (flags & DFA_DUMP_UNIQ_PERMS)
 
265
                        dfa.dump_uniq_perms("dfa");
 
266
 
 
267
                if (flags & DFA_CONTROL_MINIMIZE) {
 
268
                        dfa.minimize(flags);
 
269
 
 
270
                        if (flags & DFA_DUMP_MIN_UNIQ_PERMS)
 
271
                                dfa.dump_uniq_perms("minimized dfa");
 
272
                }
 
273
                if (flags & DFA_CONTROL_REMOVE_UNREACHABLE)
 
274
                        dfa.remove_unreachable(flags);
 
275
 
 
276
                if (flags & DFA_DUMP_STATES)
 
277
                        dfa.dump(cerr);
 
278
 
 
279
                if (flags & DFA_DUMP_GRAPH)
 
280
                        dfa.dump_dot_graph(cerr);
 
281
 
 
282
                map<uchar, uchar> eq;
 
283
                if (flags & DFA_CONTROL_EQUIV) {
 
284
                        eq = dfa.equivalence_classes(flags);
 
285
                        dfa.apply_equivalence_classes(eq);
 
286
 
 
287
                        if (flags & DFA_DUMP_EQUIV) {
 
288
                                cerr << "\nDFA equivalence class\n";
 
289
                                dump_equivalence_classes(cerr, eq);
 
290
                        }
 
291
                } else if (flags & DFA_DUMP_EQUIV)
 
292
                        cerr << "\nDFA did not generate an equivalence class\n";
 
293
 
 
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, "");
 
298
        }
 
299
        catch(int error) {
 
300
                *size = 0;
 
301
                return NULL;
 
302
        }
 
303
 
 
304
        stringbuf *buf = stream.rdbuf();
 
305
 
 
306
        buf->pubseekpos(0);
 
307
        *size = buf->in_avail();
 
308
 
 
309
        buffer = (char *)malloc(*size);
 
310
        if (!buffer)
 
311
                return NULL;
 
312
        buf->sgetn(buffer, *size);
 
313
        return buffer;
 
314
}