diff --git a/.gitignore b/.gitignore index f6c66862b..00e4b7414 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,7 @@ parser/libapparmor_re/hfa.o parser/libapparmor_re/libapparmor_re.a parser/libapparmor_re/parse.o parser/mount.o +parser/mqueue.o parser/network.o parser/parser_alias.o parser/parser_common.o diff --git a/parser/Makefile b/parser/Makefile index 39bf38d3d..f95fd4af2 100644 --- a/parser/Makefile +++ b/parser/Makefile @@ -101,10 +101,11 @@ SRCS = parser_common.c parser_include.c parser_interface.c parser_lex.c \ parser_yacc.c parser_regex.c parser_variable.c parser_policy.c \ parser_alias.c common_optarg.c lib.c network.c \ mount.cc dbus.cc profile.cc rule.cc signal.cc ptrace.cc \ - af_rule.cc af_unix.cc policy_cache.c default_features.c userns.cc + af_rule.cc af_unix.cc policy_cache.c default_features.c userns.cc \ + mqueue.cc HDRS = parser.h parser_include.h immunix.h mount.h dbus.h lib.h profile.h \ rule.h common_optarg.h signal.h ptrace.h network.h af_rule.h af_unix.h \ - policy_cache.h file_cache.h userns.h + policy_cache.h file_cache.h userns.h mqueue.h TOOLS = apparmor_parser OBJECTS = $(patsubst %.cc, %.o, $(SRCS:.c=.o)) @@ -304,6 +305,9 @@ rule.o: rule.cc rule.h policydb.h userns.o: userns.cc userns.h parser.h parser_yacc.h rule.h $(APPARMOR_H) $(CXX) $(EXTRA_CFLAGS) -c -o $@ $< +mqueue.o: mqueue.cc mqueue.h parser.h immunix.h profile.h parser_yacc.h rule.h $(APPARMOR_H) + $(CXX) $(EXTRA_CFLAGS) -c -o $@ $< + parser_version.h: Makefile @echo \#define PARSER_VERSION \"$(VERSION)\" > .ver @mv -f .ver $@ diff --git a/parser/apparmor.d.pod b/parser/apparmor.d.pod index 0b6637674..fbd324bdc 100644 --- a/parser/apparmor.d.pod +++ b/parser/apparmor.d.pod @@ -123,7 +123,7 @@ B = [ ( I | I ',' | I ) B = ( I | I ) [ '\r' ] '\n' -B = ( I | I | I | I | I | I | I | I | I | I ) +B = ( I | I | I | I | I | I | I | I | I | I | I ) B = ( I | I | I ) @@ -176,6 +176,20 @@ B = ( 'ro' | 'rw' | 'nosuid' | 'suid' | 'nodev' | 'dev' | 'noexec' B = ( I | I ) ... +B = [ I ] 'mqueue' [ I ] [ I ] [ I ] [ I ] + +B = I | I + +B = '(' Comma or space separated list of I ')' + +B = ( 'r' | 'w' | 'rw' | 'read' | 'write' | 'create' | 'open' | 'delete' | 'getattr' | 'setattr' ) + +B = 'type' '=' ( 'posix' | 'sysv' ) + +B = 'label' '=' '(' '"' I '"' | I ')' + +B = I + B = [ I ] pivot_root [ oldroot=I ] [ I ] [ '-E' I ] B = I @@ -1057,6 +1071,51 @@ Matches only: =back +=head2 Message Queue rules + +AppArmor supports mediation of POSIX and SYSV message queues. + +AppArmor Message Queue permissions are implied when a rule does not explicitly +state an access list. By default, all Message Queue permissions are implied. + +AppArmor Message Queue permissions become more restricted as further information +is specified. Policy can be specified by determining its access mode, type, +label, and message queue name. + +Regarding access modes, 'r' and 'read' are used to read messages from the queue. +'w' and 'write' are used to write to the message queue. 'create' is used to create +the message queue, and 'open' is used to get the message queue identifier when the +queue is already created. 'delete' is used to remove the message queue. The access +modes to get and set attributes of the message queue are 'setattr' and 'getattr'. + +The type of the policy can be either 'posix' or 'sysv'. This information is +relevant when the message queue name is not specified, and when specified can be +inferred by the queue name, since message queues' name for posix must start with '/', +and message queues' key for SYSV must be a positive integer. + +The policy label is the label assigned to the message queue when it is created. + +The message queue name can be either a string starting with '/' if the type +is POSIX, or a positive integer if the type is SYSV. If the type is not +specified, then it will be inferred by the queue name. + +Example AppArmor Message Queue rules: + + # Allow all Message Queue access + mqueue, + + # Explicitly allow all Message Queue access, + mqueue (create, open, delete, read, write, getattr, setattr), + + # Explicitly deny use of Message Queue + deny mqueue, + + # Allow all access for POSIX queue of name /bar + mqueue type=posix /bar, + + # Allow create permission for a SYSV queue of label foo + mqueue create label=foo 123, + =head2 Pivot Root Rules AppArmor mediates changing of the root filesystem through the pivot_root(2) diff --git a/parser/mqueue.cc b/parser/mqueue.cc new file mode 100644 index 000000000..4b7ae34f5 --- /dev/null +++ b/parser/mqueue.cc @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2022 + * Canonical, Ltd. (All rights reserved) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, contact Novell, Inc. or Canonical + * Ltd. + */ + +#include "parser.h" +#include "profile.h" +#include "mqueue.h" + +#include +#include +#include +#include + +int parse_mqueue_mode(const char *str_mode, int *mode, int fail) +{ + return parse_X_mode("mqueue", AA_VALID_MQUEUE_PERMS, str_mode, mode, fail); +} + +static bool is_all_digits(char *str) +{ + const char *s = str; + while (*str && isdigit(*str)) + str++; + return str != s && *str == 0; +} + +void mqueue_rule::validate_qname(void) +{ + if (qname[0] == '/') { + // TODO full syntax check of name + if (qtype == mqueue_sysv) + yyerror("mqueue type=sysv invalid name '%s', sysv " + "message queues must be identified by a " + "positive integer.\n", qname); + qtype = mqueue_posix; // implied by name + } else if (is_all_digits(qname)) { + if (qtype == mqueue_posix) + yyerror("mqueue type=posix invalid name '%s', posix " + "message queues names must begin with a /\n", + qname); + qtype = mqueue_sysv; // implied + } else { + yyerror("mqueue invalid name '%s', message queue names must begin with a / or be a positive integer.\n", qname); + } +} + +void mqueue_rule::move_conditionals(struct cond_entry *conds) +{ + struct cond_entry *cond_ent; + + list_for_each(conds, cond_ent) { + /* for now disallow keyword 'in' (list) */ + if (!cond_ent->eq) + yyerror("keyword \"in\" is not allowed in mqueue rules\n"); + + if (strcmp(cond_ent->name, "label") == 0) { + move_conditional_value("mqueue", &label, cond_ent); + } else if (strcmp(cond_ent->name, "type") == 0) { + char *tmp = NULL; + move_conditional_value("mqueue", &tmp, cond_ent); + if (strcmp(tmp, "posix") == 0) + qtype = mqueue_posix; + else if (strcmp(tmp, "sysv") == 0) + qtype = mqueue_sysv; + else + yyerror("mqueue invalid type='%s'\n", tmp); + free(tmp); + } else { + yyerror("invalid mqueue rule conditional \"%s\"\n", + cond_ent->name); + } + } +} + +mqueue_rule::mqueue_rule(int mode_p, struct cond_entry *conds, char *qname_p): + qtype(mqueue_unspecified), qname(qname_p), label(NULL), audit(0), deny(0) +{ + move_conditionals(conds); + free_cond_list(conds); + + if (qname) + validate_qname(); + if (mode_p) { + // do we want to allow perms to imply type like we do for + // qname? + if (qtype == mqueue_posix && (mode_p & ~AA_VALID_POSIX_MQ_PERMS)) { + yyerror("mode contains invalid permissions for mqueue type=posix\n"); + } else if (qtype == mqueue_sysv && (mode_p & ~AA_VALID_SYSV_MQ_PERMS)) { + yyerror("mode contains invalid permissions for mqueue type=sysv\n"); + } else if (mode_p & ~AA_VALID_MQUEUE_PERMS) { + yyerror("mode contains invalid permissions for mqueue\n"); + } + mode = mode_p; + } else { + // default to all perms + mode = AA_VALID_MQUEUE_PERMS; + } + qname = qname_p; + +} + +ostream &mqueue_rule::dump(ostream &os) +{ + if (audit) + os << "audit "; + if (deny) + os << "deny "; + + os << "mqueue "; + + // do we want to always put type out or leave it implied if there + // is a qname + if (qtype == mqueue_posix) + os << "type=posix"; + else if (qtype == mqueue_sysv) + os << "type=sysv"; + + if (mode != AA_VALID_MQUEUE_PERMS) { + os << "("; + + if (mode & AA_MQUEUE_WRITE) + os << "write "; + if (mode & AA_MQUEUE_READ) + os << "read "; + if (mode & AA_MQUEUE_OPEN) + os << "open "; + if (mode & AA_MQUEUE_CREATE) + os << "create "; + if (mode & AA_MQUEUE_DELETE) + os << "delete "; + if (mode & AA_MQUEUE_SETATTR) + os << "setattr "; + if (mode & AA_MQUEUE_GETATTR) + os << "getattr "; + + os << ")"; + } + + if (qname) + os << " " << qname; + + os << ",\n"; + + return os; +} + +int mqueue_rule::expand_variables(void) +{ + int error = expand_entry_variables(&qname); + if (error) + return error; + error = expand_entry_variables(&label); + if (error) + return error; + + return 0; +} + +/* TODO: this is not right, need separate warning for each type */ +void mqueue_rule::warn_once(const char *name) +{ + if (qtype == mqueue_unspecified) + rule_t::warn_once(name, "mqueue rules not enforced"); + else if (qtype == mqueue_posix) + rule_t::warn_once(name, "mqueue type=posix rules not enforced"); + else if (qtype == mqueue_sysv) + rule_t::warn_once(name, "mqueue type=sysv rules not enforced"); +} + +int mqueue_rule::gen_policy_re(Profile &prof) +{ + std::string labelbuf; + std::string buf; + const int size = 2; + const char *vec[size]; + + + if (qtype == mqueue_posix && !features_supports_posix_mqueue) { + warn_once(prof.name); + // return RULE_NOT_SUPPORTED; + } else if (qtype == mqueue_sysv && !features_supports_sysv_mqueue) { + warn_once(prof.name); + // return RULE_NOT_SUPPORTED; + } else if (qtype == mqueue_unspecified && + !(features_supports_posix_mqueue || + features_supports_sysv_mqueue)) { + warn_once(prof.name); + // should split into warning where posix and sysv can + // be separated from nothing being enforced + // return RULE_NOT_SUPPORTED; + } + + /* always generate a label and mqueue entry */ + + //buffer << "(" << "\\x" << std::setfill('0') << std::setw(2) << std::hex << AA_CLASS_LABEL << "|)"; //is this required? + + // posix and generic + if (qtype != mqueue_sysv) { + std::ostringstream buffer; + buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << AA_CLASS_POSIX_MQUEUE; + buf.assign(buffer.str()); + if (qname) { + if (!convert_entry(buf, qname)) + goto fail; + } else { + buf += default_match_pattern; + } + vec[0] = buf.c_str(); + + if (label) { + if (!convert_entry(labelbuf, label)) + goto fail; + vec[1] = labelbuf.c_str(); + } else { + vec[1] = anyone_match_pattern; + } + + if (mode & AA_VALID_POSIX_MQ_PERMS) { + if (!prof.policy.rules->add_rule_vec(deny, mode, audit, size, vec, + dfaflags, false)) + goto fail; + } + } + // sysv and generic + if (qtype != mqueue_posix) { + std::ostringstream buffer; + buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << AA_CLASS_SYSV_MQUEUE; + buf.assign(buffer.str()); + if (qname) { + if (!convert_entry(buf, qname)) + goto fail; + } else { + buf += default_match_pattern; + } + vec[0] = buf.c_str(); + + if (label) { + if (!convert_entry(labelbuf, label)) + goto fail; + vec[1] = labelbuf.c_str(); + } else { + vec[1] = anyone_match_pattern; + } + + if (mode & AA_VALID_SYSV_MQ_PERMS) { + if (!label && !prof.policy.rules->add_rule_vec(deny, mode, audit, 1, vec, dfaflags, false)) + goto fail; + /* also provide label match with perm */ + if (!prof.policy.rules->add_rule_vec(deny, mode, audit, size, vec, dfaflags, false)) + goto fail; + } + } + + return RULE_OK; + +fail: + return RULE_ERROR; +} diff --git a/parser/mqueue.h b/parser/mqueue.h new file mode 100644 index 000000000..fdbc0d38d --- /dev/null +++ b/parser/mqueue.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2022 + * Canonical Ltd. (All rights reserved) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, contact Novell, Inc. or Canonical + * Ltd. + */ + +/* sysv and posix mqueue mediation. */ + +#ifndef __AA_MQUEUE_H +#define __AA_MQUEUE_H + +#include "immunix.h" +#include "parser.h" + +#define AA_MQUEUE_WRITE AA_MAY_WRITE +#define AA_MQUEUE_READ AA_MAY_READ + +#define AA_MQUEUE_CREATE 0x0010 /* create */ +#define AA_MQUEUE_DELETE 0x0020 /* destroy, unlink */ +#define AA_MQUEUE_OPEN 0x0040 /* associate */ +#define AA_MQUEUE_RENAME 0x0080 /* ?? pair */ + +#define AA_MQUEUE_SETATTR 0x0100 /* setattr */ +#define AA_MQUEUE_GETATTR 0x0200 /* getattr */ + +#define AA_MQUEUE_CHMOD 0x1000 /* pair */ +#define AA_MQUEUE_CHOWN 0x2000 /* pair */ +#define AA_MQUEUE_CHGRP 0x4000 /* pair */ +#define AA_MQUEUE_LOCK 0x8000 /* LINK_SUBSET overlaid */ + +/* sysv and posix mqueues use different terminology, allow mapping + * between. To be as common as possible. + * + * sysv and posix mqueues have different levels of mediation possible + * in the kernel. Only the most basic mqueue rules can be shared + * eg. + * mqueue rw, + * mqueue rw label=foo, + * + * kernel doesn't allow for us to control + * - posix + * - notify + * - getattr/setattr + * - labels at anything other than mqueue label, via mqueue inode. + */ + +#define AA_VALID_POSIX_MQ_PERMS (AA_MQUEUE_WRITE | AA_MQUEUE_READ | \ + AA_MQUEUE_CREATE | AA_MQUEUE_DELETE | \ + AA_MQUEUE_OPEN) + + /* TBD - for now make it wider than posix */ +#define AA_VALID_SYSV_MQ_PERMS (AA_MQUEUE_WRITE | AA_MQUEUE_READ | \ + AA_MQUEUE_CREATE | AA_MQUEUE_DELETE | \ + AA_MQUEUE_OPEN | \ + AA_MQUEUE_SETATTR | AA_MQUEUE_GETATTR) + +#define AA_VALID_MQUEUE_PERMS (AA_VALID_POSIX_MQ_PERMS | \ + AA_VALID_SYSV_MQ_PERMS) + +// warning getting into overlap area + +/* Type of mqueue - can be explicit or implied by rule id/path */ +typedef enum mqueue_type { + mqueue_unspecified, + mqueue_posix, + mqueue_sysv +} mqueue_type; + + +int parse_mqueue_mode(const char *str_mode, int *mode, int fail); + +class mqueue_rule: public rule_t { + void move_conditionals(struct cond_entry *conds); +public: + mqueue_type qtype; + char *qname; + char *label; + int mode; + int audit; + int deny; + + mqueue_rule(int mode, struct cond_entry *conds, char *qname = NULL); + virtual ~mqueue_rule() + { + free(qname); + free(label); + }; + + virtual ostream &dump(ostream &os); + virtual int expand_variables(void); + virtual int gen_policy_re(Profile &prof); + virtual void post_process(Profile &prof unused) { }; + +protected: + virtual void warn_once(const char *name) override; + void validate_qname(void); +}; + +#endif /* __AA_MQUEUE_H */ diff --git a/parser/parser.h b/parser/parser.h index 992e3d833..a2e1a30be 100644 --- a/parser/parser.h +++ b/parser/parser.h @@ -345,6 +345,8 @@ extern int features_supports_unix; extern int features_supports_stacking; extern int features_supports_domain_xattr; extern int features_supports_userns; +extern int features_supports_posix_mqueue; +extern int features_supports_sysv_mqueue; extern int kernel_supports_oob; extern int conf_verbose; extern int conf_quiet; diff --git a/parser/parser_common.c b/parser/parser_common.c index db3d7b357..3f798ecfc 100644 --- a/parser/parser_common.c +++ b/parser/parser_common.c @@ -79,6 +79,8 @@ int features_supports_ptrace = 0; /* kernel supports ptrace rules */ int features_supports_stacking = 0; /* kernel supports stacking */ int features_supports_domain_xattr = 0; /* x attachment cond */ int features_supports_userns = 0; /* kernel supports user namespace */ +int features_supports_posix_mqueue = 0; /* kernel supports mqueue rules */ +int features_supports_sysv_mqueue = 0; /* kernel supports mqueue rules */ int kernel_supports_oob = 0; /* out of band transitions */ int conf_verbose = 0; int conf_quiet = 0; diff --git a/parser/parser_lex.l b/parser/parser_lex.l index 7798d8833..1a07ca91c 100644 --- a/parser/parser_lex.l +++ b/parser/parser_lex.l @@ -328,6 +328,7 @@ GT > %x INCLUDE_EXISTS %x ABI_MODE %x USERNS_MODE +%x MQUEUE_MODE %% @@ -340,7 +341,7 @@ GT > } %} -{ +{ {WS}+ { DUMP_PREPROCESS; /* Ignoring whitespace */ } } @@ -376,7 +377,7 @@ GT > yyterminate(); } -{ +{ (peer|xattrs)/{WS}*={WS}*\( { /* we match to the = in the lexer so that we can switch scanner * state. By the time the parser see the = it may be too late @@ -560,17 +561,25 @@ GT > listen { RETURN_TOKEN(TOK_LISTEN); } accept { RETURN_TOKEN(TOK_ACCEPT); } connect { RETURN_TOKEN(TOK_CONNECT); } - getattr { RETURN_TOKEN(TOK_GETATTR); } - setattr { RETURN_TOKEN(TOK_SETATTR); } getopt { RETURN_TOKEN(TOK_GETOPT); } setopt { RETURN_TOKEN(TOK_SETOPT); } shutdown { RETURN_TOKEN(TOK_SHUTDOWN); } } -{ +{ create { RETURN_TOKEN(TOK_CREATE); } } +{ + open { RETURN_TOKEN(TOK_OPEN); } + delete { RETURN_TOKEN(TOK_DELETE); } +} + +{ + getattr { RETURN_TOKEN(TOK_GETATTR); } + setattr { RETURN_TOKEN(TOK_SETATTR); } +} + { bind { RETURN_TOKEN(TOK_BIND); } } @@ -590,7 +599,7 @@ GT > tracedby { RETURN_TOKEN(TOK_TRACEDBY); } } -{ +{ read { RETURN_TOKEN(TOK_READ); } write { RETURN_TOKEN(TOK_WRITE); } {OPEN_PAREN} { @@ -606,7 +615,7 @@ GT > {ARROW} { RETURN_TOKEN(TOK_ARROW); } } -{ +{ ({IDS_NOEQ}|{LABEL}|{QUOTED_ID}) { yylval.id = processid(yytext, yyleng); RETURN_TOKEN(TOK_ID); @@ -731,13 +740,16 @@ include/{WS} { case TOK_USERNS: state = USERNS_MODE; break; + case TOK_MQUEUE: + state = MQUEUE_MODE; + break; default: /* nothing */ break; } PUSH_AND_RETURN(state, token); } -{ +{ {END_OF_RULE} { if (YY_START != INITIAL) POP_NODUMP(); @@ -745,14 +757,14 @@ include/{WS} { } } -{ +{ \r?\n { DUMP_PREPROCESS; current_lineno++; } } -{ +{ (.|\n) { DUMP_PREPROCESS; /* Something we didn't expect */ @@ -788,4 +800,5 @@ unordered_map state_names = { STATE_TABLE_ENT(INCLUDE_EXISTS), STATE_TABLE_ENT(ABI_MODE), STATE_TABLE_ENT(USERNS_MODE), + STATE_TABLE_ENT(MQUEUE_MODE), }; diff --git a/parser/parser_main.c b/parser/parser_main.c index 9d9d70e37..83597ebdd 100644 --- a/parser/parser_main.c +++ b/parser/parser_main.c @@ -944,6 +944,12 @@ void set_supported_features() features_supports_userns = features_intersect(kernel_features, policy_features, "namespaces/mask/userns_create"); + features_supports_posix_mqueue = features_intersect(kernel_features, + policy_features, + "ipc/posix_mqueue"); + features_supports_sysv_mqueue = features_intersect(kernel_features, + policy_features, + "ipc/sysv_mqueue"); } static bool do_print_cache_dir(aa_features *features, int dirfd, const char *path) diff --git a/parser/parser_misc.c b/parser/parser_misc.c index 3b7aee75e..36d847ca2 100644 --- a/parser/parser_misc.c +++ b/parser/parser_misc.c @@ -121,6 +121,9 @@ static struct keyword_table keyword_table[] = { {"readby", TOK_READBY}, {"abi", TOK_ABI}, {"userns", TOK_USERNS}, + {"mqueue", TOK_MQUEUE}, + {"delete", TOK_DELETE}, + {"open", TOK_OPEN}, /* terminate */ {NULL, 0} diff --git a/parser/parser_regex.c b/parser/parser_regex.c index 9c614157a..8cd8f15d3 100644 --- a/parser/parser_regex.c +++ b/parser/parser_regex.c @@ -936,6 +936,8 @@ static const char *mediates_extended_net = CLASS_STR(AA_CLASS_NET); static const char *mediates_netv8 = CLASS_STR(AA_CLASS_NETV8); static const char *mediates_net_unix = CLASS_SUB_STR(AA_CLASS_NET, AF_UNIX); static const char *mediates_ns = CLASS_STR(AA_CLASS_NS); +static const char *mediates_posix_mqueue = CLASS_STR(AA_CLASS_POSIX_MQUEUE); +static const char *mediates_sysv_mqueue = CLASS_STR(AA_CLASS_SYSV_MQUEUE); int process_profile_policydb(Profile *prof) { @@ -981,6 +983,12 @@ int process_profile_policydb(Profile *prof) if (features_supports_userns && !prof->policy.rules->add_rule(mediates_ns, 0, AA_MAY_READ, 0, dfaflags)) goto out; + if (features_supports_posix_mqueue && + !prof->policy.rules->add_rule(mediates_posix_mqueue, 0, AA_MAY_READ, 0, dfaflags)) + goto out; + if (features_supports_sysv_mqueue && + !prof->policy.rules->add_rule(mediates_sysv_mqueue, 0, AA_MAY_READ, 0, dfaflags)) + goto out; if (prof->policy.rules->rule_count > 0) { int xmatch_len = 0; diff --git a/parser/parser_yacc.y b/parser/parser_yacc.y index 1ea38363b..3f516ce5c 100644 --- a/parser/parser_yacc.y +++ b/parser/parser_yacc.y @@ -143,6 +143,8 @@ void add_local_entry(Profile *prof); %token TOK_READBY %token TOK_ABI %token TOK_USERNS +%token TOK_MQUEUE +%token TOK_DELETE /* rlimits */ %token TOK_RLIMIT @@ -179,6 +181,7 @@ void add_local_entry(Profile *prof); #include "ptrace.h" #include "af_unix.h" #include "userns.h" + #include "mqueue.h" } %union { @@ -196,6 +199,7 @@ void add_local_entry(Profile *prof); ptrace_rule *ptrace_entry; unix_rule *unix_entry; userns_rule *userns_entry; + mqueue_rule *mqueue_entry; flagvals flags; int fmode; @@ -279,6 +283,10 @@ void add_local_entry(Profile *prof); %type userns_perms %type opt_userns_perm %type userns_rule +%type mqueue_perm +%type mqueue_perms +%type opt_mqueue_perm +%type mqueue_rule %% @@ -920,6 +928,22 @@ rules: rules opt_prefix capability $$ = $1; }; +rules: rules opt_prefix mqueue_rule + { + if ($2.owner) + yyerror(_("owner prefix not allowed on mqueue rules")); //is this true? + if ($2.deny && $2.audit) { + $3->deny = 1; + } else if ($2.deny) { + $3->deny = 1; + $3->audit = $3->mode; + } else if ($2.audit) { + $3->audit = $3->mode; + } + $1->rule_ents.push_back($3); + $$ = $1; + }; + rules: rules hat { PDEBUG("Matched: hat rule\n"); @@ -1591,6 +1615,62 @@ userns_rule: TOK_USERNS opt_userns_perm opt_conds TOK_END_OF_RULE $$ = ent; } +mqueue_perm: TOK_VALUE + { + if (strcmp($1, "create") == 0) + $$ = AA_MQUEUE_CREATE; + else if (strcmp($1, "open") == 0) + $$ = AA_MQUEUE_OPEN; + else if (strcmp($1, "delete") == 0) + $$ = AA_MQUEUE_DELETE; + else if (strcmp($1, "getattr") == 0) + $$ = AA_MQUEUE_GETATTR; + else if (strcmp($1, "setattr") == 0) + $$ = AA_MQUEUE_SETATTR; + else if (strcmp($1, "write") == 0) + $$ = AA_MQUEUE_WRITE; + else if (strcmp($1, "read") == 0) + $$ = AA_MQUEUE_READ; + else if ($1) { + parse_mqueue_mode($1, &$$, 1); + } else + $$ = 0; + + if ($1) + free($1); + } + | TOK_CREATE { $$ = AA_MQUEUE_CREATE; } + | TOK_OPEN { $$ = AA_MQUEUE_OPEN; } + | TOK_DELETE { $$ = AA_MQUEUE_DELETE; } + | TOK_GETATTR { $$ = AA_MQUEUE_GETATTR; } + | TOK_SETATTR { $$ = AA_MQUEUE_SETATTR; } + | TOK_WRITE { $$ = AA_MQUEUE_WRITE; } + | TOK_READ { $$ = AA_MQUEUE_READ; } + | TOK_MODE + { + parse_mqueue_mode($1, &$$, 1); + free($1); + } + +mqueue_perms: { /* nothing */ $$ = 0; } + | mqueue_perms mqueue_perm { $$ = $1 | $2; } + | mqueue_perms TOK_COMMA mqueue_perm { $$ = $1 | $3; } + +opt_mqueue_perm: { /* nothing */ $$ = 0; } + | mqueue_perm { $$ = $1; } + | TOK_OPENPAREN mqueue_perms TOK_CLOSEPAREN { $$ = $2; } + +mqueue_rule: TOK_MQUEUE opt_mqueue_perm opt_conds TOK_END_OF_RULE + { + mqueue_rule *ent = new mqueue_rule($2, $3); + $$ = ent; + } + | TOK_MQUEUE opt_mqueue_perm opt_conds TOK_ID TOK_END_OF_RULE + { + mqueue_rule *ent = new mqueue_rule($2, $3, $4); + $$ = ent; + } + hat_start: TOK_CARET {} | TOK_HAT {} diff --git a/parser/policydb.h b/parser/policydb.h index 4d7420d51..860b4278d 100644 --- a/parser/policydb.h +++ b/parser/policydb.h @@ -34,6 +34,8 @@ #define AA_CLASS_SIGNAL 10 #define AA_CLASS_NETV8 14 #define AA_CLASS_LABEL 16 +#define AA_CLASS_POSIX_MQUEUE 17 +#define AA_CLASS_SYSV_MQUEUE 18 #define AA_CLASS_NS 21 /* defined in libapparmor's apparmor.h #define AA_CLASS_DBUS 32 */