mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-08-22 01:57:43 +00:00
Convert mount and dbus to be subclasses of a generic rule class
This will simplify add new features as most of the code can reside in its own class. There are still things to improve but its a start. Signed-off-by: John Johansen <john.johansen@canonical.com> Acked-by: Steve Beattie <steve@nxnw.org>
This commit is contained in:
parent
54a24c2b6a
commit
a066f80372
@ -79,8 +79,8 @@ EXTRA_CFLAGS+=-DSUBDOMAIN_CONFDIR=\"${CONFDIR}\"
|
||||
SRCS = parser_common.c parser_include.c parser_interface.c parser_lex.c \
|
||||
parser_main.c parser_misc.c parser_merge.c parser_symtab.c \
|
||||
parser_yacc.c parser_regex.c parser_variable.c parser_policy.c \
|
||||
parser_alias.c mount.c dbus.c lib.c profile.cc
|
||||
HDRS = parser.h parser_include.h immunix.h mount.h dbus.h lib.h profile.h
|
||||
parser_alias.c mount.c dbus.c lib.c profile.cc rule.c
|
||||
HDRS = parser.h parser_include.h immunix.h mount.h dbus.h lib.h profile.h rule.h
|
||||
TOOLS = apparmor_parser
|
||||
|
||||
OBJECTS = $(SRCS:.c=.o)
|
||||
@ -188,7 +188,7 @@ apparmor_parser: $(OBJECTS) $(AAREOBJECTS) $(LIBAPPARMOR_A)
|
||||
parser_yacc.c parser_yacc.h: parser_yacc.y parser.h profile.h
|
||||
$(YACC) $(YFLAGS) -o parser_yacc.c parser_yacc.y
|
||||
|
||||
parser_lex.c: parser_lex.l parser_yacc.h parser.h profile.h
|
||||
parser_lex.c: parser_lex.l parser_yacc.h parser.h profile.h mount.h dbus.h
|
||||
$(LEX) ${LEXFLAGS} -o$@ $<
|
||||
|
||||
parser_lex.o: parser_lex.c parser.h parser_yacc.h
|
||||
@ -230,18 +230,21 @@ parser_alias.o: parser_alias.c parser.h profile.h
|
||||
parser_common.o: parser_common.c parser.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
mount.o: mount.c mount.h parser.h immunix.h
|
||||
mount.o: mount.c mount.h parser.h immunix.h rule.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
lib.o: lib.c lib.h parser.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
dbus.o: dbus.c dbus.h parser.h immunix.h parser_yacc.h $(APPARMOR_H)
|
||||
dbus.o: dbus.c dbus.h parser.h immunix.h parser_yacc.h rule.h $(APPARMOR_H)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
profile.o: profile.cc profile.h parser.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
rule.o: rule.c rule.h policydb.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_version.h: Makefile
|
||||
@echo \#define PARSER_VERSION \"$(VERSION)\" > .ver
|
||||
@mv -f .ver $@
|
||||
|
399
parser/dbus.c
399
parser/dbus.c
@ -20,23 +20,91 @@
|
||||
#include <string.h>
|
||||
#include <sys/apparmor.h>
|
||||
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "parser.h"
|
||||
#include "profile.h"
|
||||
#include "parser_yacc.h"
|
||||
#include "dbus.h"
|
||||
|
||||
void free_dbus_entry(struct dbus_entry *ent)
|
||||
{
|
||||
if (!ent)
|
||||
return;
|
||||
free(ent->bus);
|
||||
free(ent->name);
|
||||
free(ent->peer_label);
|
||||
free(ent->path);
|
||||
free(ent->interface);
|
||||
free(ent->member);
|
||||
#define _(s) gettext(s)
|
||||
|
||||
free(ent);
|
||||
static int parse_dbus_sub_mode(const char *str_mode, int *result, int fail, const char *mode_desc __unused)
|
||||
{
|
||||
int mode = 0;
|
||||
const char *p;
|
||||
|
||||
PDEBUG("Parsing DBus mode: %s\n", str_mode);
|
||||
|
||||
if (!str_mode)
|
||||
return 0;
|
||||
|
||||
p = str_mode;
|
||||
while (*p) {
|
||||
char current = *p;
|
||||
char lower;
|
||||
|
||||
reeval:
|
||||
switch (current) {
|
||||
case COD_READ_CHAR:
|
||||
PDEBUG("Parsing DBus mode: found %s READ\n", mode_desc);
|
||||
mode |= AA_DBUS_RECEIVE;
|
||||
break;
|
||||
|
||||
case COD_WRITE_CHAR:
|
||||
PDEBUG("Parsing DBus mode: found %s WRITE\n",
|
||||
mode_desc);
|
||||
mode |= AA_DBUS_SEND;
|
||||
break;
|
||||
|
||||
/* error cases */
|
||||
|
||||
default:
|
||||
lower = tolower(current);
|
||||
switch (lower) {
|
||||
case COD_READ_CHAR:
|
||||
case COD_WRITE_CHAR:
|
||||
PDEBUG("Parsing DBus mode: found invalid upper case char %c\n",
|
||||
current);
|
||||
warn_uppercase();
|
||||
current = lower;
|
||||
goto reeval;
|
||||
break;
|
||||
default:
|
||||
if (fail)
|
||||
yyerror(_("Internal: unexpected DBus mode character '%c' in input"),
|
||||
current);
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
PDEBUG("Parsed DBus mode: %s 0x%x\n", str_mode, mode);
|
||||
|
||||
*result = mode;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int parse_dbus_mode(const char *str_mode, int *mode, int fail)
|
||||
{
|
||||
*mode = 0;
|
||||
if (!parse_dbus_sub_mode(str_mode, mode, fail, ""))
|
||||
return 0;
|
||||
if (*mode & ~AA_VALID_DBUS_PERMS) {
|
||||
if (fail)
|
||||
yyerror(_("Internal error generated invalid DBus perm 0x%x\n"),
|
||||
mode);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int list_len(struct value_list *v)
|
||||
@ -60,7 +128,7 @@ static void move_conditional_value(char **dst_ptr, struct cond_entry *cond_ent)
|
||||
cond_ent->vals->value = NULL;
|
||||
}
|
||||
|
||||
static void move_conditionals(struct dbus_entry *ent, struct cond_entry *conds)
|
||||
void dbus_rule::move_conditionals(struct cond_entry *conds)
|
||||
{
|
||||
struct cond_entry *cond_ent;
|
||||
|
||||
@ -73,17 +141,17 @@ static void move_conditionals(struct dbus_entry *ent, struct cond_entry *conds)
|
||||
cond_ent->name);
|
||||
|
||||
if (strcmp(cond_ent->name, "bus") == 0) {
|
||||
move_conditional_value(&ent->bus, cond_ent);
|
||||
move_conditional_value(&bus, cond_ent);
|
||||
} else if (strcmp(cond_ent->name, "name") == 0) {
|
||||
move_conditional_value(&ent->name, cond_ent);
|
||||
move_conditional_value(&name, cond_ent);
|
||||
} else if (strcmp(cond_ent->name, "label") == 0) {
|
||||
move_conditional_value(&ent->peer_label, cond_ent);
|
||||
move_conditional_value(&peer_label, cond_ent);
|
||||
} else if (strcmp(cond_ent->name, "path") == 0) {
|
||||
move_conditional_value(&ent->path, cond_ent);
|
||||
move_conditional_value(&path, cond_ent);
|
||||
} else if (strcmp(cond_ent->name, "interface") == 0) {
|
||||
move_conditional_value(&ent->interface, cond_ent);
|
||||
move_conditional_value(&interface, cond_ent);
|
||||
} else if (strcmp(cond_ent->name, "member") == 0) {
|
||||
move_conditional_value(&ent->member, cond_ent);
|
||||
move_conditional_value(&member, cond_ent);
|
||||
} else {
|
||||
yyerror("invalid dbus conditional \"%s\"\n",
|
||||
cond_ent->name);
|
||||
@ -91,129 +159,252 @@ static void move_conditionals(struct dbus_entry *ent, struct cond_entry *conds)
|
||||
}
|
||||
}
|
||||
|
||||
struct dbus_entry *new_dbus_entry(int mode, struct cond_entry *conds,
|
||||
struct cond_entry *peer_conds)
|
||||
dbus_rule::dbus_rule(int mode_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)
|
||||
{
|
||||
struct dbus_entry *ent;
|
||||
int name_is_subject_cond = 0, message_rule = 0, service_rule = 0;
|
||||
|
||||
ent = (struct dbus_entry*) calloc(1, sizeof(struct dbus_entry));
|
||||
if (!ent)
|
||||
goto out;
|
||||
|
||||
/* Move the global/subject conditionals over & check the results */
|
||||
move_conditionals(ent, conds);
|
||||
if (ent->name)
|
||||
move_conditionals(conds);
|
||||
if (name)
|
||||
name_is_subject_cond = 1;
|
||||
if (ent->peer_label)
|
||||
if (peer_label)
|
||||
yyerror("dbus \"label\" conditional can only be used inside of the \"peer=()\" grouping\n");
|
||||
|
||||
/* Move the peer conditionals */
|
||||
move_conditionals(ent, peer_conds);
|
||||
move_conditionals(peer_conds);
|
||||
|
||||
if (ent->path || ent->interface || ent->member || ent->peer_label ||
|
||||
(ent->name && !name_is_subject_cond))
|
||||
if (path || interface || member || peer_label ||
|
||||
(name && !name_is_subject_cond))
|
||||
message_rule = 1;
|
||||
|
||||
if (ent->name && name_is_subject_cond)
|
||||
if (name && name_is_subject_cond)
|
||||
service_rule = 1;
|
||||
|
||||
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) {
|
||||
ent->mode = mode;
|
||||
if (ent->mode & ~AA_VALID_DBUS_PERMS)
|
||||
if (mode_p) {
|
||||
mode = mode_p;
|
||||
if (mode & ~AA_VALID_DBUS_PERMS)
|
||||
yyerror("mode contains unknown dbus accesss\n");
|
||||
else if (message_rule && (ent->mode & AA_DBUS_BIND))
|
||||
else if (message_rule && (mode & AA_DBUS_BIND))
|
||||
yyerror("dbus \"bind\" access cannot be used with message rule conditionals\n");
|
||||
else if (service_rule && (ent->mode & (AA_DBUS_SEND | AA_DBUS_RECEIVE)))
|
||||
else if (service_rule && (mode & (AA_DBUS_SEND | AA_DBUS_RECEIVE)))
|
||||
yyerror("dbus \"send\" and/or \"receive\" accesses cannot be used with service rule conditionals\n");
|
||||
else if (ent->mode & AA_DBUS_EAVESDROP &&
|
||||
(ent->path || ent->interface || ent->member ||
|
||||
ent->peer_label || ent->name)) {
|
||||
else if (mode & AA_DBUS_EAVESDROP &&
|
||||
(path || interface || member ||
|
||||
peer_label || name)) {
|
||||
yyerror("dbus \"eavesdrop\" access can only contain a bus conditional\n");
|
||||
}
|
||||
} else {
|
||||
if (message_rule)
|
||||
ent->mode = (AA_DBUS_SEND | AA_DBUS_RECEIVE);
|
||||
mode = (AA_DBUS_SEND | AA_DBUS_RECEIVE);
|
||||
else if (service_rule)
|
||||
ent->mode = (AA_DBUS_BIND);
|
||||
mode = (AA_DBUS_BIND);
|
||||
else
|
||||
ent->mode = AA_VALID_DBUS_PERMS;
|
||||
mode = AA_VALID_DBUS_PERMS;
|
||||
}
|
||||
|
||||
out:
|
||||
free_cond_list(conds);
|
||||
free_cond_list(peer_conds);
|
||||
return ent;
|
||||
}
|
||||
|
||||
struct dbus_entry *dup_dbus_entry(struct dbus_entry *orig)
|
||||
ostream &dbus_rule::dump(ostream &os)
|
||||
{
|
||||
struct dbus_entry *ent = NULL;
|
||||
ent = (struct dbus_entry *) calloc(1, sizeof(struct dbus_entry));
|
||||
if (!ent)
|
||||
return NULL;
|
||||
if (audit)
|
||||
os << "audit ";
|
||||
if (deny)
|
||||
os << "deny ";
|
||||
|
||||
DUP_STRING(orig, ent, bus, err);
|
||||
DUP_STRING(orig, ent, name, err);
|
||||
DUP_STRING(orig, ent, peer_label, err);
|
||||
DUP_STRING(orig, ent, path, err);
|
||||
DUP_STRING(orig, ent, interface, err);
|
||||
DUP_STRING(orig, ent, member, err);
|
||||
ent->mode = orig->mode;
|
||||
ent->audit = orig->audit;
|
||||
ent->deny = orig->deny;
|
||||
os << "dbus ( ";
|
||||
|
||||
ent->next = orig->next;
|
||||
if (mode & AA_DBUS_SEND)
|
||||
os << "send ";
|
||||
if (mode & AA_DBUS_RECEIVE)
|
||||
os << "receive ";
|
||||
if (mode & AA_DBUS_BIND)
|
||||
os << "bind ";
|
||||
if (mode & AA_DBUS_EAVESDROP)
|
||||
os << "eavesdrop ";
|
||||
os << ")";
|
||||
|
||||
return ent;
|
||||
if (bus)
|
||||
os << " bus=\"" << bus << "\"";
|
||||
if ((mode & AA_DBUS_BIND) && name)
|
||||
os << " name=\"" << name << "\"";
|
||||
if (path)
|
||||
os << " path=\"" << path << "\"";
|
||||
if (interface)
|
||||
os << " interface=\"" << interface << "\"";
|
||||
if (member)
|
||||
os << " member=\"" << member << os << "\"";
|
||||
|
||||
err:
|
||||
free_dbus_entry(ent);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void print_dbus_entry(struct dbus_entry *ent)
|
||||
{
|
||||
if (ent->audit)
|
||||
fprintf(stderr, "audit ");
|
||||
if (ent->deny)
|
||||
fprintf(stderr, "deny ");
|
||||
|
||||
fprintf(stderr, "dbus ( ");
|
||||
|
||||
if (ent->mode & AA_DBUS_SEND)
|
||||
fprintf(stderr, "send ");
|
||||
if (ent->mode & AA_DBUS_RECEIVE)
|
||||
fprintf(stderr, "receive ");
|
||||
if (ent->mode & AA_DBUS_BIND)
|
||||
fprintf(stderr, "bind ");
|
||||
if (ent->mode & AA_DBUS_EAVESDROP)
|
||||
fprintf(stderr, "eavesdrop ");
|
||||
fprintf(stderr, ")");
|
||||
|
||||
if (ent->bus)
|
||||
fprintf(stderr, " bus=\"%s\"", ent->bus);
|
||||
if ((ent->mode & AA_DBUS_BIND) && ent->name)
|
||||
fprintf(stderr, " name=\"%s\"", ent->name);
|
||||
if (ent->path)
|
||||
fprintf(stderr, " path=\"%s\"", ent->path);
|
||||
if (ent->interface)
|
||||
fprintf(stderr, " interface=\"%s\"", ent->interface);
|
||||
if (ent->member)
|
||||
fprintf(stderr, " member=\"%s\"", ent->member);
|
||||
|
||||
if (!(ent->mode & AA_DBUS_BIND) && (ent->peer_label || ent->name)) {
|
||||
fprintf(stderr, " peer=( ");
|
||||
if (ent->peer_label)
|
||||
fprintf(stderr, "label=\"%s\" ", ent->peer_label);
|
||||
if (ent->name)
|
||||
fprintf(stderr, "name=\"%s\" ", ent->name);
|
||||
fprintf(stderr, ")");
|
||||
if (!(mode & AA_DBUS_BIND) && (peer_label || name)) {
|
||||
os << " peer=( ";
|
||||
if (peer_label)
|
||||
os << "label=\"" << peer_label << "\" ";
|
||||
if (name)
|
||||
os << "name=\"" << name << "\" ";
|
||||
os << ")";
|
||||
}
|
||||
|
||||
fprintf(stderr, ",\n");
|
||||
os << ",\n";
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
int dbus_rule::expand_variables(void)
|
||||
{
|
||||
int error = expand_entry_variables(&bus);
|
||||
if (error)
|
||||
return error;
|
||||
error = expand_entry_variables(&name);
|
||||
if (error)
|
||||
return error;
|
||||
error = expand_entry_variables(&peer_label);
|
||||
if (error)
|
||||
return error;
|
||||
error = expand_entry_variables(&path);
|
||||
if (error)
|
||||
return error;
|
||||
error = expand_entry_variables(&interface);
|
||||
if (error)
|
||||
return error;
|
||||
error = expand_entry_variables(&member);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* do we want to warn once/profile or just once per compile?? */
|
||||
static void warn_once(const char *name)
|
||||
{
|
||||
static const char *warned_name = NULL;
|
||||
|
||||
if (warned_name != name) {
|
||||
cerr << "Warning from profile " << name << " (";
|
||||
if (current_filename)
|
||||
cerr << current_filename;
|
||||
else
|
||||
cerr << "stdin";
|
||||
cerr << ") dbus rules not enforced\n";
|
||||
warned_name = name;
|
||||
}
|
||||
}
|
||||
|
||||
int dbus_rule::gen_policy_re(Profile &prof)
|
||||
{
|
||||
std::string busbuf;
|
||||
std::string namebuf;
|
||||
std::string peer_labelbuf;
|
||||
std::string pathbuf;
|
||||
std::string ifacebuf;
|
||||
std::string memberbuf;
|
||||
std::ostringstream buffer;
|
||||
const char *vec[6];
|
||||
|
||||
pattern_t ptype;
|
||||
int pos;
|
||||
|
||||
if (!kernel_supports_dbus) {
|
||||
warn_once(prof.name);
|
||||
return RULE_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << AA_CLASS_DBUS;
|
||||
busbuf.append(buffer.str());
|
||||
|
||||
if (bus) {
|
||||
ptype = convert_aaregex_to_pcre(bus, 0, busbuf, &pos);
|
||||
if (ptype == ePatternInvalid)
|
||||
goto fail;
|
||||
} else {
|
||||
/* match any char except \000 0 or more times */
|
||||
busbuf.append(default_match_pattern);
|
||||
}
|
||||
vec[0] = busbuf.c_str();
|
||||
|
||||
if (name) {
|
||||
ptype = convert_aaregex_to_pcre(name, 0, namebuf, &pos);
|
||||
if (ptype == ePatternInvalid)
|
||||
goto fail;
|
||||
vec[1] = namebuf.c_str();
|
||||
} else {
|
||||
/* match any char except \000 0 or more times */
|
||||
vec[1] = default_match_pattern;
|
||||
}
|
||||
|
||||
if (peer_label) {
|
||||
ptype = convert_aaregex_to_pcre(peer_label, 0,
|
||||
peer_labelbuf, &pos);
|
||||
if (ptype == ePatternInvalid)
|
||||
goto fail;
|
||||
vec[2] = peer_labelbuf.c_str();
|
||||
} else {
|
||||
/* match any char except \000 0 or more times */
|
||||
vec[2] = default_match_pattern;
|
||||
}
|
||||
|
||||
if (path) {
|
||||
ptype = convert_aaregex_to_pcre(path, 0, pathbuf, &pos);
|
||||
if (ptype == ePatternInvalid)
|
||||
goto fail;
|
||||
vec[3] = pathbuf.c_str();
|
||||
} else {
|
||||
/* match any char except \000 0 or more times */
|
||||
vec[3] = default_match_pattern;
|
||||
}
|
||||
|
||||
if (interface) {
|
||||
ptype = convert_aaregex_to_pcre(interface, 0, ifacebuf, &pos);
|
||||
if (ptype == ePatternInvalid)
|
||||
goto fail;
|
||||
vec[4] = ifacebuf.c_str();
|
||||
} else {
|
||||
/* match any char except \000 0 or more times */
|
||||
vec[4] = default_match_pattern;
|
||||
}
|
||||
|
||||
if (member) {
|
||||
ptype = convert_aaregex_to_pcre(member, 0, memberbuf, &pos);
|
||||
if (ptype == ePatternInvalid)
|
||||
goto fail;
|
||||
vec[5] = memberbuf.c_str();
|
||||
} else {
|
||||
/* match any char except \000 0 or more times */
|
||||
vec[5] = default_match_pattern;
|
||||
}
|
||||
|
||||
if (mode & AA_DBUS_BIND) {
|
||||
if (!aare_add_rule_vec(prof.policy.rules, deny,
|
||||
mode & AA_DBUS_BIND,
|
||||
audit & AA_DBUS_BIND,
|
||||
2, vec, dfaflags))
|
||||
goto fail;
|
||||
}
|
||||
if (mode & (AA_DBUS_SEND | AA_DBUS_RECEIVE)) {
|
||||
if (!aare_add_rule_vec(prof.policy.rules, deny,
|
||||
mode & (AA_DBUS_SEND | AA_DBUS_RECEIVE),
|
||||
audit & (AA_DBUS_SEND | AA_DBUS_RECEIVE),
|
||||
6, vec, dfaflags))
|
||||
goto fail;
|
||||
}
|
||||
if (mode & AA_DBUS_EAVESDROP) {
|
||||
if (!aare_add_rule_vec(prof.policy.rules, deny,
|
||||
mode & AA_DBUS_EAVESDROP,
|
||||
audit & AA_DBUS_EAVESDROP,
|
||||
1, vec, dfaflags))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
prof.policy.count++;
|
||||
return RULE_OK;
|
||||
|
||||
fail:
|
||||
return RULE_ERROR;
|
||||
}
|
||||
|
@ -20,8 +20,14 @@
|
||||
#define __AA_DBUS_H
|
||||
|
||||
#include "parser.h"
|
||||
#include "rule.h"
|
||||
#include "profile.h"
|
||||
|
||||
struct dbus_entry {
|
||||
extern int parse_dbus_mode(const char *str_mode, int *mode, int fail);
|
||||
|
||||
class dbus_rule: public rule_t {
|
||||
void move_conditionals(struct cond_entry *conds);
|
||||
public:
|
||||
char *bus;
|
||||
/**
|
||||
* Be careful! ->name can be the subject or the peer name, depending on
|
||||
@ -37,13 +43,23 @@ struct dbus_entry {
|
||||
int audit;
|
||||
int deny;
|
||||
|
||||
struct dbus_entry *next;
|
||||
dbus_rule(int mode_p, struct cond_entry *conds,
|
||||
struct cond_entry *peer_conds);
|
||||
virtual ~dbus_rule() {
|
||||
free(bus);
|
||||
free(name);
|
||||
free(peer_label);
|
||||
free(path);
|
||||
free(interface);
|
||||
free(member);
|
||||
};
|
||||
|
||||
virtual ostream &dump(ostream &os);
|
||||
virtual int expand_variables(void);
|
||||
virtual int gen_policy_re(Profile &prof);
|
||||
virtual void post_process(Profile &prof __unused) { };
|
||||
|
||||
|
||||
};
|
||||
|
||||
void free_dbus_entry(struct dbus_entry *ent);
|
||||
struct dbus_entry *new_dbus_entry(int mode, struct cond_entry *conds,
|
||||
struct cond_entry *peer_conds);
|
||||
struct dbus_entry *dup_dbus_entry(struct dbus_entry *ent);
|
||||
void print_dbus_entry(struct dbus_entry *ent);
|
||||
|
||||
#endif /* __AA_DBUS_H */
|
||||
|
575
parser/mount.c
575
parser/mount.c
@ -215,8 +215,12 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <linux/limits.h>
|
||||
#include <iostream>
|
||||
|
||||
#include "parser.h"
|
||||
#include "policydb.h"
|
||||
#include "profile.h"
|
||||
#include "mount.h"
|
||||
|
||||
struct mnt_keyword_table {
|
||||
@ -389,146 +393,469 @@ static struct value_list *extract_options(struct cond_entry **conds, int eq)
|
||||
return list;
|
||||
}
|
||||
|
||||
struct mnt_entry *new_mnt_entry(struct cond_entry *src_conds, char *device,
|
||||
struct cond_entry *dst_conds __unused, char *mnt_point,
|
||||
int allow)
|
||||
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):
|
||||
mnt_point(mnt_point_p), device(device_p), trans(NULL), opts(NULL),
|
||||
audit(0), deny(0)
|
||||
{
|
||||
/* FIXME: dst_conds are ignored atm */
|
||||
dev_type = extract_fstype(&src_conds);
|
||||
|
||||
struct mnt_entry *ent;
|
||||
ent = (struct mnt_entry *) calloc(1, sizeof(struct mnt_entry));
|
||||
if (ent) {
|
||||
ent->mnt_point = mnt_point;
|
||||
ent->device = device;
|
||||
ent->dev_type = extract_fstype(&src_conds);
|
||||
if (src_conds) {
|
||||
struct value_list *list = extract_options(&src_conds, 0);
|
||||
|
||||
ent->flags = 0;
|
||||
ent->inv_flags = 0;
|
||||
opts = extract_options(&src_conds, 1);
|
||||
if (opts)
|
||||
flags = extract_flags(&opts, &inv_flags);
|
||||
|
||||
if (src_conds) {
|
||||
unsigned int flags = 0, inv_flags = 0;
|
||||
struct value_list *list = extract_options(&src_conds, 0);
|
||||
if (list) {
|
||||
unsigned int tmpflags, tmpinv_flags = 0;
|
||||
|
||||
ent->opts = extract_options(&src_conds, 1);
|
||||
if (ent->opts)
|
||||
ent->flags = extract_flags(&ent->opts,
|
||||
&ent->inv_flags);
|
||||
tmpflags = extract_flags(&list, &tmpinv_flags);
|
||||
/* these flags are optional so set both */
|
||||
tmpflags |= tmpinv_flags;
|
||||
tmpinv_flags |= tmpflags;
|
||||
|
||||
if (list) {
|
||||
flags = extract_flags(&list, &inv_flags);
|
||||
/* these flags are optional so set both */
|
||||
flags |= inv_flags;
|
||||
inv_flags |= flags;
|
||||
flags |= tmpflags;
|
||||
inv_flags |= tmpinv_flags;
|
||||
|
||||
ent->flags |= flags;
|
||||
ent->inv_flags |= inv_flags;
|
||||
|
||||
if (ent->opts)
|
||||
list_append(ent->opts, list);
|
||||
else if (list)
|
||||
ent->opts = list;
|
||||
}
|
||||
if (opts)
|
||||
list_append(opts, list);
|
||||
else if (list)
|
||||
opts = list;
|
||||
}
|
||||
}
|
||||
|
||||
if (allow & AA_DUMMY_REMOUNT) {
|
||||
allow = AA_MAY_MOUNT;
|
||||
ent->flags |= MS_REMOUNT;
|
||||
ent->inv_flags = 0;
|
||||
} else if (!(ent->flags | ent->inv_flags)) {
|
||||
/* no flag options, and not remount, allow everything */
|
||||
ent->flags = MS_ALL_FLAGS;
|
||||
ent->inv_flags = MS_ALL_FLAGS;
|
||||
if (allow_p & AA_DUMMY_REMOUNT) {
|
||||
allow_p = AA_MAY_MOUNT;
|
||||
flags |= MS_REMOUNT;
|
||||
inv_flags = 0;
|
||||
} else if (!(flags | inv_flags)) {
|
||||
/* no flag options, and not remount, allow everything */
|
||||
flags = MS_ALL_FLAGS;
|
||||
inv_flags = MS_ALL_FLAGS;
|
||||
}
|
||||
|
||||
allow = allow_p;
|
||||
|
||||
if (src_conds) {
|
||||
PERROR(" unsupported mount conditions\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
ostream &mnt_rule::dump(ostream &os)
|
||||
{
|
||||
if (allow & AA_MAY_MOUNT)
|
||||
os << "mount";
|
||||
else if (allow & AA_MAY_UMOUNT)
|
||||
os << "umount";
|
||||
else if (allow & AA_MAY_PIVOTROOT)
|
||||
os << "pivotroot";
|
||||
else
|
||||
os << "error: unknonwn mount perm";
|
||||
|
||||
os << " (0x" << hex << flags << " - 0x" << inv_flags << ") ";
|
||||
if (dev_type) {
|
||||
os << " type=";
|
||||
print_value_list(dev_type);
|
||||
}
|
||||
if (opts) {
|
||||
os << " options=";
|
||||
print_value_list(opts);
|
||||
}
|
||||
if (device)
|
||||
os << " " << device;
|
||||
if (mnt_point)
|
||||
os << " -> " << mnt_point;
|
||||
if (trans)
|
||||
os << " -> " << trans;
|
||||
|
||||
const char *prefix = deny ? "deny" : "";
|
||||
os << " " << prefix << "(0x" << hex << allow << "/0x" << audit << ")";
|
||||
os << ",\n";
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
/* does not currently support expansion of vars in options */
|
||||
int mnt_rule::expand_variables(void)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
error = expand_entry_variables(&mnt_point);
|
||||
if (error)
|
||||
return error;
|
||||
error = expand_entry_variables(&device);
|
||||
if (error)
|
||||
return error;
|
||||
error = expand_entry_variables(&trans);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int build_mnt_flags(char *buffer, int size, unsigned int flags,
|
||||
unsigned int inv_flags)
|
||||
{
|
||||
char *p = buffer;
|
||||
int i, len = 0;
|
||||
|
||||
if (flags == MS_ALL_FLAGS) {
|
||||
/* all flags are optional */
|
||||
len = snprintf(p, size, "%s", default_match_pattern);
|
||||
if (len < 0 || len >= size)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
for (i = 0; i <= 31; ++i) {
|
||||
if ((flags & inv_flags) & (1 << i))
|
||||
len = snprintf(p, size, "(\\x%02x|)", i + 1);
|
||||
else if (flags & (1 << i))
|
||||
len = snprintf(p, size, "\\x%02x", i + 1);
|
||||
else /* no entry = not set */
|
||||
continue;
|
||||
|
||||
if (len < 0 || len >= size)
|
||||
return FALSE;
|
||||
p += len;
|
||||
size -= len;
|
||||
}
|
||||
|
||||
/* this needs to go once the backend is updated. */
|
||||
if (buffer == p) {
|
||||
/* match nothing - use impossible 254 as regex parser doesn't
|
||||
* like the empty string
|
||||
*/
|
||||
if (size < 9)
|
||||
return FALSE;
|
||||
|
||||
strcpy(p, "(\\xfe|)");
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int build_mnt_opts(std::string& buffer, struct value_list *opts)
|
||||
{
|
||||
struct value_list *ent;
|
||||
pattern_t ptype;
|
||||
int pos;
|
||||
|
||||
if (!opts) {
|
||||
buffer.append(default_match_pattern);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
list_for_each(opts, ent) {
|
||||
ptype = convert_aaregex_to_pcre(ent->value, 0, buffer, &pos);
|
||||
if (ptype == ePatternInvalid)
|
||||
return FALSE;
|
||||
|
||||
if (ent->next)
|
||||
buffer.append(",");
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* do we want to warn once/profile or just once per compile?? */
|
||||
static void warn_once(const char *name)
|
||||
{
|
||||
static const char *warned_name = NULL;
|
||||
|
||||
if (warned_name != name) {
|
||||
cerr << "Warning from profile " << name << " (";
|
||||
if (current_filename)
|
||||
cerr << current_filename;
|
||||
else
|
||||
cerr << "stdin";
|
||||
cerr << ") mount rules not enforced\n";
|
||||
warned_name = name;
|
||||
}
|
||||
}
|
||||
|
||||
int mnt_rule::gen_policy_re(Profile &prof)
|
||||
{
|
||||
std::string mntbuf;
|
||||
std::string devbuf;
|
||||
std::string typebuf;
|
||||
char flagsbuf[PATH_MAX + 3];
|
||||
std::string optsbuf;
|
||||
char class_mount_hdr[64];
|
||||
const char *vec[5];
|
||||
int count = 0;
|
||||
unsigned int tmpflags, tmpinv_flags;
|
||||
|
||||
if (!kernel_supports_mount) {
|
||||
warn_once(prof.name);
|
||||
return RULE_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
sprintf(class_mount_hdr, "\\x%02x", AA_CLASS_MOUNT);
|
||||
|
||||
/* a single mount rule may result in multiple matching rules being
|
||||
* created in the backend to cover all the possible choices
|
||||
*/
|
||||
|
||||
if ((allow & AA_MAY_MOUNT) && (flags & MS_REMOUNT)
|
||||
&& !device && !dev_type) {
|
||||
int tmpallow;
|
||||
/* remount can't be conditional on device and type */
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (mnt_point) {
|
||||
/* both device && mnt_point or just mnt_point */
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
} else {
|
||||
if (!convert_entry(mntbuf, device))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
}
|
||||
/* skip device */
|
||||
vec[1] = default_match_pattern;
|
||||
/* skip type */
|
||||
vec[2] = default_match_pattern;
|
||||
|
||||
ent->allow = allow;
|
||||
tmpflags = flags;
|
||||
tmpinv_flags = inv_flags;
|
||||
if (tmpflags != MS_ALL_FLAGS)
|
||||
tmpflags &= MS_REMOUNT_FLAGS;
|
||||
if (tmpinv_flags != MS_ALL_FLAGS)
|
||||
tmpflags &= MS_REMOUNT_FLAGS;
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, tmpflags, tmpinv_flags))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
|
||||
if (src_conds) {
|
||||
PERROR(" unsupported mount conditions\n");
|
||||
if (opts)
|
||||
tmpallow = AA_MATCH_CONT;
|
||||
else
|
||||
tmpallow = allow;
|
||||
|
||||
/* rule for match without required data || data MATCH_CONT */
|
||||
if (!aare_add_rule_vec(prof.policy.rules, deny, tmpallow,
|
||||
audit | AA_AUDIT_MNT_DATA, 4,
|
||||
vec, dfaflags))
|
||||
goto fail;
|
||||
count++;
|
||||
|
||||
if (opts) {
|
||||
/* rule with data match required */
|
||||
optsbuf.clear();
|
||||
if (!build_mnt_opts(optsbuf, opts))
|
||||
goto fail;
|
||||
vec[4] = optsbuf.c_str();
|
||||
if (!aare_add_rule_vec(prof.policy.rules, deny,
|
||||
allow,
|
||||
audit | AA_AUDIT_MNT_DATA,
|
||||
5, vec, dfaflags))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if ((allow & AA_MAY_MOUNT) && (flags & MS_BIND)
|
||||
&& !dev_type && !opts) {
|
||||
/* bind mount rules can't be conditional on dev_type or data */
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
if (!clear_and_convert_entry(devbuf, device))
|
||||
goto fail;
|
||||
vec[1] = devbuf.c_str();
|
||||
/* skip type */
|
||||
vec[2] = default_match_pattern;
|
||||
|
||||
tmpflags = flags;
|
||||
tmpinv_flags = inv_flags;
|
||||
if (tmpflags != MS_ALL_FLAGS)
|
||||
tmpflags &= MS_BIND_FLAGS;
|
||||
if (tmpinv_flags != MS_ALL_FLAGS)
|
||||
tmpflags &= MS_BIND_FLAGS;
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, tmpflags, tmpinv_flags))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
if (!aare_add_rule_vec(prof.policy.rules, deny, allow,
|
||||
audit, 4, vec, dfaflags))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
if ((allow & AA_MAY_MOUNT) &&
|
||||
(flags & (MS_UNBINDABLE | MS_PRIVATE | MS_SLAVE | MS_SHARED))
|
||||
&& !device && !dev_type && !opts) {
|
||||
/* change type base rules can not be conditional on device,
|
||||
* device type or data
|
||||
*/
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
/* skip device and type */
|
||||
vec[1] = default_match_pattern;
|
||||
vec[2] = default_match_pattern;
|
||||
|
||||
tmpflags = flags;
|
||||
tmpinv_flags = inv_flags;
|
||||
if (tmpflags != MS_ALL_FLAGS)
|
||||
tmpflags &= MS_MAKE_FLAGS;
|
||||
if (tmpinv_flags != MS_ALL_FLAGS)
|
||||
tmpflags &= MS_MAKE_FLAGS;
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, tmpflags, tmpinv_flags))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
if (!aare_add_rule_vec(prof.policy.rules, deny, allow,
|
||||
audit, 4, vec, dfaflags))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
if ((allow & AA_MAY_MOUNT) && (flags & MS_MOVE)
|
||||
&& !dev_type && !opts) {
|
||||
/* mount move rules can not be conditional on dev_type,
|
||||
* or data
|
||||
*/
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
if (!clear_and_convert_entry(devbuf, device))
|
||||
goto fail;
|
||||
vec[1] = devbuf.c_str();
|
||||
/* skip type */
|
||||
vec[2] = default_match_pattern;
|
||||
|
||||
tmpflags = flags;
|
||||
tmpinv_flags = inv_flags;
|
||||
if (tmpflags != MS_ALL_FLAGS)
|
||||
tmpflags &= MS_MOVE_FLAGS;
|
||||
if (tmpinv_flags != MS_ALL_FLAGS)
|
||||
tmpflags &= MS_MOVE_FLAGS;
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, tmpflags, tmpinv_flags))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
if (!aare_add_rule_vec(prof.policy.rules, deny, allow,
|
||||
audit, 4, vec, dfaflags))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
if ((allow & AA_MAY_MOUNT) &&
|
||||
(flags | inv_flags) & ~MS_CMDS) {
|
||||
int tmpallow;
|
||||
/* generic mount if flags are set that are not covered by
|
||||
* above commands
|
||||
*/
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
if (!clear_and_convert_entry(devbuf, device))
|
||||
goto fail;
|
||||
vec[1] = devbuf.c_str();
|
||||
typebuf.clear();
|
||||
if (!build_list_val_expr(typebuf, dev_type))
|
||||
goto fail;
|
||||
vec[2] = typebuf.c_str();
|
||||
|
||||
tmpflags = flags;
|
||||
tmpinv_flags = inv_flags;
|
||||
if (tmpflags != MS_ALL_FLAGS)
|
||||
tmpflags &= ~MS_CMDS;
|
||||
if (tmpinv_flags != MS_ALL_FLAGS)
|
||||
tmpinv_flags &= ~MS_CMDS;
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, tmpflags, tmpinv_flags))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
|
||||
if (opts)
|
||||
tmpallow = AA_MATCH_CONT;
|
||||
else
|
||||
tmpallow = allow;
|
||||
|
||||
/* rule for match without required data || data MATCH_CONT */
|
||||
if (!aare_add_rule_vec(prof.policy.rules, deny, tmpallow,
|
||||
audit | AA_AUDIT_MNT_DATA, 4,
|
||||
vec, dfaflags))
|
||||
goto fail;
|
||||
count++;
|
||||
|
||||
if (opts) {
|
||||
/* rule with data match required */
|
||||
optsbuf.clear();
|
||||
if (!build_mnt_opts(optsbuf, opts))
|
||||
goto fail;
|
||||
vec[4] = optsbuf.c_str();
|
||||
if (!aare_add_rule_vec(prof.policy.rules, deny,
|
||||
allow,
|
||||
audit | AA_AUDIT_MNT_DATA,
|
||||
5, vec, dfaflags))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (allow & 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 (!aare_add_rule_vec(prof.policy.rules, deny, allow,
|
||||
audit, 1, vec, dfaflags))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
if (allow & AA_MAY_PIVOTROOT) {
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
if (!clear_and_convert_entry(devbuf, device))
|
||||
goto fail;
|
||||
vec[1] = devbuf.c_str();
|
||||
if (!aare_add_rule_vec(prof.policy.rules, deny, allow,
|
||||
audit, 2, vec, dfaflags))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
|
||||
if (!count)
|
||||
/* didn't actually encode anything */
|
||||
goto fail;
|
||||
|
||||
prof.policy.count++;
|
||||
return RULE_OK;
|
||||
|
||||
fail:
|
||||
PERROR("Enocoding of mount rule failed\n");
|
||||
return RULE_ERROR;
|
||||
}
|
||||
|
||||
void mnt_rule::post_process(Profile &prof)
|
||||
{
|
||||
if (trans) {
|
||||
unsigned int mode = 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));
|
||||
|
||||
trans = NULL;
|
||||
}
|
||||
|
||||
return ent;
|
||||
}
|
||||
|
||||
void free_mnt_entry(struct mnt_entry *ent)
|
||||
{
|
||||
if (!ent)
|
||||
return;
|
||||
|
||||
free_mnt_entry(ent->next);
|
||||
free_value_list(ent->opts);
|
||||
free_value_list(ent->dev_type);
|
||||
free(ent->device);
|
||||
free(ent->mnt_point);
|
||||
free(ent->trans);
|
||||
|
||||
free(ent);
|
||||
}
|
||||
|
||||
struct mnt_entry *dup_mnt_entry(struct mnt_entry *orig)
|
||||
{
|
||||
struct mnt_entry *entry = NULL;
|
||||
|
||||
entry = (struct mnt_entry *) calloc(1, sizeof(struct mnt_entry));
|
||||
if (!entry)
|
||||
return NULL;
|
||||
|
||||
DUP_STRING(orig, entry, mnt_point, err);
|
||||
DUP_STRING(orig, entry, device, err);
|
||||
DUP_STRING(orig, entry, trans, err);
|
||||
|
||||
entry->dev_type = dup_value_list(orig->dev_type);
|
||||
if (orig->dev_type && !(entry->dev_type))
|
||||
goto err;
|
||||
|
||||
entry->opts = dup_value_list(orig->opts);
|
||||
if (orig->opts && !(entry->opts))
|
||||
goto err;
|
||||
|
||||
entry->flags = orig->flags;
|
||||
entry->inv_flags = orig->inv_flags;
|
||||
|
||||
entry->allow = orig->allow;
|
||||
entry->audit = orig->audit;
|
||||
entry->deny = orig->deny;
|
||||
|
||||
entry->next = orig->next;
|
||||
|
||||
return entry;
|
||||
|
||||
err:
|
||||
free_mnt_entry(entry);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void print_mnt_entry(struct mnt_entry *entry)
|
||||
{
|
||||
if (entry->allow & AA_MAY_MOUNT)
|
||||
fprintf(stderr, "mount");
|
||||
else if (entry->allow & AA_MAY_UMOUNT)
|
||||
fprintf(stderr, "umount");
|
||||
else if (entry->allow & AA_MAY_PIVOTROOT)
|
||||
fprintf(stderr, "pivotroot");
|
||||
else
|
||||
fprintf(stderr, "error: unknonwn mount perm");
|
||||
|
||||
fprintf(stderr, " (0x%x - 0x%x) ", entry->flags, entry->inv_flags);
|
||||
if (entry->dev_type) {
|
||||
fprintf(stderr, " type=");
|
||||
print_value_list(entry->dev_type);
|
||||
}
|
||||
if (entry->opts) {
|
||||
fprintf(stderr, " options=");
|
||||
print_value_list(entry->opts);
|
||||
}
|
||||
if (entry->device)
|
||||
fprintf(stderr, " %s", entry->device);
|
||||
if (entry->mnt_point)
|
||||
fprintf(stderr, " -> %s", entry->mnt_point);
|
||||
if (entry->trans)
|
||||
fprintf(stderr, " -> %s", entry->trans);
|
||||
|
||||
fprintf(stderr, " %s (0x%x/0x%x)", entry->deny ? "deny" : "", entry->allow, entry->audit);
|
||||
fprintf(stderr, ",\n");
|
||||
}
|
||||
|
@ -19,7 +19,11 @@
|
||||
#ifndef __AA_MOUNT_H
|
||||
#define __AA_MOUNT_H
|
||||
|
||||
#include <ostream>
|
||||
|
||||
#include "parser.h"
|
||||
#include "rule.h"
|
||||
|
||||
|
||||
#define MS_RDONLY (1 << 0)
|
||||
#define MS_RW 0
|
||||
@ -109,7 +113,8 @@
|
||||
* remapped to a mount option*/
|
||||
|
||||
|
||||
struct mnt_entry {
|
||||
class mnt_rule: public rule_t {
|
||||
public:
|
||||
char *mnt_point;
|
||||
char *device;
|
||||
char *trans;
|
||||
@ -120,17 +125,26 @@ struct mnt_entry {
|
||||
|
||||
int allow, audit;
|
||||
int deny;
|
||||
struct mnt_entry *next;
|
||||
|
||||
mnt_rule(struct cond_entry *src_conds, char *device_p,
|
||||
struct cond_entry *dst_conds __unused, char *mnt_point_p,
|
||||
int allow_p);
|
||||
virtual ~mnt_rule()
|
||||
{
|
||||
free_value_list(opts);
|
||||
free_value_list(dev_type);
|
||||
free(device);
|
||||
free(mnt_point);
|
||||
free(trans);
|
||||
}
|
||||
|
||||
virtual ostream &dump(ostream &os);
|
||||
virtual int expand_variables(void);
|
||||
virtual int gen_policy_re(Profile &prof);
|
||||
virtual void post_process(Profile &prof __unused);
|
||||
};
|
||||
|
||||
void print_mnt_entry(struct mnt_entry *entry);
|
||||
|
||||
int is_valid_mnt_cond(const char *name, int src);
|
||||
struct mnt_entry *new_mnt_entry(struct cond_entry *sconds, char *device,
|
||||
struct cond_entry *dconds, char *mnt_point,
|
||||
int mode);
|
||||
struct mnt_entry *dup_mnt_entry(struct mnt_entry *orig);
|
||||
void free_mnt_entry(struct mnt_entry *ent);
|
||||
|
||||
|
||||
#endif /* __AA_MOUNT_H */
|
||||
|
@ -30,12 +30,13 @@
|
||||
#include "libapparmor_re/apparmor_re.h"
|
||||
#include "libapparmor_re/aare_rules.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include <set>
|
||||
class Profile;
|
||||
|
||||
struct mnt_ent;
|
||||
class rule_t;
|
||||
|
||||
/* Global variable to pass token to lexer. Will be replaced by parameter
|
||||
* when lexer and parser are made reentrant
|
||||
@ -256,9 +257,14 @@ extern int yylex(void);
|
||||
extern const char *basedir;
|
||||
|
||||
/* parser_regex.c */
|
||||
extern const char *default_match_pattern;
|
||||
extern pattern_t convert_aaregex_to_pcre(const char *aare, int anchor,
|
||||
std::string& pcre, int *first_re_pos);
|
||||
extern int build_list_val_expr(std::string& buffer, struct value_list *list);
|
||||
extern int convert_entry(std::string& buffer, char *entry);
|
||||
extern int clear_and_convert_entry(std::string& buffer, char *entry);
|
||||
extern int process_regex(Profile *prof);
|
||||
extern int post_process_entry(struct cod_entry *entry);
|
||||
extern int process_dbus(Profile *prof);
|
||||
|
||||
extern void reset_regex(void);
|
||||
|
||||
@ -267,11 +273,13 @@ extern int process_policydb(Profile *prof);
|
||||
extern int process_policy_ents(Profile *prof);
|
||||
|
||||
/* parser_variable.c */
|
||||
int expand_entry_variables(char **name);
|
||||
extern int process_variables(Profile *prof);
|
||||
extern struct var_string *split_out_var(const char *string);
|
||||
extern void free_var_string(struct var_string *var);
|
||||
|
||||
/* parser_misc.c */
|
||||
extern void warn_uppercase(void);
|
||||
extern int is_blacklisted(const char *name, const char *path);
|
||||
extern struct value_list *new_value_list(char *value);
|
||||
extern struct value_list *dup_value_list(struct value_list *list);
|
||||
@ -289,7 +297,6 @@ extern int name_to_capability(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_dbus_mode(const char *str_mode, int *mode, int fail);
|
||||
extern struct cod_entry *new_entry(char *ns, char *id, int mode, char *link_id);
|
||||
extern struct aa_network_entry *new_network_ent(unsigned int family,
|
||||
unsigned int type,
|
||||
@ -303,15 +310,13 @@ extern size_t get_af_max(void);
|
||||
extern int str_to_boolean(const char* str);
|
||||
extern struct cod_entry *copy_cod_entry(struct cod_entry *cod);
|
||||
extern void free_cod_entries(struct cod_entry *list);
|
||||
extern void free_mnt_entries(struct mnt_entry *list);
|
||||
extern void free_dbus_entries(struct dbus_entry *list);
|
||||
extern void __debug_capabilities(uint64_t capset, const char *name);
|
||||
void __debug_network(unsigned int *array, const char *name);
|
||||
void debug_cod_entries(struct cod_entry *list);
|
||||
|
||||
|
||||
/* parser_symtab.c */
|
||||
struct set_value {;
|
||||
struct set_value {
|
||||
char *val;
|
||||
struct set_value *next;
|
||||
};
|
||||
@ -345,9 +350,10 @@ extern int cache_fd;
|
||||
/* parser_policy.c */
|
||||
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_mnt_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);
|
||||
|
@ -596,7 +596,7 @@ int str_to_boolean(const char *value)
|
||||
|
||||
static int warned_uppercase = 0;
|
||||
|
||||
static void warn_uppercase(void)
|
||||
void warn_uppercase(void)
|
||||
{
|
||||
if (!warned_uppercase) {
|
||||
pwarn(_("Uppercase qualifiers \"RWLIMX\" are deprecated, please convert to lowercase\n"
|
||||
@ -792,81 +792,6 @@ int parse_mode(const char *str_mode)
|
||||
return mode;
|
||||
}
|
||||
|
||||
static int parse_dbus_sub_mode(const char *str_mode, int *result, int fail, const char *mode_desc __unused)
|
||||
{
|
||||
int mode = 0;
|
||||
const char *p;
|
||||
|
||||
PDEBUG("Parsing DBus mode: %s\n", str_mode);
|
||||
|
||||
if (!str_mode)
|
||||
return 0;
|
||||
|
||||
p = str_mode;
|
||||
while (*p) {
|
||||
char current = *p;
|
||||
char lower;
|
||||
|
||||
reeval:
|
||||
switch (current) {
|
||||
case COD_READ_CHAR:
|
||||
PDEBUG("Parsing DBus mode: found %s READ\n", mode_desc);
|
||||
mode |= AA_DBUS_RECEIVE;
|
||||
break;
|
||||
|
||||
case COD_WRITE_CHAR:
|
||||
PDEBUG("Parsing DBus mode: found %s WRITE\n",
|
||||
mode_desc);
|
||||
mode |= AA_DBUS_SEND;
|
||||
break;
|
||||
|
||||
/* error cases */
|
||||
|
||||
default:
|
||||
lower = tolower(current);
|
||||
switch (lower) {
|
||||
case COD_READ_CHAR:
|
||||
case COD_WRITE_CHAR:
|
||||
PDEBUG("Parsing DBus mode: found invalid upper case char %c\n",
|
||||
current);
|
||||
warn_uppercase();
|
||||
current = lower;
|
||||
goto reeval;
|
||||
break;
|
||||
default:
|
||||
if (fail)
|
||||
yyerror(_("Internal: unexpected DBus mode character '%c' in input"),
|
||||
current);
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
PDEBUG("Parsed DBus mode: %s 0x%x\n", str_mode, mode);
|
||||
|
||||
*result = mode;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int parse_dbus_mode(const char *str_mode, int *mode, int fail)
|
||||
{
|
||||
*mode = 0;
|
||||
if (!parse_dbus_sub_mode(str_mode, mode, fail, ""))
|
||||
return 0;
|
||||
if (*mode & ~AA_VALID_DBUS_PERMS) {
|
||||
if (fail)
|
||||
yyerror(_("Internal error generated invalid DBus perm 0x%x\n"),
|
||||
mode);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct cod_entry *new_entry(char *ns, char *id, int mode, char *link_id)
|
||||
{
|
||||
struct cod_entry *entry = NULL;
|
||||
@ -938,30 +863,6 @@ void free_cod_entries(struct cod_entry *list)
|
||||
free(list);
|
||||
}
|
||||
|
||||
void free_mnt_entries(struct mnt_entry *list)
|
||||
{
|
||||
if (!list)
|
||||
return;
|
||||
if (list->next)
|
||||
free_mnt_entries(list->next);
|
||||
free(list->mnt_point);
|
||||
free(list->device);
|
||||
free_value_list(list->dev_type);
|
||||
free_value_list(list->opts);
|
||||
|
||||
free(list);
|
||||
}
|
||||
|
||||
void free_dbus_entries(struct dbus_entry *list)
|
||||
{
|
||||
if (!list)
|
||||
return;
|
||||
if (list->next)
|
||||
free_dbus_entries(list->next);
|
||||
|
||||
free_dbus_entry(list);
|
||||
}
|
||||
|
||||
static void debug_base_perm_mask(int mask)
|
||||
{
|
||||
if (HAS_MAY_READ(mask))
|
||||
|
@ -32,8 +32,6 @@
|
||||
|
||||
#include "parser.h"
|
||||
#include "profile.h"
|
||||
#include "mount.h"
|
||||
#include "dbus.h"
|
||||
#include "parser_yacc.h"
|
||||
|
||||
/* #define DEBUG */
|
||||
@ -70,7 +68,7 @@ void add_hat_to_policy(Profile *prof, Profile *hat)
|
||||
}
|
||||
}
|
||||
|
||||
static int add_entry_to_x_table(Profile *prof, char *name)
|
||||
int add_entry_to_x_table(Profile *prof, char *name)
|
||||
{
|
||||
int i;
|
||||
for (i = (AA_EXEC_LOCAL >> 10) + 1; i < AA_EXEC_COUNT; i++) {
|
||||
@ -192,29 +190,10 @@ void post_process_file_entries(Profile *prof)
|
||||
}
|
||||
}
|
||||
|
||||
void post_process_mnt_entries(Profile *prof)
|
||||
void post_process_rule_entries(Profile *prof)
|
||||
{
|
||||
struct mnt_entry *entry;
|
||||
|
||||
list_for_each(prof->mnt_ents, entry) {
|
||||
if (entry->trans) {
|
||||
unsigned int mode = 0;
|
||||
int n = add_entry_to_x_table(prof, entry->trans);
|
||||
if (!n) {
|
||||
PERROR("Profile %s has too many specified profile transitions.\n", prof->name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (entry->allow & AA_USER_EXEC)
|
||||
mode |= SHIFT_MODE(n << 10, AA_USER_SHIFT);
|
||||
if (entry->allow & AA_OTHER_EXEC)
|
||||
mode |= SHIFT_MODE(n << 10, AA_OTHER_SHIFT);
|
||||
entry->allow = ((entry->allow & ~AA_ALL_EXEC_MODIFIERS) |
|
||||
(mode & AA_ALL_EXEC_MODIFIERS));
|
||||
|
||||
entry->trans = NULL;
|
||||
}
|
||||
}
|
||||
for (RuleList::iterator i = prof->rule_ents.begin(); i != prof->rule_ents.end(); i++)
|
||||
(*i)->post_process(*prof);
|
||||
}
|
||||
|
||||
|
||||
|
@ -35,9 +35,8 @@
|
||||
#include "profile.h"
|
||||
#include "libapparmor_re/apparmor_re.h"
|
||||
#include "libapparmor_re/aare_rules.h"
|
||||
#include "mount.h"
|
||||
#include "dbus.h"
|
||||
#include "policydb.h"
|
||||
#include "rule.h"
|
||||
|
||||
enum error_type {
|
||||
e_no_error,
|
||||
@ -45,7 +44,7 @@ enum error_type {
|
||||
};
|
||||
|
||||
/* match any char except \000 0 or more times */
|
||||
static const char *default_match_pattern = "[^\\000]*";
|
||||
const char *default_match_pattern = "[^\\000]*";
|
||||
|
||||
/* Filters out multiple slashes (except if the first two are slashes,
|
||||
* that's a distinct namespace in linux) and trailing slashes.
|
||||
@ -90,8 +89,8 @@ static void filter_slashes(char *path)
|
||||
|
||||
/* converts the apparmor regex in aare and appends pcre regex output
|
||||
* to pcre string */
|
||||
static pattern_t convert_aaregex_to_pcre(const char *aare, int anchor,
|
||||
std::string& pcre, int *first_re_pos)
|
||||
pattern_t convert_aaregex_to_pcre(const char *aare, int anchor,
|
||||
std::string& pcre, int *first_re_pos)
|
||||
{
|
||||
#define update_re_pos(X) if (!(*first_re_pos)) { *first_re_pos = (X); }
|
||||
#define MAX_ALT_DEPTH 50
|
||||
@ -612,7 +611,7 @@ out:
|
||||
return error;
|
||||
}
|
||||
|
||||
static int build_list_val_expr(std::string& buffer, struct value_list *list)
|
||||
int build_list_val_expr(std::string& buffer, struct value_list *list)
|
||||
{
|
||||
struct value_list *ent;
|
||||
pattern_t ptype;
|
||||
@ -642,7 +641,7 @@ fail:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int convert_entry(std::string& buffer, char *entry)
|
||||
int convert_entry(std::string& buffer, char *entry)
|
||||
{
|
||||
pattern_t ptype;
|
||||
int pos;
|
||||
@ -658,486 +657,18 @@ static int convert_entry(std::string& buffer, char *entry)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int clear_and_convert_entry(std::string& buffer, char *entry)
|
||||
int clear_and_convert_entry(std::string& buffer, char *entry)
|
||||
{
|
||||
buffer.clear();
|
||||
return convert_entry(buffer, entry);
|
||||
}
|
||||
|
||||
static int build_mnt_flags(char *buffer, int size, unsigned int flags,
|
||||
unsigned int inv_flags)
|
||||
{
|
||||
char *p = buffer;
|
||||
int i, len = 0;
|
||||
|
||||
if (flags == MS_ALL_FLAGS) {
|
||||
/* all flags are optional */
|
||||
len = snprintf(p, size, "%s", default_match_pattern);
|
||||
if (len < 0 || len >= size)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
for (i = 0; i <= 31; ++i) {
|
||||
if ((flags & inv_flags) & (1 << i))
|
||||
len = snprintf(p, size, "(\\x%02x|)", i + 1);
|
||||
else if (flags & (1 << i))
|
||||
len = snprintf(p, size, "\\x%02x", i + 1);
|
||||
else /* no entry = not set */
|
||||
continue;
|
||||
|
||||
if (len < 0 || len >= size)
|
||||
return FALSE;
|
||||
p += len;
|
||||
size -= len;
|
||||
}
|
||||
|
||||
/* this needs to go once the backend is updated. */
|
||||
if (buffer == p) {
|
||||
/* match nothing - use impossible 254 as regex parser doesn't
|
||||
* like the empty string
|
||||
*/
|
||||
if (size < 9)
|
||||
return FALSE;
|
||||
|
||||
strcpy(p, "(\\xfe|)");
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int build_mnt_opts(std::string& buffer, struct value_list *opts)
|
||||
{
|
||||
struct value_list *ent;
|
||||
pattern_t ptype;
|
||||
int pos;
|
||||
|
||||
if (!opts) {
|
||||
buffer.append(default_match_pattern);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
list_for_each(opts, ent) {
|
||||
ptype = convert_aaregex_to_pcre(ent->value, 0, buffer, &pos);
|
||||
if (ptype == ePatternInvalid)
|
||||
return FALSE;
|
||||
|
||||
if (ent->next)
|
||||
buffer.append(",");
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int process_mnt_entry(aare_ruleset_t *dfarules, struct mnt_entry *entry)
|
||||
{
|
||||
std::string mntbuf;
|
||||
std::string devbuf;
|
||||
std::string typebuf;
|
||||
char flagsbuf[PATH_MAX + 3];
|
||||
std::string optsbuf;
|
||||
char class_mount_hdr[64];
|
||||
const char *vec[5];
|
||||
int count = 0;
|
||||
unsigned int flags, inv_flags;
|
||||
|
||||
sprintf(class_mount_hdr, "\\x%02x", AA_CLASS_MOUNT);
|
||||
|
||||
/* a single mount rule may result in multiple matching rules being
|
||||
* created in the backend to cover all the possible choices
|
||||
*/
|
||||
|
||||
if ((entry->allow & AA_MAY_MOUNT) && (entry->flags & MS_REMOUNT)
|
||||
&& !entry->device && !entry->dev_type) {
|
||||
int allow;
|
||||
/* remount can't be conditional on device and type */
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (entry->mnt_point) {
|
||||
/* both device && mnt_point or just mnt_point */
|
||||
if (!convert_entry(mntbuf, entry->mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
} else {
|
||||
if (!convert_entry(mntbuf, entry->device))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
}
|
||||
/* skip device */
|
||||
vec[1] = default_match_pattern;
|
||||
/* skip type */
|
||||
vec[2] = default_match_pattern;
|
||||
|
||||
flags = entry->flags;
|
||||
inv_flags = entry->inv_flags;
|
||||
if (flags != MS_ALL_FLAGS)
|
||||
flags &= MS_REMOUNT_FLAGS;
|
||||
if (inv_flags != MS_ALL_FLAGS)
|
||||
flags &= MS_REMOUNT_FLAGS;
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, flags, inv_flags))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
|
||||
if (entry->opts)
|
||||
allow = AA_MATCH_CONT;
|
||||
else
|
||||
allow = entry->allow;
|
||||
|
||||
/* rule for match without required data || data MATCH_CONT */
|
||||
if (!aare_add_rule_vec(dfarules, entry->deny, allow,
|
||||
entry->audit | AA_AUDIT_MNT_DATA, 4,
|
||||
vec, dfaflags))
|
||||
goto fail;
|
||||
count++;
|
||||
|
||||
if (entry->opts) {
|
||||
/* rule with data match required */
|
||||
optsbuf.clear();
|
||||
if (!build_mnt_opts(optsbuf, entry->opts))
|
||||
goto fail;
|
||||
vec[4] = optsbuf.c_str();
|
||||
if (!aare_add_rule_vec(dfarules, entry->deny,
|
||||
entry->allow,
|
||||
entry->audit | AA_AUDIT_MNT_DATA,
|
||||
5, vec, dfaflags))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if ((entry->allow & AA_MAY_MOUNT) && (entry->flags & MS_BIND)
|
||||
&& !entry->dev_type && !entry->opts) {
|
||||
/* bind mount rules can't be conditional on dev_type or data */
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (!convert_entry(mntbuf, entry->mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
if (!clear_and_convert_entry(devbuf, entry->device))
|
||||
goto fail;
|
||||
vec[1] = devbuf.c_str();
|
||||
/* skip type */
|
||||
vec[2] = default_match_pattern;
|
||||
|
||||
flags = entry->flags;
|
||||
inv_flags = entry->inv_flags;
|
||||
if (flags != MS_ALL_FLAGS)
|
||||
flags &= MS_BIND_FLAGS;
|
||||
if (inv_flags != MS_ALL_FLAGS)
|
||||
flags &= MS_BIND_FLAGS;
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, flags, inv_flags))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
if (!aare_add_rule_vec(dfarules, entry->deny, entry->allow,
|
||||
entry->audit, 4, vec, dfaflags))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
if ((entry->allow & AA_MAY_MOUNT) &&
|
||||
(entry->flags & (MS_UNBINDABLE | MS_PRIVATE | MS_SLAVE | MS_SHARED))
|
||||
&& !entry->device && !entry->dev_type && !entry->opts) {
|
||||
/* change type base rules can not be conditional on device,
|
||||
* device type or data
|
||||
*/
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (!convert_entry(mntbuf, entry->mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
/* skip device and type */
|
||||
vec[1] = default_match_pattern;
|
||||
vec[2] = default_match_pattern;
|
||||
|
||||
flags = entry->flags;
|
||||
inv_flags = entry->inv_flags;
|
||||
if (flags != MS_ALL_FLAGS)
|
||||
flags &= MS_MAKE_FLAGS;
|
||||
if (inv_flags != MS_ALL_FLAGS)
|
||||
flags &= MS_MAKE_FLAGS;
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, flags, inv_flags))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
if (!aare_add_rule_vec(dfarules, entry->deny, entry->allow,
|
||||
entry->audit, 4, vec, dfaflags))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
if ((entry->allow & AA_MAY_MOUNT) && (entry->flags & MS_MOVE)
|
||||
&& !entry->dev_type && !entry->opts) {
|
||||
/* mount move rules can not be conditional on dev_type,
|
||||
* or data
|
||||
*/
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (!convert_entry(mntbuf, entry->mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
if (!clear_and_convert_entry(devbuf, entry->device))
|
||||
goto fail;
|
||||
vec[1] = devbuf.c_str();
|
||||
/* skip type */
|
||||
vec[2] = default_match_pattern;
|
||||
|
||||
flags = entry->flags;
|
||||
inv_flags = entry->inv_flags;
|
||||
if (flags != MS_ALL_FLAGS)
|
||||
flags &= MS_MOVE_FLAGS;
|
||||
if (inv_flags != MS_ALL_FLAGS)
|
||||
flags &= MS_MOVE_FLAGS;
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, flags, inv_flags))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
if (!aare_add_rule_vec(dfarules, entry->deny, entry->allow,
|
||||
entry->audit, 4, vec, dfaflags))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
if ((entry->allow & AA_MAY_MOUNT) &&
|
||||
(entry->flags | entry->inv_flags) & ~MS_CMDS) {
|
||||
int allow;
|
||||
/* generic mount if flags are set that are not covered by
|
||||
* above commands
|
||||
*/
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (!convert_entry(mntbuf, entry->mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
if (!clear_and_convert_entry(devbuf, entry->device))
|
||||
goto fail;
|
||||
vec[1] = devbuf.c_str();
|
||||
typebuf.clear();
|
||||
if (!build_list_val_expr(typebuf, entry->dev_type))
|
||||
goto fail;
|
||||
vec[2] = typebuf.c_str();
|
||||
|
||||
flags = entry->flags;
|
||||
inv_flags = entry->inv_flags;
|
||||
if (flags != MS_ALL_FLAGS)
|
||||
flags &= ~MS_CMDS;
|
||||
if (inv_flags != MS_ALL_FLAGS)
|
||||
flags &= ~MS_CMDS;
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, flags, inv_flags))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
|
||||
if (entry->opts)
|
||||
allow = AA_MATCH_CONT;
|
||||
else
|
||||
allow = entry->allow;
|
||||
|
||||
/* rule for match without required data || data MATCH_CONT */
|
||||
if (!aare_add_rule_vec(dfarules, entry->deny, allow,
|
||||
entry->audit | AA_AUDIT_MNT_DATA, 4,
|
||||
vec, dfaflags))
|
||||
goto fail;
|
||||
count++;
|
||||
|
||||
if (entry->opts) {
|
||||
/* rule with data match required */
|
||||
optsbuf.clear();
|
||||
if (!build_mnt_opts(optsbuf, entry->opts))
|
||||
goto fail;
|
||||
vec[4] = optsbuf.c_str();
|
||||
if (!aare_add_rule_vec(dfarules, entry->deny,
|
||||
entry->allow,
|
||||
entry->audit | AA_AUDIT_MNT_DATA,
|
||||
5, vec, dfaflags))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (entry->allow & AA_MAY_UMOUNT) {
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (!convert_entry(mntbuf, entry->mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
if (!aare_add_rule_vec(dfarules, entry->deny, entry->allow,
|
||||
entry->audit, 1, vec, dfaflags))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
if (entry->allow & AA_MAY_PIVOTROOT) {
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (!convert_entry(mntbuf, entry->mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
if (!clear_and_convert_entry(devbuf, entry->device))
|
||||
goto fail;
|
||||
vec[1] = devbuf.c_str();
|
||||
if (!aare_add_rule_vec(dfarules, entry->deny, entry->allow,
|
||||
entry->audit, 2, vec, dfaflags))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
|
||||
if (!count)
|
||||
/* didn't actually encode anything */
|
||||
goto fail;
|
||||
|
||||
return TRUE;
|
||||
|
||||
fail:
|
||||
PERROR("Enocoding of mount rule failed\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
static int process_dbus_entry(aare_ruleset_t *dfarules, struct dbus_entry *entry)
|
||||
{
|
||||
std::string busbuf;
|
||||
std::string namebuf;
|
||||
std::string peer_labelbuf;
|
||||
std::string pathbuf;
|
||||
std::string ifacebuf;
|
||||
std::string memberbuf;
|
||||
std::ostringstream buffer;
|
||||
const char *vec[6];
|
||||
|
||||
pattern_t ptype;
|
||||
int pos;
|
||||
|
||||
if (!entry) /* shouldn't happen */
|
||||
return TRUE;
|
||||
|
||||
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << AA_CLASS_DBUS;
|
||||
busbuf.append(buffer.str());
|
||||
|
||||
if (entry->bus) {
|
||||
ptype = convert_aaregex_to_pcre(entry->bus, 0, busbuf, &pos);
|
||||
if (ptype == ePatternInvalid)
|
||||
goto fail;
|
||||
} else {
|
||||
/* match any char except \000 0 or more times */
|
||||
busbuf.append(default_match_pattern);
|
||||
}
|
||||
vec[0] = busbuf.c_str();
|
||||
|
||||
if (entry->name) {
|
||||
ptype = convert_aaregex_to_pcre(entry->name, 0, namebuf, &pos);
|
||||
if (ptype == ePatternInvalid)
|
||||
goto fail;
|
||||
vec[1] = namebuf.c_str();
|
||||
} else {
|
||||
/* match any char except \000 0 or more times */
|
||||
vec[1] = default_match_pattern;
|
||||
}
|
||||
|
||||
if (entry->peer_label) {
|
||||
ptype = convert_aaregex_to_pcre(entry->peer_label, 0,
|
||||
peer_labelbuf, &pos);
|
||||
if (ptype == ePatternInvalid)
|
||||
goto fail;
|
||||
vec[2] = peer_labelbuf.c_str();
|
||||
} else {
|
||||
/* match any char except \000 0 or more times */
|
||||
vec[2] = default_match_pattern;
|
||||
}
|
||||
|
||||
if (entry->path) {
|
||||
ptype = convert_aaregex_to_pcre(entry->path, 0, pathbuf, &pos);
|
||||
if (ptype == ePatternInvalid)
|
||||
goto fail;
|
||||
vec[3] = pathbuf.c_str();
|
||||
} else {
|
||||
/* match any char except \000 0 or more times */
|
||||
vec[3] = default_match_pattern;
|
||||
}
|
||||
|
||||
if (entry->interface) {
|
||||
ptype = convert_aaregex_to_pcre(entry->interface, 0, ifacebuf, &pos);
|
||||
if (ptype == ePatternInvalid)
|
||||
goto fail;
|
||||
vec[4] = ifacebuf.c_str();
|
||||
} else {
|
||||
/* match any char except \000 0 or more times */
|
||||
vec[4] = default_match_pattern;
|
||||
}
|
||||
|
||||
if (entry->member) {
|
||||
ptype = convert_aaregex_to_pcre(entry->member, 0, memberbuf, &pos);
|
||||
if (ptype == ePatternInvalid)
|
||||
goto fail;
|
||||
vec[5] = memberbuf.c_str();
|
||||
} else {
|
||||
/* match any char except \000 0 or more times */
|
||||
vec[5] = default_match_pattern;
|
||||
}
|
||||
|
||||
if (entry->mode & AA_DBUS_BIND) {
|
||||
if (!aare_add_rule_vec(dfarules, entry->deny,
|
||||
entry->mode & AA_DBUS_BIND,
|
||||
entry->audit & AA_DBUS_BIND,
|
||||
2, vec, dfaflags))
|
||||
goto fail;
|
||||
}
|
||||
if (entry->mode & (AA_DBUS_SEND | AA_DBUS_RECEIVE)) {
|
||||
if (!aare_add_rule_vec(dfarules, entry->deny,
|
||||
entry->mode & (AA_DBUS_SEND | AA_DBUS_RECEIVE),
|
||||
entry->audit & (AA_DBUS_SEND | AA_DBUS_RECEIVE),
|
||||
6, vec, dfaflags))
|
||||
goto fail;
|
||||
}
|
||||
if (entry->mode & AA_DBUS_EAVESDROP) {
|
||||
if (!aare_add_rule_vec(dfarules, entry->deny,
|
||||
entry->mode & AA_DBUS_EAVESDROP,
|
||||
entry->audit & AA_DBUS_EAVESDROP,
|
||||
1, vec, dfaflags))
|
||||
goto fail;
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
fail:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int post_process_mnt_ents(Profile *prof)
|
||||
{
|
||||
int ret = TRUE;
|
||||
int count = 0;
|
||||
|
||||
/* Add fns for rules that should be added to policydb here */
|
||||
if (prof->mnt_ents && kernel_supports_mount) {
|
||||
struct mnt_entry *entry;
|
||||
list_for_each(prof->mnt_ents, entry) {
|
||||
if (!process_mnt_entry(prof->policy.rules, entry))
|
||||
ret = FALSE;
|
||||
count++;
|
||||
}
|
||||
} else if (prof->mnt_ents && !kernel_supports_mount)
|
||||
pwarn("profile %s mount rules not enforced\n", prof->name);
|
||||
|
||||
prof->policy.count += count;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int post_process_dbus_ents(Profile *prof)
|
||||
{
|
||||
int ret = TRUE;
|
||||
int count = 0;
|
||||
|
||||
if (prof->dbus_ents && kernel_supports_dbus) {
|
||||
struct dbus_entry *entry;
|
||||
|
||||
list_for_each(prof->dbus_ents, entry) {
|
||||
if (!process_dbus_entry(prof->policy.rules, entry))
|
||||
ret = FALSE;
|
||||
count++;
|
||||
}
|
||||
} else if (prof->dbus_ents && !kernel_supports_dbus)
|
||||
pwarn("profile %s dbus rules not enforced\n", prof->name);
|
||||
|
||||
prof->policy.count += count;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int post_process_policydb_ents(Profile *prof)
|
||||
{
|
||||
if (!post_process_mnt_ents(prof))
|
||||
return FALSE;
|
||||
if (!post_process_dbus_ents(prof))
|
||||
return FALSE;
|
||||
for (RuleList::iterator i = prof->rule_ents.begin(); i != prof->rule_ents.end(); i++) {
|
||||
if ((*i)->gen_policy_re(*prof) == RULE_ERROR)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
* along with this program; if not, contact Novell, Inc.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
@ -213,13 +214,15 @@ static int expand_by_alternations(struct set_value **valuelist,
|
||||
}
|
||||
|
||||
/* doesn't handle variables in options atm */
|
||||
static int expand_entry_variables(char **name, void *entry)
|
||||
int expand_entry_variables(char **name)
|
||||
{
|
||||
struct set_value *valuelist;
|
||||
struct var_string *split_var;
|
||||
int ret;
|
||||
|
||||
if (!entry) /* can happen when entry is optional */
|
||||
assert(name);
|
||||
|
||||
if (!*name) /* can happen when entry is optional */
|
||||
return 0;
|
||||
|
||||
while ((split_var = split_out_var(*name))) {
|
||||
@ -251,7 +254,7 @@ static int process_variables_in_entries(struct cod_entry *entry_list)
|
||||
struct cod_entry *entry;
|
||||
|
||||
list_for_each(entry_list, entry) {
|
||||
error = expand_entry_variables(&entry->name, entry);
|
||||
error = expand_entry_variables(&entry->name);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
@ -259,69 +262,24 @@ static int process_variables_in_entries(struct cod_entry *entry_list)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* does not currently support expansion of vars in options */
|
||||
static int process_variables_in_mnt_entries(struct mnt_entry *entry_list)
|
||||
static int process_variables_in_rules(Profile &prof)
|
||||
{
|
||||
int error = 0;
|
||||
struct mnt_entry *entry;
|
||||
|
||||
list_for_each(entry_list, entry) {
|
||||
error = expand_entry_variables(&entry->mnt_point, entry);
|
||||
for (RuleList::iterator i = prof.rule_ents.begin(); i != prof.rule_ents.end(); i++) {
|
||||
int error = (*i)->expand_variables();
|
||||
if (error)
|
||||
return error;
|
||||
error = expand_entry_variables(&entry->device, entry);
|
||||
if (error)
|
||||
return error;
|
||||
error = expand_entry_variables(&entry->trans, entry);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int process_dbus_variables(struct dbus_entry *entry_list)
|
||||
{
|
||||
int error = 0;
|
||||
struct dbus_entry *entry;
|
||||
|
||||
list_for_each(entry_list, entry) {
|
||||
error = expand_entry_variables(&entry->bus, entry);
|
||||
if (error)
|
||||
return error;
|
||||
error = expand_entry_variables(&entry->name, entry);
|
||||
if (error)
|
||||
return error;
|
||||
error = expand_entry_variables(&entry->peer_label, entry);
|
||||
if (error)
|
||||
return error;
|
||||
error = expand_entry_variables(&entry->path, entry);
|
||||
if (error)
|
||||
return error;
|
||||
error = expand_entry_variables(&entry->interface, entry);
|
||||
if (error)
|
||||
return error;
|
||||
error = expand_entry_variables(&entry->member, entry);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int process_profile_variables(Profile *prof)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
error = process_variables_in_entries(prof->entries);
|
||||
|
||||
if (!error)
|
||||
error = process_variables_in_mnt_entries(prof->mnt_ents);
|
||||
|
||||
if (!error)
|
||||
error = process_dbus_variables(prof->dbus_ents);
|
||||
error = process_variables_in_entries(prof->entries);
|
||||
if (!error)
|
||||
error = process_variables_in_rules(*prof);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
@ -72,11 +72,11 @@ int parser_token = 0;
|
||||
|
||||
struct cod_entry *do_file_rule(char *ns, char *id, int mode,
|
||||
char *link_id, char *nt);
|
||||
struct mnt_entry *do_mnt_rule(struct cond_entry *src_conds, char *src,
|
||||
struct cond_entry *dst_conds, char *dst,
|
||||
int mode);
|
||||
struct mnt_entry *do_pivot_rule(struct cond_entry *old, char *root,
|
||||
char *transition);
|
||||
mnt_rule *do_mnt_rule(struct cond_entry *src_conds, char *src,
|
||||
struct cond_entry *dst_conds, char *dst,
|
||||
int mode);
|
||||
mnt_rule *do_pivot_rule(struct cond_entry *old, char *root,
|
||||
char *transition);
|
||||
|
||||
void add_local_entry(Profile *prof);
|
||||
|
||||
@ -162,6 +162,12 @@ void add_local_entry(Profile *prof);
|
||||
/* debug flag values */
|
||||
%token TOK_FLAGS
|
||||
|
||||
%code requires {
|
||||
#include "profile.h"
|
||||
#include "mount.h"
|
||||
#include "dbus.h"
|
||||
}
|
||||
|
||||
%union {
|
||||
char *id;
|
||||
char *flag_id;
|
||||
@ -170,8 +176,9 @@ void add_local_entry(Profile *prof);
|
||||
Profile *prof;
|
||||
struct cod_net_entry *net_entry;
|
||||
struct cod_entry *user_entry;
|
||||
struct mnt_entry *mnt_entry;
|
||||
struct dbus_entry *dbus_entry;
|
||||
|
||||
mnt_rule *mnt_entry;
|
||||
dbus_rule *dbus_entry;
|
||||
|
||||
flagvals flags;
|
||||
int fmode;
|
||||
@ -281,7 +288,7 @@ profile_base: TOK_ID opt_id flags TOK_OPEN rules TOK_CLOSE
|
||||
prof->flags.complain = 1;
|
||||
|
||||
post_process_file_entries(prof);
|
||||
post_process_mnt_entries(prof);
|
||||
post_process_rule_entries(prof);
|
||||
PDEBUG("%s: flags='%s%s'\n",
|
||||
$2,
|
||||
prof->flags.complain ? "complain, " : "",
|
||||
@ -667,8 +674,8 @@ rules: rules opt_prefix mnt_rule
|
||||
} else if ($2.audit) {
|
||||
$3->audit = $3->allow;
|
||||
}
|
||||
$3->next = $1->mnt_ents;
|
||||
$1->mnt_ents = $3;
|
||||
|
||||
$1->rule_ents.push_back($3);
|
||||
$$ = $1;
|
||||
}
|
||||
|
||||
@ -684,8 +691,7 @@ rules: rules opt_prefix dbus_rule
|
||||
} else if ($2.audit) {
|
||||
$3->audit = $3->mode;
|
||||
}
|
||||
$3->next = $1->dbus_ents;
|
||||
$1->dbus_ents = $3;
|
||||
$1->rule_ents.push_back($3);
|
||||
$$ = $1;
|
||||
}
|
||||
|
||||
@ -1196,9 +1202,9 @@ opt_dbus_perm: { /* nothing */ $$ = 0; }
|
||||
|
||||
dbus_rule: TOK_DBUS opt_dbus_perm opt_conds opt_cond_list TOK_END_OF_RULE
|
||||
{
|
||||
struct dbus_entry *ent;
|
||||
dbus_rule *ent;
|
||||
|
||||
ent = new_dbus_entry($2, $3, $4);
|
||||
ent = new dbus_rule($2, $3, $4);
|
||||
if (!ent) {
|
||||
yyerror(_("Memory allocation error."));
|
||||
}
|
||||
@ -1366,12 +1372,10 @@ int verify_mnt_conds(struct cond_entry *conds, int src)
|
||||
return error;
|
||||
}
|
||||
|
||||
struct mnt_entry *do_mnt_rule(struct cond_entry *src_conds, char *src,
|
||||
struct cond_entry *dst_conds, char *dst,
|
||||
int mode)
|
||||
mnt_rule *do_mnt_rule(struct cond_entry *src_conds, char *src,
|
||||
struct cond_entry *dst_conds, char *dst,
|
||||
int mode)
|
||||
{
|
||||
struct mnt_entry *ent;
|
||||
|
||||
if (verify_mnt_conds(src_conds, MNT_SRC_OPT) != 0)
|
||||
yyerror(_("bad mount rule"));
|
||||
|
||||
@ -1382,7 +1386,7 @@ struct mnt_entry *do_mnt_rule(struct cond_entry *src_conds, char *src,
|
||||
if (dst_conds)
|
||||
yyerror(_("mount point conditions not currently supported"));
|
||||
|
||||
ent = new_mnt_entry(src_conds, src, dst_conds, dst, mode);
|
||||
mnt_rule *ent = new mnt_rule(src_conds, src, dst_conds, dst, mode);
|
||||
if (!ent) {
|
||||
yyerror(_("Memory allocation error."));
|
||||
}
|
||||
@ -1390,10 +1394,8 @@ struct mnt_entry *do_mnt_rule(struct cond_entry *src_conds, char *src,
|
||||
return ent;
|
||||
}
|
||||
|
||||
struct mnt_entry *do_pivot_rule(struct cond_entry *old, char *root,
|
||||
char *transition)
|
||||
mnt_rule *do_pivot_rule(struct cond_entry *old, char *root, char *transition)
|
||||
{
|
||||
struct mnt_entry *ent = NULL;
|
||||
char *device = NULL;
|
||||
if (old) {
|
||||
if (strcmp(old->name, "oldroot") != 0)
|
||||
@ -1405,8 +1407,7 @@ struct mnt_entry *do_pivot_rule(struct cond_entry *old, char *root,
|
||||
free_cond_entry(old);
|
||||
}
|
||||
|
||||
ent = new_mnt_entry(NULL, device, NULL, root,
|
||||
AA_MAY_PIVOTROOT);
|
||||
mnt_rule *ent = new mnt_rule(NULL, device, NULL, root, AA_MAY_PIVOTROOT);
|
||||
ent->trans = transition;
|
||||
|
||||
return ent;
|
||||
|
@ -13,6 +13,7 @@
|
||||
*/
|
||||
|
||||
#include "profile.h"
|
||||
#include "rule.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -62,8 +63,9 @@ Profile::~Profile()
|
||||
{
|
||||
hat_table.clear();
|
||||
free_cod_entries(entries);
|
||||
free_mnt_entries(mnt_ents);
|
||||
free_dbus_entries(dbus_ents);
|
||||
|
||||
for (RuleList::iterator i = rule_ents.begin(); i != rule_ents.end(); i++)
|
||||
delete *i;
|
||||
if (dfa.rules)
|
||||
aare_delete_ruleset(dfa.rules);
|
||||
if (dfa.dfa)
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <set>
|
||||
|
||||
#include "parser.h"
|
||||
#include "rule.h"
|
||||
|
||||
class Profile;
|
||||
|
||||
@ -153,8 +154,7 @@ public:
|
||||
|
||||
char *exec_table[AA_EXEC_COUNT];
|
||||
struct cod_entry *entries;
|
||||
struct mnt_entry *mnt_ents;
|
||||
struct dbus_entry *dbus_ents;
|
||||
RuleList rule_ents;
|
||||
|
||||
ProfileList hat_table;
|
||||
|
||||
@ -179,9 +179,6 @@ public:
|
||||
std::fill(exec_table, exec_table + AA_EXEC_COUNT, (char *)NULL);
|
||||
|
||||
entries = NULL;
|
||||
mnt_ents = NULL;
|
||||
dbus_ents = NULL;
|
||||
|
||||
};
|
||||
|
||||
virtual ~Profile();
|
||||
|
Loading…
x
Reference in New Issue
Block a user