~ubuntu-branches/ubuntu/trusty/apparmor/trusty-updates

« back to all changes in this revision

Viewing changes to .pc/change-signal-syntax.patch/parser/signal.c

  • Committer: Package Import Robot
  • Author(s): Jamie Strandboge
  • Date: 2014-04-04 01:07:24 UTC
  • Revision ID: package-import@ubuntu.com-20140404010724-n7pyk2cd5er3gi6m
Tags: 2.8.95~2430-0ubuntu5
debian/control: add versioned Breaks to apparmor for lxc, libvirt-bin,
lightdm and apparmor-easyprof-ubuntu

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *   Copyright (c) 2014
 
3
 *   Canonical, Ltd. (All rights reserved)
 
4
 *
 
5
 *   This program is free software; you can redistribute it and/or
 
6
 *   modify it under the terms of version 2 of the GNU General Public
 
7
 *   License published by the Free Software Foundation.
 
8
 *
 
9
 *   This program is distributed in the hope that it will be useful,
 
10
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 *   GNU General Public License for more details.
 
13
 *
 
14
 *   You should have received a copy of the GNU General Public License
 
15
 *   along with this program; if not, contact Novell, Inc. or Canonical
 
16
 *   Ltd.
 
17
 */
 
18
 
 
19
#include <stdlib.h>
 
20
#include <string.h>
 
21
#include <sys/apparmor.h>
 
22
 
 
23
#include <iomanip>
 
24
#include <string>
 
25
#include <iostream>
 
26
#include <sstream>
 
27
#include <map>
 
28
 
 
29
#include "parser.h"
 
30
#include "profile.h"
 
31
#include "parser_yacc.h"
 
32
#include "signal.h"
 
33
 
 
34
#define MAXMAPPED_SIG 35
 
35
#define MINRT_SIG 128           /* base of RT sigs */
 
36
#define MAXRT_SIG 32            /* Max RT above MINRT_SIG */
 
37
 
 
38
/* Signal names mapped to and internal ordering */
 
39
static struct signal_map { const char *name; int num; } signal_map[] = {
 
40
        {"hup",         1},
 
41
        {"int",         2},
 
42
        {"quit",        3},
 
43
        {"ill",         4},
 
44
        {"trap",        5},
 
45
        {"abrt",        6},
 
46
        {"bus",         7},
 
47
        {"fpe",         8},
 
48
        {"kill",        9},
 
49
        {"usr1",        10},
 
50
        {"segv",        11},
 
51
        {"usr2",        12},
 
52
        {"pipe",        13},
 
53
        {"alrm",        14},
 
54
        {"term",        15},
 
55
        {"stkflt",      16},
 
56
        {"chld",        17},
 
57
        {"cont",        18},
 
58
        {"stop",        19},
 
59
        {"stp",         20},
 
60
        {"ttin",        21},
 
61
        {"ttou",        22},
 
62
        {"urg",         23},
 
63
        {"xcpu",        24},
 
64
        {"xfsz",        25},
 
65
        {"vtalrm",      26},
 
66
        {"prof",        27},
 
67
        {"winch",       28},
 
68
        {"io",          29},
 
69
        {"pwr",         30},
 
70
        {"sys",         31},
 
71
        {"emt",         32},
 
72
        {"exists",      35},
 
73
 
 
74
        /* terminate */
 
75
        {NULL,          0}
 
76
};
 
77
 
 
78
/* this table is ordered post sig_map[sig] mapping */
 
79
static const char *const sig_names[MAXMAPPED_SIG + 1] = {
 
80
        "unknown",
 
81
        "hup",
 
82
        "int",
 
83
        "quit",
 
84
        "ill",
 
85
        "trap",
 
86
        "abrt",
 
87
        "bus",
 
88
        "fpe",
 
89
        "kill",
 
90
        "usr1",
 
91
        "segv",
 
92
        "usr2",
 
93
        "pipe",
 
94
        "alrm",
 
95
        "term",
 
96
        "stkflt",
 
97
        "chld",
 
98
        "cont",
 
99
        "stop",
 
100
        "stp",
 
101
        "ttin",
 
102
        "ttou",
 
103
        "urg",
 
104
        "xcpu",
 
105
        "xfsz",
 
106
        "vtalrm",
 
107
        "prof",
 
108
        "winch",
 
109
        "io",
 
110
        "pwr",
 
111
        "sys",
 
112
        "emt",
 
113
        "lost",
 
114
        "unused",
 
115
 
 
116
        "exists",       /* always last existance test mapped to MAXMAPPED_SIG */
 
117
};
 
118
 
 
119
 
 
120
int parse_signal_mode(const char *str_mode, int *mode, int fail)
 
121
{
 
122
        return parse_X_mode("signal", AA_VALID_SIGNAL_PERMS, str_mode, mode, fail);
 
123
}
 
124
 
 
125
static int find_signal_mapping(const char *sig)
 
126
{
 
127
        if (strncmp("rtmin+", sig, 6) == 0) {
 
128
                char *end;
 
129
                unsigned long n = strtoul(sig + 6, &end, 10);
 
130
                if (end == sig || n > MAXRT_SIG)
 
131
                        return -1;
 
132
                return MINRT_SIG + n;
 
133
        } else {
 
134
                for (int i = 0; signal_map[i].name; i++) {
 
135
                        if (strcmp(sig, signal_map[i].name) == 0)
 
136
                                return signal_map[i].num;
 
137
                }
 
138
        }
 
139
        return -1;
 
140
}
 
141
 
 
142
void signal_rule::extract_sigs(struct value_list **list)
 
143
{
 
144
        struct value_list *entry, *tmp, *prev = NULL;
 
145
        list_for_each_safe(*list, entry, tmp) {
 
146
                int i = find_signal_mapping(entry->value);
 
147
                if (i != -1) {
 
148
                        signals.insert(i);
 
149
                        list_remove_at(*list, prev, entry);
 
150
                        free_value_list(entry);
 
151
                } else {
 
152
                        yyerror("unknown signal \"%s\"\n", entry->value);
 
153
                        prev = entry;
 
154
                }
 
155
        }
 
156
}
 
157
 
 
158
void signal_rule::move_conditionals(struct cond_entry *conds)
 
159
{
 
160
        struct cond_entry *cond_ent;
 
161
 
 
162
        list_for_each(conds, cond_ent) {
 
163
                /* for now disallow keyword 'in' (list) */
 
164
                if (!cond_ent->eq)
 
165
                        yyerror("keyword \"in\" is not allowed in signal rules\n");
 
166
                if (strcmp(cond_ent->name, "set") == 0) {
 
167
                        extract_sigs(&cond_ent->vals);
 
168
                } else {
 
169
                        yyerror("invalid signal rule conditional \"%s\"\n",
 
170
                                cond_ent->name);
 
171
                }
 
172
        }
 
173
}
 
174
 
 
175
signal_rule::signal_rule(int mode_p, struct cond_entry *conds,
 
176
                         char *peer):
 
177
        signals(), peer_label(peer), audit(0), deny(0)
 
178
{
 
179
        if (mode_p) {
 
180
                mode = mode_p;
 
181
                if (mode & ~AA_VALID_SIGNAL_PERMS)
 
182
                        yyerror("mode contains invalid permission for signals\n");
 
183
        } else {
 
184
                mode = AA_VALID_SIGNAL_PERMS;
 
185
        }
 
186
 
 
187
        move_conditionals(conds);
 
188
 
 
189
        free_cond_list(conds);
 
190
}
 
191
 
 
192
ostream &signal_rule::dump(ostream &os)
 
193
{
 
194
        if (audit)
 
195
                os << "audit ";
 
196
        if (deny)
 
197
                os << "deny ";
 
198
 
 
199
        os << "signal";
 
200
 
 
201
        if (mode != AA_VALID_SIGNAL_PERMS) {
 
202
                os << " (";
 
203
 
 
204
                if (mode & AA_MAY_SEND)
 
205
                        os << "send ";
 
206
                if (mode & AA_MAY_RECEIVE)
 
207
                        os << "receive ";
 
208
                os << ")";
 
209
        }
 
210
 
 
211
        if (!signals.empty()) {
 
212
                os << " set=(";
 
213
                for (Signals::iterator i = signals.begin(); i != signals.end();
 
214
                     i++) {
 
215
                        if (i != signals.begin())
 
216
                                os << ", ";
 
217
                        if (*i < MINRT_SIG)
 
218
                                os << sig_names[*i];
 
219
                        else
 
220
                                os << "rtmin+" << (*i - MINRT_SIG);
 
221
                }
 
222
                os << ")";
 
223
        }
 
224
 
 
225
        if (peer_label)
 
226
                os << " " << peer_label;
 
227
 
 
228
        os << ",\n";
 
229
 
 
230
        return os;
 
231
}
 
232
 
 
233
int signal_rule::expand_variables(void)
 
234
{
 
235
        return expand_entry_variables(&peer_label);
 
236
}
 
237
 
 
238
/* do we want to warn once/profile or just once per compile?? */
 
239
static void warn_once(const char *name)
 
240
{
 
241
        static const char *warned_name = NULL;
 
242
 
 
243
        if (warned_name != name) {
 
244
                cerr << "Warning from profile " << name << " (";
 
245
                if (current_filename)
 
246
                        cerr << current_filename;
 
247
                else
 
248
                        cerr << "stdin";
 
249
                cerr << ") signal rules not enforced\n";
 
250
                warned_name = name;
 
251
        }
 
252
}
 
253
 
 
254
int signal_rule::gen_policy_re(Profile &prof)
 
255
{
 
256
        std::ostringstream buffer;
 
257
        std::string buf;
 
258
 
 
259
        pattern_t ptype;
 
260
        int pos;
 
261
 
 
262
        /* Currently do not generate the rules if the kernel doesn't support
 
263
         * it. We may want to switch this so that a compile could be
 
264
         * used for full support on kernels that don't support the feature
 
265
         */
 
266
        if (!kernel_supports_signal) {
 
267
                warn_once(prof.name);
 
268
                return RULE_NOT_SUPPORTED;
 
269
        }
 
270
 
 
271
        if (signals.size() == 0) {
 
272
                /* not conditional on signal set, so will generate a label
 
273
                 * rule as well
 
274
                 */
 
275
                buffer << "(" << "\\x" << std::setfill('0') << std::setw(2) << std::hex << AA_CLASS_LABEL << "\\x" << AA_CLASS_SIGNAL << "|";
 
276
        }
 
277
 
 
278
        buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << AA_CLASS_SIGNAL;
 
279
 
 
280
        if (signals.size()) {
 
281
                buffer << "[";
 
282
                for (Signals::iterator i = signals.begin(); i != signals.end(); i++) {
 
283
                        buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << *i;
 
284
                }
 
285
                buffer << "]";
 
286
        } else {
 
287
                /* match any char */
 
288
                buffer << ".";
 
289
        }
 
290
 
 
291
        if (signals.size() == 0) {
 
292
                /* close alternation */
 
293
                buffer << ")";
 
294
        }
 
295
        if (peer_label) {
 
296
                ptype = convert_aaregex_to_pcre(peer_label, 0, buf, &pos);
 
297
                if (ptype == ePatternInvalid)
 
298
                        goto fail;
 
299
                buffer << buf;
 
300
        } else {
 
301
                buffer << anyone_match_pattern;
 
302
        }
 
303
 
 
304
        buf = buffer.str();
 
305
        if (mode & (AA_MAY_SEND | AA_MAY_RECEIVE)) {
 
306
                if (!prof.policy.rules->add_rule(buf.c_str(), deny, mode, audit,
 
307
                                                 dfaflags))
 
308
                        goto fail;
 
309
        }
 
310
 
 
311
        return RULE_OK;
 
312
 
 
313
fail:
 
314
        return RULE_ERROR;
 
315
}