parser: add parser support for message queue mediation

Message queue rules take the following format:

	mqueue [<access_mode>] [<type>] [<label>] [<mqueue name>],
	access_mode := 'r'|'w'|'rw'|'read'|'write'|
		       'create'|'open'|'delete'|
		       'getattr'|'setattr'
	type := 'type' '=' ('posix'|'sysv')
	label := 'label' '=' <target label>

Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
Signed-off-by: John Johansen <john.johansen@canonical.com>
This commit is contained in:
Georgia Garcia 2022-02-07 19:15:11 -03:00
parent f03a3198a8
commit d98c5c4cf9
13 changed files with 576 additions and 13 deletions

1
.gitignore vendored
View file

@ -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

View file

@ -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 $@

View file

@ -123,7 +123,7 @@ B<RULES> = [ ( I<LINE RULES> | I<COMMA RULES> ',' | I<BLOCK RULES> )
B<LINE RULES> = ( I<COMMENT> | I<INCLUDE> ) [ '\r' ] '\n'
B<COMMA RULES> = ( I<CAPABILITY RULE> | I<NETWORK RULE> | I<MOUNT RULE> | I<PIVOT ROOT RULE> | I<UNIX RULE> | I<FILE RULE> | I<LINK RULE> | I<CHANGE_PROFILE RULE> | I<RLIMIT RULE> | I<DBUS RULE> )
B<COMMA RULES> = ( I<CAPABILITY RULE> | I<NETWORK RULE> | I<MOUNT RULE> | I<PIVOT ROOT RULE> | I<UNIX RULE> | I<FILE RULE> | I<LINK RULE> | I<CHANGE_PROFILE RULE> | I<RLIMIT RULE> | I<DBUS RULE> | I<MQUEUE RULE> )
B<BLOCK RULES> = ( I<SUBPROFILE> | I<HAT> | I<QUALIFIER BLOCK> )
@ -176,6 +176,20 @@ B<MOUNT FLAGS> = ( 'ro' | 'rw' | 'nosuid' | 'suid' | 'nodev' | 'dev' | 'noexec'
B<MOUNT EXPRESSION> = ( I<ALPHANUMERIC> | I<AARE> ) ...
B<MQUEUE_RULE> = [ I<QUALIFIERS> ] 'mqueue' [ I<MQUEUE ACCESS PERMISSIONS> ] [ I<MQUEUE TYPE> ] [ I<MQUEUE LABEL> ] [ I<MQUEUE NAME> ]
B<MQUEUE ACCESS PERMISSIONS> = I<MQUEUE ACCESS> | I<MQUEUE ACCESS LIST>
B<MQUEUE ACCESS LIST> = '(' Comma or space separated list of I<MQUEUE ACCESS> ')'
B<MQUEUE ACCESS> = ( 'r' | 'w' | 'rw' | 'read' | 'write' | 'create' | 'open' | 'delete' | 'getattr' | 'setattr' )
B<MQUEUE TYPE> = 'type' '=' ( 'posix' | 'sysv' )
B<MQUEUE LABEL> = 'label' '=' '(' '"' I<AARE> '"' | I<AARE> ')'
B<MQUEUE NAME> = I<AARE>
B<PIVOT ROOT RULE> = [ I<QUALIFIERS> ] pivot_root [ oldroot=I<OLD PUT FILEGLOB> ] [ I<NEW ROOT FILEGLOB> ] [ '-E<gt>' I<PROFILE NAME> ]
B<SOURCE FILEGLOB> = I<FILEGLOB>
@ -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)

272
parser/mqueue.cc Normal file
View file

@ -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 <iomanip>
#include <string>
#include <iostream>
#include <sstream>
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;
}

111
parser/mqueue.h Normal file
View file

@ -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 */

View file

@ -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;

View file

@ -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;

View file

@ -328,6 +328,7 @@ GT >
%x INCLUDE_EXISTS
%x ABI_MODE
%x USERNS_MODE
%x MQUEUE_MODE
%%
@ -340,7 +341,7 @@ GT >
}
%}
<INITIAL,SUB_ID_WS,INCLUDE,INCLUDE_EXISTS,LIST_VAL_MODE,EXTCOND_MODE,LIST_COND_VAL,LIST_COND_PAREN_VAL,LIST_COND_MODE,EXTCONDLIST_MODE,ASSIGN_MODE,NETWORK_MODE,CHANGE_PROFILE_MODE,RLIMIT_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,ABI_MODE,USERNS_MODE>{
<INITIAL,SUB_ID_WS,INCLUDE,INCLUDE_EXISTS,LIST_VAL_MODE,EXTCOND_MODE,LIST_COND_VAL,LIST_COND_PAREN_VAL,LIST_COND_MODE,EXTCONDLIST_MODE,ASSIGN_MODE,NETWORK_MODE,CHANGE_PROFILE_MODE,RLIMIT_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,ABI_MODE,USERNS_MODE,MQUEUE_MODE>{
{WS}+ { DUMP_PREPROCESS; /* Ignoring whitespace */ }
}
@ -376,7 +377,7 @@ GT >
yyterminate();
}
<INITIAL,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE>{
<INITIAL,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,MQUEUE_MODE>{
(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); }
}
<UNIX_MODE,USERNS_MODE>{
<UNIX_MODE,USERNS_MODE,MQUEUE_MODE>{
create { RETURN_TOKEN(TOK_CREATE); }
}
<MQUEUE_MODE>{
open { RETURN_TOKEN(TOK_OPEN); }
delete { RETURN_TOKEN(TOK_DELETE); }
}
<UNIX_MODE,MQUEUE_MODE>{
getattr { RETURN_TOKEN(TOK_GETATTR); }
setattr { RETURN_TOKEN(TOK_SETATTR); }
}
<DBUS_MODE,UNIX_MODE>{
bind { RETURN_TOKEN(TOK_BIND); }
}
@ -590,7 +599,7 @@ GT >
tracedby { RETURN_TOKEN(TOK_TRACEDBY); }
}
<DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE>{
<DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,MQUEUE_MODE>{
read { RETURN_TOKEN(TOK_READ); }
write { RETURN_TOKEN(TOK_WRITE); }
{OPEN_PAREN} {
@ -606,7 +615,7 @@ GT >
{ARROW} { RETURN_TOKEN(TOK_ARROW); }
}
<MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE>{
<MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,MQUEUE_MODE>{
({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);
}
<INITIAL,NETWORK_MODE,RLIMIT_MODE,CHANGE_PROFILE_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,ABI_MODE,USERNS_MODE>{
<INITIAL,NETWORK_MODE,RLIMIT_MODE,CHANGE_PROFILE_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,ABI_MODE,USERNS_MODE,MQUEUE_MODE>{
{END_OF_RULE} {
if (YY_START != INITIAL)
POP_NODUMP();
@ -745,14 +757,14 @@ include/{WS} {
}
}
<INITIAL,SUB_ID_WS,INCLUDE,INCLUDE_EXISTS,LIST_VAL_MODE,EXTCOND_MODE,LIST_COND_VAL,LIST_COND_PAREN_VAL,LIST_COND_MODE,EXTCONDLIST_MODE,NETWORK_MODE,CHANGE_PROFILE_MODE,RLIMIT_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,ABI_MODE,USERNS_MODE>{
<INITIAL,SUB_ID_WS,INCLUDE,INCLUDE_EXISTS,LIST_VAL_MODE,EXTCOND_MODE,LIST_COND_VAL,LIST_COND_PAREN_VAL,LIST_COND_MODE,EXTCONDLIST_MODE,NETWORK_MODE,CHANGE_PROFILE_MODE,RLIMIT_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,ABI_MODE,USERNS_MODE,MQUEUE_MODE>{
\r?\n {
DUMP_PREPROCESS;
current_lineno++;
}
}
<INITIAL,SUB_ID,SUB_ID_WS,SUB_VALUE,LIST_VAL_MODE,EXTCOND_MODE,LIST_COND_VAL,LIST_COND_PAREN_VAL,LIST_COND_MODE,EXTCONDLIST_MODE,ASSIGN_MODE,NETWORK_MODE,CHANGE_PROFILE_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,RLIMIT_MODE,INCLUDE,INCLUDE_EXISTS,ABI_MODE,USERNS_MODE>{
<INITIAL,SUB_ID,SUB_ID_WS,SUB_VALUE,LIST_VAL_MODE,EXTCOND_MODE,LIST_COND_VAL,LIST_COND_PAREN_VAL,LIST_COND_MODE,EXTCONDLIST_MODE,ASSIGN_MODE,NETWORK_MODE,CHANGE_PROFILE_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,RLIMIT_MODE,INCLUDE,INCLUDE_EXISTS,ABI_MODE,USERNS_MODE,MQUEUE_MODE>{
(.|\n) {
DUMP_PREPROCESS;
/* Something we didn't expect */
@ -788,4 +800,5 @@ unordered_map<int, string> state_names = {
STATE_TABLE_ENT(INCLUDE_EXISTS),
STATE_TABLE_ENT(ABI_MODE),
STATE_TABLE_ENT(USERNS_MODE),
STATE_TABLE_ENT(MQUEUE_MODE),
};

View file

@ -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)

View file

@ -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}

View file

@ -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;

View file

@ -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 <fmode> userns_perms
%type <fmode> opt_userns_perm
%type <userns_entry> userns_rule
%type <fmode> mqueue_perm
%type <fmode> mqueue_perms
%type <fmode> opt_mqueue_perm
%type <mqueue_entry> 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 {}

View file

@ -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 */