mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-08-31 06:16:03 +00:00
Merge Cleanup parser frontend in preparation for extended permissions
The parser front end is inconsistent about how it handles permissions and rules. This makes extending the permission set and fixing inconsistencies between say file and af_unix rules difficult and prone to failures. This is a set of work to cleanup the frontend parse handling, and middle semantic checks, dedup, and processing of rules and their permissions. It also is starting to lay the ground work for the parser retaining more information to output better error, and debug messages. Signed-off-by: John Johansen <john.johansen@canonical.com> MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/802 Approved-by: Georgia Garcia <georgia.garcia@canonical.com> Merged-by: John Johansen <john@jjmx.net>
This commit is contained in:
@@ -103,9 +103,16 @@ SRCS = parser_common.c parser_include.c parser_interface.c parser_lex.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 \
|
||||
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 mqueue.h
|
||||
STATIC_HDRS = af_rule.h af_unix.h capability.h common_optarg.h dbus.h \
|
||||
file_cache.h immunix.h lib.h mount.h network.h parser.h \
|
||||
parser_include.h parser_version.h policy_cache.h policydb.h \
|
||||
profile.h ptrace.h rule.h signal.h userns.h mqueue.h
|
||||
|
||||
SPECIAL_HDRS = parser_yacc.h unit_test.h base_cap_names.h
|
||||
GENERATED_HDRS = af_names.h generated_af_names.h \
|
||||
cap_names.h generated_cap_names.h parser_version.h
|
||||
LIBAA_HDRS = libapparmor_re/apparmor_re.h libapparmor_re/aare_rules.h
|
||||
|
||||
TOOLS = apparmor_parser
|
||||
|
||||
OBJECTS = $(patsubst %.cc, %.o, $(SRCS:.c=.o))
|
||||
@@ -167,8 +174,11 @@ else
|
||||
endif
|
||||
export Q VERBOSE BUILD_OUTPUT
|
||||
|
||||
po/${NAME}.pot: ${SRCS} ${HDRS}
|
||||
$(MAKE) -C po ${NAME}.pot NAME=${NAME} SOURCES="${SRCS} ${HDRS}"
|
||||
HDRS=$(STATIC_HDRS) $(GENERATED_HDRS) parser_yacc.h $(LIBAA_HDRS) $(APPARMOR_H)
|
||||
|
||||
|
||||
po/${NAME}.pot: ${SRCS} ${STATIC_HDRS}
|
||||
$(MAKE) -C po ${NAME}.pot NAME=${NAME} SOURCES="${SRCS} ${STATIC_HDRS}"
|
||||
|
||||
techdoc.pdf: techdoc.tex
|
||||
timestamp=$(shell date --utc "+%Y%m%d%H%M%S%z" -r $< );\
|
||||
@@ -218,94 +228,94 @@ apparmor_parser: $(OBJECTS) $(AAREOBJECTS) $(LIBAPPARMOR_A)
|
||||
$(CXX) $(LDFLAGS) $(EXTRA_CFLAGS) -o $@ $(OBJECTS) $(LIBS) \
|
||||
${LEXLIB} $(AAREOBJECTS) $(AARE_LDFLAGS) $(AALIB)
|
||||
|
||||
parser_yacc.c parser_yacc.h: parser_yacc.y parser.h profile.h file_cache.h
|
||||
parser_yacc.c parser_yacc.h: parser_yacc.y $(STATIC_HDRS) $(DYNAMIC_HDRS)
|
||||
$(YACC) $(YFLAGS) -o parser_yacc.c parser_yacc.y
|
||||
|
||||
parser_lex.c: parser_lex.l parser_yacc.h parser.h profile.h mount.h dbus.h policy_cache.h file_cache.h
|
||||
parser_lex.c: parser_lex.l $(HDRS)
|
||||
$(LEX) ${LEXFLAGS} -o$@ $<
|
||||
|
||||
parser_lex.o: parser_lex.c parser.h parser_yacc.h
|
||||
parser_lex.o: parser_lex.c $(HDRS)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_misc.o: parser_misc.c parser.h parser_yacc.h profile.h cap_names.h $(APPARMOR_H)
|
||||
parser_misc.o: parser_misc.c $(HDRS) unit_test.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_yacc.o: parser_yacc.c parser_yacc.h $(APPARMOR_H)
|
||||
parser_yacc.o: parser_yacc.c $(HDRS)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_main.o: parser_main.c parser.h parser_version.h policy_cache.h file_cache.h libapparmor_re/apparmor_re.h $(APPARMOR_H)
|
||||
parser_main.o: parser_main.c $(HDRS)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_interface.o: parser_interface.c parser.h profile.h libapparmor_re/apparmor_re.h
|
||||
parser_interface.o: parser_interface.c $(HDRS)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_include.o: parser_include.c parser.h parser_include.h file_cache.h
|
||||
parser_include.o: parser_include.c $(HDRS)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_merge.o: parser_merge.c parser.h profile.h
|
||||
parser_merge.o: parser_merge.c $(HDRS)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_regex.o: parser_regex.c parser.h profile.h libapparmor_re/apparmor_re.h libapparmor_re/aare_rules.h $(APPARMOR_H)
|
||||
parser_regex.o: parser_regex.c $(HDRS) unit_test.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_symtab.o: parser_symtab.c parser.h
|
||||
parser_symtab.o: parser_symtab.c $(HDRS) unit_test.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_variable.o: parser_variable.c parser.h profile.h
|
||||
parser_variable.o: parser_variable.c $(HDRS) unit_test.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_policy.o: parser_policy.c parser.h parser_yacc.h profile.h
|
||||
parser_policy.o: parser_policy.c $(HDRS)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_alias.o: parser_alias.c parser.h profile.h
|
||||
parser_alias.o: parser_alias.c $(HDRS)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_common.o: parser_common.c parser.h file_cache.h
|
||||
parser_common.o: parser_common.c $(HDRS)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
mount.o: mount.cc mount.h parser.h immunix.h rule.h
|
||||
mount.o: mount.cc mount.h $(HDRS)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
common_optarg.o: common_optarg.c common_optarg.h parser.h libapparmor_re/apparmor_re.h
|
||||
common_optarg.o: common_optarg.c $(HDRS)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
policy_cache.o: policy_cache.c policy_cache.h parser.h lib.h
|
||||
policy_cache.o: policy_cache.c $(HDRS)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
lib.o: lib.c lib.h parser.h
|
||||
lib.o: lib.c $(HDRS) unit_test.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
dbus.o: dbus.cc dbus.h parser.h immunix.h parser_yacc.h rule.h $(APPARMOR_H)
|
||||
dbus.o: dbus.cc $(HDRS)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
signal.o: signal.cc signal.h parser.h immunix.h parser_yacc.h rule.h $(APPARMOR_H)
|
||||
signal.o: signal.cc $(HDRS)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
ptrace.o: ptrace.cc ptrace.h parser.h immunix.h parser_yacc.h rule.h $(APPARMOR_H)
|
||||
ptrace.o: ptrace.cc $(HDRS)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
network.o: network.c network.h parser.h immunix.h parser_yacc.h rule.h af_names.h $(APPARMOR_H)
|
||||
network.o: network.c $(HDRS)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
default_features.o: default_features.c parser.h
|
||||
default_features.o: default_features.c $(HDRS)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
af_rule.o: af_rule.cc af_rule.h network.h parser.h profile.h immunix.h parser_yacc.h rule.h $(APPARMOR_H)
|
||||
af_rule.o: af_rule.cc $(HDRS)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
af_unix.o: af_unix.cc af_unix.h network.h af_rule.h parser.h profile.h immunix.h parser_yacc.h $(APPARMOR_H)
|
||||
af_unix.o: af_unix.cc $(HDRS)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
profile.o: profile.cc profile.h parser.h network.h
|
||||
profile.o: profile.cc $(HDRS)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
rule.o: rule.cc rule.h policydb.h
|
||||
rule.o: rule.cc $(HDRS)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
userns.o: userns.cc userns.h parser.h parser_yacc.h rule.h $(APPARMOR_H)
|
||||
userns.o: userns.cc $(HDRS)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
mqueue.o: mqueue.cc mqueue.h parser.h immunix.h profile.h parser_yacc.h rule.h $(APPARMOR_H)
|
||||
mqueue.o: mqueue.cc $(HDRS)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_version.h: Makefile
|
||||
@@ -320,7 +330,7 @@ generated_af_names.h: ../common/list_af_names.sh
|
||||
../common/list_af_names.sh > $@
|
||||
|
||||
af_names.h: generated_af_names.h base_af_names.h
|
||||
cat base_af_names.h | diff -u - generated_af_names.h | grep -v '^.AF_MAX' | grep '^\+[^+]' ; \
|
||||
@cat base_af_names.h | diff -u - generated_af_names.h | grep -v '^.AF_MAX' | grep '^\+[^+]' ; \
|
||||
if [ $$? -eq 1 ] ; then \
|
||||
cat base_af_names.h | LC_ALL=C sed -n -e 's/[ \t]\?AF_MAX[ \t]\+[0-9]\+,//g' -e 's/[ \t]\+\?AF_\([A-Z0-9_]\+\)[ \t]\+\([0-9]\+\),/#ifndef AF_\1\n# define AF_\1 \2\n#endif\nAA_GEN_NET_ENT("\L\1", \UAF_\1)\n/pg' > $@ ; \
|
||||
cat base_af_names.h | LC_ALL=C sed -n -e 's/AF_MAX[ \t]\+\([0-9]\+\),\?.*/\n#define AA_AF_MAX \1\n/p' >> $@ ; \
|
||||
@@ -450,10 +460,8 @@ clean: pod_clean
|
||||
rm -f $(TOOLS) $(TESTS)
|
||||
rm -f $(LEX_C_FILES)
|
||||
rm -f $(YACC_C_FILES)
|
||||
rm -f parser_version.h
|
||||
rm -f $(NAME)*.tar.gz $(NAME)*.tgz
|
||||
rm -f af_names.h generated_af_names.h
|
||||
rm -f cap_names.h generated_cap_names.h
|
||||
rm -f $(GENERATED_HDRS)
|
||||
rm -rf techdoc.aux techdoc.out techdoc.log techdoc.pdf techdoc.toc techdoc.txt techdoc/
|
||||
$(MAKE) -s -C $(AAREDIR) clean
|
||||
$(MAKE) -s -C po clean
|
||||
|
@@ -90,43 +90,34 @@ int af_rule::move_base_cond(struct cond_entry *ent, bool peer)
|
||||
return true;
|
||||
}
|
||||
|
||||
ostream &af_rule::dump_prefix(ostream &os)
|
||||
{
|
||||
if (audit)
|
||||
os << "audit ";
|
||||
if (deny)
|
||||
os << "deny ";
|
||||
return os;
|
||||
}
|
||||
|
||||
ostream &af_rule::dump_local(ostream &os)
|
||||
{
|
||||
if (mode != AA_VALID_NET_PERMS) {
|
||||
if (perms != AA_VALID_NET_PERMS) {
|
||||
os << " (";
|
||||
|
||||
if (mode & AA_NET_SEND)
|
||||
if (perms & AA_NET_SEND)
|
||||
os << "send ";
|
||||
if (mode & AA_NET_RECEIVE)
|
||||
if (perms & AA_NET_RECEIVE)
|
||||
os << "receive ";
|
||||
if (mode & AA_NET_CREATE)
|
||||
if (perms & AA_NET_CREATE)
|
||||
os << "create ";
|
||||
if (mode & AA_NET_SHUTDOWN)
|
||||
if (perms & AA_NET_SHUTDOWN)
|
||||
os << "shutdown ";
|
||||
if (mode & AA_NET_CONNECT)
|
||||
if (perms & AA_NET_CONNECT)
|
||||
os << "connect ";
|
||||
if (mode & AA_NET_SETATTR)
|
||||
if (perms & AA_NET_SETATTR)
|
||||
os << "setattr ";
|
||||
if (mode & AA_NET_GETATTR)
|
||||
if (perms & AA_NET_GETATTR)
|
||||
os << "getattr ";
|
||||
if (mode & AA_NET_BIND)
|
||||
if (perms & AA_NET_BIND)
|
||||
os << "bind ";
|
||||
if (mode & AA_NET_ACCEPT)
|
||||
if (perms & AA_NET_ACCEPT)
|
||||
os << "accept ";
|
||||
if (mode & AA_NET_LISTEN)
|
||||
if (perms & AA_NET_LISTEN)
|
||||
os << "listen ";
|
||||
if (mode & AA_NET_SETOPT)
|
||||
if (perms & AA_NET_SETOPT)
|
||||
os << "setopt ";
|
||||
if (mode & AA_NET_GETOPT)
|
||||
if (perms & AA_NET_GETOPT)
|
||||
os << "getopt ";
|
||||
os << ")";
|
||||
}
|
||||
@@ -148,8 +139,8 @@ ostream &af_rule::dump_peer(ostream &os)
|
||||
|
||||
ostream &af_rule::dump(ostream &os)
|
||||
{
|
||||
dump_prefix(os);
|
||||
os << af_name;
|
||||
prefix_rule_t::dump(os);
|
||||
os << af_name();
|
||||
dump_local(os);
|
||||
if (has_peer_conds()) {
|
||||
os << " peer=(";
|
||||
|
@@ -25,6 +25,8 @@
|
||||
|
||||
#include "rule.h"
|
||||
|
||||
#define AF_ANY -1
|
||||
|
||||
enum cond_side { local_cond, peer_cond, either_cond };
|
||||
|
||||
struct supported_cond {
|
||||
@@ -35,23 +37,21 @@ struct supported_cond {
|
||||
enum cond_side side ;
|
||||
};
|
||||
|
||||
class af_rule: public rule_t {
|
||||
class af_rule: public perms_rule_t {
|
||||
public:
|
||||
std::string af_name;
|
||||
int af;
|
||||
char *sock_type;
|
||||
int sock_type_n;
|
||||
char *proto;
|
||||
int proto_n;
|
||||
char *label;
|
||||
char *peer_label;
|
||||
int mode;
|
||||
int audit;
|
||||
bool deny;
|
||||
|
||||
af_rule(const char *name): af_name(name), sock_type(NULL),
|
||||
af_rule(int f):
|
||||
perms_rule_t(AA_CLASS_NET),
|
||||
af(f), sock_type(NULL),
|
||||
sock_type_n(-1), proto(NULL), proto_n(0), label(NULL),
|
||||
peer_label(NULL), mode(0), audit(0), deny(0)
|
||||
{}
|
||||
peer_label(NULL) { }
|
||||
|
||||
virtual ~af_rule()
|
||||
{
|
||||
@@ -61,18 +61,21 @@ public:
|
||||
free(peer_label);
|
||||
};
|
||||
|
||||
const char *af_name(void) {
|
||||
if (af != AF_ANY)
|
||||
return net_find_af_name(af);
|
||||
return "*";
|
||||
}
|
||||
bool cond_check(struct supported_cond *cond, struct cond_entry *ent,
|
||||
bool peer, const char *rname);
|
||||
int move_base_cond(struct cond_entry *conds, bool peer);
|
||||
|
||||
virtual bool has_peer_conds(void) { return peer_label ? true : false; }
|
||||
virtual ostream &dump_prefix(ostream &os);
|
||||
virtual ostream &dump_local(ostream &os);
|
||||
virtual ostream &dump_peer(ostream &os);
|
||||
virtual ostream &dump(ostream &os);
|
||||
virtual int expand_variables(void);
|
||||
virtual int gen_policy_re(Profile &prof) = 0;
|
||||
virtual void post_process(Profile &prof unused) { };
|
||||
};
|
||||
|
||||
#endif /* __AA_AF_RULE_H */
|
||||
|
@@ -32,9 +32,9 @@
|
||||
/* See unix(7) for autobind address definition */
|
||||
#define autobind_address_pattern "\\x00[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]";
|
||||
|
||||
int parse_unix_mode(const char *str_mode, int *mode, int fail)
|
||||
int parse_unix_perms(const char *str_perms, perms_t *perms, int fail)
|
||||
{
|
||||
return parse_X_mode("unix", AA_VALID_NET_PERMS, str_mode, mode, fail);
|
||||
return parse_X_perms("unix", AA_VALID_NET_PERMS, str_perms, perms, fail);
|
||||
}
|
||||
|
||||
|
||||
@@ -95,8 +95,8 @@ void unix_rule::move_peer_conditionals(struct cond_entry *conds)
|
||||
}
|
||||
}
|
||||
|
||||
unix_rule::unix_rule(unsigned int type_p, bool audit_p, bool denied):
|
||||
af_rule("unix"), addr(NULL), peer_addr(NULL)
|
||||
unix_rule::unix_rule(unsigned int type_p, audit_t audit_p, rule_mode_t rule_mode_p):
|
||||
af_rule(AF_UNIX), addr(NULL), peer_addr(NULL)
|
||||
{
|
||||
if (type_p != 0xffffffff) {
|
||||
sock_type_n = type_p;
|
||||
@@ -104,26 +104,26 @@ unix_rule::unix_rule(unsigned int type_p, bool audit_p, bool denied):
|
||||
if (!sock_type)
|
||||
yyerror("socket rule: invalid socket type '%d'", type_p);
|
||||
}
|
||||
mode = AA_VALID_NET_PERMS;
|
||||
audit = audit_p ? AA_VALID_NET_PERMS : 0;
|
||||
deny = denied;
|
||||
perms = AA_VALID_NET_PERMS;
|
||||
audit = audit_p;
|
||||
rule_mode = rule_mode_p;
|
||||
}
|
||||
|
||||
unix_rule::unix_rule(int mode_p, struct cond_entry *conds,
|
||||
unix_rule::unix_rule(perms_t perms_p, struct cond_entry *conds,
|
||||
struct cond_entry *peer_conds):
|
||||
af_rule("unix"), addr(NULL), peer_addr(NULL)
|
||||
af_rule(AF_UNIX), addr(NULL), peer_addr(NULL)
|
||||
{
|
||||
move_conditionals(conds);
|
||||
move_peer_conditionals(peer_conds);
|
||||
|
||||
if (mode_p) {
|
||||
mode = mode_p;
|
||||
if (mode & ~AA_VALID_NET_PERMS)
|
||||
yyerror("mode contains invalid permissions for unix socket rules\n");
|
||||
else if ((mode & ~AA_PEER_NET_PERMS) && has_peer_conds())
|
||||
if (perms_p) {
|
||||
perms = perms_p;
|
||||
if (perms & ~AA_VALID_NET_PERMS)
|
||||
yyerror("perms contains invalid permissions for unix socket rules\n");
|
||||
else if ((perms & ~AA_PEER_NET_PERMS) && has_peer_conds())
|
||||
yyerror("unix socket 'create', 'shutdown', 'setattr', 'getattr', 'bind', 'listen', 'setopt', and/or 'getopt' accesses cannot be used with peer socket conditionals\n");
|
||||
} else {
|
||||
mode = AA_VALID_NET_PERMS;
|
||||
perms = AA_VALID_NET_PERMS;
|
||||
}
|
||||
|
||||
free_cond_list(conds);
|
||||
@@ -187,15 +187,15 @@ static void writeu16(std::ostringstream &o, int v)
|
||||
#define CMD_OPT 4
|
||||
|
||||
void unix_rule::downgrade_rule(Profile &prof) {
|
||||
unsigned int mask = (unsigned int) -1;
|
||||
perms_t mask = (perms_t) -1;
|
||||
|
||||
if (!prof.net.allow && !prof.alloc_net_table())
|
||||
yyerror(_("Memory allocation error."));
|
||||
if (sock_type_n != -1)
|
||||
mask = 1 << sock_type_n;
|
||||
if (!deny) {
|
||||
if (rule_mode != RULE_DENY) {
|
||||
prof.net.allow[AF_UNIX] |= mask;
|
||||
if (audit)
|
||||
if (audit == AUDIT_FORCE)
|
||||
prof.net.audit[AF_UNIX] |= mask;
|
||||
} else {
|
||||
/* deny rules have to be dropped because the downgrade makes
|
||||
@@ -309,7 +309,7 @@ int unix_rule::gen_policy_re(Profile &prof)
|
||||
std::ostringstream buffer;
|
||||
std::string buf;
|
||||
|
||||
int mask = mode;
|
||||
perms_t mask = perms;
|
||||
|
||||
/* always generate a downgraded rule. This doesn't change generated
|
||||
* policy size and allows the binary policy to be loaded against
|
||||
@@ -334,9 +334,9 @@ int unix_rule::gen_policy_re(Profile &prof)
|
||||
write_to_prot(buffer);
|
||||
if ((mask & AA_NET_CREATE) && !has_peer_conds()) {
|
||||
buf = buffer.str();
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(), deny,
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY,
|
||||
map_perms(AA_NET_CREATE),
|
||||
map_perms(audit & AA_NET_CREATE),
|
||||
map_perms(audit == AUDIT_FORCE ? AA_NET_CREATE : 0),
|
||||
dfaflags))
|
||||
goto fail;
|
||||
mask &= ~AA_NET_CREATE;
|
||||
@@ -359,9 +359,9 @@ int unix_rule::gen_policy_re(Profile &prof)
|
||||
tmp << "\\x00";
|
||||
|
||||
buf = tmp.str();
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(), deny,
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY,
|
||||
map_perms(AA_NET_BIND),
|
||||
map_perms(audit & AA_NET_BIND),
|
||||
map_perms(audit == AUDIT_FORCE ? AA_NET_BIND : 0),
|
||||
dfaflags))
|
||||
goto fail;
|
||||
/* clear if auto, else generic need to generate addr below */
|
||||
@@ -384,9 +384,9 @@ int unix_rule::gen_policy_re(Profile &prof)
|
||||
AA_LOCAL_NET_PERMS & ~AA_LOCAL_NET_CMD;
|
||||
if (mask & local_mask) {
|
||||
buf = buffer.str();
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(), deny,
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY,
|
||||
map_perms(mask & local_mask),
|
||||
map_perms(audit & local_mask),
|
||||
map_perms(audit == AUDIT_FORCE ? mask & local_mask : 0),
|
||||
dfaflags))
|
||||
goto fail;
|
||||
}
|
||||
@@ -398,9 +398,9 @@ int unix_rule::gen_policy_re(Profile &prof)
|
||||
/* TODO: backlog conditional: for now match anything*/
|
||||
tmp << "..";
|
||||
buf = tmp.str();
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(), deny,
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY,
|
||||
map_perms(AA_NET_LISTEN),
|
||||
map_perms(audit & AA_NET_LISTEN),
|
||||
map_perms(audit == AUDIT_FORCE ? AA_NET_LISTEN : 0),
|
||||
dfaflags))
|
||||
goto fail;
|
||||
}
|
||||
@@ -411,9 +411,9 @@ int unix_rule::gen_policy_re(Profile &prof)
|
||||
/* TODO: sockopt conditional: for now match anything */
|
||||
tmp << "..";
|
||||
buf = tmp.str();
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(), deny,
|
||||
map_perms(mask & AA_NET_OPT),
|
||||
map_perms(audit & AA_NET_OPT),
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY,
|
||||
map_perms(AA_NET_OPT),
|
||||
map_perms(audit == AUDIT_FORCE ? AA_NET_OPT : 0),
|
||||
dfaflags))
|
||||
goto fail;
|
||||
}
|
||||
@@ -432,7 +432,7 @@ int unix_rule::gen_policy_re(Profile &prof)
|
||||
goto fail;
|
||||
|
||||
buf = buffer.str();
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(), deny, map_perms(mode & AA_PEER_NET_PERMS), map_perms(audit), dfaflags))
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, map_perms(perms & AA_PEER_NET_PERMS), map_perms(audit == AUDIT_FORCE ? perms & AA_PEER_NET_PERMS : 0), dfaflags))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@@ -24,7 +24,7 @@
|
||||
#include "profile.h"
|
||||
#include "af_rule.h"
|
||||
|
||||
int parse_unix_mode(const char *str_mode, int *mode, int fail);
|
||||
int parse_unix_perms(const char *str_mode, perms_t *perms, int fail);
|
||||
|
||||
class unix_rule: public af_rule {
|
||||
void write_to_prot(std::ostringstream &buffer);
|
||||
@@ -37,8 +37,8 @@ public:
|
||||
char *addr;
|
||||
char *peer_addr;
|
||||
|
||||
unix_rule(unsigned int type_p, bool audit_p, bool denied);
|
||||
unix_rule(int mode, struct cond_entry *conds,
|
||||
unix_rule(unsigned int type_p, audit_t audit_p, rule_mode_t rule_mode_p);
|
||||
unix_rule(perms_t perms, struct cond_entry *conds,
|
||||
struct cond_entry *peer_conds);
|
||||
virtual ~unix_rule()
|
||||
{
|
||||
@@ -46,6 +46,13 @@ public:
|
||||
free(peer_addr);
|
||||
};
|
||||
|
||||
virtual bool valid_prefix(const prefixes &p, const char *&error) {
|
||||
if (p.owner) {
|
||||
error = "owner prefix not allowed on unix rules";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
virtual bool has_peer_conds(void) {
|
||||
return af_rule::has_peer_conds() || peer_addr;
|
||||
}
|
||||
@@ -54,7 +61,6 @@ public:
|
||||
virtual ostream &dump_peer(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;
|
||||
|
@@ -30,9 +30,9 @@
|
||||
#include "dbus.h"
|
||||
|
||||
|
||||
int parse_dbus_mode(const char *str_mode, int *mode, int fail)
|
||||
int parse_dbus_perms(const char *str_perms, perms_t *perms, int fail)
|
||||
{
|
||||
return parse_X_mode("DBus", AA_VALID_DBUS_PERMS, str_mode, mode, fail);
|
||||
return parse_X_perms("DBus", AA_VALID_DBUS_PERMS, str_perms, perms, fail);
|
||||
}
|
||||
|
||||
void dbus_rule::move_conditionals(struct cond_entry *conds)
|
||||
@@ -66,10 +66,9 @@ void dbus_rule::move_conditionals(struct cond_entry *conds)
|
||||
}
|
||||
}
|
||||
|
||||
dbus_rule::dbus_rule(int mode_p, struct cond_entry *conds,
|
||||
dbus_rule::dbus_rule(perms_t perms_p, struct cond_entry *conds,
|
||||
struct cond_entry *peer_conds):
|
||||
bus(NULL), name(NULL), peer_label(NULL), path(NULL), interface(NULL), member(NULL),
|
||||
mode(0), audit(0), deny(0)
|
||||
perms_rule_t(AA_CLASS_DBUS), bus(NULL), name(NULL), peer_label(NULL), path(NULL), interface(NULL), member(NULL)
|
||||
{
|
||||
int name_is_subject_cond = 0, message_rule = 0, service_rule = 0;
|
||||
|
||||
@@ -93,27 +92,27 @@ dbus_rule::dbus_rule(int mode_p, struct cond_entry *conds,
|
||||
if (message_rule && service_rule)
|
||||
yyerror("dbus rule contains message conditionals and service conditionals\n");
|
||||
|
||||
/* Copy mode. If no mode was specified, assign an implied mode. */
|
||||
if (mode_p) {
|
||||
mode = mode_p;
|
||||
if (mode & ~AA_VALID_DBUS_PERMS)
|
||||
yyerror("mode contains unknown dbus access\n");
|
||||
else if (message_rule && (mode & AA_DBUS_BIND))
|
||||
/* Copy perms. If no perms was specified, assign an implied perms. */
|
||||
if (perms_p) {
|
||||
perms = perms_p;
|
||||
if (perms & ~AA_VALID_DBUS_PERMS)
|
||||
yyerror("perms contains unknown dbus access\n");
|
||||
else if (message_rule && (perms & AA_DBUS_BIND))
|
||||
yyerror("dbus \"bind\" access cannot be used with message rule conditionals\n");
|
||||
else if (service_rule && (mode & (AA_DBUS_SEND | AA_DBUS_RECEIVE)))
|
||||
else if (service_rule && (perms & (AA_DBUS_SEND | AA_DBUS_RECEIVE)))
|
||||
yyerror("dbus \"send\" and/or \"receive\" accesses cannot be used with service rule conditionals\n");
|
||||
else if (mode & AA_DBUS_EAVESDROP &&
|
||||
else if (perms & AA_DBUS_EAVESDROP &&
|
||||
(path || interface || member ||
|
||||
peer_label || name)) {
|
||||
yyerror("dbus \"eavesdrop\" access can only contain a bus conditional\n");
|
||||
}
|
||||
} else {
|
||||
if (message_rule)
|
||||
mode = (AA_DBUS_SEND | AA_DBUS_RECEIVE);
|
||||
perms = (AA_DBUS_SEND | AA_DBUS_RECEIVE);
|
||||
else if (service_rule)
|
||||
mode = (AA_DBUS_BIND);
|
||||
perms = (AA_DBUS_BIND);
|
||||
else
|
||||
mode = AA_VALID_DBUS_PERMS;
|
||||
perms = AA_VALID_DBUS_PERMS;
|
||||
}
|
||||
|
||||
free_cond_list(conds);
|
||||
@@ -122,26 +121,23 @@ dbus_rule::dbus_rule(int mode_p, struct cond_entry *conds,
|
||||
|
||||
ostream &dbus_rule::dump(ostream &os)
|
||||
{
|
||||
if (audit)
|
||||
os << "audit ";
|
||||
if (deny)
|
||||
os << "deny ";
|
||||
class_rule_t::dump(os);
|
||||
|
||||
os << "dbus ( ";
|
||||
|
||||
if (mode & AA_DBUS_SEND)
|
||||
os << " ( ";
|
||||
/* override default perms */
|
||||
if (perms & AA_DBUS_SEND)
|
||||
os << "send ";
|
||||
if (mode & AA_DBUS_RECEIVE)
|
||||
if (perms & AA_DBUS_RECEIVE)
|
||||
os << "receive ";
|
||||
if (mode & AA_DBUS_BIND)
|
||||
if (perms & AA_DBUS_BIND)
|
||||
os << "bind ";
|
||||
if (mode & AA_DBUS_EAVESDROP)
|
||||
if (perms & AA_DBUS_EAVESDROP)
|
||||
os << "eavesdrop ";
|
||||
os << ")";
|
||||
|
||||
if (bus)
|
||||
os << " bus=\"" << bus << "\"";
|
||||
if ((mode & AA_DBUS_BIND) && name)
|
||||
if ((perms & AA_DBUS_BIND) && name)
|
||||
os << " name=\"" << name << "\"";
|
||||
if (path)
|
||||
os << " path=\"" << path << "\"";
|
||||
@@ -150,7 +146,7 @@ ostream &dbus_rule::dump(ostream &os)
|
||||
if (member)
|
||||
os << " member=\"" << member << "\"";
|
||||
|
||||
if (!(mode & AA_DBUS_BIND) && (peer_label || name)) {
|
||||
if (!(perms & AA_DBUS_BIND) && (peer_label || name)) {
|
||||
os << " peer=( ";
|
||||
if (peer_label)
|
||||
os << "label=\"" << peer_label << "\" ";
|
||||
@@ -277,23 +273,23 @@ int dbus_rule::gen_policy_re(Profile &prof)
|
||||
vec[5] = default_match_pattern;
|
||||
}
|
||||
|
||||
if (mode & AA_DBUS_BIND) {
|
||||
if (!prof.policy.rules->add_rule_vec(deny, mode & AA_DBUS_BIND,
|
||||
audit & AA_DBUS_BIND,
|
||||
if (perms & AA_DBUS_BIND) {
|
||||
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms & AA_DBUS_BIND,
|
||||
audit == AUDIT_FORCE ? perms & AA_DBUS_BIND : 0,
|
||||
2, vec, dfaflags, false))
|
||||
goto fail;
|
||||
}
|
||||
if (mode & (AA_DBUS_SEND | AA_DBUS_RECEIVE)) {
|
||||
if (!prof.policy.rules->add_rule_vec(deny,
|
||||
mode & (AA_DBUS_SEND | AA_DBUS_RECEIVE),
|
||||
audit & (AA_DBUS_SEND | AA_DBUS_RECEIVE),
|
||||
if (perms & (AA_DBUS_SEND | AA_DBUS_RECEIVE)) {
|
||||
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY,
|
||||
perms & (AA_DBUS_SEND | AA_DBUS_RECEIVE),
|
||||
audit == AUDIT_FORCE ? perms & (AA_DBUS_SEND | AA_DBUS_RECEIVE) : 0,
|
||||
6, vec, dfaflags, false))
|
||||
goto fail;
|
||||
}
|
||||
if (mode & AA_DBUS_EAVESDROP) {
|
||||
if (!prof.policy.rules->add_rule_vec(deny,
|
||||
mode & AA_DBUS_EAVESDROP,
|
||||
audit & AA_DBUS_EAVESDROP,
|
||||
if (perms & AA_DBUS_EAVESDROP) {
|
||||
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY,
|
||||
perms & AA_DBUS_EAVESDROP,
|
||||
audit == AUDIT_FORCE ? perms & AA_DBUS_EAVESDROP : 0,
|
||||
1, vec, dfaflags, false))
|
||||
goto fail;
|
||||
}
|
||||
|
@@ -23,9 +23,9 @@
|
||||
#include "rule.h"
|
||||
#include "profile.h"
|
||||
|
||||
extern int parse_dbus_mode(const char *str_mode, int *mode, int fail);
|
||||
extern int parse_dbus_perms(const char *str_mode, perms_t *mode, int fail);
|
||||
|
||||
class dbus_rule: public rule_t {
|
||||
class dbus_rule: public perms_rule_t {
|
||||
void move_conditionals(struct cond_entry *conds);
|
||||
public:
|
||||
char *bus;
|
||||
@@ -39,11 +39,8 @@ public:
|
||||
char *path;
|
||||
char *interface;
|
||||
char *member;
|
||||
int mode;
|
||||
int audit;
|
||||
int deny;
|
||||
|
||||
dbus_rule(int mode_p, struct cond_entry *conds,
|
||||
dbus_rule(perms_t perms_p, struct cond_entry *conds,
|
||||
struct cond_entry *peer_conds);
|
||||
virtual ~dbus_rule() {
|
||||
free(bus);
|
||||
@@ -53,11 +50,17 @@ public:
|
||||
free(interface);
|
||||
free(member);
|
||||
};
|
||||
virtual bool valid_prefix(const prefixes &p, const char *&error) {
|
||||
if (p.owner) {
|
||||
error = "owner prefix not allowed on dbus rules";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
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;
|
||||
|
@@ -98,7 +98,7 @@
|
||||
#define AA_LINK_BITS ((AA_OLD_MAY_LINK << AA_USER_SHIFT) | \
|
||||
(AA_OLD_MAY_LINK << AA_OTHER_SHIFT))
|
||||
|
||||
#define SHIFT_MODE(MODE, SHIFT) ((((MODE) & AA_BASE_PERMS) << (SHIFT))\
|
||||
#define SHIFT_PERMS(MODE, SHIFT) ((((MODE) & AA_BASE_PERMS) << (SHIFT))\
|
||||
| ((MODE) & ~AA_FILE_PERMS))
|
||||
#define SHIFT_TO_BASE(MODE, SHIFT) ((((MODE) & AA_FILE_PERMS) >> (SHIFT))\
|
||||
| ((MODE) & ~AA_FILE_PERMS))
|
||||
|
128
parser/mount.cc
128
parser/mount.cc
@@ -467,9 +467,10 @@ static void process_one_option(struct cond_entry *&opts, unsigned int &flags,
|
||||
|
||||
mnt_rule::mnt_rule(struct cond_entry *src_conds, char *device_p,
|
||||
struct cond_entry *dst_conds unused, char *mnt_point_p,
|
||||
int allow_p):
|
||||
perms_t perms_p):
|
||||
perms_rule_t(AA_CLASS_MOUNT),
|
||||
mnt_point(mnt_point_p), device(device_p), trans(NULL), opts(NULL),
|
||||
flagsv(0), opt_flagsv(0), audit(0), deny(0)
|
||||
flagsv(0), opt_flagsv(0)
|
||||
{
|
||||
/* FIXME: dst_conds are ignored atm */
|
||||
dev_type = extract_fstype(&src_conds);
|
||||
@@ -506,7 +507,7 @@ mnt_rule::mnt_rule(struct cond_entry *src_conds, char *device_p,
|
||||
/* throw away tmpinv_flags, only needed in
|
||||
* consistancy check
|
||||
*/
|
||||
if (allow_p & AA_DUMMY_REMOUNT)
|
||||
if (perms_p & AA_DUMMY_REMOUNT)
|
||||
tmpflags |= MS_REMOUNT;
|
||||
|
||||
if (conflicting_flags(tmpflags, tmpinv_flags)) {
|
||||
@@ -526,7 +527,7 @@ mnt_rule::mnt_rule(struct cond_entry *src_conds, char *device_p,
|
||||
|
||||
if (!(flagsv.size() + opt_flagsv.size())) {
|
||||
/* no flag options, and not remount, allow everything */
|
||||
if (allow_p & AA_DUMMY_REMOUNT) {
|
||||
if (perms_p & AA_DUMMY_REMOUNT) {
|
||||
flagsv.push_back(MS_REMOUNT);
|
||||
opt_flagsv.push_back(MS_REMOUNT_FLAGS & ~MS_REMOUNT);
|
||||
} else {
|
||||
@@ -535,7 +536,7 @@ mnt_rule::mnt_rule(struct cond_entry *src_conds, char *device_p,
|
||||
}
|
||||
} else if (!(flagsv.size())) {
|
||||
/* no flags but opts set */
|
||||
if (allow_p & AA_DUMMY_REMOUNT)
|
||||
if (perms_p & AA_DUMMY_REMOUNT)
|
||||
flagsv.push_back(MS_REMOUNT);
|
||||
else
|
||||
flagsv.push_back(0);
|
||||
@@ -543,19 +544,21 @@ mnt_rule::mnt_rule(struct cond_entry *src_conds, char *device_p,
|
||||
opt_flagsv.push_back(0);
|
||||
}
|
||||
|
||||
if (allow_p & AA_DUMMY_REMOUNT) {
|
||||
allow_p = AA_MAY_MOUNT;
|
||||
if (perms_p & AA_DUMMY_REMOUNT) {
|
||||
perms_p = AA_MAY_MOUNT;
|
||||
}
|
||||
allow = allow_p;
|
||||
perms = perms_p;
|
||||
}
|
||||
|
||||
ostream &mnt_rule::dump(ostream &os)
|
||||
{
|
||||
if (allow & AA_MAY_MOUNT)
|
||||
prefix_rule_t::dump(os);
|
||||
|
||||
if (perms & AA_MAY_MOUNT)
|
||||
os << "mount";
|
||||
else if (allow & AA_MAY_UMOUNT)
|
||||
else if (perms & AA_MAY_UMOUNT)
|
||||
os << "umount";
|
||||
else if (allow & AA_MAY_PIVOTROOT)
|
||||
else if (perms & AA_MAY_PIVOTROOT)
|
||||
os << "pivotroot";
|
||||
else
|
||||
os << "error: unknown mount perm";
|
||||
@@ -580,8 +583,8 @@ ostream &mnt_rule::dump(ostream &os)
|
||||
if (trans)
|
||||
os << " -> " << trans;
|
||||
|
||||
const char *prefix = deny ? "deny" : "";
|
||||
os << " " << prefix << "(0x" << hex << allow << "/0x" << audit << ")";
|
||||
|
||||
os << " " << "(0x" << hex << perms << "/0x" << (audit != AUDIT_UNSPECIFIED ? perms : 0) << ")";
|
||||
os << ",\n";
|
||||
|
||||
return os;
|
||||
@@ -699,7 +702,6 @@ int mnt_rule::gen_policy_remount(Profile &prof, int &count,
|
||||
std::string optsbuf;
|
||||
char class_mount_hdr[64];
|
||||
const char *vec[5];
|
||||
int tmpallow;
|
||||
|
||||
sprintf(class_mount_hdr, "\\x%02x", AA_CLASS_MOUNT);
|
||||
|
||||
@@ -727,14 +729,20 @@ int mnt_rule::gen_policy_remount(Profile &prof, int &count,
|
||||
|
||||
vec[3] = flagsbuf;
|
||||
|
||||
if (opts)
|
||||
tmpallow = AA_MATCH_CONT;
|
||||
else
|
||||
tmpallow = allow;
|
||||
|
||||
/* rule for match without required data || data MATCH_CONT */
|
||||
if (!prof.policy.rules->add_rule_vec(deny, tmpallow,
|
||||
audit | AA_AUDIT_MNT_DATA, 4,
|
||||
perms_t tmpperms, tmpaudit;
|
||||
if (opts) {
|
||||
tmpperms = AA_MATCH_CONT;
|
||||
tmpaudit = 0;
|
||||
} else {
|
||||
/* dependent on full expansion of any data match perms */
|
||||
tmpperms = perms;
|
||||
tmpaudit = audit == AUDIT_FORCE ? perms : 0;
|
||||
}
|
||||
/* match for up to but not including data
|
||||
* if a data match is required this only has AA_MATCH_CONT perms
|
||||
* else it has full perms
|
||||
*/
|
||||
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, tmpperms, tmpaudit, 4,
|
||||
vec, dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
@@ -745,8 +753,8 @@ int mnt_rule::gen_policy_remount(Profile &prof, int &count,
|
||||
if (!build_mnt_opts(optsbuf, opts))
|
||||
goto fail;
|
||||
vec[4] = optsbuf.c_str();
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow,
|
||||
audit | AA_AUDIT_MNT_DATA,
|
||||
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms,
|
||||
(audit == AUDIT_FORCE ? perms : 0),
|
||||
5, vec, dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
@@ -787,7 +795,8 @@ int mnt_rule::gen_policy_bind_mount(Profile &prof, int &count,
|
||||
opt_flags & MS_BIND_FLAGS))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow, audit, 4, vec,
|
||||
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0,
|
||||
4, vec,
|
||||
dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
@@ -828,7 +837,8 @@ int mnt_rule::gen_policy_change_mount_type(Profile &prof, int &count,
|
||||
opt_flags & MS_MAKE_FLAGS))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow, audit, 4, vec,
|
||||
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0,
|
||||
4, vec,
|
||||
dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
@@ -870,7 +880,8 @@ int mnt_rule::gen_policy_move_mount(Profile &prof, int &count,
|
||||
opt_flags & MS_MOVE_FLAGS))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow, audit, 4, vec,
|
||||
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0,
|
||||
4, vec,
|
||||
dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
@@ -891,7 +902,6 @@ int mnt_rule::gen_policy_new_mount(Profile &prof, int &count,
|
||||
std::string optsbuf;
|
||||
char class_mount_hdr[64];
|
||||
const char *vec[5];
|
||||
int tmpallow;
|
||||
|
||||
sprintf(class_mount_hdr, "\\x%02x", AA_CLASS_MOUNT);
|
||||
|
||||
@@ -913,14 +923,16 @@ int mnt_rule::gen_policy_new_mount(Profile &prof, int &count,
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
|
||||
if (opts)
|
||||
tmpallow = AA_MATCH_CONT;
|
||||
else
|
||||
tmpallow = allow;
|
||||
|
||||
perms_t tmpperms, tmpaudit;
|
||||
if (opts) {
|
||||
tmpperms = AA_MATCH_CONT;
|
||||
tmpaudit = 0;
|
||||
} else {
|
||||
tmpperms = perms;
|
||||
tmpaudit = audit == AUDIT_FORCE ? perms : 0;
|
||||
}
|
||||
/* rule for match without required data || data MATCH_CONT */
|
||||
if (!prof.policy.rules->add_rule_vec(deny, tmpallow,
|
||||
audit | AA_AUDIT_MNT_DATA, 4,
|
||||
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, tmpperms, tmpaudit, 4,
|
||||
vec, dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
@@ -931,8 +943,8 @@ int mnt_rule::gen_policy_new_mount(Profile &prof, int &count,
|
||||
if (!build_mnt_opts(optsbuf, opts))
|
||||
goto fail;
|
||||
vec[4] = optsbuf.c_str();
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow,
|
||||
audit | AA_AUDIT_MNT_DATA,
|
||||
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms,
|
||||
audit == AUDIT_FORCE ? perms : 0,
|
||||
5, vec, dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
@@ -951,7 +963,7 @@ int mnt_rule::gen_flag_rules(Profile &prof, int &count, unsigned int flags,
|
||||
* XXX: added !flags to cover cases like:
|
||||
* mount options in (bind) /d -> /4,
|
||||
*/
|
||||
if ((allow & AA_MAY_MOUNT) && (!flags || flags == MS_ALL_FLAGS)) {
|
||||
if ((perms & AA_MAY_MOUNT) && (!flags || flags == MS_ALL_FLAGS)) {
|
||||
/* no mount flags specified, generate multiple rules */
|
||||
if (!device && !dev_type &&
|
||||
gen_policy_remount(prof, count, flags, opt_flags) == RULE_ERROR)
|
||||
@@ -967,20 +979,20 @@ int mnt_rule::gen_flag_rules(Profile &prof, int &count, unsigned int flags,
|
||||
return RULE_ERROR;
|
||||
|
||||
return gen_policy_new_mount(prof, count, flags, opt_flags);
|
||||
} else if ((allow & AA_MAY_MOUNT) && (flags & MS_REMOUNT)
|
||||
} else if ((perms & AA_MAY_MOUNT) && (flags & MS_REMOUNT)
|
||||
&& !device && !dev_type) {
|
||||
return gen_policy_remount(prof, count, flags, opt_flags);
|
||||
} else if ((allow & AA_MAY_MOUNT) && (flags & MS_BIND)
|
||||
} else if ((perms & AA_MAY_MOUNT) && (flags & MS_BIND)
|
||||
&& !dev_type && !opts) {
|
||||
return gen_policy_bind_mount(prof, count, flags, opt_flags);
|
||||
} else if ((allow & AA_MAY_MOUNT) &&
|
||||
} else if ((perms & AA_MAY_MOUNT) &&
|
||||
(flags & (MS_MAKE_CMDS))
|
||||
&& !device && !dev_type && !opts) {
|
||||
return gen_policy_change_mount_type(prof, count, flags, opt_flags);
|
||||
} else if ((allow & AA_MAY_MOUNT) && (flags & MS_MOVE)
|
||||
} else if ((perms & AA_MAY_MOUNT) && (flags & MS_MOVE)
|
||||
&& !dev_type && !opts) {
|
||||
return gen_policy_move_mount(prof, count, flags, opt_flags);
|
||||
} else if ((allow & AA_MAY_MOUNT) &&
|
||||
} else if ((perms & AA_MAY_MOUNT) &&
|
||||
((flags | opt_flags) & ~MS_CMDS)) {
|
||||
/* generic mount if flags are set that are not covered by
|
||||
* above commands
|
||||
@@ -1017,18 +1029,19 @@ int mnt_rule::gen_policy_re(Profile &prof)
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
if (allow & AA_MAY_UMOUNT) {
|
||||
if (perms & AA_MAY_UMOUNT) {
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow, audit, 1, vec,
|
||||
dfaflags, false))
|
||||
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms,
|
||||
(audit == AUDIT_FORCE ? perms : 0), 1, vec,
|
||||
dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
if (allow & AA_MAY_PIVOTROOT) {
|
||||
if (perms & AA_MAY_PIVOTROOT) {
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
@@ -1037,8 +1050,9 @@ int mnt_rule::gen_policy_re(Profile &prof)
|
||||
if (!clear_and_convert_entry(devbuf, device))
|
||||
goto fail;
|
||||
vec[1] = devbuf.c_str();
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow, audit, 2, vec,
|
||||
dfaflags, false))
|
||||
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms,
|
||||
(audit == AUDIT_FORCE ? perms : 0), 2, vec,
|
||||
dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
@@ -1054,22 +1068,22 @@ fail:
|
||||
return RULE_ERROR;
|
||||
}
|
||||
|
||||
void mnt_rule::post_process(Profile &prof)
|
||||
void mnt_rule::post_parse_profile(Profile &prof)
|
||||
{
|
||||
if (trans) {
|
||||
unsigned int mode = 0;
|
||||
perms_t perms = 0;
|
||||
int n = add_entry_to_x_table(&prof, trans);
|
||||
if (!n) {
|
||||
PERROR("Profile %s has too many specified profile transitions.\n", prof.name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (allow & AA_USER_EXEC)
|
||||
mode |= SHIFT_MODE(n << 10, AA_USER_SHIFT);
|
||||
if (allow & AA_OTHER_EXEC)
|
||||
mode |= SHIFT_MODE(n << 10, AA_OTHER_SHIFT);
|
||||
allow = ((allow & ~AA_ALL_EXEC_MODIFIERS) |
|
||||
(mode & AA_ALL_EXEC_MODIFIERS));
|
||||
if (perms & AA_USER_EXEC)
|
||||
perms |= SHIFT_PERMS(n << 10, AA_USER_SHIFT);
|
||||
if (perms & AA_OTHER_EXEC)
|
||||
perms |= SHIFT_PERMS(n << 10, AA_OTHER_SHIFT);
|
||||
perms = ((perms & ~AA_ALL_EXEC_MODIFIERS) |
|
||||
(perms & AA_ALL_EXEC_MODIFIERS));
|
||||
|
||||
trans = NULL;
|
||||
}
|
||||
|
@@ -120,7 +120,7 @@
|
||||
* remapped to a mount option*/
|
||||
|
||||
|
||||
class mnt_rule: public rule_t {
|
||||
class mnt_rule: public perms_rule_t {
|
||||
int gen_policy_remount(Profile &prof, int &count, unsigned int flags,
|
||||
unsigned int opt_flags);
|
||||
int gen_policy_bind_mount(Profile &prof, int &count, unsigned int flags,
|
||||
@@ -143,12 +143,10 @@ public:
|
||||
|
||||
std::vector<unsigned int> flagsv, opt_flagsv;
|
||||
|
||||
int allow, audit;
|
||||
int deny;
|
||||
|
||||
mnt_rule(struct cond_entry *src_conds, char *device_p,
|
||||
struct cond_entry *dst_conds unused, char *mnt_point_p,
|
||||
int allow_p);
|
||||
perms_t perms_p);
|
||||
virtual ~mnt_rule()
|
||||
{
|
||||
free_value_list(opts);
|
||||
@@ -158,10 +156,17 @@ public:
|
||||
free(trans);
|
||||
}
|
||||
|
||||
virtual bool valid_prefix(const prefixes &p, const char *&error) {
|
||||
if (p.owner) {
|
||||
error = "owner prefix not allowed on mount rules";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
virtual ostream &dump(ostream &os);
|
||||
virtual int expand_variables(void);
|
||||
virtual int gen_policy_re(Profile &prof);
|
||||
virtual void post_process(Profile &prof unused);
|
||||
virtual void post_parse_profile(Profile &prof unused);
|
||||
|
||||
protected:
|
||||
virtual void warn_once(const char *name) override;
|
||||
|
@@ -25,9 +25,9 @@
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
int parse_mqueue_mode(const char *str_mode, int *mode, int fail)
|
||||
int parse_mqueue_perms(const char *str_perms, perms_t *perms, int fail)
|
||||
{
|
||||
return parse_X_mode("mqueue", AA_VALID_MQUEUE_PERMS, str_mode, mode, fail);
|
||||
return parse_X_perms("mqueue", AA_VALID_MQUEUE_PERMS, str_perms, perms, fail);
|
||||
}
|
||||
|
||||
static bool is_all_digits(char *str)
|
||||
@@ -86,28 +86,31 @@ void mqueue_rule::move_conditionals(struct cond_entry *conds)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
mqueue_rule::mqueue_rule(perms_t perms_p, struct cond_entry *conds, char *qname_p):
|
||||
// mqueue uses multiple classes, arbitrary choice to represent group
|
||||
// withing the AST
|
||||
perms_rule_t(AA_CLASS_POSIX_MQUEUE),
|
||||
qtype(mqueue_unspecified), qname(qname_p), label(NULL)
|
||||
{
|
||||
move_conditionals(conds);
|
||||
free_cond_list(conds);
|
||||
|
||||
if (qname)
|
||||
validate_qname();
|
||||
if (mode_p) {
|
||||
if (perms_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");
|
||||
if (qtype == mqueue_posix && (perms_p & ~AA_VALID_POSIX_MQ_PERMS)) {
|
||||
yyerror("perms contains invalid permissions for mqueue type=posix\n");
|
||||
} else if (qtype == mqueue_sysv && (perms_p & ~AA_VALID_SYSV_MQ_PERMS)) {
|
||||
yyerror("perms contains invalid permissions for mqueue type=sysv\n");
|
||||
} else if (perms_p & ~AA_VALID_MQUEUE_PERMS) {
|
||||
yyerror("perms contains invalid permissions for mqueue\n");
|
||||
}
|
||||
mode = mode_p;
|
||||
perms = perms_p;
|
||||
} else {
|
||||
// default to all perms
|
||||
mode = AA_VALID_MQUEUE_PERMS;
|
||||
perms = AA_VALID_MQUEUE_PERMS;
|
||||
}
|
||||
qname = qname_p;
|
||||
|
||||
@@ -115,36 +118,31 @@ mqueue_rule::mqueue_rule(int mode_p, struct cond_entry *conds, char *qname_p):
|
||||
|
||||
ostream &mqueue_rule::dump(ostream &os)
|
||||
{
|
||||
if (audit)
|
||||
os << "audit ";
|
||||
if (deny)
|
||||
os << "deny ";
|
||||
|
||||
os << "mqueue ";
|
||||
class_rule_t::dump(os);
|
||||
|
||||
// do we want to always put type out or leave it implied if there
|
||||
// is a qname
|
||||
if (qtype == mqueue_posix)
|
||||
os << "type=posix";
|
||||
os << " type=posix";
|
||||
else if (qtype == mqueue_sysv)
|
||||
os << "type=sysv";
|
||||
os << " type=sysv";
|
||||
|
||||
if (mode != AA_VALID_MQUEUE_PERMS) {
|
||||
os << "(";
|
||||
if (perms != AA_VALID_MQUEUE_PERMS) {
|
||||
os << " ( ";
|
||||
|
||||
if (mode & AA_MQUEUE_WRITE)
|
||||
if (perms & AA_MQUEUE_WRITE)
|
||||
os << "write ";
|
||||
if (mode & AA_MQUEUE_READ)
|
||||
if (perms & AA_MQUEUE_READ)
|
||||
os << "read ";
|
||||
if (mode & AA_MQUEUE_OPEN)
|
||||
if (perms & AA_MQUEUE_OPEN)
|
||||
os << "open ";
|
||||
if (mode & AA_MQUEUE_CREATE)
|
||||
if (perms & AA_MQUEUE_CREATE)
|
||||
os << "create ";
|
||||
if (mode & AA_MQUEUE_DELETE)
|
||||
if (perms & AA_MQUEUE_DELETE)
|
||||
os << "delete ";
|
||||
if (mode & AA_MQUEUE_SETATTR)
|
||||
if (perms & AA_MQUEUE_SETATTR)
|
||||
os << "setattr ";
|
||||
if (mode & AA_MQUEUE_GETATTR)
|
||||
if (perms & AA_MQUEUE_GETATTR)
|
||||
os << "getattr ";
|
||||
|
||||
os << ")";
|
||||
@@ -229,14 +227,14 @@ int mqueue_rule::gen_policy_re(Profile &prof)
|
||||
vec[1] = anyone_match_pattern;
|
||||
}
|
||||
|
||||
if (mode & AA_VALID_POSIX_MQ_PERMS) {
|
||||
if (perms & AA_VALID_POSIX_MQ_PERMS) {
|
||||
/* store perms at name match so label doesn't need
|
||||
* to be checked
|
||||
*/
|
||||
if (!label && !prof.policy.rules->add_rule_vec(deny, mode, audit, 1, vec, dfaflags, false))
|
||||
if (!label && !prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, 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))
|
||||
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, size, vec, dfaflags, false))
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
@@ -267,11 +265,11 @@ int mqueue_rule::gen_policy_re(Profile &prof)
|
||||
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))
|
||||
if (perms & AA_VALID_SYSV_MQ_PERMS) {
|
||||
if (!label && !prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, 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))
|
||||
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, size, vec, dfaflags, false))
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
@@ -79,29 +79,33 @@ typedef enum mqueue_type {
|
||||
} mqueue_type;
|
||||
|
||||
|
||||
int parse_mqueue_mode(const char *str_mode, int *mode, int fail);
|
||||
int parse_mqueue_perms(const char *str_perms, perms_t *perms, int fail);
|
||||
|
||||
class mqueue_rule: public rule_t {
|
||||
class mqueue_rule: public perms_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);
|
||||
mqueue_rule(perms_t perms, struct cond_entry *conds, char *qname = NULL);
|
||||
virtual ~mqueue_rule()
|
||||
{
|
||||
free(qname);
|
||||
free(label);
|
||||
};
|
||||
|
||||
virtual bool valid_prefix(const prefixes &p, const char *&error) {
|
||||
// not yet, but soon
|
||||
if (p.owner) {
|
||||
error = _("owner prefix not allowed on mqueue rules");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
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;
|
||||
|
@@ -32,9 +32,9 @@
|
||||
#include "network.h"
|
||||
|
||||
|
||||
int parse_net_mode(const char *str_mode, int *mode, int fail)
|
||||
int parse_net_perms(const char *str_mode, perms_t *mode, int fail)
|
||||
{
|
||||
return parse_X_mode("net", AA_VALID_NET_PERMS, str_mode, mode, fail);
|
||||
return parse_X_perms("net", AA_VALID_NET_PERMS, str_mode, mode, fail);
|
||||
}
|
||||
|
||||
/* Bleah C++ doesn't have non-trivial designated initializers so we just
|
||||
|
@@ -100,7 +100,7 @@ static inline uint32_t map_perms(uint32_t mask)
|
||||
};
|
||||
|
||||
|
||||
int parse_net_mode(const char *str_mode, int *mode, int fail);
|
||||
int parse_net_perms(const char *str_mode, perms_t *perms, int fail);
|
||||
extern struct aa_network_entry *new_network_ent(unsigned int family,
|
||||
unsigned int type,
|
||||
unsigned int protocol);
|
||||
|
@@ -36,14 +36,14 @@
|
||||
#include "immunix.h"
|
||||
#include "libapparmor_re/apparmor_re.h"
|
||||
#include "libapparmor_re/aare_rules.h"
|
||||
#include "rule.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include <set>
|
||||
class Profile;
|
||||
class rule_t;
|
||||
|
||||
|
||||
#define MODULE_NAME "apparmor"
|
||||
|
||||
@@ -88,11 +88,6 @@ extern dfaflags_t werrflags;
|
||||
|
||||
typedef enum pattern_t pattern_t;
|
||||
|
||||
struct prefixes {
|
||||
int audit;
|
||||
int deny;
|
||||
int owner;
|
||||
};
|
||||
|
||||
struct cod_pattern {
|
||||
char *regex; // posix regex
|
||||
@@ -127,13 +122,13 @@ struct cod_entry {
|
||||
char *nt_name;
|
||||
Profile *prof; /* Special profile defined
|
||||
* just for this executable */
|
||||
int mode; /* mode is 'or' of AA_* bits */
|
||||
int audit; /* audit flags for mode */
|
||||
int deny; /* TRUE or FALSE */
|
||||
perms_t perms; /* perms is 'or' of AA_* bits */
|
||||
audit_t audit;
|
||||
rule_mode_t rule_mode;
|
||||
|
||||
int alias_ignore; /* ignore for alias processing */
|
||||
bool alias_ignore; /* ignore for alias processing */
|
||||
|
||||
int subset;
|
||||
bool subset;
|
||||
|
||||
pattern_t pattern_type;
|
||||
struct cod_pattern pat;
|
||||
@@ -449,12 +444,12 @@ extern char *processunquoted(const char *string, int len);
|
||||
extern int get_keyword_token(const char *keyword);
|
||||
extern int get_rlimit(const char *name);
|
||||
extern char *process_var(const char *var);
|
||||
extern int parse_mode(const char *mode);
|
||||
extern int parse_X_mode(const char *X, int valid, const char *str_mode, int *mode, int fail);
|
||||
extern perms_t parse_perms(const char *permstr);
|
||||
extern int parse_X_perms(const char *X, int valid, const char *str_perms, perms_t *perms, int fail);
|
||||
bool label_contains_ns(const char *label);
|
||||
bool parse_label(bool *_stack, char **_ns, char **_name,
|
||||
const char *label, bool yyerr);
|
||||
extern struct cod_entry *new_entry(char *id, int mode, char *link_id);
|
||||
extern struct cod_entry *new_entry(char *id, perms_t perms, char *link_id);
|
||||
|
||||
/* returns -1 if value != true or false, otherwise 0 == false, 1 == true */
|
||||
extern int str_to_boolean(const char* str);
|
||||
@@ -504,8 +499,6 @@ extern void add_to_list(Profile *profile);
|
||||
extern void add_hat_to_policy(Profile *policy, Profile *hat);
|
||||
extern int add_entry_to_x_table(Profile *prof, char *name);
|
||||
extern void add_entry_to_policy(Profile *policy, struct cod_entry *entry);
|
||||
extern void post_process_file_entries(Profile *prof);
|
||||
extern void post_process_rule_entries(Profile *prof);
|
||||
extern int post_process_policy(int debug_only);
|
||||
extern int process_profile_regex(Profile *prof);
|
||||
extern int process_profile_variables(Profile *prof);
|
||||
|
@@ -120,7 +120,7 @@ static void process_entries(const void *nodep, VISIT value, int level unused)
|
||||
len = strlen((*t)->from);
|
||||
|
||||
list_for_each(target_list, entry) {
|
||||
if ((entry->mode & AA_SHARED_PERMS) || entry->alias_ignore)
|
||||
if ((entry->perms & AA_SHARED_PERMS) || entry->alias_ignore)
|
||||
continue;
|
||||
if (entry->name && strncmp((*t)->from, entry->name, len) == 0) {
|
||||
char *n = do_alias(*t, entry->name);
|
||||
@@ -141,7 +141,7 @@ static void process_entries(const void *nodep, VISIT value, int level unused)
|
||||
dup->link_name = n;
|
||||
}
|
||||
if (dup) {
|
||||
dup->alias_ignore = 1;
|
||||
dup->alias_ignore = true;
|
||||
/* adds to the front of the list, list iteratition
|
||||
* will skip it
|
||||
*/
|
||||
|
@@ -44,12 +44,15 @@ static int file_comp(const void *c1, const void *c2)
|
||||
return res;
|
||||
|
||||
if ((*e1)->link_name)
|
||||
res = (*e2)->subset - (*e1)->subset;
|
||||
res = ((int) (*e2)->subset) - ((int) (*e1)->subset);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
if ((*e1)->deny != (*e2)->deny)
|
||||
return (*e1)->deny < (*e2)->deny ? -1 : 1;
|
||||
if ((*e1)->rule_mode != (*e2)->rule_mode)
|
||||
return (*e1)->rule_mode < (*e2)->rule_mode ? -1 : 1;
|
||||
|
||||
if ((*e1)->audit != (*e2)->audit)
|
||||
return (*e1)->audit < (*e2)->audit ? -1 : 1;
|
||||
|
||||
return strcmp((*e1)->name, (*e2)->name);
|
||||
}
|
||||
@@ -89,13 +92,12 @@ static int process_file_entries(Profile *prof)
|
||||
}
|
||||
|
||||
/* check for merged x consistency */
|
||||
if (!is_merged_x_consistent(cur->mode, next->mode)) {
|
||||
if (!is_merged_x_consistent(cur->perms, next->perms)) {
|
||||
PERROR(_("profile %s: has merged rule %s with conflicting x modifiers\n"),
|
||||
prof->name, cur->name);
|
||||
return -1;
|
||||
}
|
||||
cur->mode |= next->mode;
|
||||
cur->audit |= next->audit;
|
||||
cur->perms |= next->perms;
|
||||
cur->next = next->next;
|
||||
|
||||
next->next = NULL;
|
||||
|
@@ -540,139 +540,139 @@ void warn_uppercase(void)
|
||||
}
|
||||
}
|
||||
|
||||
static int parse_sub_mode(const char *str_mode, const char *mode_desc unused)
|
||||
static perms_t parse_sub_perms(const char *str_perms, const char *perms_desc unused)
|
||||
{
|
||||
|
||||
#define IS_DIFF_QUAL(mode, q) (((mode) & AA_MAY_EXEC) && (((mode) & AA_EXEC_TYPE) != ((q) & AA_EXEC_TYPE)))
|
||||
#define IS_DIFF_QUAL(perms, q) (((perms) & AA_MAY_EXEC) && (((perms) & AA_EXEC_TYPE) != ((q) & AA_EXEC_TYPE)))
|
||||
|
||||
int mode = 0;
|
||||
perms_t perms = 0;
|
||||
const char *p;
|
||||
|
||||
PDEBUG("Parsing mode: %s\n", str_mode);
|
||||
PDEBUG("Parsing perms: %s\n", str_perms);
|
||||
|
||||
if (!str_mode)
|
||||
if (!str_perms)
|
||||
return 0;
|
||||
|
||||
p = str_mode;
|
||||
p = str_perms;
|
||||
while (*p) {
|
||||
char thisc = *p;
|
||||
char next = *(p + 1);
|
||||
char lower;
|
||||
int tmode = 0;
|
||||
perms_t tperms = 0;
|
||||
|
||||
reeval:
|
||||
switch (thisc) {
|
||||
case COD_READ_CHAR:
|
||||
if (read_implies_exec) {
|
||||
PDEBUG("Parsing mode: found %s READ imply X\n", mode_desc);
|
||||
mode |= AA_MAY_READ | AA_OLD_EXEC_MMAP;
|
||||
PDEBUG("Parsing perms: found %s READ imply X\n", perms_desc);
|
||||
perms |= AA_MAY_READ | AA_OLD_EXEC_MMAP;
|
||||
} else {
|
||||
PDEBUG("Parsing mode: found %s READ\n", mode_desc);
|
||||
mode |= AA_MAY_READ;
|
||||
PDEBUG("Parsing perms: found %s READ\n", perms_desc);
|
||||
perms |= AA_MAY_READ;
|
||||
}
|
||||
break;
|
||||
|
||||
case COD_WRITE_CHAR:
|
||||
PDEBUG("Parsing mode: found %s WRITE\n", mode_desc);
|
||||
if ((mode & AA_MAY_APPEND) && !(mode & AA_MAY_WRITE))
|
||||
PDEBUG("Parsing perms: found %s WRITE\n", perms_desc);
|
||||
if ((perms & AA_MAY_APPEND) && !(perms & AA_MAY_WRITE))
|
||||
yyerror(_("Conflict 'a' and 'w' perms are mutually exclusive."));
|
||||
mode |= AA_MAY_WRITE | AA_MAY_APPEND;
|
||||
perms |= AA_MAY_WRITE | AA_MAY_APPEND;
|
||||
break;
|
||||
|
||||
case COD_APPEND_CHAR:
|
||||
PDEBUG("Parsing mode: found %s APPEND\n", mode_desc);
|
||||
if (mode & AA_MAY_WRITE)
|
||||
PDEBUG("Parsing perms: found %s APPEND\n", perms_desc);
|
||||
if (perms & AA_MAY_WRITE)
|
||||
yyerror(_("Conflict 'a' and 'w' perms are mutually exclusive."));
|
||||
mode |= AA_MAY_APPEND;
|
||||
perms |= AA_MAY_APPEND;
|
||||
break;
|
||||
|
||||
case COD_LINK_CHAR:
|
||||
PDEBUG("Parsing mode: found %s LINK\n", mode_desc);
|
||||
mode |= AA_OLD_MAY_LINK;
|
||||
PDEBUG("Parsing perms: found %s LINK\n", perms_desc);
|
||||
perms |= AA_OLD_MAY_LINK;
|
||||
break;
|
||||
|
||||
case COD_LOCK_CHAR:
|
||||
PDEBUG("Parsing mode: found %s LOCK\n", mode_desc);
|
||||
mode |= AA_OLD_MAY_LOCK;
|
||||
PDEBUG("Parsing perms: found %s LOCK\n", perms_desc);
|
||||
perms |= AA_OLD_MAY_LOCK;
|
||||
break;
|
||||
|
||||
case COD_INHERIT_CHAR:
|
||||
PDEBUG("Parsing mode: found INHERIT\n");
|
||||
if (mode & AA_EXEC_MODIFIERS) {
|
||||
PDEBUG("Parsing perms: found INHERIT\n");
|
||||
if (perms & AA_EXEC_MODIFIERS) {
|
||||
yyerror(_("Exec qualifier 'i' invalid, conflicting qualifier already specified"));
|
||||
} else {
|
||||
if (next != tolower(next))
|
||||
warn_uppercase();
|
||||
mode |= (AA_EXEC_INHERIT | AA_MAY_EXEC);
|
||||
perms |= (AA_EXEC_INHERIT | AA_MAY_EXEC);
|
||||
p++; /* skip 'x' */
|
||||
}
|
||||
break;
|
||||
|
||||
case COD_UNSAFE_UNCONFINED_CHAR:
|
||||
tmode = AA_EXEC_UNSAFE;
|
||||
tperms = AA_EXEC_UNSAFE;
|
||||
pwarn(WARN_DANGEROUS, _("Unconfined exec qualifier (%c%c) allows some dangerous environment variables "
|
||||
"to be passed to the unconfined process; 'man 5 apparmor.d' for details.\n"),
|
||||
COD_UNSAFE_UNCONFINED_CHAR, COD_EXEC_CHAR);
|
||||
/* fall through */
|
||||
case COD_UNCONFINED_CHAR:
|
||||
tmode |= AA_EXEC_UNCONFINED | AA_MAY_EXEC;
|
||||
PDEBUG("Parsing mode: found UNCONFINED\n");
|
||||
if (IS_DIFF_QUAL(mode, tmode)) {
|
||||
tperms |= AA_EXEC_UNCONFINED | AA_MAY_EXEC;
|
||||
PDEBUG("Parsing perms: found UNCONFINED\n");
|
||||
if (IS_DIFF_QUAL(perms, tperms)) {
|
||||
yyerror(_("Exec qualifier '%c' invalid, conflicting qualifier already specified"),
|
||||
thisc);
|
||||
} else {
|
||||
if (next != tolower(next))
|
||||
warn_uppercase();
|
||||
mode |= tmode;
|
||||
perms |= tperms;
|
||||
p++; /* skip 'x' */
|
||||
}
|
||||
tmode = 0;
|
||||
tperms = 0;
|
||||
break;
|
||||
|
||||
case COD_UNSAFE_PROFILE_CHAR:
|
||||
case COD_UNSAFE_LOCAL_CHAR:
|
||||
tmode = AA_EXEC_UNSAFE;
|
||||
tperms = AA_EXEC_UNSAFE;
|
||||
/* fall through */
|
||||
case COD_PROFILE_CHAR:
|
||||
case COD_LOCAL_CHAR:
|
||||
if (tolower(thisc) == COD_UNSAFE_PROFILE_CHAR)
|
||||
tmode |= AA_EXEC_PROFILE | AA_MAY_EXEC;
|
||||
tperms |= AA_EXEC_PROFILE | AA_MAY_EXEC;
|
||||
else
|
||||
{
|
||||
tmode |= AA_EXEC_LOCAL | AA_MAY_EXEC;
|
||||
tperms |= AA_EXEC_LOCAL | AA_MAY_EXEC;
|
||||
}
|
||||
PDEBUG("Parsing mode: found PROFILE\n");
|
||||
PDEBUG("Parsing perms: found PROFILE\n");
|
||||
if (tolower(next) == COD_INHERIT_CHAR) {
|
||||
tmode |= AA_EXEC_INHERIT;
|
||||
if (IS_DIFF_QUAL(mode, tmode)) {
|
||||
tperms |= AA_EXEC_INHERIT;
|
||||
if (IS_DIFF_QUAL(perms, tperms)) {
|
||||
yyerror(_("Exec qualifier '%c%c' invalid, conflicting qualifier already specified"), thisc, next);
|
||||
} else {
|
||||
mode |= tmode;
|
||||
perms |= tperms;
|
||||
p += 2; /* skip x */
|
||||
}
|
||||
} else if (tolower(next) == COD_UNSAFE_UNCONFINED_CHAR) {
|
||||
tmode |= AA_EXEC_PUX;
|
||||
if (IS_DIFF_QUAL(mode, tmode)) {
|
||||
tperms |= AA_EXEC_PUX;
|
||||
if (IS_DIFF_QUAL(perms, tperms)) {
|
||||
yyerror(_("Exec qualifier '%c%c' invalid, conflicting qualifier already specified"), thisc, next);
|
||||
} else {
|
||||
mode |= tmode;
|
||||
perms |= tperms;
|
||||
p += 2; /* skip x */
|
||||
}
|
||||
} else if (IS_DIFF_QUAL(mode, tmode)) {
|
||||
} else if (IS_DIFF_QUAL(perms, tperms)) {
|
||||
yyerror(_("Exec qualifier '%c' invalid, conflicting qualifier already specified"), thisc);
|
||||
|
||||
} else {
|
||||
if (next != tolower(next))
|
||||
warn_uppercase();
|
||||
mode |= tmode;
|
||||
perms |= tperms;
|
||||
p++; /* skip 'x' */
|
||||
}
|
||||
tmode = 0;
|
||||
tperms = 0;
|
||||
break;
|
||||
|
||||
case COD_MMAP_CHAR:
|
||||
PDEBUG("Parsing mode: found %s MMAP\n", mode_desc);
|
||||
mode |= AA_OLD_EXEC_MMAP;
|
||||
PDEBUG("Parsing perms: found %s MMAP\n", perms_desc);
|
||||
perms |= AA_OLD_EXEC_MMAP;
|
||||
break;
|
||||
|
||||
case COD_EXEC_CHAR:
|
||||
@@ -680,7 +680,7 @@ reeval:
|
||||
* but invalid for regular x transitions
|
||||
* sort it out later.
|
||||
*/
|
||||
mode |= AA_MAY_EXEC;
|
||||
perms |= AA_MAY_EXEC;
|
||||
break;
|
||||
|
||||
/* error cases */
|
||||
@@ -695,13 +695,13 @@ reeval:
|
||||
case COD_INHERIT_CHAR:
|
||||
case COD_MMAP_CHAR:
|
||||
case COD_EXEC_CHAR:
|
||||
PDEBUG("Parsing mode: found invalid upper case char %c\n", thisc);
|
||||
PDEBUG("Parsing perms: found invalid upper case char %c\n", thisc);
|
||||
warn_uppercase();
|
||||
thisc = lower;
|
||||
goto reeval;
|
||||
break;
|
||||
default:
|
||||
yyerror(_("Internal: unexpected mode character '%c' in input"),
|
||||
yyerror(_("Internal: unexpected perms character '%c' in input"),
|
||||
thisc);
|
||||
break;
|
||||
}
|
||||
@@ -711,33 +711,33 @@ reeval:
|
||||
p++;
|
||||
}
|
||||
|
||||
PDEBUG("Parsed mode: %s 0x%x\n", str_mode, mode);
|
||||
PDEBUG("Parsed perms: %s 0x%x\n", str_perms, perms);
|
||||
|
||||
return mode;
|
||||
return perms;
|
||||
}
|
||||
|
||||
int parse_mode(const char *str_mode)
|
||||
perms_t parse_perms(const char *str_perms)
|
||||
{
|
||||
int tmp, mode = 0;
|
||||
tmp = parse_sub_mode(str_mode, "");
|
||||
mode = SHIFT_MODE(tmp, AA_USER_SHIFT);
|
||||
mode |= SHIFT_MODE(tmp, AA_OTHER_SHIFT);
|
||||
if (mode & ~AA_VALID_PERMS)
|
||||
yyerror(_("Internal error generated invalid perm 0x%llx\n"), mode);
|
||||
return mode;
|
||||
perms_t tmp, perms = 0;
|
||||
tmp = parse_sub_perms(str_perms, "");
|
||||
perms = SHIFT_PERMS(tmp, AA_USER_SHIFT);
|
||||
perms |= SHIFT_PERMS(tmp, AA_OTHER_SHIFT);
|
||||
if (perms & ~AA_VALID_PERMS)
|
||||
yyerror(_("Internal error generated invalid perm 0x%llx\n"), perms);
|
||||
return perms;
|
||||
}
|
||||
|
||||
static int parse_X_sub_mode(const char *X, const char *str_mode, int *result, int fail, const char *mode_desc unused)
|
||||
static int parse_X_sub_perms(const char *X, const char *str_perms, perms_t *result, int fail, const char *perms_desc unused)
|
||||
{
|
||||
int mode = 0;
|
||||
perms_t perms = 0;
|
||||
const char *p;
|
||||
|
||||
PDEBUG("Parsing %s mode: %s\n", X, str_mode);
|
||||
PDEBUG("Parsing %s perms: %s\n", X, str_perms);
|
||||
|
||||
if (!str_mode)
|
||||
if (!str_perms)
|
||||
return 0;
|
||||
|
||||
p = str_mode;
|
||||
p = str_perms;
|
||||
while (*p) {
|
||||
char current = *p;
|
||||
char lower;
|
||||
@@ -745,14 +745,14 @@ static int parse_X_sub_mode(const char *X, const char *str_mode, int *result, in
|
||||
reeval:
|
||||
switch (current) {
|
||||
case COD_READ_CHAR:
|
||||
PDEBUG("Parsing %s mode: found %s READ\n", X, mode_desc);
|
||||
mode |= AA_DBUS_RECEIVE;
|
||||
PDEBUG("Parsing %s perms: found %s READ\n", X, perms_desc);
|
||||
perms |= AA_DBUS_RECEIVE;
|
||||
break;
|
||||
|
||||
case COD_WRITE_CHAR:
|
||||
PDEBUG("Parsing %s mode: found %s WRITE\n", X,
|
||||
mode_desc);
|
||||
mode |= AA_DBUS_SEND;
|
||||
PDEBUG("Parsing %s perms: found %s WRITE\n", X,
|
||||
perms_desc);
|
||||
perms |= AA_DBUS_SEND;
|
||||
break;
|
||||
|
||||
/* error cases */
|
||||
@@ -762,7 +762,7 @@ reeval:
|
||||
switch (lower) {
|
||||
case COD_READ_CHAR:
|
||||
case COD_WRITE_CHAR:
|
||||
PDEBUG("Parsing %s mode: found invalid upper case char %c\n",
|
||||
PDEBUG("Parsing %s perms: found invalid upper case char %c\n",
|
||||
X, current);
|
||||
warn_uppercase();
|
||||
current = lower;
|
||||
@@ -770,7 +770,7 @@ reeval:
|
||||
break;
|
||||
default:
|
||||
if (fail)
|
||||
yyerror(_("Internal: unexpected %s mode character '%c' in input"),
|
||||
yyerror(_("Internal: unexpected %s perms character '%c' in input"),
|
||||
X, current);
|
||||
else
|
||||
return 0;
|
||||
@@ -781,21 +781,21 @@ reeval:
|
||||
p++;
|
||||
}
|
||||
|
||||
PDEBUG("Parsed %s mode: %s 0x%x\n", X, str_mode, mode);
|
||||
PDEBUG("Parsed %s perms: %s 0x%x\n", X, str_perms, perms);
|
||||
|
||||
*result = mode;
|
||||
*result = perms;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int parse_X_mode(const char *X, int valid, const char *str_mode, int *mode, int fail)
|
||||
int parse_X_perms(const char *X, int valid, const char *str_perms, perms_t *perms, int fail)
|
||||
{
|
||||
*mode = 0;
|
||||
if (!parse_X_sub_mode(X, str_mode, mode, fail, ""))
|
||||
*perms = 0;
|
||||
if (!parse_X_sub_perms(X, str_perms, perms, fail, ""))
|
||||
return 0;
|
||||
if (*mode & ~valid) {
|
||||
if (*perms & ~valid) {
|
||||
if (fail)
|
||||
yyerror(_("Internal error generated invalid %s perm 0x%x\n"),
|
||||
X, mode);
|
||||
X, perms);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
@@ -950,7 +950,7 @@ alloc_fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
struct cod_entry *new_entry(char *id, int mode, char *link_id)
|
||||
struct cod_entry *new_entry(char *id, perms_t perms, char *link_id)
|
||||
{
|
||||
struct cod_entry *entry = NULL;
|
||||
|
||||
@@ -960,9 +960,9 @@ struct cod_entry *new_entry(char *id, int mode, char *link_id)
|
||||
|
||||
entry->name = id;
|
||||
entry->link_name = link_id;
|
||||
entry->mode = mode;
|
||||
entry->audit = 0;
|
||||
entry->deny = FALSE;
|
||||
entry->perms = perms;
|
||||
entry->audit = AUDIT_UNSPECIFIED;
|
||||
entry->rule_mode = RULE_UNSPECIFIED;
|
||||
|
||||
entry->pattern_type = ePatternInvalid;
|
||||
entry->pat.regex = NULL;
|
||||
@@ -984,9 +984,9 @@ struct cod_entry *copy_cod_entry(struct cod_entry *orig)
|
||||
DUP_STRING(orig, entry, name, err);
|
||||
DUP_STRING(orig, entry, link_name, err);
|
||||
DUP_STRING(orig, entry, nt_name, err);
|
||||
entry->mode = orig->mode;
|
||||
entry->perms = orig->perms;
|
||||
entry->audit = orig->audit;
|
||||
entry->deny = orig->deny;
|
||||
entry->rule_mode = orig->rule_mode;
|
||||
|
||||
/* XXX - need to create copies of the patterns, too */
|
||||
entry->pattern_type = orig->pattern_type;
|
||||
@@ -1043,20 +1043,20 @@ void debug_cod_entries(struct cod_entry *list)
|
||||
printf("--- Entries ---\n");
|
||||
|
||||
list_for_each(list, item) {
|
||||
printf("Mode:\t");
|
||||
if (HAS_CHANGE_PROFILE(item->mode))
|
||||
printf("Perms:\t");
|
||||
if (HAS_CHANGE_PROFILE(item->perms))
|
||||
printf(" change_profile");
|
||||
if (HAS_EXEC_UNSAFE(item->mode))
|
||||
if (HAS_EXEC_UNSAFE(item->perms))
|
||||
printf(" unsafe");
|
||||
debug_base_perm_mask(SHIFT_TO_BASE(item->mode, AA_USER_SHIFT));
|
||||
debug_base_perm_mask(SHIFT_TO_BASE(item->perms, AA_USER_SHIFT));
|
||||
printf(":");
|
||||
debug_base_perm_mask(SHIFT_TO_BASE(item->mode, AA_OTHER_SHIFT));
|
||||
debug_base_perm_mask(SHIFT_TO_BASE(item->perms, AA_OTHER_SHIFT));
|
||||
if (item->name)
|
||||
printf("\tName:\t(%s)\n", item->name);
|
||||
else
|
||||
printf("\tName:\tNULL\n");
|
||||
|
||||
if (AA_LINK_BITS & item->mode)
|
||||
if (AA_LINK_BITS & item->perms)
|
||||
printf("\tlink:\t(%s)\n", item->link_name ? item->link_name : "/**");
|
||||
|
||||
}
|
||||
|
@@ -70,188 +70,6 @@ void add_hat_to_policy(Profile *prof, Profile *hat)
|
||||
}
|
||||
}
|
||||
|
||||
int add_entry_to_x_table(Profile *prof, char *name)
|
||||
{
|
||||
int i;
|
||||
for (i = (AA_EXEC_LOCAL >> 10) + 1; i < AA_EXEC_COUNT; i++) {
|
||||
if (!prof->exec_table[i]) {
|
||||
prof->exec_table[i] = name;
|
||||
return i;
|
||||
} else if (strcmp(prof->exec_table[i], name) == 0) {
|
||||
/* name already in table */
|
||||
free(name);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
free(name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_named_transition(Profile *prof, struct cod_entry *entry)
|
||||
{
|
||||
char *name = NULL;
|
||||
|
||||
/* check to see if it is a local transition */
|
||||
if (!label_contains_ns(entry->nt_name)) {
|
||||
char *sub = strstr(entry->nt_name, "//");
|
||||
/* does the subprofile name match the rule */
|
||||
|
||||
if (sub && strncmp(prof->name, sub, sub - entry->nt_name) &&
|
||||
strcmp(sub + 2, entry->name) == 0) {
|
||||
free(entry->nt_name);
|
||||
entry->nt_name = NULL;
|
||||
return AA_EXEC_LOCAL >> 10;
|
||||
} else if (((entry->mode & AA_USER_EXEC_MODIFIERS) ==
|
||||
SHIFT_MODE(AA_EXEC_LOCAL, AA_USER_SHIFT)) ||
|
||||
((entry->mode & AA_OTHER_EXEC_MODIFIERS) ==
|
||||
SHIFT_MODE(AA_EXEC_LOCAL, AA_OTHER_SHIFT))) {
|
||||
if (strcmp(entry->nt_name, entry->name) == 0) {
|
||||
free(entry->nt_name);
|
||||
entry->nt_name = NULL;
|
||||
return AA_EXEC_LOCAL >> 10;
|
||||
}
|
||||
/* specified as cix so profile name is implicit */
|
||||
name = (char *) malloc(strlen(prof->name) + strlen(entry->nt_name)
|
||||
+ 3);
|
||||
if (!name) {
|
||||
PERROR("Memory allocation error\n");
|
||||
exit(1);
|
||||
}
|
||||
sprintf(name, "%s//%s", prof->name, entry->nt_name);
|
||||
free(entry->nt_name);
|
||||
entry->nt_name = NULL;
|
||||
} else {
|
||||
/**
|
||||
* pass control of the memory pointed to by nt_name
|
||||
* from entry to add_entry_to_x_table()
|
||||
*/
|
||||
name = entry->nt_name;
|
||||
entry->nt_name = NULL;
|
||||
}
|
||||
} else {
|
||||
/**
|
||||
* pass control of the memory pointed to by nt_name
|
||||
* from entry to add_entry_to_x_table()
|
||||
*/
|
||||
name = entry->nt_name;
|
||||
entry->nt_name = NULL;
|
||||
}
|
||||
|
||||
return add_entry_to_x_table(prof, name);
|
||||
}
|
||||
|
||||
void add_entry_to_policy(Profile *prof, struct cod_entry *entry)
|
||||
{
|
||||
entry->next = prof->entries;
|
||||
prof->entries = entry;
|
||||
}
|
||||
|
||||
static bool add_proc_access(Profile *prof, const char *rule)
|
||||
{
|
||||
/* FIXME: should use @{PROC}/@{PID}/attr/{apparmor/,}{current,exec} */
|
||||
struct cod_entry *new_ent;
|
||||
/* allow probe for new interfaces */
|
||||
char *buffer = strdup("/proc/*/attr/apparmor/");
|
||||
if (!buffer) {
|
||||
PERROR("Memory allocation error\n");
|
||||
return FALSE;
|
||||
}
|
||||
new_ent = new_entry(buffer, AA_MAY_READ, NULL);
|
||||
if (!new_ent) {
|
||||
free(buffer);
|
||||
PERROR("Memory allocation error\n");
|
||||
return FALSE;
|
||||
}
|
||||
add_entry_to_policy(prof, new_ent);
|
||||
|
||||
/* allow probe if apparmor is enabled for the old interface */
|
||||
buffer = strdup("/sys/module/apparmor/parameters/enabled");
|
||||
if (!buffer) {
|
||||
PERROR("Memory allocation error\n");
|
||||
return FALSE;
|
||||
}
|
||||
new_ent = new_entry(buffer, AA_MAY_READ, NULL);
|
||||
if (!new_ent) {
|
||||
free(buffer);
|
||||
PERROR("Memory allocation error\n");
|
||||
return FALSE;
|
||||
}
|
||||
add_entry_to_policy(prof, new_ent);
|
||||
|
||||
/* allow setting on new and old interfaces */
|
||||
buffer = strdup(rule);
|
||||
if (!buffer) {
|
||||
PERROR("Memory allocation error\n");
|
||||
return FALSE;
|
||||
}
|
||||
new_ent = new_entry(buffer, AA_MAY_WRITE, NULL);
|
||||
if (!new_ent) {
|
||||
free(buffer);
|
||||
PERROR("Memory allocation error\n");
|
||||
return FALSE;
|
||||
}
|
||||
add_entry_to_policy(prof, new_ent);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#define CHANGEPROFILE_PATH "/proc/*/attr/{apparmor/,}{current,exec}"
|
||||
void post_process_file_entries(Profile *prof)
|
||||
{
|
||||
struct cod_entry *entry;
|
||||
int cp_mode = 0;
|
||||
|
||||
list_for_each(prof->entries, entry) {
|
||||
if (entry->nt_name) {
|
||||
int mode = 0;
|
||||
int n = add_named_transition(prof, entry);
|
||||
if (!n) {
|
||||
PERROR("Profile %s has too many specified profile transitions.\n", prof->name);
|
||||
exit(1);
|
||||
}
|
||||
if (entry->mode & AA_USER_EXEC)
|
||||
mode |= SHIFT_MODE(n << 10, AA_USER_SHIFT);
|
||||
if (entry->mode & AA_OTHER_EXEC)
|
||||
mode |= SHIFT_MODE(n << 10, AA_OTHER_SHIFT);
|
||||
entry->mode = ((entry->mode & ~AA_ALL_EXEC_MODIFIERS) |
|
||||
(mode & AA_ALL_EXEC_MODIFIERS));
|
||||
}
|
||||
/* FIXME: currently change_profile also implies onexec */
|
||||
cp_mode |= entry->mode & (AA_CHANGE_PROFILE);
|
||||
}
|
||||
|
||||
/* if there are change_profile rules, this implies that we need
|
||||
* access to some /proc/ interfaces
|
||||
*/
|
||||
if (cp_mode & AA_CHANGE_PROFILE) {
|
||||
if (!add_proc_access(prof, CHANGEPROFILE_PATH))
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void post_process_rule_entries(Profile *prof)
|
||||
{
|
||||
for (RuleList::iterator i = prof->rule_ents.begin(); i != prof->rule_ents.end(); i++)
|
||||
(*i)->post_process(*prof);
|
||||
}
|
||||
|
||||
|
||||
#define CHANGEHAT_PATH "/proc/[0-9]*/attr/{apparmor/,}current"
|
||||
|
||||
/* add file rules to access /proc files to call change_hat()
|
||||
*/
|
||||
static int profile_add_hat_rules(Profile *prof)
|
||||
{
|
||||
/* don't add hat rules if not hat or profile doesn't have hats */
|
||||
if (!(prof->flags.flags & FLAG_HAT) && prof->hat_table.empty())
|
||||
return 0;
|
||||
|
||||
if (!add_proc_access(prof, CHANGEHAT_PATH))
|
||||
return ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int load_policy_list(ProfileList &list, int option,
|
||||
aa_kernel_interface *kernel_interface, int cache_fd)
|
||||
{
|
||||
@@ -392,12 +210,7 @@ int post_process_profile(Profile *profile, int debug_only)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
error = profile_add_hat_rules(profile);
|
||||
if (error) {
|
||||
PERROR(_("ERROR adding hat access rule for profile %s\n"),
|
||||
profile->name);
|
||||
return error;
|
||||
}
|
||||
profile->add_implied_rules();
|
||||
|
||||
error = process_profile_variables(profile);
|
||||
if (error) {
|
||||
|
@@ -575,7 +575,7 @@ build:
|
||||
|
||||
static int warn_change_profile = 1;
|
||||
|
||||
static bool is_change_profile_mode(int mode)
|
||||
static bool is_change_profile_perms(perms_t perms)
|
||||
{
|
||||
/**
|
||||
* A change_profile entry will have the AA_CHANGE_PROFILE bit set.
|
||||
@@ -583,13 +583,13 @@ static bool is_change_profile_mode(int mode)
|
||||
* set by the frontend parser. That means that it is incorrect to
|
||||
* identify change_profile modes using a test like this:
|
||||
*
|
||||
* (mode & ~AA_CHANGE_PROFILE)
|
||||
* (perms & ~AA_CHANGE_PROFILE)
|
||||
*
|
||||
* The above test would incorrectly return true on a
|
||||
* change_profile mode that has the
|
||||
* (AA_EXEC_BITS | ALL_AA_EXEC_UNSAFE) bits set.
|
||||
*/
|
||||
return mode & AA_CHANGE_PROFILE;
|
||||
return perms & AA_CHANGE_PROFILE;
|
||||
}
|
||||
|
||||
static int process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry)
|
||||
@@ -602,7 +602,7 @@ static int process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry)
|
||||
return TRUE;
|
||||
|
||||
|
||||
if (!is_change_profile_mode(entry->mode))
|
||||
if (!is_change_profile_perms(entry->perms))
|
||||
filter_slashes(entry->name);
|
||||
ptype = convert_aaregex_to_pcre(entry->name, 0, glob_default, tbuf, &pos);
|
||||
if (ptype == ePatternInvalid)
|
||||
@@ -613,10 +613,10 @@ static int process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry)
|
||||
/* ix implies m but the apparmor module does not add m bit to
|
||||
* dfa states like it does for pcre
|
||||
*/
|
||||
if ((entry->mode >> AA_OTHER_SHIFT) & AA_EXEC_INHERIT)
|
||||
entry->mode |= AA_OLD_EXEC_MMAP << AA_OTHER_SHIFT;
|
||||
if ((entry->mode >> AA_USER_SHIFT) & AA_EXEC_INHERIT)
|
||||
entry->mode |= AA_OLD_EXEC_MMAP << AA_USER_SHIFT;
|
||||
if ((entry->perms >> AA_OTHER_SHIFT) & AA_EXEC_INHERIT)
|
||||
entry->perms |= AA_OLD_EXEC_MMAP << AA_OTHER_SHIFT;
|
||||
if ((entry->perms >> AA_USER_SHIFT) & AA_EXEC_INHERIT)
|
||||
entry->perms |= AA_OLD_EXEC_MMAP << AA_USER_SHIFT;
|
||||
|
||||
/* the link bit on the first pair entry should not get masked
|
||||
* out by a deny rule, as both pieces of the link pair must
|
||||
@@ -627,24 +627,26 @@ static int process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry)
|
||||
* than link in the entry.
|
||||
* TODO: split link and change_profile entries earlier
|
||||
*/
|
||||
if (entry->deny) {
|
||||
if ((entry->mode & ~AA_LINK_BITS) &&
|
||||
!is_change_profile_mode(entry->mode) &&
|
||||
!dfarules->add_rule(tbuf.c_str(), entry->deny,
|
||||
entry->mode & ~(AA_LINK_BITS | AA_CHANGE_PROFILE),
|
||||
entry->audit & ~(AA_LINK_BITS | AA_CHANGE_PROFILE),
|
||||
if (entry->rule_mode == RULE_DENY) {
|
||||
if ((entry->perms & ~AA_LINK_BITS) &&
|
||||
!is_change_profile_perms(entry->perms) &&
|
||||
!dfarules->add_rule(tbuf.c_str(), entry->rule_mode == RULE_DENY,
|
||||
entry->perms & ~(AA_LINK_BITS | AA_CHANGE_PROFILE),
|
||||
entry->audit == AUDIT_FORCE ? entry->perms & ~(AA_LINK_BITS | AA_CHANGE_PROFILE) : 0,
|
||||
dfaflags))
|
||||
return FALSE;
|
||||
} else if (!is_change_profile_mode(entry->mode)) {
|
||||
if (!dfarules->add_rule(tbuf.c_str(), entry->deny, entry->mode,
|
||||
entry->audit, dfaflags))
|
||||
} else if (!is_change_profile_perms(entry->perms)) {
|
||||
if (!dfarules->add_rule(tbuf.c_str(),
|
||||
entry->rule_mode == RULE_DENY, entry->perms,
|
||||
entry->audit == AUDIT_FORCE ? entry->perms : 0,
|
||||
dfaflags))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (entry->mode & (AA_LINK_BITS)) {
|
||||
if (entry->perms & (AA_LINK_BITS)) {
|
||||
/* add the pair rule */
|
||||
std::string lbuf;
|
||||
int perms = AA_LINK_BITS & entry->mode;
|
||||
int perms = AA_LINK_BITS & entry->perms;
|
||||
const char *vec[2];
|
||||
int pos;
|
||||
vec[0] = tbuf.c_str();
|
||||
@@ -660,10 +662,10 @@ static int process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry)
|
||||
perms |= LINK_TO_LINK_SUBSET(perms);
|
||||
vec[1] = "/[^/].*";
|
||||
}
|
||||
if (!dfarules->add_rule_vec(entry->deny, perms, entry->audit & AA_LINK_BITS, 2, vec, dfaflags, false))
|
||||
if (!dfarules->add_rule_vec(entry->rule_mode == RULE_DENY, perms, entry->audit == AUDIT_FORCE ? perms & AA_LINK_BITS : 0, 2, vec, dfaflags, false))
|
||||
return FALSE;
|
||||
}
|
||||
if (is_change_profile_mode(entry->mode)) {
|
||||
if (is_change_profile_perms(entry->perms)) {
|
||||
const char *vec[3];
|
||||
std::string lbuf, xbuf;
|
||||
autofree char *ns = NULL;
|
||||
@@ -671,7 +673,7 @@ static int process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry)
|
||||
int index = 1;
|
||||
uint32_t onexec_perms = AA_ONEXEC;
|
||||
|
||||
if ((warnflags & WARN_RULE_DOWNGRADED) && entry->audit && warn_change_profile) {
|
||||
if ((warnflags & WARN_RULE_DOWNGRADED) && entry->audit == AUDIT_FORCE && warn_change_profile) {
|
||||
/* don't have profile name here, so until this code
|
||||
* gets refactored just throw out a generic warning
|
||||
*/
|
||||
@@ -711,13 +713,13 @@ static int process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry)
|
||||
}
|
||||
|
||||
/* regular change_profile rule */
|
||||
if (!dfarules->add_rule_vec(entry->deny,
|
||||
if (!dfarules->add_rule_vec(entry->rule_mode == RULE_DENY,
|
||||
AA_CHANGE_PROFILE | onexec_perms,
|
||||
0, index - 1, &vec[1], dfaflags, false))
|
||||
return FALSE;
|
||||
|
||||
/* onexec rules - both rules are needed for onexec */
|
||||
if (!dfarules->add_rule_vec(entry->deny, onexec_perms,
|
||||
if (!dfarules->add_rule_vec(entry->rule_mode == RULE_DENY, onexec_perms,
|
||||
0, 1, vec, dfaflags, false))
|
||||
return FALSE;
|
||||
|
||||
@@ -725,8 +727,8 @@ static int process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry)
|
||||
* pick up any exec bits, from the frontend parser, related to
|
||||
* unsafe exec transitions
|
||||
*/
|
||||
onexec_perms |= (entry->mode & (AA_EXEC_BITS | ALL_AA_EXEC_UNSAFE));
|
||||
if (!dfarules->add_rule_vec(entry->deny, onexec_perms,
|
||||
onexec_perms |= (entry->perms & (AA_EXEC_BITS | ALL_AA_EXEC_UNSAFE));
|
||||
if (!dfarules->add_rule_vec(entry->rule_mode == RULE_DENY, onexec_perms,
|
||||
0, index, vec, dfaflags, false))
|
||||
return FALSE;
|
||||
}
|
||||
@@ -841,6 +843,8 @@ int clear_and_convert_entry(std::string& buffer, char *entry)
|
||||
int post_process_policydb_ents(Profile *prof)
|
||||
{
|
||||
for (RuleList::iterator i = prof->rule_ents.begin(); i != prof->rule_ents.end(); i++) {
|
||||
if ((*i)->flags & RULE_FLAG_DELETED)
|
||||
continue;
|
||||
if ((*i)->gen_policy_re(*prof) == RULE_ERROR)
|
||||
return FALSE;
|
||||
}
|
||||
|
@@ -267,7 +267,9 @@ static int process_variables_in_entries(struct cod_entry *entry_list)
|
||||
static int process_variables_in_rules(Profile &prof)
|
||||
{
|
||||
for (RuleList::iterator i = prof.rule_ents.begin(); i != prof.rule_ents.end(); i++) {
|
||||
int error = (*i)->expand_variables();
|
||||
if ((*i)->flags & RULE_FLAG_DELETED)
|
||||
continue;
|
||||
int error = (*i)->expand_variables();
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
@@ -63,14 +63,15 @@
|
||||
|
||||
int parser_token = 0;
|
||||
|
||||
struct cod_entry *do_file_rule(char *id, int mode, char *link_id, char *nt);
|
||||
struct cod_entry *do_file_rule(char *id, perms_t perms, char *link_id, char *nt);
|
||||
mnt_rule *do_mnt_rule(struct cond_entry *src_conds, char *src,
|
||||
struct cond_entry *dst_conds, char *dst,
|
||||
int mode);
|
||||
perms_t perms);
|
||||
mnt_rule *do_pivot_rule(struct cond_entry *old, char *root,
|
||||
char *transition);
|
||||
static void abi_features(char *filename, bool search);
|
||||
void add_local_entry(Profile *prof);
|
||||
bool add_prefix(struct cod_entry *entry, const prefixes &p, const char *&error);
|
||||
bool check_x_qualifier(struct cod_entry *entry, const char *&errror);
|
||||
|
||||
%}
|
||||
|
||||
@@ -200,9 +201,10 @@ void add_local_entry(Profile *prof);
|
||||
unix_rule *unix_entry;
|
||||
userns_rule *userns_entry;
|
||||
mqueue_rule *mqueue_entry;
|
||||
prefix_rule_t *prefix_entry;
|
||||
|
||||
flagvals flags;
|
||||
int fmode;
|
||||
perms_t fperms;
|
||||
uint64_t cap;
|
||||
unsigned int allowed_protocol;
|
||||
char *set_var;
|
||||
@@ -214,16 +216,19 @@ void add_local_entry(Profile *prof);
|
||||
int boolean;
|
||||
struct prefixes prefix;
|
||||
IncludeCache_t *includecache;
|
||||
audit_t audit;
|
||||
rule_mode_t rule_mode;
|
||||
}
|
||||
|
||||
%type <id> TOK_ID
|
||||
%type <id> TOK_CONDID
|
||||
%type <id> TOK_CONDLISTID
|
||||
%type <mode> TOK_MODE
|
||||
%type <fmode> file_mode
|
||||
%type <fperms> file_perms
|
||||
%type <prof> profile_base
|
||||
%type <prof> profile
|
||||
%type <prof> rules
|
||||
%type <prof> block
|
||||
%type <prof> hat
|
||||
%type <prof> local_profile
|
||||
%type <prof> cond_rule
|
||||
@@ -252,40 +257,41 @@ void add_local_entry(Profile *prof);
|
||||
%type <id> id_or_var
|
||||
%type <id> opt_id_or_var
|
||||
%type <boolean> opt_subset_flag
|
||||
%type <boolean> opt_audit_flag
|
||||
%type <audit> opt_audit_flag
|
||||
%type <boolean> opt_owner_flag
|
||||
%type <boolean> opt_profile_flag
|
||||
%type <boolean> opt_flags
|
||||
%type <boolean> opt_perm_mode
|
||||
%type <rule_mode> opt_rule_mode
|
||||
%type <id> opt_id
|
||||
%type <prefix> opt_prefix
|
||||
%type <fmode> dbus_perm
|
||||
%type <fmode> dbus_perms
|
||||
%type <fmode> opt_dbus_perm
|
||||
%type <fperms> dbus_perm
|
||||
%type <fperms> dbus_perms
|
||||
%type <fperms> opt_dbus_perm
|
||||
%type <dbus_entry> dbus_rule
|
||||
%type <fmode> signal_perm
|
||||
%type <fmode> signal_perms
|
||||
%type <fmode> opt_signal_perm
|
||||
%type <prefix_entry> prefix_rule
|
||||
%type <fperms> signal_perm
|
||||
%type <fperms> signal_perms
|
||||
%type <fperms> opt_signal_perm
|
||||
%type <signal_entry> signal_rule
|
||||
%type <fmode> ptrace_perm
|
||||
%type <fmode> ptrace_perms
|
||||
%type <fmode> opt_ptrace_perm
|
||||
%type <fperms> ptrace_perm
|
||||
%type <fperms> ptrace_perms
|
||||
%type <fperms> opt_ptrace_perm
|
||||
%type <ptrace_entry> ptrace_rule
|
||||
%type <fmode> net_perm
|
||||
%type <fmode> net_perms
|
||||
%type <fmode> opt_net_perm
|
||||
%type <fperms> net_perm
|
||||
%type <fperms> net_perms
|
||||
%type <fperms> opt_net_perm
|
||||
%type <unix_entry> unix_rule
|
||||
%type <id> opt_target
|
||||
%type <id> opt_named_transition
|
||||
%type <boolean> opt_exec_mode
|
||||
%type <boolean> opt_file
|
||||
%type <fmode> userns_perm
|
||||
%type <fmode> userns_perms
|
||||
%type <fmode> opt_userns_perm
|
||||
%type <fperms> userns_perm
|
||||
%type <fperms> userns_perms
|
||||
%type <fperms> opt_userns_perm
|
||||
%type <userns_entry> userns_rule
|
||||
%type <fmode> mqueue_perm
|
||||
%type <fmode> mqueue_perms
|
||||
%type <fmode> opt_mqueue_perm
|
||||
%type <fperms> mqueue_perm
|
||||
%type <fperms> mqueue_perms
|
||||
%type <fperms> opt_mqueue_perm
|
||||
%type <mqueue_entry> mqueue_rule
|
||||
%%
|
||||
|
||||
@@ -394,8 +400,7 @@ profile_base: TOK_ID opt_id_or_var opt_cond_list flags TOK_OPEN
|
||||
*/
|
||||
prof->flags.mode = MODE_COMPLAIN;
|
||||
|
||||
post_process_file_entries(prof);
|
||||
post_process_rule_entries(prof);
|
||||
prof->post_parse_profile();
|
||||
prof->flags.debug(cerr);
|
||||
|
||||
/* restore previous blocks include cache */
|
||||
@@ -432,7 +437,6 @@ local_profile: TOK_PROFILE profile_base
|
||||
|
||||
if ($2)
|
||||
PDEBUG("Matched: local profile %s { ... }\n", prof->name);
|
||||
prof->local = 1;
|
||||
$$ = prof;
|
||||
};
|
||||
|
||||
@@ -646,25 +650,25 @@ flagval: TOK_VALUE
|
||||
$$ = fv;
|
||||
};
|
||||
|
||||
opt_subset_flag: { /* nothing */ $$ = 0; }
|
||||
| TOK_SUBSET { $$ = 1; }
|
||||
| TOK_LE { $$ = 1; }
|
||||
opt_subset_flag: { /* nothing */ $$ = false; }
|
||||
| TOK_SUBSET { $$ = true; }
|
||||
| TOK_LE { $$ = true; }
|
||||
|
||||
opt_audit_flag: { /* nothing */ $$ = 0; }
|
||||
| TOK_AUDIT { $$ = 1; };
|
||||
opt_audit_flag: { /* nothing */ $$ = AUDIT_UNSPECIFIED; }
|
||||
| TOK_AUDIT { $$ = AUDIT_FORCE; };
|
||||
|
||||
opt_owner_flag: { /* nothing */ $$ = 0; }
|
||||
| TOK_OWNER { $$ = 1; };
|
||||
| TOK_OTHER { $$ = 2; };
|
||||
|
||||
opt_perm_mode: { /* nothing */ $$ = 0; }
|
||||
| TOK_ALLOW { $$ = 0; }
|
||||
| TOK_DENY { $$ = 1; }
|
||||
opt_rule_mode: { /* nothing */ $$ = RULE_UNSPECIFIED; }
|
||||
| TOK_ALLOW { $$ = RULE_ALLOW; }
|
||||
| TOK_DENY { $$ = RULE_DENY; }
|
||||
|
||||
opt_prefix: opt_audit_flag opt_perm_mode opt_owner_flag
|
||||
opt_prefix: opt_audit_flag opt_rule_mode opt_owner_flag
|
||||
{
|
||||
$$.audit = $1;
|
||||
$$.deny = $2;
|
||||
$$.rule_mode = $2;
|
||||
$$.owner = $3;
|
||||
}
|
||||
|
||||
@@ -681,64 +685,44 @@ rules: rules abi_rule { /* nothing */ }
|
||||
|
||||
rules: rules opt_prefix rule
|
||||
{
|
||||
const char *error;
|
||||
PDEBUG("matched: rules rule\n");
|
||||
PDEBUG("rules rule: (%s)\n", $3->name);
|
||||
if (!$3)
|
||||
yyerror(_("Assert: `rule' returned NULL."));
|
||||
$3->deny = $2.deny;
|
||||
if (($2.deny && ($3->mode & AA_EXEC_BITS) &&
|
||||
($3->mode & ALL_AA_EXEC_TYPE)))
|
||||
yyerror(_("Invalid mode, in deny rules 'x' must not be preceded by exec qualifier 'i', 'p', or 'u'"));
|
||||
else if (!$2.deny && ($3->mode & AA_EXEC_BITS) &&
|
||||
!($3->mode & ALL_AA_EXEC_TYPE) &&
|
||||
!($3->nt_name))
|
||||
yyerror(_("Invalid mode, 'x' must be preceded by exec qualifier 'i', 'p', 'c', or 'u'"));
|
||||
|
||||
if ($2.owner == 1)
|
||||
$3->mode &= (AA_USER_PERMS | AA_SHARED_PERMS);
|
||||
else if ($2.owner == 2)
|
||||
$3->mode &= (AA_OTHER_PERMS | AA_SHARED_PERMS);
|
||||
/* only set audit ctl quieting if the rule is not audited */
|
||||
if (($2.deny && !$2.audit) || (!$2.deny && $2.audit))
|
||||
$3->audit = $3->mode & ~ALL_AA_EXEC_TYPE;
|
||||
|
||||
if (!add_prefix($3, $2, error)) {
|
||||
yyerror(_("%s"), error);
|
||||
}
|
||||
add_entry_to_policy($1, $3);
|
||||
$$ = $1;
|
||||
};
|
||||
|
||||
block: TOK_OPEN rules TOK_CLOSE
|
||||
{
|
||||
$$ = $2;
|
||||
};
|
||||
|
||||
rules: rules opt_prefix TOK_OPEN rules TOK_CLOSE
|
||||
rules: rules opt_prefix block
|
||||
{
|
||||
struct cod_entry *entry, *tmp;
|
||||
if ($2.deny)
|
||||
yyerror(_("deny prefix not allowed"));
|
||||
|
||||
PDEBUG("matched: %s%s%sblock\n", $2.audit ? "audit " : "",
|
||||
$2.deny ? "deny " : "", $2.owner ? "owner " : "");
|
||||
list_for_each_safe($4->entries, entry, tmp) {
|
||||
PDEBUG("matched: %s%s%sblock\n", $2.audit == AUDIT_FORCE ? "audit " : "",
|
||||
$2.rule_mode == RULE_DENY ? "deny " : "", $2.owner ? "owner " : "");
|
||||
list_for_each_safe($3->entries, entry, tmp) {
|
||||
const char *error;
|
||||
entry->next = NULL;
|
||||
if (entry->mode & AA_EXEC_BITS) {
|
||||
if (entry->deny &&
|
||||
(entry->mode & ALL_AA_EXEC_TYPE))
|
||||
yyerror(_("Invalid mode, in deny rules 'x' must not be preceded by exec qualifier 'i', 'p', or 'u'"));
|
||||
else if (!entry->deny &&
|
||||
!(entry->mode & ALL_AA_EXEC_TYPE))
|
||||
yyerror(_("Invalid mode, 'x' must be preceded by exec qualifier 'i', 'p', or 'u'"));
|
||||
if (!add_prefix(entry, $2, error)) {
|
||||
yyerror(_("%s"), error);
|
||||
}
|
||||
if ($2.owner == 1)
|
||||
entry->mode &= (AA_USER_PERMS | AA_SHARED_PERMS);
|
||||
else if ($2.owner == 2)
|
||||
entry->mode &= (AA_OTHER_PERMS | AA_SHARED_PERMS);
|
||||
|
||||
if ($2.audit && !entry->deny)
|
||||
entry->audit = entry->mode & ~ALL_AA_EXEC_TYPE;
|
||||
else if (!$2.audit && entry->deny)
|
||||
entry->audit = entry->mode & ~ALL_AA_EXEC_TYPE;
|
||||
/* transfer rule for now, TODO keep block and just
|
||||
* apply add_prefix to block rule and have it do
|
||||
* the work
|
||||
*/
|
||||
add_entry_to_policy($1, entry);
|
||||
}
|
||||
$4->entries = NULL;
|
||||
$3->entries = NULL;
|
||||
// fix me transfer rules and free sub profile
|
||||
delete $4;
|
||||
delete $3;
|
||||
$$ = $1;
|
||||
};
|
||||
|
||||
@@ -759,30 +743,30 @@ rules: rules opt_prefix network_rule
|
||||
* downgrade if needed
|
||||
*/
|
||||
if (entry->family == AF_UNIX) {
|
||||
unix_rule *rule = new unix_rule(entry->type, $2.audit, $2.deny);
|
||||
unix_rule *rule = new unix_rule(entry->type, $2.audit, $2.rule_mode);
|
||||
if (!rule)
|
||||
yyerror(_("Memory allocation error."));
|
||||
$1->rule_ents.push_back(rule);
|
||||
}
|
||||
if (entry->type > SOCK_PACKET) {
|
||||
/* setting mask instead of a bit */
|
||||
if ($2.deny) {
|
||||
if ($2.rule_mode == RULE_DENY) {
|
||||
$1->net.deny[entry->family] |= entry->type;
|
||||
if (!$2.audit)
|
||||
if ($2.audit != AUDIT_FORCE)
|
||||
$1->net.quiet[entry->family] |= entry->type;
|
||||
} else {
|
||||
$1->net.allow[entry->family] |= entry->type;
|
||||
if ($2.audit)
|
||||
if ($2.audit == AUDIT_FORCE)
|
||||
$1->net.audit[entry->family] |= entry->type;
|
||||
}
|
||||
} else {
|
||||
if ($2.deny) {
|
||||
if ($2.rule_mode == RULE_DENY) {
|
||||
$1->net.deny[entry->family] |= 1 << entry->type;
|
||||
if (!$2.audit)
|
||||
if ($2.audit != AUDIT_FORCE)
|
||||
$1->net.quiet[entry->family] |= 1 << entry->type;
|
||||
} else {
|
||||
$1->net.allow[entry->family] |= 1 << entry->type;
|
||||
if ($2.audit)
|
||||
if ($2.audit == AUDIT_FORCE)
|
||||
$1->net.audit[entry->family] |= 1 << entry->type;
|
||||
}
|
||||
}
|
||||
@@ -792,99 +776,19 @@ rules: rules opt_prefix network_rule
|
||||
$$ = $1;
|
||||
}
|
||||
|
||||
rules: rules opt_prefix mnt_rule
|
||||
{
|
||||
if ($2.owner)
|
||||
yyerror(_("owner prefix not allowed on mount rules"));
|
||||
if ($2.deny && $2.audit) {
|
||||
$3->deny = 1;
|
||||
} else if ($2.deny) {
|
||||
$3->deny = 1;
|
||||
$3->audit = $3->allow;
|
||||
} else if ($2.audit) {
|
||||
$3->audit = $3->allow;
|
||||
}
|
||||
prefix_rule : mnt_rule { $$ = $1; }
|
||||
| dbus_rule { $$ = $1; }
|
||||
| signal_rule { $$ = $1; }
|
||||
| ptrace_rule { $$ = $1; }
|
||||
| unix_rule { $$ = $1; }
|
||||
| userns_rule { $$ = $1; }
|
||||
| mqueue_rule { $$ = $1; }
|
||||
|
||||
$1->rule_ents.push_back($3);
|
||||
$$ = $1;
|
||||
}
|
||||
|
||||
rules: rules opt_prefix dbus_rule
|
||||
rules: rules opt_prefix prefix_rule
|
||||
{
|
||||
if ($2.owner)
|
||||
yyerror(_("owner prefix not allowed on dbus rules"));
|
||||
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 opt_prefix signal_rule
|
||||
{
|
||||
if ($2.owner)
|
||||
yyerror(_("owner prefix not allowed on signal rules"));
|
||||
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 opt_prefix ptrace_rule
|
||||
{
|
||||
if ($2.owner)
|
||||
yyerror(_("owner prefix not allowed on ptrace rules"));
|
||||
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 opt_prefix unix_rule
|
||||
{
|
||||
if ($2.owner)
|
||||
yyerror(_("owner prefix not allowed on unix rules"));
|
||||
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 opt_prefix userns_rule
|
||||
{
|
||||
if ($2.owner)
|
||||
yyerror(_("owner prefix not allowed on userns rules"));
|
||||
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;
|
||||
}
|
||||
const char *error;
|
||||
if (!$3->add_prefix($2, error))
|
||||
yyerror(error);
|
||||
$1->rule_ents.push_back($3);
|
||||
$$ = $1;
|
||||
}
|
||||
@@ -897,13 +801,13 @@ rules: rules opt_prefix change_profile
|
||||
yyerror(_("Assert: `change_profile' returned NULL."));
|
||||
if ($2.owner)
|
||||
yyerror(_("owner prefix not allowed on unix rules"));
|
||||
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;
|
||||
if (($2.rule_mode == RULE_DENY) && $2.audit == AUDIT_FORCE) {
|
||||
$3->rule_mode = RULE_DENY;
|
||||
} else if ($2.rule_mode == RULE_DENY) {
|
||||
$3->rule_mode = RULE_DENY;
|
||||
$3->audit = AUDIT_FORCE;
|
||||
} else if ($2.audit != AUDIT_UNSPECIFIED) {
|
||||
$3->audit = $2.audit;
|
||||
}
|
||||
add_entry_to_policy($1, $3);
|
||||
$$ = $1;
|
||||
@@ -914,36 +818,20 @@ rules: rules opt_prefix capability
|
||||
if ($2.owner)
|
||||
yyerror(_("owner prefix not allowed on capability rules"));
|
||||
|
||||
if ($2.deny && $2.audit) {
|
||||
if ($2.rule_mode == RULE_DENY && $2.audit == AUDIT_FORCE) {
|
||||
$1->caps.deny |= $3;
|
||||
} else if ($2.deny) {
|
||||
} else if ($2.rule_mode == RULE_DENY) {
|
||||
$1->caps.deny |= $3;
|
||||
$1->caps.quiet |= $3;
|
||||
} else {
|
||||
$1->caps.allow |= $3;
|
||||
if ($2.audit)
|
||||
if ($2.audit != AUDIT_UNSPECIFIED)
|
||||
$1->caps.audit |= $3;
|
||||
}
|
||||
|
||||
$$ = $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");
|
||||
@@ -959,7 +847,6 @@ rules: rules local_profile
|
||||
if (!$2)
|
||||
yyerror(_("Assert: 'local_profile rule' returned NULL."));
|
||||
add_hat_to_policy($1, $2);
|
||||
add_local_entry($2);
|
||||
$$ = $1;
|
||||
};
|
||||
|
||||
@@ -1068,42 +955,42 @@ rules: rules TOK_SET TOK_RLIMIT TOK_ID TOK_LE TOK_VALUE opt_id TOK_END_OF_RULE
|
||||
};
|
||||
|
||||
|
||||
cond_rule: TOK_IF expr TOK_OPEN rules TOK_CLOSE
|
||||
cond_rule: TOK_IF expr block
|
||||
{
|
||||
Profile *ret = NULL;
|
||||
PDEBUG("Matched: found conditional rules\n");
|
||||
if ($2) {
|
||||
ret = $4;
|
||||
ret = $3;
|
||||
} else {
|
||||
delete $4;
|
||||
delete $3;
|
||||
}
|
||||
$$ = ret;
|
||||
}
|
||||
|
||||
cond_rule: TOK_IF expr TOK_OPEN rules TOK_CLOSE TOK_ELSE TOK_OPEN rules TOK_CLOSE
|
||||
cond_rule: TOK_IF expr block TOK_ELSE block
|
||||
{
|
||||
Profile *ret = NULL;
|
||||
PDEBUG("Matched: found conditional else rules\n");
|
||||
if ($2) {
|
||||
ret = $4;
|
||||
delete $8;
|
||||
ret = $3;
|
||||
delete $5;
|
||||
} else {
|
||||
ret = $8;
|
||||
delete $4;
|
||||
ret = $5;
|
||||
delete $3;
|
||||
}
|
||||
$$ = ret;
|
||||
}
|
||||
|
||||
cond_rule: TOK_IF expr TOK_OPEN rules TOK_CLOSE TOK_ELSE cond_rule
|
||||
cond_rule: TOK_IF expr block TOK_ELSE cond_rule
|
||||
{
|
||||
Profile *ret = NULL;
|
||||
PDEBUG("Matched: found conditional else-if rules\n");
|
||||
if ($2) {
|
||||
ret = $4;
|
||||
delete $7;
|
||||
ret = $3;
|
||||
delete $5;
|
||||
} else {
|
||||
ret = $7;
|
||||
delete $4;
|
||||
ret = $5;
|
||||
delete $3;
|
||||
}
|
||||
$$ = ret;
|
||||
}
|
||||
@@ -1183,12 +1070,12 @@ opt_exec_mode: { /* nothing */ $$ = EXEC_MODE_EMPTY; }
|
||||
opt_file: { /* nothing */ $$ = 0; }
|
||||
| TOK_FILE { $$ = 1; }
|
||||
|
||||
frule: id_or_var file_mode opt_named_transition TOK_END_OF_RULE
|
||||
frule: id_or_var file_perms opt_named_transition TOK_END_OF_RULE
|
||||
{
|
||||
$$ = do_file_rule($1, $2, NULL, $3);
|
||||
};
|
||||
|
||||
frule: file_mode opt_subset_flag id_or_var opt_named_transition TOK_END_OF_RULE
|
||||
frule: file_perms opt_subset_flag id_or_var opt_named_transition TOK_END_OF_RULE
|
||||
{
|
||||
if ($2 && ($1 & ~AA_LINK_BITS))
|
||||
yyerror(_("subset can only be used with link rules."));
|
||||
@@ -1223,19 +1110,19 @@ file_rule: TOK_FILE TOK_END_OF_RULE
|
||||
file_rule_tail: opt_exec_mode frule
|
||||
{
|
||||
if ($1 != EXEC_MODE_EMPTY) {
|
||||
if (!($2->mode & AA_EXEC_BITS))
|
||||
if (!($2->perms & AA_EXEC_BITS))
|
||||
yyerror(_("unsafe rule missing exec permissions"));
|
||||
if ($1 == EXEC_MODE_UNSAFE) {
|
||||
$2->mode |= (($2->mode & AA_EXEC_BITS) << 8) &
|
||||
$2->perms |= (($2->perms & AA_EXEC_BITS) << 8) &
|
||||
ALL_AA_EXEC_UNSAFE;
|
||||
}
|
||||
else if ($1 == EXEC_MODE_SAFE)
|
||||
$2->mode &= ~ALL_AA_EXEC_UNSAFE;
|
||||
$2->perms &= ~ALL_AA_EXEC_UNSAFE;
|
||||
}
|
||||
$$ = $2;
|
||||
};
|
||||
|
||||
file_rule_tail: opt_exec_mode id_or_var file_mode id_or_var
|
||||
file_rule_tail: opt_exec_mode id_or_var file_perms id_or_var
|
||||
{
|
||||
/* Oopsie, we appear to be missing an EOL marker. If we
|
||||
* were *smart*, we could work around it. Since we're
|
||||
@@ -1387,7 +1274,7 @@ dbus_perm: TOK_VALUE
|
||||
else if (strcmp($1, "eavesdrop") == 0)
|
||||
$$ = AA_DBUS_EAVESDROP;
|
||||
else if ($1) {
|
||||
parse_dbus_mode($1, &$$, 1);
|
||||
parse_dbus_perms($1, &$$, 1);
|
||||
} else
|
||||
$$ = 0;
|
||||
|
||||
@@ -1402,7 +1289,7 @@ dbus_perm: TOK_VALUE
|
||||
| TOK_EAVESDROP { $$ = AA_DBUS_EAVESDROP; }
|
||||
| TOK_MODE
|
||||
{
|
||||
parse_dbus_mode($1, &$$, 1);
|
||||
parse_dbus_perms($1, &$$, 1);
|
||||
free($1);
|
||||
}
|
||||
|
||||
@@ -1457,7 +1344,7 @@ net_perm: TOK_VALUE
|
||||
else if (strcmp($1, "receive") == 0 || strcmp($1, "read") == 0)
|
||||
$$ = AA_NET_RECEIVE;
|
||||
else if ($1) {
|
||||
parse_net_mode($1, &$$, 1);
|
||||
parse_net_perms($1, &$$, 1);
|
||||
} else
|
||||
$$ = 0;
|
||||
|
||||
@@ -1480,7 +1367,7 @@ net_perm: TOK_VALUE
|
||||
| TOK_WRITE { $$ = AA_NET_SEND; }
|
||||
| TOK_MODE
|
||||
{
|
||||
parse_unix_mode($1, &$$, 1);
|
||||
parse_unix_perms($1, &$$, 1);
|
||||
free($1);
|
||||
}
|
||||
|
||||
@@ -1515,7 +1402,7 @@ signal_perm: TOK_VALUE
|
||||
else if (strcmp($1, "receive") == 0 || strcmp($1, "read") == 0)
|
||||
$$ = AA_MAY_RECEIVE;
|
||||
else if ($1) {
|
||||
parse_signal_mode($1, &$$, 1);
|
||||
parse_signal_perms($1, &$$, 1);
|
||||
} else
|
||||
$$ = 0;
|
||||
|
||||
@@ -1528,7 +1415,7 @@ signal_perm: TOK_VALUE
|
||||
| TOK_WRITE { $$ = AA_MAY_SEND; }
|
||||
| TOK_MODE
|
||||
{
|
||||
parse_signal_mode($1, &$$, 1);
|
||||
parse_signal_perms($1, &$$, 1);
|
||||
free($1);
|
||||
}
|
||||
|
||||
@@ -1557,7 +1444,7 @@ ptrace_perm: TOK_VALUE
|
||||
else if (strcmp($1, "readby") == 0)
|
||||
$$ = AA_MAY_READBY;
|
||||
else if ($1)
|
||||
parse_ptrace_mode($1, &$$, 1);
|
||||
parse_ptrace_perms($1, &$$, 1);
|
||||
else
|
||||
$$ = 0;
|
||||
|
||||
@@ -1571,7 +1458,7 @@ ptrace_perm: TOK_VALUE
|
||||
| TOK_READBY { $$ = AA_MAY_READBY; }
|
||||
| TOK_MODE
|
||||
{
|
||||
parse_ptrace_mode($1, &$$, 1);
|
||||
parse_ptrace_perms($1, &$$, 1);
|
||||
free($1);
|
||||
}
|
||||
|
||||
@@ -1632,7 +1519,7 @@ mqueue_perm: TOK_VALUE
|
||||
else if (strcmp($1, "read") == 0)
|
||||
$$ = AA_MQUEUE_READ;
|
||||
else if ($1) {
|
||||
parse_mqueue_mode($1, &$$, 1);
|
||||
parse_mqueue_perms($1, &$$, 1);
|
||||
} else
|
||||
$$ = 0;
|
||||
|
||||
@@ -1648,7 +1535,7 @@ mqueue_perm: TOK_VALUE
|
||||
| TOK_READ { $$ = AA_MQUEUE_READ; }
|
||||
| TOK_MODE
|
||||
{
|
||||
parse_mqueue_mode($1, &$$, 1);
|
||||
parse_mqueue_perms($1, &$$, 1);
|
||||
free($1);
|
||||
}
|
||||
|
||||
@@ -1674,18 +1561,18 @@ mqueue_rule: TOK_MQUEUE opt_mqueue_perm opt_conds TOK_END_OF_RULE
|
||||
hat_start: TOK_CARET {}
|
||||
| TOK_HAT {}
|
||||
|
||||
file_mode: TOK_MODE
|
||||
file_perms: TOK_MODE
|
||||
{
|
||||
/* A single TOK_MODE maps to the same permission in all
|
||||
* of user::other */
|
||||
$$ = parse_mode($1);
|
||||
$$ = parse_perms($1);
|
||||
free($1);
|
||||
}
|
||||
|
||||
change_profile: TOK_CHANGE_PROFILE opt_exec_mode opt_id opt_named_transition TOK_END_OF_RULE
|
||||
{
|
||||
struct cod_entry *entry;
|
||||
int mode = AA_CHANGE_PROFILE;
|
||||
perms_t perms = AA_CHANGE_PROFILE;
|
||||
int exec_mode = $2;
|
||||
char *exec = $3;
|
||||
char *target = $4;
|
||||
@@ -1694,9 +1581,9 @@ change_profile: TOK_CHANGE_PROFILE opt_exec_mode opt_id opt_named_transition TOK
|
||||
/* exec bits required to trigger rule conflict if
|
||||
* for overlapping safe and unsafe exec rules
|
||||
*/
|
||||
mode |= AA_EXEC_BITS;
|
||||
perms |= AA_EXEC_BITS;
|
||||
if (exec_mode == EXEC_MODE_UNSAFE)
|
||||
mode |= ALL_AA_EXEC_UNSAFE;
|
||||
perms |= ALL_AA_EXEC_UNSAFE;
|
||||
else if (exec_mode == EXEC_MODE_SAFE &&
|
||||
!features_supports_stacking) {
|
||||
pwarn(WARN_RULE_DOWNGRADED, "downgrading change_profile safe rule to unsafe due to lack of necessary kernel support\n");
|
||||
@@ -1720,7 +1607,7 @@ change_profile: TOK_CHANGE_PROFILE opt_exec_mode opt_id opt_named_transition TOK
|
||||
yyerror(_("Memory allocation error."));
|
||||
}
|
||||
|
||||
entry = new_entry(target, mode, exec);
|
||||
entry = new_entry(target, perms, exec);
|
||||
if (!entry)
|
||||
yyerror(_("Memory allocation error."));
|
||||
|
||||
@@ -1793,11 +1680,11 @@ void yyerror(const char *msg, ...)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct cod_entry *do_file_rule(char *id, int mode, char *link_id, char *nt)
|
||||
struct cod_entry *do_file_rule(char *id, perms_t perms, char *link_id, char *nt)
|
||||
{
|
||||
struct cod_entry *entry;
|
||||
PDEBUG("Matched: tok_id (%s) tok_mode (0x%x)\n", id, mode);
|
||||
entry = new_entry(id, mode, link_id);
|
||||
PDEBUG("Matched: tok_id (%s) tok_perms (0x%x)\n", id, perms);
|
||||
entry = new_entry(id, perms, link_id);
|
||||
if (!entry)
|
||||
yyerror(_("Memory allocation error."));
|
||||
entry->nt_name = nt;
|
||||
@@ -1805,31 +1692,6 @@ struct cod_entry *do_file_rule(char *id, int mode, char *link_id, char *nt)
|
||||
return entry;
|
||||
}
|
||||
|
||||
/* Note: NOT currently in use, used for
|
||||
* /foo x -> { /bah, } style transitions
|
||||
*/
|
||||
void add_local_entry(Profile *prof)
|
||||
{
|
||||
/* ugh this has to be called after the hat is attached to its parent */
|
||||
if (prof->local_mode) {
|
||||
struct cod_entry *entry;
|
||||
char *trans = (char *) malloc(strlen(prof->parent->name) +
|
||||
strlen(prof->name) + 3);
|
||||
char *name = strdup(prof->name);
|
||||
if (!trans)
|
||||
yyerror(_("Memory allocation error."));
|
||||
sprintf(name, "%s//%s", prof->parent->name, prof->name);
|
||||
|
||||
entry = new_entry(name, prof->local_mode, NULL);
|
||||
entry->audit = prof->local_audit;
|
||||
entry->nt_name = trans;
|
||||
if (!entry)
|
||||
yyerror(_("Memory allocation error."));
|
||||
|
||||
add_entry_to_policy(prof, entry);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *mnt_cond_msg[] = {"",
|
||||
" not allowed as source conditional",
|
||||
" not allowed as target conditional",
|
||||
@@ -1859,7 +1721,7 @@ int verify_mnt_conds(struct cond_entry *conds, int src)
|
||||
|
||||
mnt_rule *do_mnt_rule(struct cond_entry *src_conds, char *src,
|
||||
struct cond_entry *dst_conds, char *dst,
|
||||
int mode)
|
||||
perms_t perms)
|
||||
{
|
||||
if (verify_mnt_conds(src_conds, MNT_SRC_OPT) != 0)
|
||||
yyerror(_("bad mount rule"));
|
||||
@@ -1871,7 +1733,7 @@ mnt_rule *do_mnt_rule(struct cond_entry *src_conds, char *src,
|
||||
if (dst_conds)
|
||||
yyerror(_("mount point conditions not currently supported"));
|
||||
|
||||
mnt_rule *ent = new mnt_rule(src_conds, src, dst_conds, dst, mode);
|
||||
mnt_rule *ent = new mnt_rule(src_conds, src, dst_conds, dst, perms);
|
||||
if (!ent) {
|
||||
yyerror(_("Memory allocation error."));
|
||||
}
|
||||
@@ -1957,3 +1819,44 @@ static void abi_features(char *filename, bool search)
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
bool check_x_qualifier(struct cod_entry *entry, const char *&error)
|
||||
{
|
||||
if (entry->perms & AA_EXEC_BITS) {
|
||||
if ((entry->rule_mode == RULE_DENY) &&
|
||||
(entry->perms & ALL_AA_EXEC_TYPE)) {
|
||||
error = _("Invalid perms, in deny rules 'x' must not be preceded by exec qualifier 'i', 'p', or 'u'");
|
||||
return false;
|
||||
} else if ((entry->rule_mode != RULE_DENY) &&
|
||||
!(entry->perms & ALL_AA_EXEC_TYPE)) {
|
||||
error = _("Invalid perms, 'x' must be preceded by exec qualifier 'i', 'p', or 'u'");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// cod_entry version of ->add_prefix here just as file rules aren't converted yet
|
||||
bool add_prefix(struct cod_entry *entry, const prefixes &p, const char *&error)
|
||||
{
|
||||
/* modifiers aren't correctly stored for cod_entries yet so
|
||||
* we can't conflict on them easily. Leave that until conversion
|
||||
* to rule_t
|
||||
*/
|
||||
/* apply rule mode */
|
||||
entry->rule_mode = p.rule_mode;
|
||||
|
||||
/* apply owner/other */
|
||||
if (p.owner == 1)
|
||||
entry->perms &= (AA_USER_PERMS | AA_SHARED_PERMS);
|
||||
else if (p.owner == 2)
|
||||
entry->perms &= (AA_OTHER_PERMS | AA_SHARED_PERMS);
|
||||
|
||||
/* implied audit modifier */
|
||||
if (p.audit == AUDIT_FORCE && (entry->rule_mode != RULE_DENY))
|
||||
entry->audit = AUDIT_FORCE;
|
||||
else if (p.audit != AUDIT_FORCE && (entry->rule_mode == RULE_DENY))
|
||||
entry->audit = AUDIT_FORCE;
|
||||
|
||||
return check_x_qualifier(entry, error);
|
||||
}
|
||||
|
@@ -32,13 +32,21 @@
|
||||
#define AA_CLASS_NS_DOMAIN 8
|
||||
#define AA_CLASS_PTRACE 9
|
||||
#define AA_CLASS_SIGNAL 10
|
||||
#define AA_CLASS_XMATCH 11
|
||||
#define AA_CLASS_ENV 12
|
||||
#define AA_CLASS_ARGV 13
|
||||
#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_MODULE 19
|
||||
#define AA_CLASS_DISPLAY_LSM 20
|
||||
#define AA_CLASS_NS 21
|
||||
#define AA_CLASS_IO_URING 22
|
||||
|
||||
#define AA_CLASS_X 31
|
||||
/* defined in libapparmor's apparmor.h #define AA_CLASS_DBUS 32 */
|
||||
#define AA_CLASS_X 33
|
||||
|
||||
extern const char *aa_class_table[];
|
||||
|
||||
#endif /* __AA_POLICYDB_H */
|
||||
|
@@ -14,9 +14,12 @@
|
||||
|
||||
#include "profile.h"
|
||||
#include "rule.h"
|
||||
#include "parser.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
const char *profile_mode_table[] = {
|
||||
"",
|
||||
@@ -118,3 +121,241 @@ Profile::~Profile()
|
||||
free(net.quiet);
|
||||
}
|
||||
|
||||
static bool comp (rule_t *lhs, rule_t *rhs) { return (*lhs < *rhs); }
|
||||
|
||||
bool Profile::merge_rules(void)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
for (RuleList::iterator i = rule_ents.begin(); i != rule_ents.end(); ) {
|
||||
if ((*i)->is_mergeable())
|
||||
count++;
|
||||
}
|
||||
if (count < 2)
|
||||
return 0;
|
||||
|
||||
std::vector<rule_t *> table(count);
|
||||
int n = 0;
|
||||
for (RuleList::iterator i = rule_ents.begin(); i != rule_ents.end(); ) {
|
||||
if ((*i)->is_mergeable())
|
||||
table[n++] = *i;
|
||||
}
|
||||
|
||||
std::sort(table.begin(), table.end(), comp);
|
||||
|
||||
for (int i = 0, j = 1; j < count; j++) {
|
||||
if (table[i]->cmp(*table[j]) == 0) {
|
||||
if (!table[i]->merge(*table[j]))
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
i = j;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int add_entry_to_x_table(Profile *prof, char *name)
|
||||
{
|
||||
int i;
|
||||
for (i = (AA_EXEC_LOCAL >> 10) + 1; i < AA_EXEC_COUNT; i++) {
|
||||
if (!prof->exec_table[i]) {
|
||||
prof->exec_table[i] = name;
|
||||
return i;
|
||||
} else if (strcmp(prof->exec_table[i], name) == 0) {
|
||||
/* name already in table */
|
||||
free(name);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
free(name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void add_entry_to_policy(Profile *prof, struct cod_entry *entry)
|
||||
{
|
||||
entry->next = prof->entries;
|
||||
prof->entries = entry;
|
||||
}
|
||||
|
||||
static int add_named_transition(Profile *prof, struct cod_entry *entry)
|
||||
{
|
||||
char *name = NULL;
|
||||
|
||||
/* check to see if it is a local transition */
|
||||
if (!label_contains_ns(entry->nt_name)) {
|
||||
char *sub = strstr(entry->nt_name, "//");
|
||||
/* does the subprofile name match the rule */
|
||||
|
||||
if (sub && strncmp(prof->name, sub, sub - entry->nt_name) &&
|
||||
strcmp(sub + 2, entry->name) == 0) {
|
||||
free(entry->nt_name);
|
||||
entry->nt_name = NULL;
|
||||
return AA_EXEC_LOCAL >> 10;
|
||||
} else if (((entry->perms & AA_USER_EXEC_MODIFIERS) ==
|
||||
SHIFT_PERMS(AA_EXEC_LOCAL, AA_USER_SHIFT)) ||
|
||||
((entry->perms & AA_OTHER_EXEC_MODIFIERS) ==
|
||||
SHIFT_PERMS(AA_EXEC_LOCAL, AA_OTHER_SHIFT))) {
|
||||
if (strcmp(entry->nt_name, entry->name) == 0) {
|
||||
free(entry->nt_name);
|
||||
entry->nt_name = NULL;
|
||||
return AA_EXEC_LOCAL >> 10;
|
||||
}
|
||||
/* specified as cix so profile name is implicit */
|
||||
name = (char *) malloc(strlen(prof->name) + strlen(entry->nt_name)
|
||||
+ 3);
|
||||
if (!name) {
|
||||
PERROR("Memory allocation error\n");
|
||||
exit(1);
|
||||
}
|
||||
sprintf(name, "%s//%s", prof->name, entry->nt_name);
|
||||
free(entry->nt_name);
|
||||
entry->nt_name = NULL;
|
||||
} else {
|
||||
/**
|
||||
* pass control of the memory pointed to by nt_name
|
||||
* from entry to add_entry_to_x_table()
|
||||
*/
|
||||
name = entry->nt_name;
|
||||
entry->nt_name = NULL;
|
||||
}
|
||||
} else {
|
||||
/**
|
||||
* pass control of the memory pointed to by nt_name
|
||||
* from entry to add_entry_to_x_table()
|
||||
*/
|
||||
name = entry->nt_name;
|
||||
entry->nt_name = NULL;
|
||||
}
|
||||
|
||||
return add_entry_to_x_table(prof, name);
|
||||
}
|
||||
|
||||
static bool add_proc_access(Profile *prof, const char *rule)
|
||||
{
|
||||
/* FIXME: should use @{PROC}/@{PID}/attr/{apparmor/,}{current,exec} */
|
||||
struct cod_entry *new_ent;
|
||||
/* allow probe for new interfaces */
|
||||
char *buffer = strdup("/proc/*/attr/apparmor/");
|
||||
if (!buffer) {
|
||||
PERROR("Memory allocation error\n");
|
||||
return FALSE;
|
||||
}
|
||||
new_ent = new_entry(buffer, AA_MAY_READ, NULL);
|
||||
if (!new_ent) {
|
||||
free(buffer);
|
||||
PERROR("Memory allocation error\n");
|
||||
return FALSE;
|
||||
}
|
||||
add_entry_to_policy(prof, new_ent);
|
||||
|
||||
/* allow probe if apparmor is enabled for the old interface */
|
||||
buffer = strdup("/sys/module/apparmor/parameters/enabled");
|
||||
if (!buffer) {
|
||||
PERROR("Memory allocation error\n");
|
||||
return FALSE;
|
||||
}
|
||||
new_ent = new_entry(buffer, AA_MAY_READ, NULL);
|
||||
if (!new_ent) {
|
||||
free(buffer);
|
||||
PERROR("Memory allocation error\n");
|
||||
return FALSE;
|
||||
}
|
||||
add_entry_to_policy(prof, new_ent);
|
||||
|
||||
/* allow setting on new and old interfaces */
|
||||
buffer = strdup(rule);
|
||||
if (!buffer) {
|
||||
PERROR("Memory allocation error\n");
|
||||
return FALSE;
|
||||
}
|
||||
new_ent = new_entry(buffer, AA_MAY_WRITE, NULL);
|
||||
if (!new_ent) {
|
||||
free(buffer);
|
||||
PERROR("Memory allocation error\n");
|
||||
return FALSE;
|
||||
}
|
||||
add_entry_to_policy(prof, new_ent);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#define CHANGEPROFILE_PATH "/proc/*/attr/{apparmor/,}{current,exec}"
|
||||
void post_process_file_entries(Profile *prof)
|
||||
{
|
||||
struct cod_entry *entry;
|
||||
perms_t cp_perms = 0;
|
||||
|
||||
list_for_each(prof->entries, entry) {
|
||||
if (entry->nt_name) {
|
||||
perms_t perms = 0;
|
||||
int n = add_named_transition(prof, entry);
|
||||
if (!n) {
|
||||
PERROR("Profile %s has too many specified profile transitions.\n", prof->name);
|
||||
exit(1);
|
||||
}
|
||||
if (entry->perms & AA_USER_EXEC)
|
||||
perms |= SHIFT_PERMS(n << 10, AA_USER_SHIFT);
|
||||
if (entry->perms & AA_OTHER_EXEC)
|
||||
perms |= SHIFT_PERMS(n << 10, AA_OTHER_SHIFT);
|
||||
entry->perms = ((entry->perms & ~AA_ALL_EXEC_MODIFIERS) |
|
||||
(perms & AA_ALL_EXEC_MODIFIERS));
|
||||
}
|
||||
/* FIXME: currently change_profile also implies onexec */
|
||||
cp_perms |= entry->perms & (AA_CHANGE_PROFILE);
|
||||
}
|
||||
|
||||
/* if there are change_profile rules, this implies that we need
|
||||
* access to some /proc/ interfaces
|
||||
*/
|
||||
if (cp_perms & AA_CHANGE_PROFILE) {
|
||||
if (!add_proc_access(prof, CHANGEPROFILE_PATH))
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void post_process_rule_entries(Profile *prof)
|
||||
{
|
||||
for (RuleList::iterator i = prof->rule_ents.begin(); i != prof->rule_ents.end(); i++) {
|
||||
if ((*i)->flags & RULE_FLAG_DELETED)
|
||||
continue;
|
||||
(*i)->post_parse_profile(*prof);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define CHANGEHAT_PATH "/proc/[0-9]*/attr/{apparmor/,}current"
|
||||
|
||||
/* add file rules to access /proc files to call change_hat()
|
||||
*/
|
||||
static int profile_add_hat_rules(Profile *prof)
|
||||
{
|
||||
/* don't add hat rules if not hat or profile doesn't have hats */
|
||||
if (!(prof->flags.flags & FLAG_HAT) && prof->hat_table.empty())
|
||||
return 0;
|
||||
|
||||
if (!add_proc_access(prof, CHANGEHAT_PATH))
|
||||
return ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Profile::post_parse_profile(void)
|
||||
{
|
||||
post_process_file_entries(this);
|
||||
post_process_rule_entries(this);
|
||||
}
|
||||
|
||||
void Profile::add_implied_rules(void)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = profile_add_hat_rules(this);
|
||||
if (error) {
|
||||
PERROR(_("ERROR adding hat access rule for profile %s\n"),
|
||||
name);
|
||||
//return error;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -189,9 +189,7 @@ public:
|
||||
|
||||
/* char *sub_name; */ /* subdomain name or NULL */
|
||||
/* int default_deny; */ /* TRUE or FALSE */
|
||||
int local;
|
||||
int local_mode; /* true if local, not hat */
|
||||
int local_audit;
|
||||
bool local;
|
||||
|
||||
Profile *parent;
|
||||
|
||||
@@ -221,8 +219,6 @@ public:
|
||||
xattrs.list = NULL;
|
||||
xattrs.name = NULL;
|
||||
|
||||
local = local_mode = local_audit = 0;
|
||||
|
||||
parent = NULL;
|
||||
|
||||
flags = { 0, MODE_UNSPECIFIED, 0, 0 };
|
||||
@@ -249,6 +245,12 @@ public:
|
||||
return strcmp(name, rhs.name) < 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Requires the merged rules have customized methods
|
||||
* cmp(), is_mergeable() and merge()
|
||||
*/
|
||||
virtual bool merge_rules(void);
|
||||
|
||||
void dump(void)
|
||||
{
|
||||
if (ns)
|
||||
@@ -259,12 +261,10 @@ public:
|
||||
else
|
||||
printf("Name:\t\t<NULL>\n");
|
||||
|
||||
if (local) {
|
||||
if (parent)
|
||||
printf("Local To:\t%s\n", parent->name);
|
||||
else
|
||||
printf("Local To:\t<NULL>\n");
|
||||
}
|
||||
if (parent)
|
||||
printf("Local To:\t%s\n", parent->name);
|
||||
else
|
||||
printf("Local To:\t<NULL>\n");
|
||||
|
||||
flags.dump(cerr);
|
||||
caps.dump();
|
||||
@@ -312,6 +312,9 @@ public:
|
||||
{
|
||||
cout << get_name(fqp);;
|
||||
}
|
||||
|
||||
void post_parse_profile(void);
|
||||
void add_implied_rules(void);
|
||||
};
|
||||
|
||||
|
||||
|
@@ -24,9 +24,9 @@
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
int parse_ptrace_mode(const char *str_mode, int *mode, int fail)
|
||||
int parse_ptrace_perms(const char *str_perms, perms_t *perms, int fail)
|
||||
{
|
||||
return parse_X_mode("ptrace", AA_VALID_PTRACE_PERMS, str_mode, mode, fail);
|
||||
return parse_X_perms("ptrace", AA_VALID_PTRACE_PERMS, str_perms, perms, fail);
|
||||
}
|
||||
|
||||
void ptrace_rule::move_conditionals(struct cond_entry *conds)
|
||||
@@ -47,15 +47,15 @@ void ptrace_rule::move_conditionals(struct cond_entry *conds)
|
||||
}
|
||||
}
|
||||
|
||||
ptrace_rule::ptrace_rule(int mode_p, struct cond_entry *conds):
|
||||
peer_label(NULL), audit(0), deny(0)
|
||||
ptrace_rule::ptrace_rule(perms_t perms_p, struct cond_entry *conds):
|
||||
perms_rule_t(AA_CLASS_PTRACE), peer_label(NULL)
|
||||
{
|
||||
if (mode_p) {
|
||||
if (mode_p & ~AA_VALID_PTRACE_PERMS)
|
||||
yyerror("mode contains invalid permissions for ptrace\n");
|
||||
mode = mode_p;
|
||||
if (perms_p) {
|
||||
if (perms_p & ~AA_VALID_PTRACE_PERMS)
|
||||
yyerror("perms contains invalid permissions for ptrace\n");
|
||||
perms = perms_p;
|
||||
} else {
|
||||
mode = AA_VALID_PTRACE_PERMS;
|
||||
perms = AA_VALID_PTRACE_PERMS;
|
||||
}
|
||||
|
||||
move_conditionals(conds);
|
||||
@@ -64,23 +64,19 @@ ptrace_rule::ptrace_rule(int mode_p, struct cond_entry *conds):
|
||||
|
||||
ostream &ptrace_rule::dump(ostream &os)
|
||||
{
|
||||
if (audit)
|
||||
os << "audit ";
|
||||
if (deny)
|
||||
os << "deny ";
|
||||
class_rule_t::dump(os);
|
||||
|
||||
os << "ptrace";
|
||||
|
||||
if (mode != AA_VALID_PTRACE_PERMS) {
|
||||
/* override default perm dump */
|
||||
if (perms != AA_VALID_PTRACE_PERMS) {
|
||||
os << " (";
|
||||
|
||||
if (mode & AA_MAY_READ)
|
||||
if (perms & AA_MAY_READ)
|
||||
os << "read ";
|
||||
if (mode & AA_MAY_READBY)
|
||||
if (perms & AA_MAY_READBY)
|
||||
os << "readby ";
|
||||
if (mode & AA_MAY_TRACE)
|
||||
if (perms & AA_MAY_TRACE)
|
||||
os << "trace ";
|
||||
if (mode & AA_MAY_TRACEDBY)
|
||||
if (perms & AA_MAY_TRACEDBY)
|
||||
os << "tracedby ";
|
||||
os << ")";
|
||||
}
|
||||
@@ -136,8 +132,8 @@ int ptrace_rule::gen_policy_re(Profile &prof)
|
||||
}
|
||||
|
||||
buf = buffer.str();
|
||||
if (mode & AA_VALID_PTRACE_PERMS) {
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(), deny, mode, audit,
|
||||
if (perms & AA_VALID_PTRACE_PERMS) {
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0,
|
||||
dfaflags))
|
||||
goto fail;
|
||||
}
|
||||
|
@@ -27,17 +27,14 @@
|
||||
#define AA_VALID_PTRACE_PERMS (AA_MAY_READ | AA_MAY_TRACE | AA_MAY_READBY | \
|
||||
AA_MAY_TRACEDBY)
|
||||
|
||||
int parse_ptrace_mode(const char *str_mode, int *mode, int fail);
|
||||
int parse_ptrace_perms(const char *str_perms, perms_t *perms, int fail);
|
||||
|
||||
class ptrace_rule: public rule_t {
|
||||
class ptrace_rule: public perms_rule_t {
|
||||
void move_conditionals(struct cond_entry *conds);
|
||||
public:
|
||||
char *peer_label;
|
||||
int mode;
|
||||
int audit;
|
||||
int deny;
|
||||
|
||||
ptrace_rule(int mode, struct cond_entry *conds);
|
||||
ptrace_rule(perms_t perms, struct cond_entry *conds);
|
||||
virtual ~ptrace_rule()
|
||||
{
|
||||
free(peer_label);
|
||||
@@ -46,7 +43,14 @@ public:
|
||||
virtual ostream &dump(ostream &os);
|
||||
virtual int expand_variables(void);
|
||||
virtual int gen_policy_re(Profile &prof);
|
||||
virtual void post_process(Profile &prof unused) { };
|
||||
|
||||
virtual bool valid_prefix(const prefixes &p, const char *&error) {
|
||||
if (p.owner) {
|
||||
error = "owner prefix not allowed on ptrace rules";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
protected:
|
||||
virtual void warn_once(const char *name) override;
|
||||
|
@@ -19,6 +19,43 @@
|
||||
#include "parser.h"
|
||||
#include <iostream>
|
||||
|
||||
const char *aa_class_table[] = {
|
||||
"nullcond",
|
||||
"unknown",
|
||||
"file",
|
||||
"capability",
|
||||
"network",
|
||||
"rlimit",
|
||||
"domain",
|
||||
"mount",
|
||||
"unknown8",
|
||||
"ptrace",
|
||||
"signal",
|
||||
"xmatch",
|
||||
"env",
|
||||
"argv",
|
||||
"network",
|
||||
"unknown15",
|
||||
"label",
|
||||
"mqueue",
|
||||
"mqueue",
|
||||
"module",
|
||||
"display_lsm",
|
||||
"userns",
|
||||
"io_uring",
|
||||
"unknown23",
|
||||
"unknown24",
|
||||
"unknown25",
|
||||
"unknown26",
|
||||
"unknown27",
|
||||
"unknown28",
|
||||
"unknown29",
|
||||
"unknown30",
|
||||
"X",
|
||||
"dbus",
|
||||
NULL
|
||||
};
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, rule_t &rule)
|
||||
{
|
||||
return rule.dump(os);
|
||||
|
221
parser/rule.h
221
parser/rule.h
@@ -23,21 +23,69 @@
|
||||
|
||||
#include "policydb.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class Profile;
|
||||
|
||||
#define RULE_NOT_SUPPORTED 0
|
||||
#define RULE_ERROR -1
|
||||
#define RULE_OK 1
|
||||
|
||||
#define RULE_TYPE_RULE 0
|
||||
#define RULE_TYPE_PREFIX 1
|
||||
#define RULE_TYPE_PERMS 2
|
||||
// RULE_TYPE_CLASS needs to be last because various class follow it
|
||||
#define RULE_TYPE_CLASS 3
|
||||
|
||||
|
||||
typedef enum { RULE_FLAG_NONE = 0,
|
||||
RULE_FLAG_DELETED = 1, // rule deleted - skip
|
||||
RULE_FLAG_MERGED = 2, // rule merged with another rule
|
||||
RULE_FLAG_EXPANDED = 4, // variable expanded
|
||||
RULE_FLAG_SUB = 8, // rule expanded to subrule(s)
|
||||
RULE_FLAG_IMPLIED = 16, // rule not specified in policy but
|
||||
// added because it is implied
|
||||
} rule_flags_t;
|
||||
|
||||
class rule_t {
|
||||
public:
|
||||
int rule_type;
|
||||
rule_flags_t flags;
|
||||
|
||||
rule_t(int t): rule_type(t), flags(RULE_FLAG_NONE) { }
|
||||
virtual ~rule_t() { };
|
||||
|
||||
bool is_type(int type) { return rule_type == type; }
|
||||
|
||||
//virtual bool operator<(rule_t const &rhs)const = 0;
|
||||
virtual std::ostream &dump(std::ostream &os) = 0;
|
||||
|
||||
// Follow methods in order of being called by the parse
|
||||
|
||||
// called when profile is finished parsing
|
||||
virtual void post_parse_profile(Profile &prof __attribute__ ((unused))) { };
|
||||
|
||||
// called before final expansion of variables. So implied rules
|
||||
// can reference variables
|
||||
virtual void add_implied_rules(Profile &prof __attribute__ ((unused))) { };
|
||||
|
||||
// currently only called post parse
|
||||
// needs to change to being interatively called during parse
|
||||
// to support expansion in include names and profile names
|
||||
virtual int expand_variables(void) = 0;
|
||||
|
||||
// called by duplicate rule merge/elimination after final expand_vars
|
||||
virtual bool is_mergeable(void) { return false; }
|
||||
virtual int cmp(rule_t const &rhs) const {
|
||||
return rule_type < rhs.rule_type;
|
||||
}
|
||||
virtual bool operator<(rule_t const &rhs) const {
|
||||
return cmp(rhs) < 0;
|
||||
}
|
||||
virtual bool merge(rule_t &rhs __attribute__ ((unused))) { return false; };
|
||||
|
||||
// called late frontend to generate data for regex backend
|
||||
virtual int gen_policy_re(Profile &prof) = 0;
|
||||
virtual void post_process(Profile &prof) = 0;
|
||||
|
||||
protected:
|
||||
const char *warned_name = NULL;
|
||||
@@ -51,5 +99,176 @@ std::ostream &operator<<(std::ostream &os, rule_t &rule);
|
||||
|
||||
typedef std::list<rule_t *> RuleList;
|
||||
|
||||
/* Not classes so they can be used in the bison front end */
|
||||
typedef uint32_t perms_t;
|
||||
typedef enum { AUDIT_UNSPECIFIED, AUDIT_FORCE, AUDIT_QUIET } audit_t;
|
||||
typedef enum { RULE_UNSPECIFIED, RULE_ALLOW, RULE_DENY } rule_mode_t;
|
||||
|
||||
/* NOTE: we can not have a constructor for class prefixes. This is
|
||||
* because it will break bison, and we would need to transition to
|
||||
* the C++ bison bindings. Instead get around this by using a
|
||||
* special rule class that inherits prefixes and handles the
|
||||
* contruction
|
||||
*/
|
||||
class prefixes {
|
||||
public:
|
||||
audit_t audit;
|
||||
rule_mode_t rule_mode;
|
||||
int owner;
|
||||
|
||||
ostream &dump(ostream &os)
|
||||
{
|
||||
bool output = true;
|
||||
|
||||
switch (audit) {
|
||||
case AUDIT_FORCE:
|
||||
os << "audit";
|
||||
break;
|
||||
case AUDIT_QUIET:
|
||||
os << "quiet";
|
||||
break;
|
||||
default:
|
||||
output = false;
|
||||
}
|
||||
|
||||
switch (rule_mode) {
|
||||
case RULE_DENY:
|
||||
if (output)
|
||||
os << " ";
|
||||
|
||||
os << "deny";
|
||||
output = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (owner) {
|
||||
if (output)
|
||||
os << " ";
|
||||
os << "owner";
|
||||
output = true;
|
||||
}
|
||||
|
||||
if (output)
|
||||
os << " ";
|
||||
|
||||
return os;
|
||||
}
|
||||
};
|
||||
|
||||
class prefix_rule_t: public rule_t, public prefixes {
|
||||
public:
|
||||
prefix_rule_t(int t = RULE_TYPE_PREFIX) : rule_t(t)
|
||||
{
|
||||
/* Must construct prefix here see note on prefixes */
|
||||
audit = AUDIT_UNSPECIFIED;
|
||||
rule_mode = RULE_UNSPECIFIED;
|
||||
owner = 0;
|
||||
};
|
||||
|
||||
virtual bool valid_prefix(const prefixes &p, const char *&error) = 0;
|
||||
|
||||
virtual bool add_prefix(const prefixes &p, const char *&error) {
|
||||
if (!valid_prefix(p, error))
|
||||
return false;
|
||||
/* audit conflicts */
|
||||
if (p.audit != AUDIT_UNSPECIFIED) {
|
||||
if (audit != AUDIT_UNSPECIFIED &&
|
||||
audit != p.audit) {
|
||||
error = "conflicting audit prefix";
|
||||
return false;
|
||||
}
|
||||
// audit = p.audit;
|
||||
}
|
||||
|
||||
/* allow deny conflicts */
|
||||
if (p.rule_mode != RULE_UNSPECIFIED) {
|
||||
if (rule_mode != RULE_UNSPECIFIED &&
|
||||
rule_mode != p.rule_mode) {
|
||||
error = "conflicting mode prefix";
|
||||
return false;
|
||||
}
|
||||
rule_mode = p.rule_mode;
|
||||
}
|
||||
|
||||
/* owner !owner conflicts */
|
||||
if (p.owner) {
|
||||
if (owner && owner != p.owner) {
|
||||
error = "conflicting owner prefix";
|
||||
return false;
|
||||
}
|
||||
owner = p.owner;
|
||||
}
|
||||
|
||||
/* does the prefix imply a modifier */
|
||||
if (p.rule_mode == RULE_DENY && p.audit == AUDIT_FORCE) {
|
||||
rule_mode = RULE_DENY;
|
||||
} else if (p.rule_mode == RULE_DENY) {
|
||||
rule_mode = RULE_DENY;
|
||||
audit = AUDIT_FORCE;
|
||||
} else if (p.audit != AUDIT_UNSPECIFIED) {
|
||||
audit = p.audit;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool operator<(prefixes const &rhs) const {
|
||||
if ((uint) audit < (uint) rhs.audit)
|
||||
return true;
|
||||
if ((uint) rule_mode < (uint) rhs.rule_mode)
|
||||
return true;
|
||||
if (owner < rhs.owner)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
virtual bool operator<(prefix_rule_t const &rhs) const {
|
||||
if (rule_type < rhs.rule_type)
|
||||
return true;
|
||||
if (rhs.rule_type < rule_type)
|
||||
return false;
|
||||
return *this < (prefixes const &)rhs;
|
||||
}
|
||||
|
||||
virtual ostream &dump(ostream &os) {
|
||||
prefixes::dump(os);
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/* NOTE: rule_type is RULE_TYPE_CLASS + AA_CLASS */
|
||||
class class_rule_t: public prefix_rule_t {
|
||||
public:
|
||||
class_rule_t(int c): prefix_rule_t(RULE_TYPE_CLASS + c) { }
|
||||
|
||||
int aa_class(void) { return rule_type - RULE_TYPE_CLASS; }
|
||||
|
||||
virtual ostream &dump(ostream &os) {
|
||||
prefix_rule_t::dump(os);
|
||||
|
||||
os << aa_class_table[aa_class()];
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class perms_rule_t: public class_rule_t {
|
||||
public:
|
||||
perms_rule_t(int c): class_rule_t(c), perms(0) { };
|
||||
|
||||
/* defaut perms, override/mask off if none default used */
|
||||
virtual ostream &dump(ostream &os) {
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
perms_t perms;
|
||||
|
||||
};
|
||||
|
||||
#endif /* __AA_RULE_H */
|
||||
|
||||
|
@@ -116,9 +116,9 @@ static const char *const sig_names[MAXMAPPED_SIG + 1] = {
|
||||
};
|
||||
|
||||
|
||||
int parse_signal_mode(const char *str_mode, int *mode, int fail)
|
||||
int parse_signal_perms(const char *str_perms, perms_t *perms, int fail)
|
||||
{
|
||||
return parse_X_mode("signal", AA_VALID_SIGNAL_PERMS, str_mode, mode, fail);
|
||||
return parse_X_perms("signal", AA_VALID_SIGNAL_PERMS, str_perms, perms, fail);
|
||||
}
|
||||
|
||||
static int find_signal_mapping(const char *sig)
|
||||
@@ -173,15 +173,15 @@ void signal_rule::move_conditionals(struct cond_entry *conds)
|
||||
}
|
||||
}
|
||||
|
||||
signal_rule::signal_rule(int mode_p, struct cond_entry *conds):
|
||||
signals(), peer_label(NULL), audit(0), deny(0)
|
||||
signal_rule::signal_rule(perms_t perms_p, struct cond_entry *conds):
|
||||
perms_rule_t(AA_CLASS_SIGNAL), signals(), peer_label(NULL)
|
||||
{
|
||||
if (mode_p) {
|
||||
mode = mode_p;
|
||||
if (mode & ~AA_VALID_SIGNAL_PERMS)
|
||||
yyerror("mode contains invalid permission for signals\n");
|
||||
if (perms_p) {
|
||||
perms = perms_p;
|
||||
if (perms & ~AA_VALID_SIGNAL_PERMS)
|
||||
yyerror("perms contains invalid permission for signals\n");
|
||||
} else {
|
||||
mode = AA_VALID_SIGNAL_PERMS;
|
||||
perms = AA_VALID_SIGNAL_PERMS;
|
||||
}
|
||||
|
||||
move_conditionals(conds);
|
||||
@@ -191,19 +191,14 @@ signal_rule::signal_rule(int mode_p, struct cond_entry *conds):
|
||||
|
||||
ostream &signal_rule::dump(ostream &os)
|
||||
{
|
||||
if (audit)
|
||||
os << "audit ";
|
||||
if (deny)
|
||||
os << "deny ";
|
||||
class_rule_t::dump(os);
|
||||
|
||||
os << "signal";
|
||||
|
||||
if (mode != AA_VALID_SIGNAL_PERMS) {
|
||||
if (perms != AA_VALID_SIGNAL_PERMS) {
|
||||
os << " (";
|
||||
|
||||
if (mode & AA_MAY_SEND)
|
||||
if (perms & AA_MAY_SEND)
|
||||
os << "send ";
|
||||
if (mode & AA_MAY_RECEIVE)
|
||||
if (perms & AA_MAY_RECEIVE)
|
||||
os << "receive ";
|
||||
os << ")";
|
||||
}
|
||||
@@ -291,8 +286,8 @@ int signal_rule::gen_policy_re(Profile &prof)
|
||||
}
|
||||
|
||||
buf = buffer.str();
|
||||
if (mode & (AA_MAY_SEND | AA_MAY_RECEIVE)) {
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(), deny, mode, audit,
|
||||
if (perms & (AA_MAY_SEND | AA_MAY_RECEIVE)) {
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0,
|
||||
dfaflags))
|
||||
goto fail;
|
||||
}
|
||||
|
@@ -31,28 +31,31 @@
|
||||
|
||||
typedef set<int> Signals;
|
||||
|
||||
int parse_signal_mode(const char *str_mode, int *mode, int fail);
|
||||
int parse_signal_perms(const char *str_perms, perms_t *perms, int fail);
|
||||
|
||||
class signal_rule: public rule_t {
|
||||
class signal_rule: public perms_rule_t {
|
||||
void extract_sigs(struct value_list **list);
|
||||
void move_conditionals(struct cond_entry *conds);
|
||||
public:
|
||||
Signals signals;
|
||||
char *peer_label;
|
||||
int mode;
|
||||
int audit;
|
||||
int deny;
|
||||
|
||||
signal_rule(int mode, struct cond_entry *conds);
|
||||
signal_rule(perms_t perms, struct cond_entry *conds);
|
||||
virtual ~signal_rule() {
|
||||
signals.clear();
|
||||
free(peer_label);
|
||||
};
|
||||
virtual bool valid_prefix(const prefixes &p, const char *&error) {
|
||||
if (p.owner) {
|
||||
error = "owner prefix not allowed on signal rules";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
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;
|
||||
|
@@ -40,17 +40,17 @@ void userns_rule::move_conditionals(struct cond_entry *conds)
|
||||
}
|
||||
}
|
||||
|
||||
userns_rule::userns_rule(int mode_p, struct cond_entry *conds):
|
||||
audit(0), deny(0)
|
||||
userns_rule::userns_rule(perms_t perms_p, struct cond_entry *conds):
|
||||
perms_rule_t(AA_CLASS_NS)
|
||||
{
|
||||
if (mode_p) {
|
||||
if (mode_p & ~AA_VALID_USERNS_PERMS)
|
||||
yyerror("mode contains invalid permissions for userns\n");
|
||||
mode = mode_p;
|
||||
if (perms_p) {
|
||||
if (perms_p & ~AA_VALID_USERNS_PERMS)
|
||||
yyerror("perms contains invalid permissions for userns\n");
|
||||
perms = perms_p;
|
||||
|
||||
} else {
|
||||
/* default to all perms */
|
||||
mode = AA_VALID_USERNS_PERMS;
|
||||
perms = AA_VALID_USERNS_PERMS;
|
||||
}
|
||||
|
||||
move_conditionals(conds);
|
||||
@@ -59,16 +59,11 @@ userns_rule::userns_rule(int mode_p, struct cond_entry *conds):
|
||||
|
||||
ostream &userns_rule::dump(ostream &os)
|
||||
{
|
||||
if (audit)
|
||||
os << "audit ";
|
||||
if (deny)
|
||||
os << "deny ";
|
||||
class_rule_t::dump(os);
|
||||
|
||||
os << "userns ";
|
||||
|
||||
if (mode != AA_VALID_USERNS_PERMS) {
|
||||
if (mode & AA_USERNS_CREATE)
|
||||
os << "create ";
|
||||
if (perms != AA_VALID_USERNS_PERMS) {
|
||||
if (perms & AA_USERNS_CREATE)
|
||||
os << " create";
|
||||
}
|
||||
|
||||
os << ",\n";
|
||||
@@ -99,8 +94,9 @@ int userns_rule::gen_policy_re(Profile &prof)
|
||||
|
||||
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << AA_CLASS_NS;
|
||||
buf = buffer.str();
|
||||
if (mode & AA_VALID_USERNS_PERMS) {
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(), deny, mode, audit,
|
||||
if (perms & AA_VALID_USERNS_PERMS) {
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, perms,
|
||||
audit == AUDIT_FORCE ? perms : 0,
|
||||
dfaflags))
|
||||
goto fail;
|
||||
}
|
||||
|
@@ -23,22 +23,24 @@
|
||||
#define AA_USERNS_CREATE 8
|
||||
#define AA_VALID_USERNS_PERMS (AA_USERNS_CREATE)
|
||||
|
||||
class userns_rule: public rule_t {
|
||||
class userns_rule: public perms_rule_t {
|
||||
void move_conditionals(struct cond_entry *conds);
|
||||
public:
|
||||
int mode;
|
||||
int audit;
|
||||
int deny;
|
||||
|
||||
userns_rule(int mode, struct cond_entry *conds);
|
||||
userns_rule(perms_t perms, struct cond_entry *conds);
|
||||
virtual ~userns_rule()
|
||||
{
|
||||
};
|
||||
|
||||
virtual bool valid_prefix(const prefixes &p, const char *&error) {
|
||||
if (p.owner) {
|
||||
error = _("owner prefix not allowed on userns rules");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
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;
|
||||
|
Reference in New Issue
Block a user