2
0
mirror of https://gitlab.com/apparmor/apparmor synced 2025-08-22 10:07:12 +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:
John Johansen 2014-04-07 03:16:50 -07:00
parent 54a24c2b6a
commit a066f80372
13 changed files with 875 additions and 949 deletions

View File

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

View File

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

View File

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

View File

@ -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");
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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