diff --git a/parser/Makefile b/parser/Makefile index 42ac4e1b7..b3097d9fc 100644 --- a/parser/Makefile +++ b/parser/Makefile @@ -80,9 +80,10 @@ 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 common_optarg.c lib.c network.c \ - mount.cc dbus.cc profile.cc rule.cc signal.cc ptrace.cc + mount.cc dbus.cc profile.cc rule.cc signal.cc ptrace.cc \ + af_rule.cc af_unix.cc HDRS = parser.h parser_include.h immunix.h mount.h dbus.h lib.h profile.h \ - rule.h common_optarg.h signal.h ptrace.h network.h + rule.h common_optarg.h signal.h ptrace.h network.h af_rule.h af_unix.h TOOLS = apparmor_parser OBJECTS = $(SRCS:.c=.o) @@ -254,6 +255,12 @@ ptrace.o: ptrace.cc ptrace.h parser.h immunix.h parser_yacc.h rule.h $(APPARMOR_ network.o: network.c network.h parser.h immunix.h parser_yacc.h rule.h af_names.h $(APPARMOR_H) $(CXX) $(EXTRA_CFLAGS) -c -o $@ $< +af_rule.o: af_rule.cc af_rule.h network.h parser.h immunix.h parser_yacc.h rule + $(CXX) $(EXTRA_CFLAGS) -c -o $@ $< + +af_unix.o: af_unix.cc af_unix.h network.h af_rule.h parser.h immunix.h parser_y + $(CXX) $(EXTRA_CFLAGS) -c -o $@ $< + profile.o: profile.cc profile.h parser.h network.h $(CXX) $(EXTRA_CFLAGS) -c -o $@ $< diff --git a/parser/af_rule.cc b/parser/af_rule.cc new file mode 100644 index 000000000..74693f3ad --- /dev/null +++ b/parser/af_rule.cc @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2014 + * Canonical, Ltd. (All rights reserved) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, contact Novell, Inc. or Canonical + * Ltd. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include "network.h" +#include "parser.h" +#include "profile.h" +#include "parser_yacc.h" +#include "af_rule.h" + + +/* need to move this table to stl */ +static struct supported_cond supported_conds[] = { + { "type", true, false, false, local_cond }, + { "protocol", false, false, false, local_cond }, + { "label", true, false, false, peer_cond }, + { NULL, false, false, false, local_cond }, /* eol sentinal */ +}; + +bool af_rule::cond_check(struct supported_cond *conds, struct cond_entry *ent, + bool peer, const char *rname) +{ + struct supported_cond *i; + for (i = conds; i->name; i++) { + if (strcmp(ent->name, i->name) != 0) + continue; + if (!i->supported) + yyerror("%s rule: '%s' conditional is not currently supported\n", rname, ent->name); + if (!peer && (i->side == peer_cond)) + yyerror("%s rule: '%s' conditional is only valid in the peer expression\n", rname, ent->name); + if (peer && (i->side == local_cond)) + yyerror("%s rule: '%s' conditional is not allowed in the peer expression\n", rname, ent->name); + if (!ent->eq && !i->in) + yyerror("%s rule: keyword 'in' is not allowed in '%s' socket conditional\n", rname, ent->name); + if (list_len(ent->vals) > 1 && !i->multivalue) + yyerror("%s rule: conditional '%s' only supports a single value\n", rname, ent->name); + return true; + } + + /* not in support table */ + return false; +} + +/* generic af supported conds. + * returns: true if processed, else false + */ +int af_rule::move_base_cond(struct cond_entry *ent, bool peer) +{ + if (!cond_check(supported_conds, ent, peer, "unknown")) + return false; + + if (strcmp(ent->name, "type") == 0) { + move_conditional_value("socket rule", &sock_type, ent); + sock_type_n = net_find_type_val(sock_type); + if (sock_type_n == -1) + yyerror("socket rule: invalid socket type '%s'", sock_type); + } else if (strcmp(ent->name, "protocol") == 0) { + yyerror("socket rule: 'protocol' conditional is not currently supported\n"); + } else if (strcmp(ent->name, "label") == 0) { + if (peer) + move_conditional_value("unix", &label, ent); + else + move_conditional_value("unix", &peer_label, ent); + } else + return false; + + return true; +} + +ostream &af_rule::dump_prefix(ostream &os) +{ + if (audit) + os << "audit "; + if (deny) + os << "deny "; + return os; +} + +ostream &af_rule::dump_local(ostream &os) +{ + if (mode != AA_VALID_NET_PERMS) { + os << " ("; + + if (mode & AA_NET_SEND) + os << "send "; + if (mode & AA_NET_RECEIVE) + os << "receive "; + if (mode & AA_NET_CREATE) + os << "create "; + if (mode & AA_NET_SHUTDOWN) + os << "shutdown "; + if (mode & AA_NET_CONNECT) + os << "connect "; + if (mode & AA_NET_SETATTR) + os << "setattr "; + if (mode & AA_NET_GETATTR) + os << "getattr "; + if (mode & AA_NET_BIND) + os << "bind "; + if (mode & AA_NET_ACCEPT) + os << "accept "; + if (mode & AA_NET_LISTEN) + os << "listen "; + if (mode & AA_NET_SETOPT) + os << "setopt "; + if (mode & AA_NET_GETOPT) + os << "getopt "; + os << ")"; + } + + if (sock_type) + os << " type=" << sock_type; + if (proto) + os << " protocol=" << proto; + return os; +} + +ostream &af_rule::dump_peer(ostream &os) +{ + if (peer_label) + os << " label=\"" << peer_label << "\""; + + return os; +} + +ostream &af_rule::dump(ostream &os) +{ + os << dump_prefix(os); + os << af_name; + os << dump_local(os); + if (has_peer_conds()) + os << " peer=(" << dump_peer(os) << ")"; + os << ",\n"; + + return os; +} + +int af_rule::expand_variables(void) +{ + int error = expand_entry_variables(&label); + if (error) + return error; + error = expand_entry_variables(&peer_label); + if (error) + return error; + + return 0; +} diff --git a/parser/af_rule.h b/parser/af_rule.h new file mode 100644 index 000000000..3af0f6144 --- /dev/null +++ b/parser/af_rule.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2014 + * Canonical Ltd. (All rights reserved) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, contact Novell, Inc. or Canonical + * Ltd. + */ +#ifndef __AA_AF_RULE_H +#define __AA_AF_RULE_H + +#include "immunix.h" +#include "network.h" +#include "parser.h" +#include "profile.h" + +#include "rule.h" + +enum cond_side { local_cond, peer_cond, either_cond }; + +struct supported_cond { + const char *name; + bool supported; + bool in; + bool multivalue; + enum cond_side side ; +}; + +class af_rule: public rule_t { +public: + std::string af_name; + char *sock_type; + int sock_type_n; + char *proto; + int proto_n; + char *label; + char *peer_label; + int mode; + int audit; + bool deny; + + af_rule(const char *name): af_name(name), sock_type(NULL), + sock_type_n(-1), proto(NULL), proto_n(0), label(NULL), + peer_label(NULL), mode(0), audit(0), deny(0) + {} + + virtual ~af_rule() + { + free(sock_type); + free(proto); + free(label); + free(peer_label); + }; + + bool cond_check(struct supported_cond *cond, struct cond_entry *ent, + bool peer, const char *rname); + int move_base_cond(struct cond_entry *conds, bool peer); + + virtual bool has_peer_conds(void) { return peer_label ? true : false; } + virtual ostream &dump_prefix(ostream &os); + virtual ostream &dump_local(ostream &os); + virtual ostream &dump_peer(ostream &os); + virtual ostream &dump(ostream &os); + virtual int expand_variables(void); + virtual int gen_policy_re(Profile &prof) = 0; + virtual void post_process(Profile &prof __unused) { }; +}; + +#endif /* __AA_AF_RULE_H */ diff --git a/parser/af_unix.cc b/parser/af_unix.cc new file mode 100644 index 000000000..06c6e3423 --- /dev/null +++ b/parser/af_unix.cc @@ -0,0 +1,386 @@ +/* + * Copyright (c) 2014 + * Canonical, Ltd. (All rights reserved) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, contact Novell, Inc. or Canonical + * Ltd. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include "network.h" +#include "parser.h" +#include "profile.h" +#include "af_unix.h" + +int parse_unix_mode(const char *str_mode, int *mode, int fail) +{ + return parse_X_mode("unix", AA_VALID_NET_PERMS, str_mode, mode, fail); +} + + +static struct supported_cond supported_conds[] = { + { "path", true, false, false, either_cond }, + { NULL, false, false, false, local_cond }, /* sentinal */ +}; + +void unix_rule::move_conditionals(struct cond_entry *conds) +{ + struct cond_entry *ent; + + list_for_each(conds, ent) { + + if (!cond_check(supported_conds, ent, false, "unix") && + !move_base_cond(ent, false)) { + yyerror("unix rule: invalid conditional '%s'\n", + ent->name); + continue; + } + if (strcmp(ent->name, "path") == 0) { + move_conditional_value("unix socket", &path, ent); + if (path[0] != '@' && strcmp(path, "none") != 0) + yyerror("unix rule: invalid value for path='%s'\n", path); + } + + /* TODO: add conditionals for + * listen queue length + * attrs that can be read/set + * ops that can be read/set + * allow in on + * type, protocol + * local label match, and set + */ + } +} + +void unix_rule::move_peer_conditionals(struct cond_entry *conds) +{ + struct cond_entry *ent; + + list_for_each(conds, ent) { + if (!cond_check(supported_conds, ent, true, "unix") && + !move_base_cond(ent, true)) { + yyerror("unix rule: invalid peer conditional '%s'\n", + ent->name); + continue; + } + if (strcmp(ent->name, "path") == 0) { + move_conditional_value("unix", &peer_path, ent); + if (peer_path[0] != '@' && strcmp(path, "none") != 0) + yyerror("unix rule: invalid value for path='%s'\n", peer_path); + } + } +} + +unix_rule::unix_rule(unsigned int type_p, bool audit_p, bool denied): + af_rule("unix"), path(NULL), peer_path(NULL) +{ + if (type_p != 0xffffffff) { + sock_type_n = type_p; + sock_type = strdup(net_find_type_name(type_p)); + if (!sock_type) + yyerror("socket rule: invalid socket type '%d'", type_p); + } + mode = AA_VALID_NET_PERMS; + audit = audit_p ? AA_VALID_NET_PERMS : 0; + deny = denied; +} + +unix_rule::unix_rule(int mode_p, struct cond_entry *conds, + struct cond_entry *peer_conds): + af_rule("unix"), path(NULL), peer_path(NULL) +{ + move_conditionals(conds); + move_peer_conditionals(peer_conds); + + if (mode_p) { + mode = mode_p; + if (mode & ~AA_VALID_NET_PERMS) + yyerror("mode contains invalid permissions for unix socket rules\n"); + else if ((mode & AA_NET_BIND) && + ((mode & AA_PEER_NET_PERMS) || has_peer_conds())) + /* Do we want to loosen this? */ + yyerror("unix socket 'bind' access cannot be used with message rule conditionals\n"); + else if ((mode & AA_NET_LISTEN) && + ((mode & AA_PEER_NET_PERMS) || has_peer_conds())) + /* Do we want to loosen this? */ + yyerror("unix socket 'listen' access cannot be used with message rule conditionals\n"); + else if ((mode & AA_NET_ACCEPT) && + ((mode & AA_PEER_NET_PERMS) || has_peer_conds())) + /* Do we want to loosen this? */ + yyerror("unix socket 'accept' access cannot be used with message rule conditionals\n"); + } else { + mode = AA_VALID_NET_PERMS; + } + + free_cond_list(conds); + free_cond_list(peer_conds); + +} + +ostream &unix_rule::dump_local(ostream &os) +{ + af_rule::dump_local(os); + if (path) + os << "path='" << path << "'"; + return os; +} + +ostream &unix_rule::dump_peer(ostream &os) +{ + af_rule::dump_peer(os); + if (peer_path) + os << "path='" << peer_path << "'"; + return os; +} + + +int unix_rule::expand_variables(void) +{ + int error = af_rule::expand_variables(); + if (error) + return error; + error = expand_entry_variables(&path); + if (error) + return error; + error = expand_entry_variables(&peer_path); + 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, const char *msg) +{ + 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 << "): " << msg << "\n"; + warned_name = name; + } +} + +static void warn_once(const char *name) +{ + warn_once(name, "extended network unix socket rules not enforced"); +} + +std::ostringstream &writeu16(std::ostringstream &o, int v) +{ + u16 tmp = htobe16((u16) v); + char *c = (char *) &tmp; + o << "\\x" << std::setfill('0') << std::setw(2) << std::hex << *c++; + o << "\\x" << std::setfill('0') << std::setw(2) << std::hex << *c; + return o; +} + +#define CMD_ADDR 1 +#define CMD_LISTEN 2 +#define CMD_ACCEPT 3 +#define CMD_OPT 4 + +void unix_rule::downgrade_rule(Profile &prof) { + if (!prof.net.allow && !prof.alloc_net_table()) + yyerror(_("Memory allocation error.")); + if (deny) { + prof.net.deny[AF_UNIX] |= 1 << sock_type_n; + if (!audit) + prof.net.quiet[AF_UNIX] |= 1 << sock_type_n; + } else { + prof.net.allow[AF_UNIX] |= 1 << sock_type_n; + if (audit) + prof.net.audit[AF_UNIX] |= 1 << sock_type_n; + } +} + +int unix_rule::gen_policy_re(Profile &prof) +{ + std::ostringstream buffer, tmp; + std::string buf; + + pattern_t ptype; + int pos; + int mask = mode; + + /* always generate a downgraded rule. This doesn't change generated + * policy size and allows the binary policy to be loaded against + * older kernels and be enforced to the best of the old network + * rules ability + */ + downgrade_rule(prof); + if (!kernel_supports_unix) { + if (kernel_supports_network) { + /* only warn if we are building against a kernel + * that requires downgrading */ + warn_once(prof.name, "downgrading extended network unix socket rule to generic network rule\n"); + /* TODO: add ability to abort instead of downgrade */ + return RULE_OK; + } + warn_once(prof.name); + return RULE_NOT_SUPPORTED; + } + + + buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << AA_CLASS_NET; + buffer << writeu16(buffer, AF_UNIX); + if (sock_type) + buffer << writeu16(buffer, sock_type_n); + else + buffer << ".."; + if (proto) + buffer << writeu16(buffer, proto_n); + else + buffer << ".."; + + if (mask & AA_NET_CREATE) { + buf = buffer.str(); + if (!prof.policy.rules->add_rule(buf.c_str(), deny, + AA_NET_CREATE, + audit & AA_NET_CREATE, + dfaflags)) + goto fail; + mask &= ~AA_NET_CREATE; + } + + /* local addr */ + if (path) { + if (strcmp(path, "none") == 0) { + buffer << "\\x01"; + } else { + /* skip leading @ */ + ptype = convert_aaregex_to_pcre(path + 1, 0, buf, &pos); + if (ptype == ePatternInvalid) + goto fail; + /* kernel starts abstract with \0 */ + buffer << "\\x00"; + buffer << buf; + } + } else + buffer << ".*"; + + /* change to out of band separator */ + buffer << "\\x00"; + + if (mask & AA_LOCAL_NET_PERMS) { + /* local label option */ + if (label) { + ptype = convert_aaregex_to_pcre(label, 0, buf, &pos); + if (ptype == ePatternInvalid) + goto fail; + /* kernel starts abstract with \0 */ + buffer << buf; + } else + tmp << anyone_match_pattern; + buffer << "\\x00"; + + /* create already masked off */ + if (mask & AA_LOCAL_NET_PERMS & ~AA_LOCAL_NET_CMD) { + buf = buffer.str(); + if (!prof.policy.rules->add_rule(buf.c_str(), deny, + mask & AA_LOCAL_NET_PERMS & ~AA_LOCAL_NET_CMD, + audit & AA_LOCAL_NET_PERMS & ~AA_LOCAL_NET_CMD, + dfaflags)) + goto fail; + } + + /* cmd selector - drop accept??? */ + if (mask & AA_NET_ACCEPT) { + tmp.str(buffer.str()); + tmp << "\\x" << std::setfill('0') << std::setw(2) << std::hex << CMD_ACCEPT; + buf = tmp.str(); + if (!prof.policy.rules->add_rule(buf.c_str(), deny, + AA_NET_ACCEPT, + audit & AA_NET_ACCEPT, + dfaflags)) + goto fail; + } + if (mask & AA_NET_LISTEN) { + tmp.str(buffer.str()); + tmp << "\\x" << std::setfill('0') << std::setw(2) << std::hex << CMD_LISTEN; + /* TODO: backlog conditional */ + tmp << ".."; + buf = tmp.str(); + if (!prof.policy.rules->add_rule(buf.c_str(), deny, + AA_NET_LISTEN, + audit & AA_NET_LISTEN, + dfaflags)) + goto fail; + } + if (mask & AA_NET_OPT) { + tmp.str(buffer.str()); + tmp << "\\x" << std::setfill('0') << std::setw(2) << std::hex << CMD_OPT; + /* TODO: sockopt conditional */ + tmp << ".."; + buf = tmp.str(); + if (!prof.policy.rules->add_rule(buf.c_str(), deny, + AA_NET_OPT, + audit & AA_NET_OPT, + dfaflags)) + goto fail; + } + mask &= ~AA_LOCAL_NET_PERMS; + } + + if (mask & AA_PEER_NET_PERMS) { + /* cmd selector */ + buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << CMD_ADDR; + + /* peer addr */ + if (peer_path) { + if (strcmp(path, "none") == 0) { + buffer << "\\x01"; + } else { + /* skip leading @ */ + ptype = convert_aaregex_to_pcre(peer_path + 1, 0, buf, &pos); + if (ptype == ePatternInvalid) + goto fail; + /* kernel starts abstract with \0 */ + buffer << "\\x00"; + buffer << buf; + } + } + /* change to out of band separator */ + buffer << "\\x00"; + + if (peer_label) { + ptype = convert_aaregex_to_pcre(peer_label, 0, buf, &pos); + if (ptype == ePatternInvalid) + goto fail; + buffer << buf; + } else { + buffer << anyone_match_pattern; + } + + buf = buffer.str(); + if (!prof.policy.rules->add_rule(buf.c_str(), deny, mode & AA_PEER_NET_PERMS, audit, dfaflags)) + goto fail; + } + + return RULE_OK; + +fail: + return RULE_ERROR; +} diff --git a/parser/af_unix.h b/parser/af_unix.h new file mode 100644 index 000000000..3eef4a0ee --- /dev/null +++ b/parser/af_unix.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2014 + * Canonical Ltd. (All rights reserved) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, contact Novell, Inc. or Canonical + * Ltd. + */ +#ifndef __AA_AF_UNIX_H +#define __AA_AF_UNIX_H + +#include "immunix.h" +#include "network.h" +#include "parser.h" +#include "profile.h" +#include "af_rule.h" + +int parse_unix_mode(const char *str_mode, int *mode, int fail); + +class unix_rule: public af_rule { + void move_conditionals(struct cond_entry *conds); + void move_peer_conditionals(struct cond_entry *conds); + void downgrade_rule(Profile &prof); +public: + char *path; + char *peer_path; + int mode; + int audit; + bool deny; + + unix_rule(unsigned int type_p, bool audit_p, bool denied); + unix_rule(int mode, struct cond_entry *conds, + struct cond_entry *peer_conds); + virtual ~unix_rule() + { + free(path); + free(peer_path); + }; + + virtual bool has_peer_conds(void) { + return af_rule::has_peer_conds() || peer_path; + } + + virtual ostream &dump_local(ostream &os); + virtual ostream &dump_peer(ostream &os); + virtual int expand_variables(void); + virtual int gen_policy_re(Profile &prof); + virtual void post_process(Profile &prof __unused) { }; +}; + +#endif /* __AA_AF_UNIX_H */ diff --git a/parser/apparmor.d.pod b/parser/apparmor.d.pod index 431396851..6f6e4588a 100644 --- a/parser/apparmor.d.pod +++ b/parser/apparmor.d.pod @@ -54,7 +54,7 @@ B = '#' I B = any characters -B = [ I ... ] [ I ... ] ( '"' I '"' | I ) [ 'flags=(complain)' ]'{' [ ( I | I | I | I | 'capability ' I | I | I | I | I | I | 'change_profile -> ' I ) ... ] '}' +B = [ I ... ] [ I ... ] ( '"' I '"' | I ) [ 'flags=(complain)' ]'{' [ ( I | I | I | I | 'capability ' I | I | I | I | I | I I | 'change_profile -> ' I ) ... ] '}' B = [ I ... ] ( I | 'profile ' I ) '{' [ ( I | I | I ) ... ] '}' @@ -157,6 +157,38 @@ B = ( 'send' | 'receive' | 'bind' | 'eavesdrop' ) (some accesses a B = B (see below for meanings) +B = [ I ] 'unix' [ I ] [ I ] [ I ] [ I ] + +B = [ 'audit' ] [ 'allow' | 'deny' ] + +B = ( I | I ) + +B = ( 'create' | 'bind' | 'listen' | 'accept' | 'connect' | 'shutdown' | 'getattr' | 'setattr' | 'getopt' | 'setopt' | 'send' | 'receive' | 'r' | 'w' | 'rw' ) + (some access modes are incompatible with some rules or require additional parameters) + +B = '(' I ( [','] )* ')' + +B = ( I | I ) + each cond can appear at most once + +B = 'type' '=' ( | '(' ( '"' '"' | )+ ')' ) + +B = 'protocol' '=' ( | '(' ( '"' '"' | )+ ')' ) + +B = ( I | I | I | I )* + each cond can appear at most once + +B = 'peer' '=' ( I | I )+ + each cond can appear at most once + +B 'path' '=' ( | '(' '"' '"' | ')' ) + +B 'label' '=' ( | '(' '"' '"' | ')' ) + +B 'attr' '=' ( | '(' '"' '"' | ')' ) + +B 'opt' '=' ( | '(' '"' '"' | ')' ) + B = I ( '"' I '"' | I ) I ',' B = [ 'audit' ] [ 'deny' ] [ 'owner' ] @@ -851,6 +883,135 @@ Example AppArmor DBus rules: # Allow and audit all eavesdropping audit dbus eavesdrop, +=head2 Unix socket rules + +AppArmor supports fine grained mediation of unix domain abstract and +anonymous sockets. Unix domain sockets with file system paths are +mediated via file access rules. +TODO: do we want to revise this to allow certain permission to be + specified by unix rules that can not be specified via file + paths? + +Abstract unix domain sockets is a nonprotable Linux extension of unix +domain sockets, see man 7 unix for more information. + +=head3 Unix socket paths + +The path component of a unix domain socket is specified by the + path= +conditional. If a path conditional is not specified as part of a rule +then the rule matches both abstract and anonymous sockets. + +In apparmor the path of an abstract unix domain socket begins with the +I<@> character, similar to how they are reported by netstat -x. The name +then follows and may contain pattern matching and any characters including +the null character. In apparmor null characters must be specified by using +an escape sequence I<\000> or I<\x00>. The pattern matching is the same +as is used by path matching so * will not match I even though it +has no special meaning with in an abstract socket name. Eg. + unix path=@*, + +Anonymous unix domain sockets have no path associated with them, however +it can be specified with the special I keyword to indicate the +rule only applies to anonymous unix domain sockets. Eg. + unix path=none, + +If the path component of a rule is not specified then the rule applies +to both abstract and anonymous sockets. + +=head3 Unix socket permissions +Unix domain socket rules are accumulated so that the granted unix +socket permissions are the union of all the listed unix rule permissions. + +Unix domain socket rules are broad and general and become more restrictive +as further information is specified. Policy may be specified down to +the path and label level. The content of the communication is not +examined. + +Unix socket rule permissions are implied when a rule does not explicitly +state an access list. By default if a rule does not have an access list +all permissions that are compatible with the specified set of local +and peer conditionals are implied. + +The create, bind, listen, shutdown, getattr, setattr permissions are +applied to the local socket. The accept, connect, send, receive permissions +apply to the combination of a local and peer. Currently it is required that +create, bind, listen, shutdown, getattr, and settr permission are only +specified in rules that do not have a peer component. +???TODO: Do we really want this???? + +If a rule is specified with a peer component it will not imply the +create, bind, listen, shutdown, getattr, or setattr permissions. + +??? TODO: Describe explicitly labeled sockets ???? !!! + +=head3 Example Unix domain socket rules: + + # Allow all permissions to unix sockets + unix, + + # Explicitly allow all unix permissions + unix (create, listen, accept, connect, send, receive, getattr, setattr, setopt, getopt), + + # Explicitly deny unix socket access ??? should this block unix file as well??? + deny unix, + + + unix type=stream, + + unix type=dgram, + + unix path=none + + unix path=@foo, + + unix type=stream path=@foo, + + unix server path=@foo, + + unix accept path=@foo peer=(label=/bar), + + unix receive path=@foo peer=(label=/bar), + + + unix path=none + + +=head3 Abstract unix domain sockets autobind + +Abstract unix domain sockets can autobind to an address. The autobind +address is a unique 5 digit string of decimal numbers, eg. @00001. There +is nothing that prevents a task from manually binding to addresses with a +similar pattern so it is impossible to reliably identify autobind addresses +from a regular address. + +=head3 Interaction of network rules and fine grained unix domain socket rules + +The coarse grained networking rules can be used to control unix domain +sockets as well. When fine grained unix domain socket mediation is available +the coase grained network rule is mapped into the equivalent unix socket +rule. + +Eg. + network unix, => unix, + + network unix stream, => unix stream, + +Fine grained mediation rules however can not be lossly converted back +to the coarse grained network rule. Eg + + unix bind path=@example, + +Has no exact match under coarse grained network rules, the closest match is +the much wider permission rule of. + network unix, + +TODO: ??? should we make unix rules imply this when fine grained mediation +is not available, or do we fail? Warning to wider is similar to the +current behavior of loading policy which specify rules that can't be +enforced. Hrmmm this behavior really needs to be a config option, to +fail or warn. + =head2 Variables AppArmor's policy language allows embedding variables into file rules diff --git a/parser/network.c b/parser/network.c index 8a1c618f3..7ca47241d 100644 --- a/parser/network.c +++ b/parser/network.c @@ -31,6 +31,11 @@ #include "network.h" +int parse_net_mode(const char *str_mode, int *mode, int fail) +{ + return parse_X_mode("net", AA_VALID_NET_PERMS, str_mode, mode, fail); +} + /* Bleah C++ doesn't have non-trivial designated initializers so we just * have to make sure these are in order. This means we are more brittle * but there isn't much we can do. diff --git a/parser/network.h b/parser/network.h index f45d86fd4..9fc5de207 100644 --- a/parser/network.h +++ b/parser/network.h @@ -33,7 +33,45 @@ #include "parser.h" #include "rule.h" -#include "profile.h" + + +#define AA_NET_WRITE 0x0002 +#define AA_NET_SEND AA_NET_WRITE +#define AA_NET_READ 0x0004 +#define AA_NET_RECEIVE AA_NET_READ + +#define AA_NET_CREATE 0x0010 +#define AA_NET_SHUTDOWN 0x0020 /* alias delete */ +#define AA_NET_CONNECT 0x0040 /* alias open */ + +#define AA_NET_SETATTR 0x0100 +#define AA_NET_GETATTR 0x0200 + +//#define AA_NET_CHMOD 0x1000 /* pair */ +//#define AA_NET_CHOWN 0x2000 /* pair */ +//#define AA_NET_CHGRP 0x4000 /* pair */ +//#define AA_NET_LOCK 0x8000 /* LINK_SUBSET overlaid */ + +#define AA_NET_ACCEPT 0x00100000 +#define AA_NET_BIND 0x00200000 +#define AA_NET_LISTEN 0x00400000 + +#define AA_NET_SETOPT 0x01000000 +#define AA_NET_GETOPT 0x02000000 + +#define AA_CONT_MATCH 0x08000000 + +#define AA_VALID_NET_PERMS (AA_NET_SEND | AA_NET_RECEIVE | AA_NET_CREATE | \ + AA_NET_SHUTDOWN | AA_NET_CONNECT | \ + AA_NET_SETATTR | AA_NET_GETATTR | AA_NET_BIND | \ + AA_NET_ACCEPT | AA_NET_LISTEN | AA_NET_SETOPT | \ + AA_NET_GETOPT | AA_CONT_MATCH) +#define AA_LOCAL_NET_PERMS (AA_NET_CREATE | AA_NET_SHUTDOWN | AA_NET_SETATTR |\ + AA_NET_GETATTR | AA_NET_BIND | AA_NET_ACCEPT | \ + AA_NET_LISTEN | AA_NET_SETOPT | AA_NET_GETOPT) +#define AA_NET_OPT (AA_NET_SETOPT | AA_NET_GETOPT) +#define AA_LOCAL_NET_CMD (AA_NET_ACCEPT | AA_NET_LISTEN | AA_NET_OPT) +#define AA_PEER_NET_PERMS (AA_VALID_NET_PERMS & ~AA_LOCAL_NET_PERMS) struct network_tuple { const char *family_name; @@ -53,6 +91,7 @@ struct aa_network_entry { struct aa_network_entry *next; }; +int parse_net_mode(const char *str_mode, int *mode, int fail); extern struct aa_network_entry *new_network_ent(unsigned int family, unsigned int type, unsigned int protocol); diff --git a/parser/parser.h b/parser/parser.h index c23af44a3..cfeb39f7f 100644 --- a/parser/parser.h +++ b/parser/parser.h @@ -291,6 +291,7 @@ extern int kernel_supports_mount; extern int kernel_supports_dbus; extern int kernel_supports_signal; extern int kernel_supports_ptrace; +extern int kernel_supports_unix; extern int conf_verbose; extern int conf_quiet; extern int names_only; diff --git a/parser/parser_common.c b/parser/parser_common.c index 39677bd5c..517435fc9 100644 --- a/parser/parser_common.c +++ b/parser/parser_common.c @@ -66,6 +66,7 @@ int net_af_max_override = -1; /* use kernel to determine af_max */ int kernel_load = 1; int kernel_supports_setload = 0; /* kernel supports atomic set loads */ int kernel_supports_network = 0; /* kernel supports network rules */ +int kernel_supports_unix = 0; /* kernel supports unix socket rules */ int kernel_supports_policydb = 0; /* kernel supports new policydb */ int kernel_supports_mount = 0; /* kernel supports mount rules */ int kernel_supports_dbus = 0; /* kernel supports dbus rules */ diff --git a/parser/parser_lex.l b/parser/parser_lex.l index 375ab1afe..a6a1e371c 100644 --- a/parser/parser_lex.l +++ b/parser/parser_lex.l @@ -258,6 +258,7 @@ LT_EQUAL <= %x DBUS_MODE %x SIGNAL_MODE %x PTRACE_MODE +%x UNIX_MODE %x CHANGE_PROFILE_MODE %x INCLUDE @@ -272,7 +273,7 @@ LT_EQUAL <= } %} -{ +{ {WS}+ { DUMP_PREPROCESS; /* Ignoring whitespace */ } } @@ -298,7 +299,7 @@ LT_EQUAL <= yyterminate(); } -{ +{ peer/{WS}*={WS}*\( { /* we match to the = in the lexer so that we can switch scanner * state. By the time the parser see the = it may be too late @@ -468,8 +469,23 @@ LT_EQUAL <= {LT_EQUAL} { RETURN_TOKEN(TOK_LE); } } -{ +{ + create { RETURN_TOKEN(TOK_CREATE); } + listen { RETURN_TOKEN(TOK_LISTEN); } + accept { RETURN_TOKEN(TOK_ACCEPT); } + connect { RETURN_TOKEN(TOK_CONNECT); } + getattr { RETURN_TOKEN(TOK_GETATTR); } + setattr { RETURN_TOKEN(TOK_SETATTR); } + getopt { RETURN_TOKEN(TOK_GETOPT); } + setopt { RETURN_TOKEN(TOK_SETOPT); } + shutdown { RETURN_TOKEN(TOK_SHUTDOWN); } +} + +{ bind { RETURN_TOKEN(TOK_BIND); } +} + +{ eavesdrop { RETURN_TOKEN(TOK_EAVESDROP); } } @@ -484,7 +500,7 @@ LT_EQUAL <= tracedby { RETURN_TOKEN(TOK_TRACEDBY); } } -{ +{ read { RETURN_TOKEN(TOK_READ); } write { RETURN_TOKEN(TOK_WRITE); } {OPEN_PAREN} { @@ -500,7 +516,7 @@ LT_EQUAL <= {ARROW} { RETURN_TOKEN(TOK_ARROW); } } -{ +{ ({IDS_NOEQ}|{PATHNAME}|{QUOTED_ID}) { yylval.id = processid(yytext, yyleng); RETURN_TOKEN(TOK_ID); @@ -592,13 +608,17 @@ LT_EQUAL <= break; case TOK_PTRACE: state = PTRACE_MODE; + break; + case TOK_UNIX: + state = UNIX_MODE; + break; default: /* nothing */ break; } PUSH_AND_RETURN(state, token); } -{ +{ {END_OF_RULE} { if (YY_START != INITIAL) POP_NODUMP(); @@ -611,7 +631,7 @@ LT_EQUAL <= } } -{ +{ [^\n] { DUMP_PREPROCESS; /* Something we didn't expect */ @@ -640,6 +660,7 @@ unordered_map state_names = { STATE_TABLE_ENT(DBUS_MODE), STATE_TABLE_ENT(SIGNAL_MODE), STATE_TABLE_ENT(PTRACE_MODE), + STATE_TABLE_ENT(UNIX_MODE), STATE_TABLE_ENT(CHANGE_PROFILE_MODE), STATE_TABLE_ENT(INCLUDE), }; diff --git a/parser/parser_main.c b/parser/parser_main.c index 85ad52bff..882ae4bc6 100644 --- a/parser/parser_main.c +++ b/parser/parser_main.c @@ -686,10 +686,14 @@ static void set_supported_features(void) { kernel_supports_policydb = 1; if (strstr(features_string, "v6")) kernel_abi_version = 6; + if (strstr(features_string, "v7")) + kernel_abi_version = 7; if (strstr(features_string, "set_load")) kernel_supports_setload = 1; if (strstr(features_string, "network")) kernel_supports_network = 1; + if (strstr(features_string, "af_unix")) + kernel_supports_unix = 1; if (strstr(features_string, "mount")) kernel_supports_mount = 1; if (strstr(features_string, "dbus")) diff --git a/parser/parser_misc.c b/parser/parser_misc.c index 0919552a1..ec3c29904 100644 --- a/parser/parser_misc.c +++ b/parser/parser_misc.c @@ -107,6 +107,7 @@ struct keyword_table { static struct keyword_table keyword_table[] = { /* network */ {"network", TOK_NETWORK}, + {"unix", TOK_UNIX}, /* misc keywords */ {"capability", TOK_CAPABILITY}, {"if", TOK_IF}, diff --git a/parser/parser_regex.c b/parser/parser_regex.c index 299dfefb4..b0735bc25 100644 --- a/parser/parser_regex.c +++ b/parser/parser_regex.c @@ -665,14 +665,17 @@ int post_process_policydb_ents(Profile *prof) return TRUE; } -#define MAKE_STR(X) #X -#define CLASS_STR(X) "\\d" MAKE_STR(X) +#define MAKE_STR(A) #A +#define CLASS_STR(X) "\\000\\d" MAKE_STR(X) +#define CLASS_SUB_STR(X, Y) MAKE_STR(X) MAKE_STR(Y) static const char *mediates_file = CLASS_STR(AA_CLASS_FILE); static const char *mediates_mount = CLASS_STR(AA_CLASS_MOUNT); static const char *mediates_dbus = CLASS_STR(AA_CLASS_DBUS); static const char *mediates_signal = CLASS_STR(AA_CLASS_SIGNAL); static const char *mediates_ptrace = CLASS_STR(AA_CLASS_PTRACE); +static const char *mediates_extended_net = CLASS_STR(AA_CLASS_NET); +static const char *mediates_net_unix = CLASS_SUB_STR(AA_CLASS_NET, AF_UNIX); int process_profile_policydb(Profile *prof) { @@ -689,7 +692,7 @@ int process_profile_policydb(Profile *prof) * to be supported */ - /* note: this activates unix domain sockets mediation on connect */ + /* note: this activates fs based unix domain sockets mediation on connect */ if (kernel_abi_version > 5 && !prof->policy.rules->add_rule(mediates_file, 0, AA_MAY_READ, 0, dfaflags)) goto out; @@ -705,6 +708,10 @@ int process_profile_policydb(Profile *prof) if (kernel_supports_ptrace && !prof->policy.rules->add_rule(mediates_ptrace, 0, AA_MAY_READ, 0, dfaflags)) goto out; + if (kernel_supports_unix && + (!prof->policy.rules->add_rule(mediates_extended_net, 0, AA_MAY_READ, 0, dfaflags) || + !prof->policy.rules->add_rule(mediates_net_unix, 0, AA_MAY_READ, 0, dfaflags))) + goto out; if (prof->policy.rules->rule_count > 0) { prof->policy.dfa = prof->policy.rules->create_dfa(&prof->policy.size, dfaflags); diff --git a/parser/parser_yacc.y b/parser/parser_yacc.y index e1626a224..af7e1c83b 100644 --- a/parser/parser_yacc.y +++ b/parser/parser_yacc.y @@ -36,6 +36,7 @@ #include "profile.h" #include "mount.h" #include "dbus.h" +#include "af_unix.h" #include "parser_include.h" #include #include @@ -103,6 +104,16 @@ void add_local_entry(Profile *prof); %token TOK_DEFINED %token TOK_CHANGE_PROFILE %token TOK_NETWORK +%token TOK_UNIX +%token TOK_CREATE +%token TOK_SHUTDOWN +%token TOK_ACCEPT +%token TOK_CONNECT +%token TOK_LISTEN +%token TOK_SETOPT +%token TOK_GETOPT +%token TOK_SETATTR +%token TOK_GETATTR %token TOK_HAT %token TOK_UNSAFE %token TOK_SAFE @@ -173,6 +184,7 @@ void add_local_entry(Profile *prof); #include "dbus.h" #include "signal.h" #include "ptrace.h" + #include "af_unix.h" } %union { @@ -188,6 +200,7 @@ void add_local_entry(Profile *prof); dbus_rule *dbus_entry; signal_rule *signal_entry; ptrace_rule *ptrace_entry; + unix_rule *unix_entry; flagvals flags; int fmode; @@ -259,6 +272,10 @@ void add_local_entry(Profile *prof); %type ptrace_perms %type opt_ptrace_perm %type ptrace_rule +%type net_perm +%type net_perms +%type opt_net_perm +%type unix_rule %type opt_named_transition %type opt_unsafe %type opt_file @@ -641,20 +658,17 @@ rules: rules opt_prefix network_rule yyerror(_("owner prefix not allowed")); if (!$3) yyerror(_("Assert: `network_rule' return invalid protocol.")); - if (!$1->net.allow) { - $1->net.allow = (unsigned int *) calloc(get_af_max(), - sizeof(unsigned int)); - $1->net.audit = (unsigned int *)calloc(get_af_max(), - sizeof(unsigned int)); - $1->net.deny = (unsigned int *)calloc(get_af_max(), - sizeof(unsigned int)); - $1->net.quiet = (unsigned int *)calloc(get_af_max(), - sizeof(unsigned int)); - if (!$1->net.allow || !$1->net.audit || - !$1->net.deny || !$1->net.quiet) - yyerror(_("Memory allocation error.")); - } + if (!$1->alloc_net_table()) + yyerror(_("Memory allocation error.")); list_for_each_safe($3, entry, tmp) { + + /* map to extended mediation if available */ + if (entry->family == AF_UNIX && kernel_supports_unix) { + unix_rule *rule = new unix_rule(entry->type, $2.audit, $2.deny); + if (!rule) + yyerror(_("Memory allocation error.")); + $1->rule_ents.push_back(rule); + } if (entry->type > SOCK_PACKET) { /* setting mask instead of a bit */ if ($2.deny) { @@ -748,6 +762,22 @@ rules: rules opt_prefix ptrace_rule $$ = $1; } +rules: rules opt_prefix unix_rule + { + if ($2.owner) + yyerror(_("owner prefix not allowed on unix rules")); + if ($2.deny && $2.audit) { + $3->deny = 1; + } else if ($2.deny) { + $3->deny = 1; + $3->audit = $3->mode; + } else if ($2.audit) { + $3->audit = $3->mode; + } + $1->rule_ents.push_back($3); + $$ = $1; + } + rules: rules change_profile { PDEBUG("matched: rules change_profile\n"); @@ -1270,6 +1300,84 @@ dbus_rule: TOK_DBUS opt_dbus_perm opt_conds opt_cond_list TOK_END_OF_RULE $$ = ent; } +net_perm: TOK_VALUE + { + if (strcmp($1, "create") == 0) + $$ = AA_NET_CREATE; + else if (strcmp($1, "bind") == 0) + $$ = AA_NET_BIND; + else if (strcmp($1, "listen") == 0) + $$ = AA_NET_LISTEN; + else if (strcmp($1, "accept") == 0) + $$ = AA_NET_ACCEPT; + else if (strcmp($1, "connect") == 0) + $$ = AA_NET_CONNECT; + else if (strcmp($1, "shutdown") == 0) + $$ = AA_NET_SHUTDOWN; + else if (strcmp($1, "getattr") == 0) + $$ = AA_NET_GETATTR; + else if (strcmp($1, "setattr") == 0) + $$ = AA_NET_SETATTR; + else if (strcmp($1, "getopt") == 0) + $$ = AA_NET_GETOPT; + else if (strcmp($1, "setopt") == 0) + $$ = AA_NET_SETOPT; + else if (strcmp($1, "send") == 0 || strcmp($1, "write") == 0) + $$ = AA_NET_SEND; + else if (strcmp($1, "receive") == 0 || strcmp($1, "read") == 0) + $$ = AA_NET_RECEIVE; + else if ($1) { + parse_net_mode($1, &$$, 1); + } else + $$ = 0; + + if ($1) + free($1); + } + | TOK_CREATE { $$ = AA_NET_CREATE; } + | TOK_BIND { $$ = AA_NET_BIND; } + | TOK_LISTEN { $$ = AA_NET_LISTEN; } + | TOK_ACCEPT { $$ = AA_NET_ACCEPT; } + | TOK_CONNECT { $$ = AA_NET_CONNECT; } + | TOK_SHUTDOWN { $$ = AA_NET_SHUTDOWN; } + | TOK_GETATTR { $$ = AA_NET_GETATTR; } + | TOK_SETATTR { $$ = AA_NET_SETATTR; } + | TOK_GETOPT { $$ = AA_NET_GETOPT; } + | TOK_SETOPT { $$ = AA_NET_SETOPT; } + | TOK_SEND { $$ = AA_NET_SEND; } + | TOK_RECEIVE { $$ = AA_NET_RECEIVE; } + | TOK_READ { $$ = AA_NET_RECEIVE; } + | TOK_WRITE { $$ = AA_NET_SEND; } + | TOK_MODE + { + parse_unix_mode($1, &$$, 1); + free($1); + } + +net_perms: { /* nothing */ $$ = 0; } + | net_perms net_perm { $$ = $1 | $2; } + | net_perms TOK_COMMA net_perm { $$ = $1 | $3; } + +opt_net_perm: { /* nothing */ $$ = 0; } + | net_perm { $$ = $1; } + | TOK_OPENPAREN net_perms TOK_CLOSEPAREN { $$ = $2; } + +unix_rule: TOK_UNIX opt_net_perm opt_conds opt_cond_list TOK_END_OF_RULE + { + unix_rule *ent; + + if ($4.name) { + if (strcmp($4.name, "peer") != 0) + yyerror(_("unix rule: invalid conditional group %s=()"), $4.name); + free($4.name); + } + ent = new unix_rule($2, $3, $4.list); + if (!ent) { + yyerror(_("Memory allocation error.")); + } + $$ = ent; + } + signal_perm: TOK_VALUE { if (strcmp($1, "send") == 0 || strcmp($1, "write") == 0) diff --git a/parser/profile.cc b/parser/profile.cc index cb5f09a50..745996794 100644 --- a/parser/profile.cc +++ b/parser/profile.cc @@ -59,6 +59,20 @@ void ProfileList::dump_profile_names(bool children) } } +bool Profile::alloc_net_table() +{ + if (net.allow) + return true; + net.allow = (unsigned int *) calloc(get_af_max(), sizeof(unsigned int)); + net.audit = (unsigned int *) calloc(get_af_max(), sizeof(unsigned int)); + net.deny = (unsigned int *) calloc(get_af_max(), sizeof(unsigned int)); + net.quiet = (unsigned int *) calloc(get_af_max(), sizeof(unsigned int)); + if (!net.allow || !net.audit || !net.deny || !net.quiet) + return false; + + return true; +} + Profile::~Profile() { hat_table.clear(); diff --git a/parser/tst/simple_tests/unix/bad_bind_1.sd b/parser/tst/simple_tests/unix/bad_bind_1.sd new file mode 100644 index 000000000..673766461 --- /dev/null +++ b/parser/tst/simple_tests/unix/bad_bind_1.sd @@ -0,0 +1,8 @@ +# +#=DESCRIPTION unix bind with non-bind member modifier +#=EXRESULT FAIL +# + +profile foo { + unix bind peer=(path=@foo ), +} diff --git a/parser/tst/simple_tests/unix/bad_bind_2.sd b/parser/tst/simple_tests/unix/bad_bind_2.sd new file mode 100644 index 000000000..3286c5ffe --- /dev/null +++ b/parser/tst/simple_tests/unix/bad_bind_2.sd @@ -0,0 +1,8 @@ +# +#=DESCRIPTION dbus bind with non-bind interface modifier +#=EXRESULT FAIL +# + +profile foo { + unix bind label=foo path=@bar, +} diff --git a/parser/tst/simple_tests/unix/bad_modifier_1.sd b/parser/tst/simple_tests/unix/bad_modifier_1.sd new file mode 100644 index 000000000..c585f34d9 --- /dev/null +++ b/parser/tst/simple_tests/unix/bad_modifier_1.sd @@ -0,0 +1,7 @@ +# +#=DESCRIPTION unix entry with a bad modifier +#=EXRESULT FAIL + +profile foo { + unix send type=dgram modifier=foo, +} diff --git a/parser/tst/simple_tests/unix/bad_modifier_2.sd b/parser/tst/simple_tests/unix/bad_modifier_2.sd new file mode 100644 index 000000000..befedf0dd --- /dev/null +++ b/parser/tst/simple_tests/unix/bad_modifier_2.sd @@ -0,0 +1,7 @@ +# +#=DESCRIPTION unix entry with a repeated modifier +#=EXRESULT FAIL + +profile foo { + unix send type=stream type=dgram, +} diff --git a/parser/tst/simple_tests/unix/bad_modifier_3.sd b/parser/tst/simple_tests/unix/bad_modifier_3.sd new file mode 100644 index 000000000..dad8c4ca7 --- /dev/null +++ b/parser/tst/simple_tests/unix/bad_modifier_3.sd @@ -0,0 +1,7 @@ +# +#=DESCRIPTION unix entry with a bad 'in' keyword +#=EXRESULT FAIL + +profile foo { + unix send type in (dgram, stream), +} diff --git a/parser/tst/simple_tests/unix/bad_modifier_4.sd b/parser/tst/simple_tests/unix/bad_modifier_4.sd new file mode 100644 index 000000000..b00cf422a --- /dev/null +++ b/parser/tst/simple_tests/unix/bad_modifier_4.sd @@ -0,0 +1,7 @@ +# +#=DESCRIPTION unix entry with a bad multivalue modifier +#=EXRESULT FAIL + +profile foo { + unix send type=(stream, dgram), +} diff --git a/parser/tst/simple_tests/unix/bad_peer_1.sd b/parser/tst/simple_tests/unix/bad_peer_1.sd new file mode 100644 index 000000000..6e36397e3 --- /dev/null +++ b/parser/tst/simple_tests/unix/bad_peer_1.sd @@ -0,0 +1,9 @@ +# +#=Description unix rule with bad 'peer' +#=EXRESULT FAIL +# + +# path must be none for anonymous or start with @ for abstract +profile foo { + unix send peer(path=wat), +} diff --git a/parser/tst/simple_tests/unix/bad_regex_01.sd b/parser/tst/simple_tests/unix/bad_regex_01.sd new file mode 100644 index 000000000..ed78b45d1 --- /dev/null +++ b/parser/tst/simple_tests/unix/bad_regex_01.sd @@ -0,0 +1,8 @@ +# +#=DESCRIPTION unix rule with a bad path regex expansion +#=EXRESULT FAIL +# + +profile foo { + unix send path=@foo{one,two peer=(label=splat), +} diff --git a/parser/tst/simple_tests/unix/bad_regex_02.sd b/parser/tst/simple_tests/unix/bad_regex_02.sd new file mode 100644 index 000000000..18c847af0 --- /dev/null +++ b/parser/tst/simple_tests/unix/bad_regex_02.sd @@ -0,0 +1,8 @@ +# +#=DESCRIPTION unix rule with a bad expansion +#=EXRESULT FAIL +# + +profile foo { + unix bind path=abcd]efg, +} diff --git a/parser/tst/simple_tests/unix/bad_regex_03.sd b/parser/tst/simple_tests/unix/bad_regex_03.sd new file mode 100644 index 000000000..31c56314b --- /dev/null +++ b/parser/tst/simple_tests/unix/bad_regex_03.sd @@ -0,0 +1,8 @@ +# +#=DESCRIPTION unix rule with a bad peer regex expansion +#=EXRESULT FAIL +# + +profile foo { + dbus send peer=(label=spla{t,r ), +} diff --git a/parser/tst/simple_tests/unix/bad_regex_04.sd b/parser/tst/simple_tests/unix/bad_regex_04.sd new file mode 100644 index 000000000..8a6bb1be0 --- /dev/null +++ b/parser/tst/simple_tests/unix/bad_regex_04.sd @@ -0,0 +1,8 @@ +# +#=DESCRIPTION unix rule with a bad path regex expansion +#=EXRESULT FAIL +# + +profile foo { + unix send path=/some/random/{path peer=(label=splat), +} diff --git a/parser/tst/simple_tests/unix/ok_bind_1.sd b/parser/tst/simple_tests/unix/ok_bind_1.sd new file mode 100644 index 000000000..6b3edd014 --- /dev/null +++ b/parser/tst/simple_tests/unix/ok_bind_1.sd @@ -0,0 +1,7 @@ +# +#=DESCRIPTION simple unix implicit bind acceptance test +#=EXRESULT PASS + +profile a_profile { + unix path=@SomeService, +} diff --git a/parser/tst/simple_tests/unix/ok_msg_1.sd b/parser/tst/simple_tests/unix/ok_msg_1.sd new file mode 100644 index 000000000..b453457c3 --- /dev/null +++ b/parser/tst/simple_tests/unix/ok_msg_1.sd @@ -0,0 +1,7 @@ +# +#=DESCRIPTION simple unix send test +#=EXRESULT PASS + +profile a_profile { + unix (send), +} diff --git a/parser/tst/simple_tests/unix/ok_msg_10.sd b/parser/tst/simple_tests/unix/ok_msg_10.sd new file mode 100644 index 000000000..8cf60a3fe --- /dev/null +++ b/parser/tst/simple_tests/unix/ok_msg_10.sd @@ -0,0 +1,7 @@ +# +#=DESCRIPTION simple unix msg test +#=EXRESULT PASS + +profile a_profile { + unix (send) peer=(label=foo), +} diff --git a/parser/tst/simple_tests/unix/ok_msg_2.sd b/parser/tst/simple_tests/unix/ok_msg_2.sd new file mode 100644 index 000000000..835fcd8a5 --- /dev/null +++ b/parser/tst/simple_tests/unix/ok_msg_2.sd @@ -0,0 +1,7 @@ +# +#=DESCRIPTION simple unix msg test +#=EXRESULT PASS + +profile a_profile { + unix (receive), +} diff --git a/parser/tst/simple_tests/unix/ok_msg_3.sd b/parser/tst/simple_tests/unix/ok_msg_3.sd new file mode 100644 index 000000000..ed1b0f2f2 --- /dev/null +++ b/parser/tst/simple_tests/unix/ok_msg_3.sd @@ -0,0 +1,7 @@ +# +#=DESCRIPTION simple unix msg test +#=EXRESULT PASS + +profile a_profile { + unix (connect), +} diff --git a/parser/tst/simple_tests/unix/ok_msg_4.sd b/parser/tst/simple_tests/unix/ok_msg_4.sd new file mode 100644 index 000000000..565d9698a --- /dev/null +++ b/parser/tst/simple_tests/unix/ok_msg_4.sd @@ -0,0 +1,7 @@ +# +#=DESCRIPTION simple unix msg test +#=EXRESULT PASS + +profile a_profile { + unix (send), +} diff --git a/parser/tst/simple_tests/unix/ok_msg_5.sd b/parser/tst/simple_tests/unix/ok_msg_5.sd new file mode 100644 index 000000000..a7547aa4a --- /dev/null +++ b/parser/tst/simple_tests/unix/ok_msg_5.sd @@ -0,0 +1,7 @@ +# +#=DESCRIPTION simple unix msg test +#=EXRESULT PASS + +profile a_profile { + unix (send, receive), +} diff --git a/parser/tst/simple_tests/unix/ok_msg_6.sd b/parser/tst/simple_tests/unix/ok_msg_6.sd new file mode 100644 index 000000000..94176a797 --- /dev/null +++ b/parser/tst/simple_tests/unix/ok_msg_6.sd @@ -0,0 +1,7 @@ +# +#=DESCRIPTION simple unix msg test +#=EXRESULT PASS + +profile a_profile { + unix (send, receive, connect), +} diff --git a/parser/tst/simple_tests/unix/ok_msg_7.sd b/parser/tst/simple_tests/unix/ok_msg_7.sd new file mode 100644 index 000000000..809451ae5 --- /dev/null +++ b/parser/tst/simple_tests/unix/ok_msg_7.sd @@ -0,0 +1,7 @@ +# +#=DESCRIPTION simple unix msg test +#=EXRESULT PASS + +profile a_profile { + unix (send) path=none, +} diff --git a/parser/tst/simple_tests/unix/ok_msg_8.sd b/parser/tst/simple_tests/unix/ok_msg_8.sd new file mode 100644 index 000000000..e0bc126cf --- /dev/null +++ b/parser/tst/simple_tests/unix/ok_msg_8.sd @@ -0,0 +1,7 @@ +# +#=DESCRIPTION simple unix msg test +#=EXRESULT PASS + +profile a_profile { + unix (send) path=@foo, +} diff --git a/parser/tst/simple_tests/unix/ok_msg_9.sd b/parser/tst/simple_tests/unix/ok_msg_9.sd new file mode 100644 index 000000000..265c7a10f --- /dev/null +++ b/parser/tst/simple_tests/unix/ok_msg_9.sd @@ -0,0 +1,7 @@ +# +#=DESCRIPTION simple unix msg test +#=EXRESULT PASS + +profile a_profile { + unix (send) peer=(path=@foo), +}