[apparmor] [patch 02/24] Convert mount and dbus to be subclasses of a generic rule class
Seth Arnold
seth.arnold at canonical.com
Tue Mar 11 06:40:01 UTC 2014
On Fri, Mar 07, 2014 at 09:31:23AM -0800, john.johansen at canonical.com wrote:
> 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 at canonical.com>
Sorry, I only made it through the first half of the patch. Some small
notes inline:
>
> ---
> parser/Makefile | 13 -
> parser/dbus.c | 388 ++++++++++++++++++++++++----------
> parser/dbus.h | 32 ++
> parser/mount.c | 534 +++++++++++++++++++++++++++++++++++++----------
> parser/mount.h | 32 ++
> parser/parser.h | 22 +
> parser/parser_misc.c | 101 --------
> parser/parser_policy.c | 29 --
> parser/parser_regex.c | 489 -------------------------------------------
> parser/parser_variable.c | 66 +----
> parser/parser_yacc.y | 51 ++--
> parser/profile.cc | 6
> parser/profile.h | 7
> parser/rule.c | 23 ++
> parser/rule.h | 51 ++++
> 15 files changed, 906 insertions(+), 938 deletions(-)
>
> --- 2.9-test.orig/parser/Makefile
> +++ 2.9-test/parser/Makefile
> @@ -79,8 +79,8 @@
> 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 @@
> 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_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 $@
> --- 2.9-test.orig/parser/dbus.c
> +++ 2.9-test/parser/dbus.c
> @@ -20,23 +20,90 @@
> #include <string.h>
> #include <sys/apparmor.h>
>
> +#include <iomanip>
> +#include <string>
> +#include <sstream>
> +
> #include "parser.h"
> #include "profile.h"
> #include "parser_yacc.h"
> #include "dbus.h"
>
> -void free_dbus_entry(struct dbus_entry *ent)
> +#define _(s) gettext(s)
> +
> +static int parse_dbus_sub_mode(const char *str_mode, int *result, int fail, const char *mode_desc __unused)
> {
> - if (!ent)
> - return;
> - free(ent->bus);
> - free(ent->name);
> - free(ent->peer_label);
> - free(ent->path);
> - free(ent->interface);
> - free(ent->member);
> + 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;
> +}
>
> - free(ent);
> +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 +127,7 @@
> 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 +140,17 @@
> 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 +158,236 @@
> }
> }
>
> -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)
> +{
> + if (audit)
> + os << "audit ";
> + if (deny)
> + os << "deny ";
> +
> + os << "dbus ( ";
> +
> + 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 << ")";
> +
> + 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 << "\"";
> +
> + if (!(mode & AA_DBUS_BIND) && (peer_label || name)) {
> + os << " peer=( ";
> + if (peer_label)
> + os << "label=\"" << peer_label << "\" ";
> + if (name)
> + os << "name=\"" << name << "\" ";
> + os << ")";
> + }
> +
> + 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;
> +}
> +
> +int dbus_rule::gen_policy_re(Profile &prof)
> {
> - struct dbus_entry *ent = NULL;
> - ent = (struct dbus_entry *) calloc(1, sizeof(struct dbus_entry));
> - if (!ent)
> - return NULL;
> -
> - 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;
> -
> - ent->next = orig->next;
> -
> - return ent;
> -
> -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, ")");
> + 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) {
> + pwarn("profile %s dbus rules not enforced\n", prof.name);
> + return RULE_NOT_SUPPORTED;
> }
>
> - fprintf(stderr, ",\n");
> + 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;
> }
> --- 2.9-test.orig/parser/dbus.h
> +++ 2.9-test/parser/dbus.h
> @@ -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 @@
> 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 */
> --- 2.9-test.orig/parser/mount.c
> +++ 2.9-test/parser/mount.c
> @@ -215,8 +215,11 @@
>
> #include <stdlib.h>
> #include <string.h>
> +#include <linux/limits.h>
>
> #include "parser.h"
> +#include "policydb.h"
> +#include "profile.h"
> #include "mount.h"
>
> struct mnt_keyword_table {
> @@ -389,146 +392,455 @@
> 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 */
> + aa_class = AA_CLASS_MOUNT;
>
> - 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);
> -
> - ent->flags = 0;
> - ent->inv_flags = 0;
> -
> - if (src_conds) {
> - unsigned int flags = 0, inv_flags = 0;
> - struct value_list *list = extract_options(&src_conds, 0);
> -
> - ent->opts = extract_options(&src_conds, 1);
> - if (ent->opts)
> - ent->flags = extract_flags(&ent->opts,
> - &ent->inv_flags);
> -
> - if (list) {
> - flags = extract_flags(&list, &inv_flags);
> - /* these flags are optional so set both */
> - flags |= inv_flags;
> - inv_flags |= flags;
> -
> - ent->flags |= flags;
> - ent->inv_flags |= inv_flags;
> -
> - if (ent->opts)
> - list_append(ent->opts, list);
> - else if (list)
> - ent->opts = list;
> - }
> - }
> + dev_type = extract_fstype(&src_conds);
>
> - 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 (src_conds) {
> + struct value_list *list = extract_options(&src_conds, 0);
>
> - ent->allow = allow;
> + opts = extract_options(&src_conds, 1);
> + if (opts)
> + flags = extract_flags(&opts, &inv_flags);
>
> - if (src_conds) {
> - PERROR(" unsupported mount conditions\n");
> - exit(1);
> + if (list) {
> + unsigned int tmpflags, tmpinv_flags = 0;
> +
> + tmpflags = extract_flags(&list, &tmpinv_flags);
> + /* these flags are optional so set both */
> + tmpflags |= tmpinv_flags;
> + tmpinv_flags |= tmpflags;
> +
> + flags |= tmpflags;
> + inv_flags |= tmpinv_flags;
> +
> + if (opts)
> + list_append(opts, list);
> + else if (list)
> + opts = list;
> }
> }
>
> - return ent;
> + 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);
> + }
> }
>
> -void free_mnt_entry(struct mnt_entry *ent)
> +ostream &mnt_rule::dump(ostream &os)
> {
> - if (!ent)
> - return;
> + 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";
>
> - 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);
> + 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";
>
> - free(ent);
> + return os;
> }
>
> -struct mnt_entry *dup_mnt_entry(struct mnt_entry *orig)
> +/* does not currently support expansion of vars in options */
> +int mnt_rule::expand_variables(void)
> {
> - struct mnt_entry *entry = NULL;
> + 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;
> +}
>
> - entry = (struct mnt_entry *) calloc(1, sizeof(struct mnt_entry));
> - if (!entry)
> - return NULL;
> +static int build_mnt_flags(char *buffer, int size, unsigned int flags,
> + unsigned int inv_flags)
> +{
> + char *p = buffer;
> + int i, len = 0;
>
> - DUP_STRING(orig, entry, mnt_point, err);
> - DUP_STRING(orig, entry, device, err);
> - DUP_STRING(orig, entry, trans, err);
> + 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;
> + }
Some odd whitespace with the line starting len = snprintf
> + 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;
> + }
>
> - entry->dev_type = dup_value_list(orig->dev_type);
> - if (orig->dev_type && !(entry->dev_type))
> - goto err;
> + /* 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;
>
> - entry->opts = dup_value_list(orig->opts);
> - if (orig->opts && !(entry->opts))
> - goto err;
> + strcpy(p, "(\\xfe|)");
> + }
>
> - entry->flags = orig->flags;
> - entry->inv_flags = orig->inv_flags;
> + return TRUE;
> +}
>
> - entry->allow = orig->allow;
> - entry->audit = orig->audit;
> - entry->deny = orig->deny;
> +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;
> + }
>
> - entry->next = orig->next;
> + list_for_each(opts, ent) {
> + ptype = convert_aaregex_to_pcre(ent->value, 0, buffer, &pos);
> + if (ptype == ePatternInvalid)
> + return FALSE;
>
> - return entry;
> + if (ent->next)
> + buffer.append(",");
> + }
>
> -err:
> - free_mnt_entry(entry);
> - return NULL;
> + return TRUE;
> }
>
> -void print_mnt_entry(struct mnt_entry *entry)
> +int mnt_rule::gen_policy_re(Profile &prof)
> {
> - 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");
> + 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) {
> + pwarn("profile %s mount rules not enforced\n", prof.name);
> + return RULE_NOT_SUPPORTED;
> + }
>
> - 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);
> + sprintf(class_mount_hdr, "\\x%02x", AA_CLASS_MOUNT);
>
> - fprintf(stderr, " %s (0x%x/0x%x)", entry->deny ? "deny" : "", entry->allow, entry->audit);
> - fprintf(stderr, ",\n");
> + /* 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;
> +
> + 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 (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;
> +
Is prof.policy.count++ correct or should that be:
prof.policy.count += count; ?
Thanks
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 490 bytes
Desc: Digital signature
URL: <https://lists.ubuntu.com/archives/apparmor/attachments/20140310/3c2f2936/attachment-0001.pgp>
More information about the AppArmor
mailing list