~ubuntu-branches/ubuntu/precise/apparmor/precise-security

« back to all changes in this revision

Viewing changes to .pc/0017-apparmor-lp979135.patch/parser/parser_yacc.y

  • Committer: Package Import Robot
  • Author(s): Steve Beattie, Jamie Strandboge, Serge Hallyn, Steve Beattie
  • Date: 2012-04-12 06:17:42 UTC
  • Revision ID: package-import@ubuntu.com-20120412061742-9v75hjko2mjtbewv
Tags: 2.7.102-0ubuntu3
[ Jamie Strandboge ]
* debian/patches/0007-ubuntu-manpage-updates.patch: update apparmor(5)
  to describe Ubuntu's two-stage policy load and how to add utilize it
  when developing policy (LP: #974089)

[ Serge Hallyn ]
* debian/apparmor.init: do nothing in a container.  This can be
  removed once stacked profiles are supported and used by lxc.
  (LP: #978297)

[ Steve Beattie ]
* debian/patches/0008-apparmor-lp963756.patch: Fix permission mapping
  for change_profile onexec (LP: #963756)
* debian/patches/0009-apparmor-lp959560-part1.patch,
  debian/patches/0010-apparmor-lp959560-part2.patch: Update the parser
  to support the 'in' keyword for value lists, and make mount
  operations aware of 'in' keyword so they can affect the flags build
  list (LP: #959560)
* debian/patches/0011-apparmor-lp872446.patch: fix logprof missing
  exec events in complain mode (LP: #872446)
* debian/patches/0012-apparmor-lp978584.patch: allow inet6 access in
  dovecot imap-login profile (LP: #978584)
* debian/patches/0013-apparmor-lp800826.patch: fix libapparmor
  log parsing library from dropping apparmor network events that
  contain ip addresses or ports in them (LP: #800826)
* debian/patches/0014-apparmor-lp979095.patch: document new mount rule
  syntax and usage in apparmor.d(5) manpage (LP: #979095)
* debian/patches/0015-apparmor-lp963756.patch: Fix change_onexec
  for profiles without attachment specification (LP: #963756,
  LP: #978038)
* debian/patches/0016-apparmor-lp968956.patch: Fix protocol error when
  loading policy to kernels without compat patches (LP: #968956)
* debian/patches/0017-apparmor-lp979135.patch: Fix change_profile to
  grant access to /proc/attr api (LP: #979135)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
%{
 
2
/*
 
3
 *   Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
 
4
 *   NOVELL (All rights reserved)
 
5
 *   Copyright (c) 2010-2012
 
6
 *   Canonical Ltd.
 
7
 *
 
8
 *   This program is free software; you can redistribute it and/or
 
9
 *   modify it under the terms of version 2 of the GNU General Public
 
10
 *   License published by the Free Software Foundation.
 
11
 *
 
12
 *   This program is distributed in the hope that it will be useful,
 
13
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
 *   GNU General Public License for more details.
 
16
 *
 
17
 *   You should have received a copy of the GNU General Public License
 
18
 *   along with this program; if not, contact Canonical, Ltd.
 
19
 */
 
20
 
 
21
#define YYERROR_VERBOSE 1
 
22
#include <stdio.h>
 
23
#include <stdarg.h>
 
24
#include <string.h>
 
25
#include <stdlib.h>
 
26
#include <getopt.h>
 
27
#include <errno.h>
 
28
#include <fcntl.h>
 
29
#include <libintl.h>
 
30
#define _(s) gettext(s)
 
31
 
 
32
/* #define DEBUG */
 
33
 
 
34
#include "parser.h"
 
35
#include "mount.h"
 
36
#include "parser_include.h"
 
37
#include <unistd.h>
 
38
#include <netinet/in.h>
 
39
#include <arpa/inet.h>
 
40
 
 
41
#include <linux/capability.h>
 
42
 
 
43
#ifndef CAP_AUDIT_WRITE
 
44
#define CAP_AUDIT_WRITE 29
 
45
#endif
 
46
#ifndef CAP_AUDIT_CONTROL
 
47
#define CAP_AUDIT_CONTROL 30
 
48
#endif
 
49
#ifndef CAP_SETFCAP
 
50
#define CAP_SETFCAP          31
 
51
#endif
 
52
#ifndef CAP_MAC_OVERRIDE
 
53
#define CAP_MAC_OVERRIDE     32
 
54
#endif
 
55
 
 
56
#define CIDR_32 htonl(0xffffffff)
 
57
#define CIDR_24 htonl(0xffffff00)
 
58
#define CIDR_16 htonl(0xffff0000)
 
59
#define CIDR_8  htonl(0xff000000)
 
60
 
 
61
/* undefine linux/capability.h CAP_TO_MASK */
 
62
#ifdef CAP_TO_MASK
 
63
#undef CAP_TO_MASK
 
64
#endif
 
65
 
 
66
#define CAP_TO_MASK(x) (1ull << (x))
 
67
 
 
68
int parser_token = 0;
 
69
 
 
70
struct cod_entry *do_file_rule(char *namespace, char *id, int mode,
 
71
                               char *link_id, char *nt);
 
72
struct mnt_entry *do_mnt_rule(struct cond_entry *src_conds, char *src,
 
73
                              struct cond_entry *dst_conds, char *dst,
 
74
                              int mode);
 
75
struct mnt_entry *do_pivot_rule(struct cond_entry *old, char *root,
 
76
                                char *transition);
 
77
 
 
78
void add_local_entry(struct codomain *cod);
 
79
 
 
80
%}
 
81
 
 
82
%token TOK_ID
 
83
%token TOK_CONDID
 
84
%token TOK_CARET
 
85
%token TOK_OPEN
 
86
%token TOK_CLOSE
 
87
%token TOK_MODE
 
88
%token TOK_END_OF_RULE
 
89
%token TOK_EQUALS
 
90
%token TOK_ARROW
 
91
%token TOK_ADD_ASSIGN
 
92
%token TOK_LE
 
93
%token TOK_SET_VAR
 
94
%token TOK_BOOL_VAR
 
95
%token TOK_VALUE
 
96
%token TOK_IF
 
97
%token TOK_ELSE
 
98
%token TOK_NOT
 
99
%token TOK_DEFINED
 
100
%token TOK_CHANGE_PROFILE
 
101
%token TOK_NETWORK
 
102
%token TOK_HAT
 
103
%token TOK_UNSAFE
 
104
%token TOK_SAFE
 
105
%token TOK_COLON
 
106
%token TOK_LINK
 
107
%token TOK_OWNER
 
108
%token TOK_OTHER
 
109
%token TOK_SUBSET
 
110
%token TOK_AUDIT
 
111
%token TOK_DENY
 
112
%token TOK_PROFILE
 
113
%token TOK_SET
 
114
%token TOK_ALIAS
 
115
%token TOK_PTRACE
 
116
%token TOK_OPENPAREN
 
117
%token TOK_CLOSEPAREN
 
118
%token TOK_COMMA
 
119
%token TOK_FILE
 
120
%token TOK_MOUNT
 
121
%token TOK_REMOUNT
 
122
%token TOK_UMOUNT
 
123
%token TOK_PIVOTROOT
 
124
%token TOK_IN
 
125
 
 
126
 /* rlimits */
 
127
%token TOK_RLIMIT
 
128
%token TOK_SOFT_RLIMIT
 
129
%token TOK_RLIMIT_CPU
 
130
%token TOK_RLIMIT_FSIZE
 
131
%token TOK_RLIMIT_DATA
 
132
%token TOK_RLIMIT_STACK
 
133
%token TOK_RLIMIT_CORE
 
134
%token TOK_RLIMIT_RSS
 
135
%token TOK_RLIMIT_NOFILE
 
136
%token TOK_RLIMIT_OFILE
 
137
%token TOK_RLIMIT_AS
 
138
%token TOK_RLIMIT_NPROC
 
139
%token TOK_RLIMIT_MEMLOCK
 
140
%token TOK_RLIMIT_LOCKS
 
141
%token TOK_RLIMIT_SIGPENDING
 
142
%token TOK_RLIMIT_MSGQUEUE
 
143
%token TOK_RLIMIT_NICE
 
144
%token TOK_RLIMIT_RTPRIO
 
145
 
 
146
/* capabilities */
 
147
%token TOK_CAPABILITY
 
148
 
 
149
/* debug flag values */
 
150
%token TOK_FLAGS
 
151
 
 
152
%union {
 
153
        char *id;
 
154
        char *flag_id;
 
155
        char *mode;
 
156
        struct aa_network_entry *network_entry;
 
157
        struct codomain *cod;
 
158
        struct cod_net_entry *net_entry;
 
159
        struct cod_entry *user_entry;
 
160
        struct mnt_entry *mnt_entry;
 
161
 
 
162
        struct flagval flags;
 
163
        int fmode;
 
164
        uint64_t cap;
 
165
        unsigned int allowed_protocol;
 
166
        char *set_var;
 
167
        char *bool_var;
 
168
        char *var_val;
 
169
        struct value_list *val_list;
 
170
        struct cond_entry *cond_entry;
 
171
        int boolean;
 
172
        struct named_transition transition;
 
173
}
 
174
 
 
175
%type <id>      TOK_ID
 
176
%type <id>      TOK_CONDID
 
177
%type <mode>    TOK_MODE
 
178
%type <fmode>   file_mode
 
179
%type <cod>     profile_base
 
180
%type <cod>     profile
 
181
%type <cod>     rules
 
182
%type <cod>     hat
 
183
%type <cod>     local_profile
 
184
%type <cod>     cond_rule
 
185
%type <network_entry> network_rule
 
186
%type <user_entry> rule
 
187
%type <user_entry> file_rule
 
188
%type <user_entry> file_rule_tail
 
189
%type <user_entry> link_rule
 
190
%type <user_entry> ptrace_rule
 
191
%type <user_entry> frule
 
192
%type <mnt_entry> mnt_rule
 
193
%type <cond_entry> opt_conds
 
194
%type <cond_entry> cond
 
195
%type <flags>   flags
 
196
%type <flags>   flagvals
 
197
%type <flags>   flagval
 
198
%type <cap>     caps
 
199
%type <cap>     capability
 
200
%type <user_entry> change_profile
 
201
%type <set_var> TOK_SET_VAR
 
202
%type <bool_var> TOK_BOOL_VAR
 
203
%type <var_val> TOK_VALUE
 
204
%type <val_list> valuelist
 
205
%type <boolean> expr
 
206
%type <id>      id_or_var
 
207
%type <boolean> opt_subset_flag
 
208
%type <boolean> opt_audit_flag
 
209
%type <boolean> opt_owner_flag
 
210
%type <boolean> opt_profile_flag
 
211
%type <boolean> opt_flags
 
212
%type <id>      opt_namespace
 
213
%type <id>      opt_id
 
214
%type <transition> opt_named_transition
 
215
%type <boolean> opt_unsafe
 
216
%type <boolean> opt_file
 
217
%%
 
218
 
 
219
 
 
220
list:    preamble profilelist
 
221
        { /* nothing */ };
 
222
 
 
223
profilelist:    { /* nothing */ };
 
224
 
 
225
profilelist:    profilelist profile
 
226
        {
 
227
                PDEBUG("Matched: list profile\n");
 
228
                add_to_list($2);
 
229
        };
 
230
 
 
231
opt_profile_flag: { /* nothing */ $$ = 0; }
 
232
        | TOK_PROFILE { $$ = 1; }
 
233
        | hat_start { $$ = 2; }
 
234
 
 
235
opt_namespace: { /* nothing */ $$ = NULL; }
 
236
        | TOK_COLON TOK_ID TOK_COLON { $$ = $2; }
 
237
 
 
238
opt_id: { /* nothing */ $$ = NULL; }
 
239
        | TOK_ID { $$ = $1; }
 
240
 
 
241
profile_base: TOK_ID opt_id flags TOK_OPEN rules TOK_CLOSE
 
242
        {
 
243
                struct codomain *cod = $5;
 
244
 
 
245
                if (!cod) {
 
246
                        yyerror(_("Memory allocation error."));
 
247
                }
 
248
 
 
249
                cod->name = $1;
 
250
                cod->attachment = $2;
 
251
                if ($2 && $2[0] != '/')
 
252
                        /* we don't support variables as part of the profile
 
253
                         * name or attachment atm
 
254
                         */
 
255
                        yyerror(_("Profile attachment must begin with a '/'."));
 
256
                cod->flags = $3;
 
257
                if (force_complain)
 
258
                        cod->flags.complain = 1;
 
259
 
 
260
                post_process_nt_entries(cod);
 
261
                post_process_mnt_entries(cod);
 
262
                PDEBUG("%s: flags='%s%s'\n",
 
263
                       $2,
 
264
                       cod->flags.complain ? "complain, " : "",
 
265
                       cod->flags.audit ? "audit" : "");
 
266
 
 
267
                $$ = cod;
 
268
 
 
269
        };
 
270
 
 
271
profile:  opt_profile_flag opt_namespace profile_base
 
272
        {
 
273
                struct codomain *cod = $3;
 
274
                if ($2)
 
275
                        PDEBUG("Matched: %s://%s { ... }\n", $2, $3->name);
 
276
                else
 
277
                        PDEBUG("Matched: %s { ... }\n", $3->name);
 
278
 
 
279
                if ($3->name[0] != '/' && !($1 || $2))
 
280
                        yyerror(_("Profile names must begin with a '/', namespace or keyword 'profile' or 'hat'."));
 
281
 
 
282
                cod->namespace = $2;
 
283
                if ($1 == 2)
 
284
                        cod->flags.hat = 1;
 
285
                $$ = cod;
 
286
        };
 
287
 
 
288
local_profile:   TOK_PROFILE profile_base
 
289
        {
 
290
 
 
291
                struct codomain *cod = $2;
 
292
 
 
293
                if ($2)
 
294
                        PDEBUG("Matched: local profile %s { ... }\n", cod->name);
 
295
                cod->local = 1;
 
296
                $$ = cod;
 
297
        };
 
298
 
 
299
hat: hat_start profile_base
 
300
        {
 
301
                struct codomain *cod = $2;
 
302
                if ($2)
 
303
                        PDEBUG("Matched: hat %s { ... }\n", cod->name);
 
304
 
 
305
                cod->flags.hat = 1;
 
306
                $$ = cod;
 
307
        };
 
308
 
 
309
preamble: { /* nothing */ }
 
310
        | preamble alias { /* nothing */ };
 
311
        | preamble varassign { /* nothing */ };
 
312
 
 
313
alias: TOK_ALIAS TOK_ID TOK_ARROW TOK_ID TOK_END_OF_RULE
 
314
        {
 
315
                if (!new_alias($2, $4))
 
316
                        yyerror(_("Failed to create alias %s -> %s\n"), $2, $4);
 
317
                free($2);
 
318
                free($4);
 
319
        };
 
320
 
 
321
varassign:      TOK_SET_VAR TOK_EQUALS valuelist
 
322
        {
 
323
                struct value_list *list = $3;
 
324
                char *var_name = process_var($1);
 
325
                int err;
 
326
                if (!list || !list->value)
 
327
                        yyerror("Assert: valuelist returned NULL");
 
328
                PDEBUG("Matched: set assignment for (%s)\n", $1);
 
329
                err = new_set_var(var_name, list->value);
 
330
                if (err) {
 
331
                        yyerror("variable %s was previously declared", $1);
 
332
                        /* FIXME: it'd be handy to report the previous location */
 
333
                }
 
334
                for (list = list->next; list; list = list->next) {
 
335
                        err = add_set_value(var_name, list->value);
 
336
                        if (err)
 
337
                                yyerror("Error adding %s to set var %s",
 
338
                                        list->value, $1);
 
339
                }
 
340
                free_value_list($3);
 
341
                free(var_name);
 
342
                free($1);
 
343
        }
 
344
 
 
345
varassign:      TOK_SET_VAR TOK_ADD_ASSIGN valuelist
 
346
        {
 
347
                struct value_list *list = $3;
 
348
                char *var_name = process_var($1);
 
349
                int err;
 
350
                if (!list || !list->value)
 
351
                        yyerror("Assert: valuelist returned NULL");
 
352
                PDEBUG("Matched: additive assignment for (%s)\n", $1);
 
353
                /* do the first one outside the loop, subsequent
 
354
                 * failures are indicative of symtab failures */
 
355
                err = add_set_value(var_name, list->value);
 
356
                if (err) {
 
357
                        yyerror("variable %s was not previously declared, but is being assigned additional values", $1);
 
358
                }
 
359
                for (list = list->next; list; list = list->next) {
 
360
                        err = add_set_value(var_name, list->value);
 
361
                        if (err)
 
362
                                yyerror("Error adding %s to set var %s",
 
363
                                        list->value, $1);
 
364
                }
 
365
                free_value_list($3);
 
366
                free(var_name);
 
367
                free($1);
 
368
        }
 
369
 
 
370
varassign:      TOK_BOOL_VAR TOK_EQUALS TOK_VALUE
 
371
        {
 
372
                int boolean, err;
 
373
                char *var_name = process_var($1);
 
374
                PDEBUG("Matched: boolean assignment (%s) to %s\n", $1, $3);
 
375
                boolean = str_to_boolean($3);
 
376
                if (boolean == -1) {
 
377
                        yyerror("Invalid boolean assignment for (%s): %s is not true or false",
 
378
                                $1, $3);
 
379
                }
 
380
                err = add_boolean_var(var_name, boolean);
 
381
                if (err) {
 
382
                        yyerror("variable %s was previously declared", $1);
 
383
                        /* FIXME: it'd be handy to report the previous location */
 
384
                }
 
385
                free(var_name);
 
386
                free($1);
 
387
                free($3);
 
388
        }
 
389
 
 
390
valuelist:      TOK_VALUE
 
391
        {
 
392
                struct value_list *val = new_value_list($1);
 
393
                if (!val)
 
394
                        yyerror(_("Memory allocation error."));
 
395
                PDEBUG("Matched: value (%s)\n", $1);
 
396
 
 
397
                $$ = val;
 
398
        }
 
399
 
 
400
valuelist:      valuelist TOK_VALUE
 
401
        {
 
402
                struct value_list *val = new_value_list($2);
 
403
                if (!val)
 
404
                        yyerror(_("Memory allocation error."));
 
405
                PDEBUG("Matched: value list\n");
 
406
 
 
407
                list_append($1, val);
 
408
                $$ = $1;
 
409
        }
 
410
 
 
411
flags:  { /* nothing */
 
412
        struct flagval fv = { 0, 0, 0, 0 };
 
413
 
 
414
                $$ = fv;
 
415
        };
 
416
 
 
417
opt_flags: { /* nothing */ $$ = 0; }
 
418
        | TOK_CONDID TOK_EQUALS
 
419
        {
 
420
                if (strcmp($1, "flags") != 0)
 
421
                        yyerror("expected flags= got %s=", $1);
 
422
                $$ = 1;
 
423
        }
 
424
 
 
425
flags:  opt_flags TOK_OPENPAREN flagvals TOK_CLOSEPAREN
 
426
        {
 
427
                $$ = $3;
 
428
        };
 
429
 
 
430
flagvals:       flagvals flagval
 
431
        {
 
432
                $1.complain = $1.complain || $2.complain;
 
433
                $1.audit = $1.audit || $2.audit;
 
434
                $1.path = $1.path | $2.path;
 
435
                if (($1.path & (PATH_CHROOT_REL | PATH_NS_REL)) ==
 
436
                    (PATH_CHROOT_REL | PATH_NS_REL))
 
437
                        yyerror(_("Profile flag chroot_relative conflicts with namespace_relative"));
 
438
 
 
439
                if (($1.path & (PATH_MEDIATE_DELETED | PATH_DELEGATE_DELETED)) ==
 
440
                    (PATH_MEDIATE_DELETED | PATH_DELEGATE_DELETED))
 
441
                        yyerror(_("Profile flag mediate_deleted conflicts with delegate_deleted"));
 
442
                if (($1.path & (PATH_ATTACH | PATH_NO_ATTACH)) ==
 
443
                    (PATH_ATTACH | PATH_NO_ATTACH))
 
444
                        yyerror(_("Profile flag attach_disconnected conflicts with no_attach_disconnected"));
 
445
                if (($1.path & (PATH_CHROOT_NSATTACH | PATH_CHROOT_NO_ATTACH)) ==
 
446
                    (PATH_CHROOT_NSATTACH | PATH_CHROOT_NO_ATTACH))
 
447
                        yyerror(_("Profile flag chroot_attach conflicts with chroot_no_attach"));
 
448
 
 
449
                $$ = $1;
 
450
        };
 
451
 
 
452
flagvals:       flagval
 
453
        {
 
454
                $$ = $1;
 
455
        };
 
456
 
 
457
flagval:        TOK_VALUE
 
458
        {
 
459
                struct flagval fv = { 0, 0, 0, 0 };
 
460
                if (strcmp($1, "debug") == 0) {
 
461
                        yyerror(_("Profile flag 'debug' is no longer valid."));
 
462
                } else if (strcmp($1, "complain") == 0) {
 
463
                        fv.complain = 1;
 
464
                } else if (strcmp($1, "audit") == 0) {
 
465
                        fv.audit = 1;
 
466
                } else if (strcmp($1, "chroot_relative") == 0) {
 
467
                        fv.path |= PATH_CHROOT_REL;
 
468
                } else if (strcmp($1, "namespace_relative") == 0) {
 
469
                        fv.path |= PATH_NS_REL;
 
470
                } else if (strcmp($1, "mediate_deleted") == 0) {
 
471
                        fv.path |= PATH_MEDIATE_DELETED;
 
472
                } else if (strcmp($1, "delegate_deleted") == 0) {
 
473
                        fv.path |= PATH_DELEGATE_DELETED;
 
474
                } else if (strcmp($1, "attach_disconnected") == 0) {
 
475
                        fv.path |= PATH_ATTACH;
 
476
                } else if (strcmp($1, "no_attach_disconnected") == 0) {
 
477
                        fv.path |= PATH_NO_ATTACH;
 
478
                } else if (strcmp($1, "chroot_attach") == 0) {
 
479
                        fv.path |= PATH_CHROOT_NSATTACH;
 
480
                } else if (strcmp($1, "chroot_no_attach") == 0) {
 
481
                        fv.path |= PATH_CHROOT_NO_ATTACH;
 
482
                } else {
 
483
                        yyerror(_("Invalid profile flag: %s."), $1);
 
484
                }
 
485
                free($1);
 
486
                $$ = fv;
 
487
        };
 
488
 
 
489
opt_subset_flag: { /* nothing */ $$ = 0; }
 
490
        | TOK_SUBSET { $$ = 1; }
 
491
        | TOK_LE { $$ = 1; }
 
492
 
 
493
opt_audit_flag: { /* nothing */ $$ = 0; }
 
494
        | TOK_AUDIT { $$ = 1; };
 
495
 
 
496
opt_owner_flag: { /* nothing */ $$ = 0; }
 
497
        | TOK_OWNER { $$ = 1; };
 
498
        | TOK_OTHER { $$ = 2; };
 
499
 
 
500
rules:  { /* nothing */ 
 
501
                struct codomain *cod = NULL;
 
502
                cod = (struct codomain *) calloc(1, sizeof(struct codomain));
 
503
                if (!cod) {
 
504
                        yyerror(_("Memory allocation error."));
 
505
                }
 
506
 
 
507
                $$ = cod;
 
508
        };
 
509
 
 
510
/*  can't fold TOK_DENY in as opt_deny_flag as it messes up the generated
 
511
 * parser, even though it shouldn't
 
512
 */
 
513
rules:  rules opt_audit_flag TOK_DENY opt_owner_flag rule
 
514
        {
 
515
                PDEBUG("matched: rules rule\n");
 
516
                PDEBUG("rules rule: (%s)\n", $5->name);
 
517
                if (!$5)
 
518
                        yyerror(_("Assert: `rule' returned NULL."));
 
519
                $5->deny = 1;
 
520
                if (($5->mode & AA_EXEC_BITS) && ($5->mode & ALL_AA_EXEC_TYPE))
 
521
                        yyerror(_("Invalid mode, in deny rules 'x' must not be preceded by exec qualifier 'i', 'p', or 'u'"));
 
522
 
 
523
                if ($4 == 1)
 
524
                        $5->mode &= (AA_USER_PERMS | AA_SHARED_PERMS | AA_USER_PTRACE);
 
525
                else if ($4 == 2)
 
526
                        $5->mode &= (AA_OTHER_PERMS | AA_SHARED_PERMS | AA_OTHER_PTRACE);
 
527
                /* only set audit ctl quieting if the rule is not audited */
 
528
                if (!$2)
 
529
                        $5->audit = $5->mode & ~ALL_AA_EXEC_TYPE;
 
530
 
 
531
                add_entry_to_policy($1, $5);
 
532
                $$ = $1;
 
533
        };
 
534
 
 
535
rules:  rules opt_audit_flag opt_owner_flag rule
 
536
        {
 
537
                PDEBUG("matched: rules rule\n");
 
538
                PDEBUG("rules rule: (%s)\n", $4->name);
 
539
                if (!$4)
 
540
                        yyerror(_("Assert: `rule' returned NULL."));
 
541
                if (($4->mode & AA_EXEC_BITS) &&
 
542
                    !($4->mode & ALL_AA_EXEC_TYPE) &&
 
543
                    !($4->nt_name))
 
544
                        yyerror(_("Invalid mode, 'x' must be preceded by exec qualifier 'i', 'p', 'c', or 'u'"));
 
545
 
 
546
                if ($3 == 1)
 
547
                        $4->mode &= (AA_USER_PERMS | AA_SHARED_PERMS | AA_USER_PTRACE);
 
548
                else if ($3 == 2)
 
549
                        $4->mode &= (AA_OTHER_PERMS | AA_SHARED_PERMS | AA_OTHER_PTRACE);
 
550
                if ($2)
 
551
                        $4->audit = $4->mode & ~ALL_AA_EXEC_TYPE;
 
552
 
 
553
                add_entry_to_policy($1, $4);
 
554
                $$ = $1;
 
555
        };
 
556
 
 
557
rules: rules opt_audit_flag opt_owner_flag TOK_OPEN rules TOK_CLOSE
 
558
        {
 
559
                struct cod_entry *entry, *tmp;
 
560
                PDEBUG("matched: audit block\n");
 
561
                list_for_each_safe($5->entries, entry, tmp) {
 
562
                        entry->next = NULL;
 
563
                        if (entry->mode & AA_EXEC_BITS) {
 
564
                                if (entry->deny &&
 
565
                                    (entry->mode & ALL_AA_EXEC_TYPE))
 
566
                                        yyerror(_("Invalid mode, in deny rules 'x' must not be preceded by exec qualifier 'i', 'p', or 'u'"));
 
567
                                else if (!entry->deny &&
 
568
                                         !(entry->mode & ALL_AA_EXEC_TYPE))
 
569
                                        yyerror(_("Invalid mode, 'x' must be preceded by exec qualifier 'i', 'p', or 'u'"));
 
570
                        }
 
571
                        if ($3 == 1)
 
572
                                entry->mode &= (AA_USER_PERMS | AA_SHARED_PERMS | AA_USER_PTRACE);
 
573
                        else if ($3 == 2)
 
574
                                entry->mode &= (AA_OTHER_PERMS | AA_SHARED_PERMS | AA_OTHER_PTRACE);
 
575
 
 
576
                        if ($2 && !entry->deny)
 
577
                                entry->audit = entry->mode & ~ALL_AA_EXEC_TYPE;
 
578
                        else if (!$2 && entry->deny)
 
579
                                 entry->audit = entry->mode & ~ALL_AA_EXEC_TYPE;
 
580
                        add_entry_to_policy($1, entry);
 
581
                }
 
582
                $5->entries = NULL;
 
583
                // fix me transfer rules and free sub codomain
 
584
                free_policy($5);
 
585
                $$ = $1;
 
586
        };
 
587
 
 
588
rules: rules opt_audit_flag TOK_DENY network_rule
 
589
        {
 
590
                struct aa_network_entry *entry, *tmp;
 
591
 
 
592
                PDEBUG("Matched: network rule\n");
 
593
                if (!$4)
 
594
                        yyerror(_("Assert: `network_rule' return invalid protocol."));
 
595
                if (!$1->network_allowed) {
 
596
                        $1->network_allowed = calloc(get_af_max(),
 
597
                                                     sizeof(unsigned int));
 
598
                        $1->audit_network = calloc(get_af_max(),
 
599
                                                   sizeof(unsigned int));
 
600
                        $1->deny_network = calloc(get_af_max(),
 
601
                                                     sizeof(unsigned int));
 
602
                        $1->quiet_network = calloc(get_af_max(),
 
603
                                                     sizeof(unsigned int));
 
604
                        if (!$1->network_allowed || !$1->audit_network ||
 
605
                            !$1->deny_network || !$1->quiet_network)
 
606
                                yyerror(_("Memory allocation error."));
 
607
                }
 
608
                list_for_each_safe($4, entry, tmp) {
 
609
                        if (entry->type > SOCK_PACKET) {
 
610
                                /* setting mask instead of a bit */
 
611
                                $1->deny_network[entry->family] |= entry->type;
 
612
                                if (!$2)
 
613
                                        $1->quiet_network[entry->family] |= entry->type;
 
614
 
 
615
                        } else {
 
616
                                $1->deny_network[entry->family] |= 1 << entry->type;
 
617
                                if (!$2)
 
618
                                        $1->quiet_network[entry->family] |= 1 << entry->type;
 
619
                        }
 
620
                        free(entry);
 
621
                }
 
622
 
 
623
                $$ = $1;
 
624
        }
 
625
 
 
626
rules: rules opt_audit_flag network_rule
 
627
        {
 
628
                struct aa_network_entry *entry, *tmp;
 
629
 
 
630
                PDEBUG("Matched: network rule\n");
 
631
                if (!$3)
 
632
                        yyerror(_("Assert: `network_rule' return invalid protocol."));
 
633
                if (!$1->network_allowed) {
 
634
                        $1->network_allowed = calloc(get_af_max(),
 
635
                                                     sizeof(unsigned int));
 
636
                        $1->audit_network = calloc(get_af_max(),
 
637
                                                   sizeof(unsigned int));
 
638
                        $1->deny_network = calloc(get_af_max(),
 
639
                                                     sizeof(unsigned int));
 
640
                        $1->quiet_network = calloc(get_af_max(),
 
641
                                                     sizeof(unsigned int));
 
642
                        if (!$1->network_allowed || !$1->audit_network ||
 
643
                            !$1->deny_network || !$1->quiet_network)
 
644
                                yyerror(_("Memory allocation error."));
 
645
                }
 
646
                list_for_each_safe($3, entry, tmp) {
 
647
                        if (entry->type > SOCK_PACKET) {
 
648
                                /* setting mask instead of a bit */
 
649
                                $1->network_allowed[entry->family] |= entry->type;
 
650
                                if ($2)
 
651
                                        $1->audit_network[entry->family] |= entry->type;
 
652
 
 
653
                        } else {
 
654
                                $1->network_allowed[entry->family] |= 1 << entry->type;
 
655
                                if ($2)
 
656
                                        $1->audit_network[entry->family] |= 1 << entry->type;
 
657
                        }
 
658
                        free(entry);
 
659
                }
 
660
 
 
661
                $$ = $1;
 
662
        }
 
663
 
 
664
rules:  rules opt_audit_flag TOK_DENY mnt_rule
 
665
        {
 
666
                $4->deny = $4->allow;
 
667
                if ($2)
 
668
                        $4->audit = $4->allow;
 
669
                $4->next = $1->mnt_ents;
 
670
                $1->mnt_ents = $4;
 
671
                $$ = $1;
 
672
        }
 
673
 
 
674
rules: rules opt_audit_flag mnt_rule
 
675
        {
 
676
                if ($2)
 
677
                        $3->audit = $3->allow;
 
678
                $3->next = $1->mnt_ents;
 
679
                $1->mnt_ents = $3;
 
680
                $$ = $1;
 
681
        }
 
682
 
 
683
rules:  rules change_profile
 
684
        {
 
685
                PDEBUG("matched: rules change_profile\n");
 
686
                PDEBUG("rules change_profile: (%s)\n", $2->name);
 
687
                if (!$2)
 
688
                        yyerror(_("Assert: `change_profile' returned NULL."));
 
689
                add_entry_to_policy($1, $2);
 
690
                $$ = $1;
 
691
        };
 
692
 
 
693
rules:  rules opt_audit_flag TOK_DENY capability
 
694
        {
 
695
                $1->deny_caps |= $4;
 
696
                if (!$2)
 
697
                        $1->quiet_caps |= $4;
 
698
                $$ = $1;
 
699
        };
 
700
 
 
701
rules:  rules opt_audit_flag capability
 
702
        {
 
703
                $1->capabilities |= $3;
 
704
                if ($2)
 
705
                        $1->audit_caps |= $3;
 
706
                $$ = $1;
 
707
        };
 
708
 
 
709
rules:  rules hat
 
710
        {
 
711
                PDEBUG("Matched: hat rule\n");
 
712
                if (!$2)
 
713
                        yyerror(_("Assert: 'hat rule' returned NULL."));
 
714
                add_hat_to_policy($1, $2);
 
715
                $$ = $1;
 
716
        };
 
717
 
 
718
rules:  rules local_profile
 
719
        {
 
720
                PDEBUG("Matched: hat rule\n");
 
721
                if (!$2)
 
722
                        yyerror(_("Assert: 'local_profile rule' returned NULL."));
 
723
                add_hat_to_policy($1, $2);
 
724
                add_local_entry($2);
 
725
                $$ = $1;
 
726
        };
 
727
 
 
728
rules:  rules cond_rule
 
729
        {
 
730
                PDEBUG("Matched: conditional rules\n");
 
731
                $$ = merge_policy($1, $2);
 
732
        }
 
733
 
 
734
rules: rules TOK_SET TOK_RLIMIT TOK_ID TOK_LE TOK_VALUE TOK_END_OF_RULE
 
735
        {
 
736
                rlim_t value = RLIM_INFINITY;
 
737
                long long tmp;
 
738
                char *end;
 
739
 
 
740
                int limit = get_rlimit($4);
 
741
                if (limit == -1)
 
742
                        yyerror("INVALID RLIMIT '%s'\n", $4);
 
743
 
 
744
                if (strcmp($6, "infinity") == 0) {
 
745
                        value = RLIM_INFINITY;
 
746
                } else {
 
747
                        const char *seconds = "seconds";
 
748
                        const char *minutes = "minutes";
 
749
                        const char *hours = "hours";
 
750
                        const char *days = "days";
 
751
                        const char *kb = "KB";
 
752
                        const char *mb = "MB";
 
753
                        const char *gb = "GB";
 
754
 
 
755
                        tmp = strtoll($6, &end, 0);
 
756
                        switch (limit) {
 
757
                        case RLIMIT_CPU:
 
758
                                if (!end || $6 == end || tmp < 0)
 
759
                                        yyerror("RLIMIT '%s' invalid value %s\n", $4, $6);
 
760
                                if (*end == '\0' ||
 
761
                                    strstr(seconds, end) == seconds) {
 
762
                                        value = tmp;
 
763
                                } else if (strstr(minutes, end) == minutes) {
 
764
                                        value = tmp * 60;
 
765
                                } else if (strstr(hours, end) == hours) {
 
766
                                        value = tmp * 60 * 60;
 
767
                                } else if (strstr(days, end) == days) {
 
768
                                        value = tmp * 60 * 60 * 24;
 
769
                                } else {
 
770
                                        yyerror("RLIMIT '%s' invalid value %s\n", $4, $6);
 
771
                                }
 
772
                                break;
 
773
                        case RLIMIT_NOFILE:
 
774
                        case RLIMIT_NPROC:
 
775
                        case RLIMIT_LOCKS:
 
776
                        case RLIMIT_SIGPENDING:
 
777
#ifdef RLIMIT_RTPRIO
 
778
                        case RLIMIT_RTPRIO:
 
779
                                if (!end || $6 == end || *end != '\0' || tmp < 0)
 
780
                                        yyerror("RLIMIT '%s' invalid value %s\n", $4, $6);
 
781
                                value = tmp;
 
782
                                break;
 
783
#endif
 
784
#ifdef RLIMIT_NICE
 
785
                        case RLIMIT_NICE:
 
786
                                if (!end || $6 == end || *end != '\0')
 
787
                                        yyerror("RLIMIT '%s' invalid value %s\n", $4, $6);
 
788
                                if (tmp < -20 || tmp > 19)
 
789
                                        yyerror("RLIMIT '%s' out of range (-20 .. 19) %d\n", $4, tmp);
 
790
                                value = tmp + 20;
 
791
                                break;
 
792
#endif
 
793
                        case RLIMIT_FSIZE:
 
794
                        case RLIMIT_DATA:
 
795
                        case RLIMIT_STACK:
 
796
                        case RLIMIT_CORE:
 
797
                        case RLIMIT_RSS:
 
798
                        case RLIMIT_AS:
 
799
                        case RLIMIT_MEMLOCK:
 
800
                        case RLIMIT_MSGQUEUE:
 
801
                                if ($6 == end || tmp < 0)
 
802
                                        yyerror("RLIMIT '%s' invalid value %s\n", $4, $6);
 
803
                                if (strstr(kb, end) == kb) {
 
804
                                        tmp *= 1024;
 
805
                                } else if (strstr(mb, end) == mb) {
 
806
                                        tmp *= 1024*1024;
 
807
                                } else if (strstr(gb, end) == gb) {
 
808
                                        tmp *= 1024*1024*1024;
 
809
                                } else if (*end != '\0') {
 
810
                                        yyerror("RLIMIT '%s' invalid value %s\n", $4, $6);
 
811
                                }
 
812
                                value = tmp;
 
813
                                break;
 
814
                        default:
 
815
                                yyerror("Unknown RLIMIT %d\n", $4);
 
816
                        }
 
817
                }
 
818
                $1->rlimits.specified |= 1 << limit;
 
819
                $1->rlimits.limits[limit] = value;
 
820
                free($4);
 
821
                free($6);
 
822
                $$ = $1;
 
823
        };
 
824
 
 
825
 
 
826
cond_rule: TOK_IF expr TOK_OPEN rules TOK_CLOSE
 
827
        {
 
828
                struct codomain *ret = NULL;
 
829
                PDEBUG("Matched: found conditional rules\n");
 
830
                if ($2) {
 
831
                        ret = $4;
 
832
                } else {
 
833
                        free_policy($4);
 
834
                }
 
835
                $$ = ret;
 
836
        }
 
837
 
 
838
cond_rule: TOK_IF expr TOK_OPEN rules TOK_CLOSE TOK_ELSE TOK_OPEN rules TOK_CLOSE
 
839
        {
 
840
                struct codomain *ret = NULL;
 
841
                PDEBUG("Matched: found conditional else rules\n");
 
842
                if ($2) {
 
843
                        ret = $4;
 
844
                        free_policy($8);
 
845
                } else {
 
846
                        ret = $8;
 
847
                        free_policy($4);
 
848
                }
 
849
                $$ = ret;
 
850
        }
 
851
 
 
852
cond_rule: TOK_IF expr TOK_OPEN rules TOK_CLOSE TOK_ELSE cond_rule
 
853
        {
 
854
                struct codomain *ret = NULL;
 
855
                PDEBUG("Matched: found conditional else-if rules\n");
 
856
                if ($2) {
 
857
                        ret = $4;
 
858
                        free_policy($7);
 
859
                } else {
 
860
                        ret = $7;
 
861
                        free_policy($4);
 
862
                }
 
863
                $$ = ret;
 
864
        }
 
865
 
 
866
expr:   TOK_NOT expr
 
867
        {
 
868
                $$ = !$2;
 
869
        }
 
870
 
 
871
expr:   TOK_BOOL_VAR
 
872
        {
 
873
                char *var_name = process_var($1);
 
874
                int boolean  = get_boolean_var(var_name);
 
875
                PDEBUG("Matched: boolean expr %s value: %d\n", $1, boolean);
 
876
                if (boolean < 0) {
 
877
                        /* FIXME check for set var */
 
878
                        yyerror(_("Unset boolean variable %s used in if-expression"),
 
879
                                $1);
 
880
                }
 
881
                $$ = boolean;
 
882
                free(var_name);
 
883
                free($1);
 
884
        }
 
885
 
 
886
expr:   TOK_DEFINED TOK_SET_VAR
 
887
        {
 
888
                char *var_name = process_var($2);
 
889
                void *set_value = get_set_var(var_name);
 
890
                PDEBUG("Matched: defined set expr %s value %lx\n", $2, (long) set_value);
 
891
                $$ = !! (long) set_value;
 
892
                free(var_name);
 
893
                free($2);
 
894
        }
 
895
 
 
896
expr:   TOK_DEFINED TOK_BOOL_VAR
 
897
        {
 
898
                char *var_name = process_var($2);
 
899
                int boolean = get_boolean_var(var_name);
 
900
                PDEBUG("Matched: defined set expr %s value %d\n", $2, boolean);
 
901
                $$ = (boolean != -1);
 
902
                free(var_name);
 
903
                free($2);
 
904
        }
 
905
 
 
906
id_or_var: TOK_ID { $$ = $1; }
 
907
id_or_var: TOK_SET_VAR { $$ = $1; };
 
908
 
 
909
opt_named_transition:
 
910
        { /* nothing */
 
911
                $$.present = 0;
 
912
                $$.namespace = NULL;
 
913
                $$.name = NULL;
 
914
        }
 
915
        | TOK_ARROW id_or_var
 
916
        {
 
917
                $$.present = 1;
 
918
                $$.namespace = NULL;
 
919
                $$.name = $2;
 
920
        }
 
921
        | TOK_ARROW TOK_COLON id_or_var TOK_COLON id_or_var
 
922
        {
 
923
                $$.present = 1;
 
924
                $$.namespace = $3;
 
925
                $$.name = $5;
 
926
        };
 
927
 
 
928
rule: file_rule { $$ = $1; }
 
929
        | link_rule { $$ = $1; }
 
930
        | ptrace_rule {$$ = $1; }
 
931
 
 
932
opt_unsafe: { /* nothing */ $$ = 0; }
 
933
        | TOK_UNSAFE { $$ = 1; };
 
934
        | TOK_SAFE { $$ = 2; };
 
935
 
 
936
opt_file: { /* nothing */ $$ = 0; }
 
937
        | TOK_FILE { $$ = 1; }
 
938
 
 
939
frule:  id_or_var file_mode opt_named_transition TOK_END_OF_RULE
 
940
        {
 
941
                $$ = do_file_rule($3.namespace, $1, $2, NULL, $3.name);
 
942
        };
 
943
 
 
944
frule:  file_mode opt_subset_flag id_or_var opt_named_transition TOK_END_OF_RULE
 
945
        {
 
946
                if ($2 && ($1 & ~AA_LINK_BITS))
 
947
                        yyerror(_("subset can only be used with link rules."));
 
948
                if ($4.present && ($1 & AA_LINK_BITS) && ($1 & AA_EXEC_BITS))
 
949
                        yyerror(_("link and exec perms conflict on a file rule using ->"));
 
950
                if ($4.present && $4.namespace && ($1 & AA_LINK_BITS))
 
951
                        yyerror(_("link perms are not allowed on a named profile transition.\n"));
 
952
                if (($1 & AA_LINK_BITS)) {
 
953
                        $$ = do_file_rule(NULL, $3, $1, $4.name, NULL);
 
954
                        $$->subset = $2;
 
955
 
 
956
                } else {
 
957
                        $$ = do_file_rule($4.namespace, $3, $1, NULL, $4.name);
 
958
                }
 
959
        };
 
960
 
 
961
file_rule: TOK_FILE TOK_END_OF_RULE
 
962
        {
 
963
                char *path = strdup("/{**,}");
 
964
                int perms = ((AA_BASE_PERMS & ~AA_EXEC_TYPE) |
 
965
                             (AA_EXEC_INHERIT | AA_MAY_EXEC));
 
966
                /* duplicate to other permission set */
 
967
                perms |= perms << AA_OTHER_SHIFT;
 
968
                if (!path)
 
969
                        yyerror(_("Memory allocation error."));
 
970
                $$ = do_file_rule(NULL, path, perms, NULL, NULL);
 
971
        }
 
972
        | opt_file file_rule_tail { $$ = $2; }
 
973
 
 
974
 
 
975
file_rule_tail: opt_unsafe frule
 
976
        {
 
977
                if ($1) {
 
978
                        if (!($2->mode & AA_EXEC_BITS))
 
979
                                yyerror(_("unsafe rule missing exec permissions"));
 
980
                        if ($1 == 1) {
 
981
                                $2->mode |= (($2->mode & AA_EXEC_BITS) << 8) &
 
982
                                         ALL_AA_EXEC_UNSAFE;
 
983
                        }
 
984
                        else if ($1 == 2)
 
985
                                $2->mode &= ~ALL_AA_EXEC_UNSAFE;
 
986
                }
 
987
                $$ = $2;
 
988
        };
 
989
 
 
990
file_rule_tail: opt_unsafe id_or_var file_mode id_or_var
 
991
        {
 
992
                /* Oopsie, we appear to be missing an EOL marker. If we
 
993
                 * were *smart*, we could work around it. Since we're
 
994
                 * obviously not smart, we'll just punt with a more
 
995
                 * sensible error. */
 
996
                yyerror(_("missing an end of line character? (entry: %s)"), $2);
 
997
        };
 
998
 
 
999
link_rule: TOK_LINK opt_subset_flag TOK_ID TOK_ARROW TOK_ID TOK_END_OF_RULE
 
1000
        {
 
1001
                struct cod_entry *entry;
 
1002
                PDEBUG("Matched: link tok_id (%s) -> (%s)\n", $3, $5);
 
1003
                entry = new_entry(NULL, $3, AA_LINK_BITS, $5);
 
1004
                entry->subset = $2;
 
1005
                PDEBUG("rule.entry: link (%s)\n", entry->name);
 
1006
                $$ = entry;
 
1007
        };
 
1008
 
 
1009
ptrace_rule: TOK_PTRACE TOK_ID TOK_END_OF_RULE
 
1010
        {
 
1011
                struct cod_entry *entry;
 
1012
                entry = new_entry(NULL, $2, AA_USER_PTRACE | AA_OTHER_PTRACE, NULL);
 
1013
                if (!entry)
 
1014
                        yyerror(_("Memory allocation error."));
 
1015
                $$ = entry;
 
1016
        };
 
1017
 
 
1018
ptrace_rule: TOK_PTRACE TOK_COLON TOK_ID TOK_COLON TOK_ID TOK_END_OF_RULE
 
1019
        {
 
1020
                struct cod_entry *entry;
 
1021
                entry = new_entry($3, $5, AA_USER_PTRACE | AA_OTHER_PTRACE, NULL);
 
1022
                if (!entry)
 
1023
                        yyerror(_("Memory allocation error."));
 
1024
                $$ = entry;
 
1025
        };
 
1026
 
 
1027
network_rule: TOK_NETWORK TOK_END_OF_RULE
 
1028
        {
 
1029
                size_t family;
 
1030
                struct aa_network_entry *new_entry, *entry = NULL;
 
1031
                for (family = AF_UNSPEC; family < get_af_max(); family++) {
 
1032
                        new_entry = new_network_ent(family, 0xffffffff,
 
1033
                                                    0xffffffff);
 
1034
                        if (!new_entry)
 
1035
                                yyerror(_("Memory allocation error."));
 
1036
                        new_entry->next = entry;
 
1037
                        entry = new_entry;
 
1038
                }
 
1039
                $$ = entry;
 
1040
        }
 
1041
 
 
1042
network_rule: TOK_NETWORK TOK_ID TOK_END_OF_RULE
 
1043
        {
 
1044
                struct aa_network_entry *entry;
 
1045
                entry = network_entry($2, NULL, NULL);
 
1046
                if (!entry)
 
1047
                        /* test for short circuiting of family */
 
1048
                        entry = network_entry(NULL, $2, NULL);
 
1049
                if (!entry)
 
1050
                        yyerror(_("Invalid network entry."));
 
1051
                free($2);
 
1052
                $$ = entry;
 
1053
        }
 
1054
 
 
1055
network_rule: TOK_NETWORK TOK_ID TOK_ID TOK_END_OF_RULE
 
1056
        {
 
1057
                struct aa_network_entry *entry;
 
1058
                entry = network_entry($2, $3, NULL);
 
1059
                if (!entry)
 
1060
                        yyerror(_("Invalid network entry."));
 
1061
                free($2);
 
1062
                free($3);
 
1063
                $$ = entry;
 
1064
        }
 
1065
 
 
1066
cond: TOK_CONDID TOK_EQUALS TOK_VALUE
 
1067
        {
 
1068
                struct cond_entry *ent;
 
1069
                struct value_list *value = new_value_list($3);
 
1070
                if (!value)
 
1071
                        yyerror(_("Memory allocation error."));
 
1072
                ent = new_cond_entry($1, 1, value);
 
1073
                if (!ent) {
 
1074
                        free_value_list(value);
 
1075
                        yyerror(_("Memory allocation error."));
 
1076
                }
 
1077
                $$ = ent;
 
1078
        }
 
1079
 
 
1080
cond: TOK_CONDID TOK_EQUALS TOK_OPENPAREN valuelist TOK_CLOSEPAREN
 
1081
        {
 
1082
                struct cond_entry *ent = new_cond_entry($1, 1, $4);
 
1083
 
 
1084
                if (!ent)
 
1085
                        yyerror(_("Memory allocation error."));
 
1086
                $$ = ent;
 
1087
        }
 
1088
 
 
1089
 
 
1090
cond: TOK_CONDID TOK_IN TOK_OPENPAREN valuelist TOK_CLOSEPAREN
 
1091
        {
 
1092
                struct cond_entry *ent = new_cond_entry($1, 0, $4);
 
1093
 
 
1094
                if (!ent)
 
1095
                        yyerror(_("Memory allocation error."));
 
1096
                $$ = ent;
 
1097
        }
 
1098
 
 
1099
opt_conds: { /* nothing */ $$ = NULL; }
 
1100
        | opt_conds cond
 
1101
        {
 
1102
                $2->next = $1;
 
1103
                $$ = $2;
 
1104
        }
 
1105
 
 
1106
mnt_rule: TOK_MOUNT opt_conds opt_id TOK_END_OF_RULE
 
1107
        {
 
1108
                $$ = do_mnt_rule($2, $3, NULL, NULL, AA_MAY_MOUNT);
 
1109
        }
 
1110
 
 
1111
mnt_rule: TOK_MOUNT opt_conds opt_id TOK_ARROW opt_conds TOK_ID TOK_END_OF_RULE
 
1112
        {
 
1113
                $$ = do_mnt_rule($2, $3, $5, $6, AA_MAY_MOUNT);
 
1114
        }
 
1115
 
 
1116
mnt_rule: TOK_REMOUNT opt_conds opt_id TOK_END_OF_RULE
 
1117
        {
 
1118
                $$ = do_mnt_rule($2, NULL, NULL, $3, AA_DUMMY_REMOUNT);
 
1119
        }
 
1120
 
 
1121
mnt_rule: TOK_UMOUNT opt_conds opt_id TOK_END_OF_RULE
 
1122
        {
 
1123
                $$ = do_mnt_rule($2, NULL, NULL, $3, AA_MAY_UMOUNT);
 
1124
        }
 
1125
 
 
1126
mnt_rule: TOK_PIVOTROOT opt_conds opt_id opt_named_transition TOK_END_OF_RULE
 
1127
        {
 
1128
                char *name = NULL;
 
1129
                if ($4.present && $4.namespace) {
 
1130
                        name = malloc(strlen($4.namespace) +
 
1131
                                      strlen($4.name) + 3);
 
1132
                        if (!name) {
 
1133
                                PERROR("Memory allocation error\n");
 
1134
                                exit(1);
 
1135
                        }
 
1136
                        sprintf(name, ":%s:%s", $4.namespace, $4.name);
 
1137
                        free($4.namespace);
 
1138
                        free($4.name);
 
1139
                } else if ($4.present)
 
1140
                        name = $4.name;
 
1141
 
 
1142
                $$ = do_pivot_rule($2, $3, name);
 
1143
        }
 
1144
 
 
1145
hat_start: TOK_CARET {}
 
1146
        | TOK_HAT {}
 
1147
 
 
1148
file_mode: TOK_MODE
 
1149
        {
 
1150
                /* A single TOK_MODE maps to the same permission in all
 
1151
                 * of user::other */
 
1152
                $$ = parse_mode($1);
 
1153
                free($1);
 
1154
        }
 
1155
 
 
1156
change_profile: TOK_CHANGE_PROFILE TOK_ARROW TOK_ID TOK_END_OF_RULE
 
1157
        {
 
1158
                struct cod_entry *entry;
 
1159
                PDEBUG("Matched change_profile: tok_id (%s)\n", $3);
 
1160
                entry = new_entry(NULL, $3, AA_CHANGE_PROFILE, NULL);
 
1161
                if (!entry)
 
1162
                        yyerror(_("Memory allocation error."));
 
1163
                PDEBUG("change_profile.entry: (%s)\n", entry->name);
 
1164
                $$ = entry;
 
1165
        };
 
1166
 
 
1167
change_profile: TOK_CHANGE_PROFILE TOK_ARROW TOK_COLON TOK_ID TOK_COLON TOK_ID TOK_END_OF_RULE
 
1168
        {
 
1169
                struct cod_entry *entry;
 
1170
                PDEBUG("Matched change_profile: tok_id (%s:%s)\n", $4, $6);
 
1171
                entry = new_entry($4, $6, AA_CHANGE_PROFILE, NULL);
 
1172
                if (!entry)
 
1173
                        yyerror(_("Memory allocation error."));
 
1174
                PDEBUG("change_profile.entry: (%s)\n", entry->name);
 
1175
                $$ = entry;
 
1176
        };
 
1177
 
 
1178
 
 
1179
capability:     TOK_CAPABILITY caps TOK_END_OF_RULE
 
1180
        {
 
1181
                if ($2 == 0) {
 
1182
                        /* bare capability keyword - set all caps */
 
1183
                        $$ = 0xffffffffffffffff;
 
1184
                } else
 
1185
                        $$ = $2;
 
1186
        };
 
1187
 
 
1188
caps: { /* nothing */ $$ = 0; }
 
1189
        | caps TOK_ID
 
1190
        {
 
1191
                int cap = name_to_capability($2);
 
1192
                if (cap == -1)
 
1193
                        yyerror(_("Invalid capability %s."), $2);
 
1194
                free($2);
 
1195
                $$ = $1 | CAP_TO_MASK(cap);
 
1196
        }
 
1197
 
 
1198
%%
 
1199
#define MAXBUFSIZE 4096
 
1200
 
 
1201
void vprintyyerror(const char *msg, va_list argptr)
 
1202
{
 
1203
        char buf[MAXBUFSIZE];
 
1204
 
 
1205
        vsnprintf(buf, sizeof(buf), msg, argptr);
 
1206
 
 
1207
        if (profilename) {
 
1208
                PERROR(_("AppArmor parser error for %s%s%s at line %d: %s\n"),
 
1209
                       profilename,
 
1210
                       current_filename ? " in " : "",
 
1211
                       current_filename ? current_filename : "",
 
1212
                       current_lineno, buf);
 
1213
        } else {
 
1214
                PERROR(_("AppArmor parser error,%s%s line %d: %s\n"),
 
1215
                       current_filename ? " in " : "",
 
1216
                       current_filename ? current_filename : "",
 
1217
                       current_lineno, buf);
 
1218
        }
 
1219
}
 
1220
 
 
1221
void printyyerror(const char *msg, ...)
 
1222
{
 
1223
        va_list arg;
 
1224
 
 
1225
        va_start(arg, msg);
 
1226
        vprintyyerror(msg, arg);
 
1227
        va_end(arg);
 
1228
}
 
1229
 
 
1230
void yyerror(const char *msg, ...)
 
1231
{
 
1232
        va_list arg;
 
1233
 
 
1234
        va_start(arg, msg);
 
1235
        vprintyyerror(msg, arg);
 
1236
        va_end(arg);
 
1237
 
 
1238
        exit(1);
 
1239
}
 
1240
 
 
1241
struct cod_entry *do_file_rule(char *namespace, char *id, int mode,
 
1242
                               char *link_id, char *nt)
 
1243
{
 
1244
                struct cod_entry *entry;
 
1245
                PDEBUG("Matched: tok_id (%s) tok_mode (0x%x)\n", id, mode);
 
1246
                entry = new_entry(namespace, id, mode, link_id);
 
1247
                if (!entry)
 
1248
                        yyerror(_("Memory allocation error."));
 
1249
                entry->nt_name = nt;
 
1250
                PDEBUG("rule.entry: (%s)\n", entry->name);
 
1251
                return entry;
 
1252
}
 
1253
 
 
1254
/* Note: NOT currently in use, used for 
 
1255
 * /foo x -> { /bah, }   style transitions
 
1256
 */
 
1257
void add_local_entry(struct codomain *cod)
 
1258
{
 
1259
        /* ugh this has to be called after the hat is attached to its parent */
 
1260
        if (cod->local_mode) {
 
1261
                struct cod_entry *entry;
 
1262
                char *trans = malloc(strlen(cod->parent->name) +
 
1263
                                    strlen(cod->name) + 3);
 
1264
                char *name = strdup(cod->name);
 
1265
                if (!trans)
 
1266
                        yyerror(_("Memory allocation error."));
 
1267
                sprintf(name, "%s//%s", cod->parent->name, cod->name);
 
1268
 
 
1269
                entry = new_entry(NULL, name, cod->local_mode, NULL);
 
1270
                entry->audit = cod->local_audit;
 
1271
                entry->nt_name = trans;
 
1272
                if (!entry)
 
1273
                        yyerror(_("Memory allocation error."));
 
1274
 
 
1275
                add_entry_to_policy(cod, entry);
 
1276
        }
 
1277
}
 
1278
 
 
1279
static char *mnt_cond_msg[] = {"",
 
1280
                         " not allowed as source conditional",
 
1281
                         " not allowed as target conditional",
 
1282
                         "",
 
1283
                         NULL};
 
1284
 
 
1285
int verify_mnt_conds(struct cond_entry *conds, int src)
 
1286
{
 
1287
        struct cond_entry *entry;
 
1288
        int error = 0;
 
1289
 
 
1290
        if (!conds)
 
1291
                return 0;
 
1292
 
 
1293
        list_for_each(conds, entry) {
 
1294
                int res = is_valid_mnt_cond(entry->name, src);
 
1295
                if (res <= 0) {
 
1296
                                printyyerror(_("invalid mount conditional %s%s"),
 
1297
                                             entry->name,
 
1298
                                             res == -1 ? "" : mnt_cond_msg[src]);
 
1299
                                error++;
 
1300
                }
 
1301
        }
 
1302
 
 
1303
        return error;
 
1304
}
 
1305
 
 
1306
struct mnt_entry *do_mnt_rule(struct cond_entry *src_conds, char *src,
 
1307
                              struct cond_entry *dst_conds, char *dst,
 
1308
                              int mode)
 
1309
{
 
1310
        struct mnt_entry *ent;
 
1311
 
 
1312
        if (verify_mnt_conds(src_conds, MNT_SRC_OPT) != 0)
 
1313
                yyerror(_("bad mount rule"));
 
1314
 
 
1315
        /* FIXME: atm conditions are not supported on dst
 
1316
        if (verify_conds(dst_conds, DST_OPT) != 0)
 
1317
                yyerror(_("bad mount rule"));
 
1318
        */
 
1319
        if (dst_conds)
 
1320
                yyerror(_("mount point conditions not currently supported"));
 
1321
 
 
1322
        ent = new_mnt_entry(src_conds, src, dst_conds, dst, mode);
 
1323
        if (!ent) {
 
1324
                yyerror(_("Memory allocation error."));
 
1325
        }
 
1326
 
 
1327
        return ent;
 
1328
}
 
1329
 
 
1330
struct mnt_entry *do_pivot_rule(struct cond_entry *old, char *root,
 
1331
                                char *transition)
 
1332
{
 
1333
        struct mnt_entry *ent = NULL;
 
1334
        char *device = NULL;
 
1335
        if (old) {
 
1336
                if (strcmp(old->name, "oldroot") != 0)
 
1337
                        yyerror(_("invalid pivotroot conditional '%s'"), old->name);
 
1338
                if (old->vals) {
 
1339
                        device = old->vals->value;
 
1340
                        old->vals->value = NULL;
 
1341
                }
 
1342
                free_cond_entry(old);
 
1343
        }
 
1344
 
 
1345
        ent = new_mnt_entry(NULL, device, NULL, root,
 
1346
                            AA_MAY_PIVOTROOT);
 
1347
        ent->trans = transition;
 
1348
 
 
1349
        return ent;
 
1350
}