~apparmor-dev/apparmor/master

« back to all changes in this revision

Viewing changes to parser/signal.cc

  • Committer: Steve Beattie
  • Date: 2019-02-19 09:38:13 UTC
  • Revision ID: sbeattie@ubuntu.com-20190219093813-ud526ee6hwn8nljz
The AppArmor project has been converted to git and is now hosted on
gitlab.

To get the converted repository, please do
  git clone https://gitlab.com/apparmor/apparmor

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 if (strcmp(cond_ent->name, "peer") == 0) {
169
 
                        move_conditional_value("signal", &peer_label, cond_ent);
170
 
                } else {
171
 
                        yyerror("invalid signal rule conditional \"%s\"\n",
172
 
                                cond_ent->name);
173
 
                }
174
 
        }
175
 
}
176
 
 
177
 
signal_rule::signal_rule(int mode_p, struct cond_entry *conds):
178
 
        signals(), peer_label(NULL), audit(0), deny(0)
179
 
{
180
 
        if (mode_p) {
181
 
                mode = mode_p;
182
 
                if (mode & ~AA_VALID_SIGNAL_PERMS)
183
 
                        yyerror("mode contains invalid permission for signals\n");
184
 
        } else {
185
 
                mode = AA_VALID_SIGNAL_PERMS;
186
 
        }
187
 
 
188
 
        move_conditionals(conds);
189
 
 
190
 
        free_cond_list(conds);
191
 
}
192
 
 
193
 
ostream &signal_rule::dump(ostream &os)
194
 
{
195
 
        if (audit)
196
 
                os << "audit ";
197
 
        if (deny)
198
 
                os << "deny ";
199
 
 
200
 
        os << "signal";
201
 
 
202
 
        if (mode != AA_VALID_SIGNAL_PERMS) {
203
 
                os << " (";
204
 
 
205
 
                if (mode & AA_MAY_SEND)
206
 
                        os << "send ";
207
 
                if (mode & AA_MAY_RECEIVE)
208
 
                        os << "receive ";
209
 
                os << ")";
210
 
        }
211
 
 
212
 
        if (!signals.empty()) {
213
 
                os << " set=(";
214
 
                for (Signals::iterator i = signals.begin(); i != signals.end();
215
 
                     i++) {
216
 
                        if (i != signals.begin())
217
 
                                os << ", ";
218
 
                        if (*i < MINRT_SIG)
219
 
                                os << sig_names[*i];
220
 
                        else
221
 
                                os << "rtmin+" << (*i - MINRT_SIG);
222
 
                }
223
 
                os << ")";
224
 
        }
225
 
 
226
 
        if (peer_label)
227
 
                os << " " << peer_label;
228
 
 
229
 
        os << ",\n";
230
 
 
231
 
        return os;
232
 
}
233
 
 
234
 
int signal_rule::expand_variables(void)
235
 
{
236
 
        return expand_entry_variables(&peer_label);
237
 
}
238
 
 
239
 
/* do we want to warn once/profile or just once per compile?? */
240
 
static void warn_once(const char *name)
241
 
{
242
 
        static const char *warned_name = NULL;
243
 
 
244
 
        if ((warnflags & WARN_RULE_NOT_ENFORCED) && warned_name != name) {
245
 
                cerr << "Warning from profile " << name << " (";
246
 
                if (current_filename)
247
 
                        cerr << current_filename;
248
 
                else
249
 
                        cerr << "stdin";
250
 
                cerr << ") signal rules not enforced\n";
251
 
                warned_name = name;
252
 
        }
253
 
}
254
 
 
255
 
int signal_rule::gen_policy_re(Profile &prof)
256
 
{
257
 
        std::ostringstream buffer;
258
 
        std::string buf;
259
 
 
260
 
        pattern_t ptype;
261
 
        int pos;
262
 
 
263
 
        /* Currently do not generate the rules if the kernel doesn't support
264
 
         * it. We may want to switch this so that a compile could be
265
 
         * used for full support on kernels that don't support the feature
266
 
         */
267
 
        if (!kernel_supports_signal) {
268
 
                warn_once(prof.name);
269
 
                return RULE_NOT_SUPPORTED;
270
 
        }
271
 
 
272
 
        if (signals.size() == 0) {
273
 
                /* not conditional on signal set, so will generate a label
274
 
                 * rule as well
275
 
                 */
276
 
                buffer << "(" << "\\x" << std::setfill('0') << std::setw(2) << std::hex << AA_CLASS_LABEL << "\\x" << AA_CLASS_SIGNAL << "|";
277
 
        }
278
 
 
279
 
        buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << AA_CLASS_SIGNAL;
280
 
 
281
 
        if (signals.size()) {
282
 
                buffer << "[";
283
 
                for (Signals::iterator i = signals.begin(); i != signals.end(); i++) {
284
 
                        buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << *i;
285
 
                }
286
 
                buffer << "]";
287
 
        } else {
288
 
                /* match any char */
289
 
                buffer << ".";
290
 
        }
291
 
 
292
 
        if (signals.size() == 0) {
293
 
                /* close alternation */
294
 
                buffer << ")";
295
 
        }
296
 
        if (peer_label) {
297
 
                ptype = convert_aaregex_to_pcre(peer_label, 0, glob_default, buf, &pos);
298
 
                if (ptype == ePatternInvalid)
299
 
                        goto fail;
300
 
                buffer << buf;
301
 
        } else {
302
 
                buffer << anyone_match_pattern;
303
 
        }
304
 
 
305
 
        buf = buffer.str();
306
 
        if (mode & (AA_MAY_SEND | AA_MAY_RECEIVE)) {
307
 
                if (!prof.policy.rules->add_rule(buf.c_str(), deny, mode, audit,
308
 
                                                 dfaflags))
309
 
                        goto fail;
310
 
        }
311
 
 
312
 
        return RULE_OK;
313
 
 
314
 
fail:
315
 
        return RULE_ERROR;
316
 
}