3
* Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
4
* NOVELL (All rights reserved)
5
* Copyright (c) 2010-2012
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.
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.
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, contact Canonical, Ltd.
21
#define YYERROR_VERBOSE 1
30
#define _(s) gettext(s)
36
#include "parser_include.h"
38
#include <netinet/in.h>
39
#include <arpa/inet.h>
41
#include <linux/capability.h>
43
#ifndef CAP_AUDIT_WRITE
44
#define CAP_AUDIT_WRITE 29
46
#ifndef CAP_AUDIT_CONTROL
47
#define CAP_AUDIT_CONTROL 30
50
#define CAP_SETFCAP 31
52
#ifndef CAP_MAC_OVERRIDE
53
#define CAP_MAC_OVERRIDE 32
56
#define CIDR_32 htonl(0xffffffff)
57
#define CIDR_24 htonl(0xffffff00)
58
#define CIDR_16 htonl(0xffff0000)
59
#define CIDR_8 htonl(0xff000000)
61
/* undefine linux/capability.h CAP_TO_MASK */
66
#define CAP_TO_MASK(x) (1ull << (x))
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,
75
struct mnt_entry *do_pivot_rule(struct cond_entry *old, char *root,
78
void add_local_entry(struct codomain *cod);
88
%token TOK_END_OF_RULE
100
%token TOK_CHANGE_PROFILE
117
%token TOK_CLOSEPAREN
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
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
147
%token TOK_CAPABILITY
149
/* debug flag values */
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;
162
struct flagval flags;
165
unsigned int allowed_protocol;
169
struct value_list *val_list;
170
struct cond_entry *cond_entry;
172
struct named_transition transition;
176
%type <id> TOK_CONDID
177
%type <mode> TOK_MODE
178
%type <fmode> file_mode
179
%type <cod> profile_base
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
196
%type <flags> flagvals
197
%type <flags> flagval
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
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
214
%type <transition> opt_named_transition
215
%type <boolean> opt_unsafe
216
%type <boolean> opt_file
220
list: preamble profilelist
223
profilelist: { /* nothing */ };
225
profilelist: profilelist profile
227
PDEBUG("Matched: list profile\n");
231
opt_profile_flag: { /* nothing */ $$ = 0; }
232
| TOK_PROFILE { $$ = 1; }
233
| hat_start { $$ = 2; }
235
opt_namespace: { /* nothing */ $$ = NULL; }
236
| TOK_COLON TOK_ID TOK_COLON { $$ = $2; }
238
opt_id: { /* nothing */ $$ = NULL; }
239
| TOK_ID { $$ = $1; }
241
profile_base: TOK_ID opt_id flags TOK_OPEN rules TOK_CLOSE
243
struct codomain *cod = $5;
246
yyerror(_("Memory allocation error."));
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
255
yyerror(_("Profile attachment must begin with a '/'."));
258
cod->flags.complain = 1;
260
post_process_nt_entries(cod);
261
post_process_mnt_entries(cod);
262
PDEBUG("%s: flags='%s%s'\n",
264
cod->flags.complain ? "complain, " : "",
265
cod->flags.audit ? "audit" : "");
271
profile: opt_profile_flag opt_namespace profile_base
273
struct codomain *cod = $3;
275
PDEBUG("Matched: %s://%s { ... }\n", $2, $3->name);
277
PDEBUG("Matched: %s { ... }\n", $3->name);
279
if ($3->name[0] != '/' && !($1 || $2))
280
yyerror(_("Profile names must begin with a '/', namespace or keyword 'profile' or 'hat'."));
288
local_profile: TOK_PROFILE profile_base
291
struct codomain *cod = $2;
294
PDEBUG("Matched: local profile %s { ... }\n", cod->name);
299
hat: hat_start profile_base
301
struct codomain *cod = $2;
303
PDEBUG("Matched: hat %s { ... }\n", cod->name);
309
preamble: { /* nothing */ }
310
| preamble alias { /* nothing */ };
311
| preamble varassign { /* nothing */ };
313
alias: TOK_ALIAS TOK_ID TOK_ARROW TOK_ID TOK_END_OF_RULE
315
if (!new_alias($2, $4))
316
yyerror(_("Failed to create alias %s -> %s\n"), $2, $4);
321
varassign: TOK_SET_VAR TOK_EQUALS valuelist
323
struct value_list *list = $3;
324
char *var_name = process_var($1);
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);
331
yyerror("variable %s was previously declared", $1);
332
/* FIXME: it'd be handy to report the previous location */
334
for (list = list->next; list; list = list->next) {
335
err = add_set_value(var_name, list->value);
337
yyerror("Error adding %s to set var %s",
345
varassign: TOK_SET_VAR TOK_ADD_ASSIGN valuelist
347
struct value_list *list = $3;
348
char *var_name = process_var($1);
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);
357
yyerror("variable %s was not previously declared, but is being assigned additional values", $1);
359
for (list = list->next; list; list = list->next) {
360
err = add_set_value(var_name, list->value);
362
yyerror("Error adding %s to set var %s",
370
varassign: TOK_BOOL_VAR TOK_EQUALS TOK_VALUE
373
char *var_name = process_var($1);
374
PDEBUG("Matched: boolean assignment (%s) to %s\n", $1, $3);
375
boolean = str_to_boolean($3);
377
yyerror("Invalid boolean assignment for (%s): %s is not true or false",
380
err = add_boolean_var(var_name, boolean);
382
yyerror("variable %s was previously declared", $1);
383
/* FIXME: it'd be handy to report the previous location */
392
struct value_list *val = new_value_list($1);
394
yyerror(_("Memory allocation error."));
395
PDEBUG("Matched: value (%s)\n", $1);
400
valuelist: valuelist TOK_VALUE
402
struct value_list *val = new_value_list($2);
404
yyerror(_("Memory allocation error."));
405
PDEBUG("Matched: value list\n");
407
list_append($1, val);
411
flags: { /* nothing */
412
struct flagval fv = { 0, 0, 0, 0 };
417
opt_flags: { /* nothing */ $$ = 0; }
418
| TOK_CONDID TOK_EQUALS
420
if (strcmp($1, "flags") != 0)
421
yyerror("expected flags= got %s=", $1);
425
flags: opt_flags TOK_OPENPAREN flagvals TOK_CLOSEPAREN
430
flagvals: flagvals flagval
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"));
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"));
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) {
464
} else if (strcmp($1, "audit") == 0) {
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;
483
yyerror(_("Invalid profile flag: %s."), $1);
489
opt_subset_flag: { /* nothing */ $$ = 0; }
490
| TOK_SUBSET { $$ = 1; }
493
opt_audit_flag: { /* nothing */ $$ = 0; }
494
| TOK_AUDIT { $$ = 1; };
496
opt_owner_flag: { /* nothing */ $$ = 0; }
497
| TOK_OWNER { $$ = 1; };
498
| TOK_OTHER { $$ = 2; };
500
rules: { /* nothing */
501
struct codomain *cod = NULL;
502
cod = (struct codomain *) calloc(1, sizeof(struct codomain));
504
yyerror(_("Memory allocation error."));
510
/* can't fold TOK_DENY in as opt_deny_flag as it messes up the generated
511
* parser, even though it shouldn't
513
rules: rules opt_audit_flag TOK_DENY opt_owner_flag rule
515
PDEBUG("matched: rules rule\n");
516
PDEBUG("rules rule: (%s)\n", $5->name);
518
yyerror(_("Assert: `rule' returned NULL."));
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'"));
524
$5->mode &= (AA_USER_PERMS | AA_SHARED_PERMS | AA_USER_PTRACE);
526
$5->mode &= (AA_OTHER_PERMS | AA_SHARED_PERMS | AA_OTHER_PTRACE);
527
/* only set audit ctl quieting if the rule is not audited */
529
$5->audit = $5->mode & ~ALL_AA_EXEC_TYPE;
531
add_entry_to_policy($1, $5);
535
rules: rules opt_audit_flag opt_owner_flag rule
537
PDEBUG("matched: rules rule\n");
538
PDEBUG("rules rule: (%s)\n", $4->name);
540
yyerror(_("Assert: `rule' returned NULL."));
541
if (($4->mode & AA_EXEC_BITS) &&
542
!($4->mode & ALL_AA_EXEC_TYPE) &&
544
yyerror(_("Invalid mode, 'x' must be preceded by exec qualifier 'i', 'p', 'c', or 'u'"));
547
$4->mode &= (AA_USER_PERMS | AA_SHARED_PERMS | AA_USER_PTRACE);
549
$4->mode &= (AA_OTHER_PERMS | AA_SHARED_PERMS | AA_OTHER_PTRACE);
551
$4->audit = $4->mode & ~ALL_AA_EXEC_TYPE;
553
add_entry_to_policy($1, $4);
557
rules: rules opt_audit_flag opt_owner_flag TOK_OPEN rules TOK_CLOSE
559
struct cod_entry *entry, *tmp;
560
PDEBUG("matched: audit block\n");
561
list_for_each_safe($5->entries, entry, tmp) {
563
if (entry->mode & AA_EXEC_BITS) {
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'"));
572
entry->mode &= (AA_USER_PERMS | AA_SHARED_PERMS | AA_USER_PTRACE);
574
entry->mode &= (AA_OTHER_PERMS | AA_SHARED_PERMS | AA_OTHER_PTRACE);
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);
583
// fix me transfer rules and free sub codomain
588
rules: rules opt_audit_flag TOK_DENY network_rule
590
struct aa_network_entry *entry, *tmp;
592
PDEBUG("Matched: network rule\n");
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."));
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;
613
$1->quiet_network[entry->family] |= entry->type;
616
$1->deny_network[entry->family] |= 1 << entry->type;
618
$1->quiet_network[entry->family] |= 1 << entry->type;
626
rules: rules opt_audit_flag network_rule
628
struct aa_network_entry *entry, *tmp;
630
PDEBUG("Matched: network rule\n");
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."));
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;
651
$1->audit_network[entry->family] |= entry->type;
654
$1->network_allowed[entry->family] |= 1 << entry->type;
656
$1->audit_network[entry->family] |= 1 << entry->type;
664
rules: rules opt_audit_flag TOK_DENY mnt_rule
666
$4->deny = $4->allow;
668
$4->audit = $4->allow;
669
$4->next = $1->mnt_ents;
674
rules: rules opt_audit_flag mnt_rule
677
$3->audit = $3->allow;
678
$3->next = $1->mnt_ents;
683
rules: rules change_profile
685
PDEBUG("matched: rules change_profile\n");
686
PDEBUG("rules change_profile: (%s)\n", $2->name);
688
yyerror(_("Assert: `change_profile' returned NULL."));
689
add_entry_to_policy($1, $2);
693
rules: rules opt_audit_flag TOK_DENY capability
697
$1->quiet_caps |= $4;
701
rules: rules opt_audit_flag capability
703
$1->capabilities |= $3;
705
$1->audit_caps |= $3;
711
PDEBUG("Matched: hat rule\n");
713
yyerror(_("Assert: 'hat rule' returned NULL."));
714
add_hat_to_policy($1, $2);
718
rules: rules local_profile
720
PDEBUG("Matched: hat rule\n");
722
yyerror(_("Assert: 'local_profile rule' returned NULL."));
723
add_hat_to_policy($1, $2);
728
rules: rules cond_rule
730
PDEBUG("Matched: conditional rules\n");
731
$$ = merge_policy($1, $2);
734
rules: rules TOK_SET TOK_RLIMIT TOK_ID TOK_LE TOK_VALUE TOK_END_OF_RULE
736
rlim_t value = RLIM_INFINITY;
740
int limit = get_rlimit($4);
742
yyerror("INVALID RLIMIT '%s'\n", $4);
744
if (strcmp($6, "infinity") == 0) {
745
value = RLIM_INFINITY;
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";
755
tmp = strtoll($6, &end, 0);
758
if (!end || $6 == end || tmp < 0)
759
yyerror("RLIMIT '%s' invalid value %s\n", $4, $6);
761
strstr(seconds, end) == seconds) {
763
} else if (strstr(minutes, end) == minutes) {
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;
770
yyerror("RLIMIT '%s' invalid value %s\n", $4, $6);
776
case RLIMIT_SIGPENDING:
779
if (!end || $6 == end || *end != '\0' || tmp < 0)
780
yyerror("RLIMIT '%s' invalid value %s\n", $4, $6);
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);
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) {
805
} else if (strstr(mb, end) == mb) {
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);
815
yyerror("Unknown RLIMIT %d\n", $4);
818
$1->rlimits.specified |= 1 << limit;
819
$1->rlimits.limits[limit] = value;
826
cond_rule: TOK_IF expr TOK_OPEN rules TOK_CLOSE
828
struct codomain *ret = NULL;
829
PDEBUG("Matched: found conditional rules\n");
838
cond_rule: TOK_IF expr TOK_OPEN rules TOK_CLOSE TOK_ELSE TOK_OPEN rules TOK_CLOSE
840
struct codomain *ret = NULL;
841
PDEBUG("Matched: found conditional else rules\n");
852
cond_rule: TOK_IF expr TOK_OPEN rules TOK_CLOSE TOK_ELSE cond_rule
854
struct codomain *ret = NULL;
855
PDEBUG("Matched: found conditional else-if rules\n");
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);
877
/* FIXME check for set var */
878
yyerror(_("Unset boolean variable %s used in if-expression"),
886
expr: TOK_DEFINED TOK_SET_VAR
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;
896
expr: TOK_DEFINED TOK_BOOL_VAR
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);
906
id_or_var: TOK_ID { $$ = $1; }
907
id_or_var: TOK_SET_VAR { $$ = $1; };
909
opt_named_transition:
915
| TOK_ARROW id_or_var
921
| TOK_ARROW TOK_COLON id_or_var TOK_COLON id_or_var
928
rule: file_rule { $$ = $1; }
929
| link_rule { $$ = $1; }
930
| ptrace_rule {$$ = $1; }
932
opt_unsafe: { /* nothing */ $$ = 0; }
933
| TOK_UNSAFE { $$ = 1; };
934
| TOK_SAFE { $$ = 2; };
936
opt_file: { /* nothing */ $$ = 0; }
937
| TOK_FILE { $$ = 1; }
939
frule: id_or_var file_mode opt_named_transition TOK_END_OF_RULE
941
$$ = do_file_rule($3.namespace, $1, $2, NULL, $3.name);
944
frule: file_mode opt_subset_flag id_or_var opt_named_transition TOK_END_OF_RULE
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);
957
$$ = do_file_rule($4.namespace, $3, $1, NULL, $4.name);
961
file_rule: TOK_FILE TOK_END_OF_RULE
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;
969
yyerror(_("Memory allocation error."));
970
$$ = do_file_rule(NULL, path, perms, NULL, NULL);
972
| opt_file file_rule_tail { $$ = $2; }
975
file_rule_tail: opt_unsafe frule
978
if (!($2->mode & AA_EXEC_BITS))
979
yyerror(_("unsafe rule missing exec permissions"));
981
$2->mode |= (($2->mode & AA_EXEC_BITS) << 8) &
985
$2->mode &= ~ALL_AA_EXEC_UNSAFE;
990
file_rule_tail: opt_unsafe id_or_var file_mode id_or_var
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
996
yyerror(_("missing an end of line character? (entry: %s)"), $2);
999
link_rule: TOK_LINK opt_subset_flag TOK_ID TOK_ARROW TOK_ID TOK_END_OF_RULE
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);
1005
PDEBUG("rule.entry: link (%s)\n", entry->name);
1009
ptrace_rule: TOK_PTRACE TOK_ID TOK_END_OF_RULE
1011
struct cod_entry *entry;
1012
entry = new_entry(NULL, $2, AA_USER_PTRACE | AA_OTHER_PTRACE, NULL);
1014
yyerror(_("Memory allocation error."));
1018
ptrace_rule: TOK_PTRACE TOK_COLON TOK_ID TOK_COLON TOK_ID TOK_END_OF_RULE
1020
struct cod_entry *entry;
1021
entry = new_entry($3, $5, AA_USER_PTRACE | AA_OTHER_PTRACE, NULL);
1023
yyerror(_("Memory allocation error."));
1027
network_rule: TOK_NETWORK TOK_END_OF_RULE
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,
1035
yyerror(_("Memory allocation error."));
1036
new_entry->next = entry;
1042
network_rule: TOK_NETWORK TOK_ID TOK_END_OF_RULE
1044
struct aa_network_entry *entry;
1045
entry = network_entry($2, NULL, NULL);
1047
/* test for short circuiting of family */
1048
entry = network_entry(NULL, $2, NULL);
1050
yyerror(_("Invalid network entry."));
1055
network_rule: TOK_NETWORK TOK_ID TOK_ID TOK_END_OF_RULE
1057
struct aa_network_entry *entry;
1058
entry = network_entry($2, $3, NULL);
1060
yyerror(_("Invalid network entry."));
1066
cond: TOK_CONDID TOK_EQUALS TOK_VALUE
1068
struct cond_entry *ent;
1069
struct value_list *value = new_value_list($3);
1071
yyerror(_("Memory allocation error."));
1072
ent = new_cond_entry($1, 1, value);
1074
free_value_list(value);
1075
yyerror(_("Memory allocation error."));
1080
cond: TOK_CONDID TOK_EQUALS TOK_OPENPAREN valuelist TOK_CLOSEPAREN
1082
struct cond_entry *ent = new_cond_entry($1, 1, $4);
1085
yyerror(_("Memory allocation error."));
1090
cond: TOK_CONDID TOK_IN TOK_OPENPAREN valuelist TOK_CLOSEPAREN
1092
struct cond_entry *ent = new_cond_entry($1, 0, $4);
1095
yyerror(_("Memory allocation error."));
1099
opt_conds: { /* nothing */ $$ = NULL; }
1106
mnt_rule: TOK_MOUNT opt_conds opt_id TOK_END_OF_RULE
1108
$$ = do_mnt_rule($2, $3, NULL, NULL, AA_MAY_MOUNT);
1111
mnt_rule: TOK_MOUNT opt_conds opt_id TOK_ARROW opt_conds TOK_ID TOK_END_OF_RULE
1113
$$ = do_mnt_rule($2, $3, $5, $6, AA_MAY_MOUNT);
1116
mnt_rule: TOK_REMOUNT opt_conds opt_id TOK_END_OF_RULE
1118
$$ = do_mnt_rule($2, NULL, NULL, $3, AA_DUMMY_REMOUNT);
1121
mnt_rule: TOK_UMOUNT opt_conds opt_id TOK_END_OF_RULE
1123
$$ = do_mnt_rule($2, NULL, NULL, $3, AA_MAY_UMOUNT);
1126
mnt_rule: TOK_PIVOTROOT opt_conds opt_id opt_named_transition TOK_END_OF_RULE
1129
if ($4.present && $4.namespace) {
1130
name = malloc(strlen($4.namespace) +
1131
strlen($4.name) + 3);
1133
PERROR("Memory allocation error\n");
1136
sprintf(name, ":%s:%s", $4.namespace, $4.name);
1139
} else if ($4.present)
1142
$$ = do_pivot_rule($2, $3, name);
1145
hat_start: TOK_CARET {}
1150
/* A single TOK_MODE maps to the same permission in all
1152
$$ = parse_mode($1);
1156
change_profile: TOK_CHANGE_PROFILE TOK_ARROW TOK_ID TOK_END_OF_RULE
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);
1162
yyerror(_("Memory allocation error."));
1163
PDEBUG("change_profile.entry: (%s)\n", entry->name);
1167
change_profile: TOK_CHANGE_PROFILE TOK_ARROW TOK_COLON TOK_ID TOK_COLON TOK_ID TOK_END_OF_RULE
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);
1173
yyerror(_("Memory allocation error."));
1174
PDEBUG("change_profile.entry: (%s)\n", entry->name);
1179
capability: TOK_CAPABILITY caps TOK_END_OF_RULE
1182
/* bare capability keyword - set all caps */
1183
$$ = 0xffffffffffffffff;
1188
caps: { /* nothing */ $$ = 0; }
1191
int cap = name_to_capability($2);
1193
yyerror(_("Invalid capability %s."), $2);
1195
$$ = $1 | CAP_TO_MASK(cap);
1199
#define MAXBUFSIZE 4096
1201
void vprintyyerror(const char *msg, va_list argptr)
1203
char buf[MAXBUFSIZE];
1205
vsnprintf(buf, sizeof(buf), msg, argptr);
1208
PERROR(_("AppArmor parser error for %s%s%s at line %d: %s\n"),
1210
current_filename ? " in " : "",
1211
current_filename ? current_filename : "",
1212
current_lineno, buf);
1214
PERROR(_("AppArmor parser error,%s%s line %d: %s\n"),
1215
current_filename ? " in " : "",
1216
current_filename ? current_filename : "",
1217
current_lineno, buf);
1221
void printyyerror(const char *msg, ...)
1226
vprintyyerror(msg, arg);
1230
void yyerror(const char *msg, ...)
1235
vprintyyerror(msg, arg);
1241
struct cod_entry *do_file_rule(char *namespace, char *id, int mode,
1242
char *link_id, char *nt)
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);
1248
yyerror(_("Memory allocation error."));
1249
entry->nt_name = nt;
1250
PDEBUG("rule.entry: (%s)\n", entry->name);
1254
/* Note: NOT currently in use, used for
1255
* /foo x -> { /bah, } style transitions
1257
void add_local_entry(struct codomain *cod)
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);
1266
yyerror(_("Memory allocation error."));
1267
sprintf(name, "%s//%s", cod->parent->name, cod->name);
1269
entry = new_entry(NULL, name, cod->local_mode, NULL);
1270
entry->audit = cod->local_audit;
1271
entry->nt_name = trans;
1273
yyerror(_("Memory allocation error."));
1275
add_entry_to_policy(cod, entry);
1279
static char *mnt_cond_msg[] = {"",
1280
" not allowed as source conditional",
1281
" not allowed as target conditional",
1285
int verify_mnt_conds(struct cond_entry *conds, int src)
1287
struct cond_entry *entry;
1293
list_for_each(conds, entry) {
1294
int res = is_valid_mnt_cond(entry->name, src);
1296
printyyerror(_("invalid mount conditional %s%s"),
1298
res == -1 ? "" : mnt_cond_msg[src]);
1306
struct mnt_entry *do_mnt_rule(struct cond_entry *src_conds, char *src,
1307
struct cond_entry *dst_conds, char *dst,
1310
struct mnt_entry *ent;
1312
if (verify_mnt_conds(src_conds, MNT_SRC_OPT) != 0)
1313
yyerror(_("bad mount rule"));
1315
/* FIXME: atm conditions are not supported on dst
1316
if (verify_conds(dst_conds, DST_OPT) != 0)
1317
yyerror(_("bad mount rule"));
1320
yyerror(_("mount point conditions not currently supported"));
1322
ent = new_mnt_entry(src_conds, src, dst_conds, dst, mode);
1324
yyerror(_("Memory allocation error."));
1330
struct mnt_entry *do_pivot_rule(struct cond_entry *old, char *root,
1333
struct mnt_entry *ent = NULL;
1334
char *device = NULL;
1336
if (strcmp(old->name, "oldroot") != 0)
1337
yyerror(_("invalid pivotroot conditional '%s'"), old->name);
1339
device = old->vals->value;
1340
old->vals->value = NULL;
1342
free_cond_entry(old);
1345
ent = new_mnt_entry(NULL, device, NULL, root,
1347
ent->trans = transition;