parser: add the ability to specify a priority prefix to rules

This enables adding a priority to a rules in policy, finishing out the
priority work done to plumb priority support through the internals in
the previous patch.

Rules have a default priority of 0. The priority prefix can be added
before the other currently support rule prefixes, ie.

  [priority prefix][audit qualifier][rule mode][owner]

If present a numerical priority can be assigned to the rule, where the
greater the number the higher the priority. Eg.

    priority=1 audit file r /etc/passwd,

    priority=-1 deny file w /etc/**,

Rule priority allows the rule with the highest priority to completely
override lower priority rules where they overlap. Within a given
priority level rules will accumulate in standard apparmor fashion.

    Eg. given
        priority=1 w   /*c,
        priority=0 r   /a*,
        priority=-1 k  /*b*,

    /abc, /bc, /ac   .. will have permissions of w
    /ab, /abb, /aaa, .. will have permissions of r
    /b, /bcb, /bab,  .. will have permissions of k

User specified rule priorities are currently capped at the arbitrary
values of 1000, and -1000.

Notes:
* not all rule types support the priority prefix. Rukes like
  - network
  - capability
  - rlimits need to be reworked
  need to be reworked to properly preserve the policy rule structure.
* this patch does not support priority on rule blocks
* this patch does not support using a variable in the priority value.

Signed-off-by: John Johansen <john.johansen@canonical.com>
This commit is contained in:
John Johansen 2024-05-11 23:33:42 -07:00
parent 61b7568e19
commit e3fca60d11
89 changed files with 1267 additions and 285 deletions

View file

@ -203,7 +203,7 @@ void unix_rule::downgrade_rule(Profile &prof) {
prof.net.audit[AF_UNIX] |= mask;
const char *error;
network_rule *netv8 = new network_rule(perms, AF_UNIX, sock_type_n);
if(!netv8->add_prefix({audit, rule_mode, owner}, error))
if(!netv8->add_prefix({0, audit, rule_mode, owner}, error))
yyerror(error);
prof.rule_ents.push_back(netv8);
} else {

View file

@ -48,6 +48,9 @@ public:
};
virtual bool valid_prefix(const prefixes &p, const char *&error) {
// priority is partially supported for unix rules
// rules that get downgraded to just network socket
// won't support them but the fine grained do.
if (p.owner) {
error = "owner prefix not allowed on unix rules";
return false;

View file

@ -32,6 +32,10 @@ public:
all_rule(void): prefix_rule_t(RULE_TYPE_ALL) { }
virtual bool valid_prefix(const prefixes &p, const char *&error) {
if (p.priority != 0) {
error = _("priority prefix not allowed on all rules");
return false;
}
if (p.owner) {
error = _("owner prefix not allowed on all rules");
return false;

View file

@ -139,9 +139,11 @@ B<HATNAME> = (must start with alphanumeric character. See aa_change_hat(2) for a
B<QUALIFIER BLOCK> = I<QUALIFIERS> I<BLOCK>
B<INTEGER> = (+ | -)? [[:digit:]]+
B<ACCESS TYPE> = ( 'allow' | 'deny' )
B<QUALIFIERS> = [ 'audit' ] [ I<ACCESS TYPE> ]
B<QUALIFIERS> = [ 'priority' '=' <INTEGER> ] [ 'audit' ] [ I<ACCESS TYPE> ]
B<CAPABILITY RULE> = [ I<QUALIFIERS> ] 'capability' [ I<CAPABILITY LIST> ]
@ -1878,6 +1880,17 @@ Rule qualifiers can modify the rule and/or permissions within the rule.
=over 4
=item B<priority>
Specifies the priority of the rule. Currently the allowed range is
-1000 to 1000 with the default priority of rule is 0. Rules with
higher priority are given preferences and will completely override
permissions of lower priority rules where they overlap. When rules
partially overlap the permissions of the higher priority rule will
completely override lower priority rules within in overlap. Within a
given priority level rules that overlap will accumulate permissions in
the standard apparmor fashion.
=item B<allow>
Specifies that permissions requests that match the rule are allowed. This

View file

@ -194,7 +194,12 @@ public:
bool parse_address(ip_conds &entry);
bool parse_port(ip_conds &entry);
// update TODO: in equality.sh when priority is a valid prefix
virtual bool valid_prefix(const prefixes &p, const char *&error) {
if (p.priority != 0) {
error = _("priority prefix not allowed on network rules");
return false;
}
if (p.owner) {
error = _("owner prefix not allowed on network rules");
return false;

View file

@ -53,6 +53,12 @@ using namespace std;
*/
extern int parser_token;
/* Arbitrary max and minimum priority that userspace can specify, internally
* we handle up to INT_MAX and INT_MIN. Do not ever allow INT_MAX, see
* note on mediates_priority
*/
#define MAX_PRIORITY 1000
#define MIN_PRIORITY -1000
#define WARN_RULE_NOT_ENFORCED 0x1
#define WARN_RULE_DOWNGRADED 0x2

View file

@ -277,6 +277,7 @@ QUOTED_ID \"{ALLOWED_QUOTED_ID}*\"
IP {NUMBER}\.{NUMBER}\.{NUMBER}\.{NUMBER}
INTEGER [+-]?{NUMBER}
HAT hat{WS}*
PROFILE profile{WS}*
KEYWORD [[:alpha:]_]+
@ -332,7 +333,7 @@ GT >
%x USERNS_MODE
%x MQUEUE_MODE
%x IOURING_MODE
%x INTEGER_MODE
%%
%{
@ -344,7 +345,7 @@ GT >
}
%}
<INITIAL,SUB_ID_WS,INCLUDE,INCLUDE_EXISTS,LIST_VAL_MODE,EXTCOND_MODE,LIST_COND_VAL,LIST_COND_PAREN_VAL,LIST_COND_MODE,EXTCONDLIST_MODE,ASSIGN_MODE,NETWORK_MODE,CHANGE_PROFILE_MODE,RLIMIT_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,ABI_MODE,USERNS_MODE,MQUEUE_MODE,IOURING_MODE>{
<INITIAL,SUB_ID_WS,INCLUDE,INCLUDE_EXISTS,LIST_VAL_MODE,EXTCOND_MODE,LIST_COND_VAL,LIST_COND_PAREN_VAL,LIST_COND_MODE,EXTCONDLIST_MODE,ASSIGN_MODE,NETWORK_MODE,CHANGE_PROFILE_MODE,RLIMIT_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,ABI_MODE,USERNS_MODE,MQUEUE_MODE,IOURING_MODE,INTEGER_MODE>{
{WS}+ { DUMP_PREPROCESS; /* Ignoring whitespace */ }
}
@ -389,6 +390,11 @@ GT >
yylval.id = processid(yytext, yyleng);
PUSH_AND_RETURN(EXTCONDLIST_MODE, TOK_CONDLISTID);
}
priority/{WS}*= {
/* has to be before {VARIABLE_NAME} matches below */
PUSH_AND_RETURN(INTEGER_MODE, TOK_PRIORITY);
}
{VARIABLE_NAME}/{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
@ -630,6 +636,15 @@ GT >
}
}
<INTEGER_MODE>{
{EQUALS} { RETURN_TOKEN(TOK_EQUALS); }
{INTEGER} {
yylval.mode = strdup(yytext);
POP_AND_RETURN(TOK_VALUE);
}
}
#include{WS}+if{WS}+exists/{WS}.*\r?\n {
/* Don't use PUSH() macro here as we don't want #include echoed out.
* It needs to be handled specially
@ -814,4 +829,5 @@ unordered_map<int, string> state_names = {
STATE_TABLE_ENT(USERNS_MODE),
STATE_TABLE_ENT(MQUEUE_MODE),
STATE_TABLE_ENT(IOURING_MODE),
STATE_TABLE_ENT(INTEGER_MODE),
};

View file

@ -131,7 +131,7 @@ static struct keyword_table keyword_table[] = {
{"override_creds", TOK_OVERRIDE_CREDS},
{"sqpoll", TOK_SQPOLL},
{"all", TOK_ALL},
{"priority", TOK_PRIORITY},
/* terminate */
{NULL, 0}
};

View file

@ -19,6 +19,7 @@
*/
#define YYERROR_VERBOSE 1
#include <limits.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
@ -149,6 +150,7 @@ static void abi_features(char *filename, bool search);
%token TOK_OVERRIDE_CREDS
%token TOK_SQPOLL
%token TOK_ALL
%token TOK_PRIORITY
/* rlimits */
%token TOK_RLIMIT
@ -269,6 +271,7 @@ static void abi_features(char *filename, bool search);
%type <id> id_or_var
%type <id> opt_id_or_var
%type <boolean> opt_subset_flag
%type <integer> opt_priority
%type <audit> opt_audit_flag
%type <owner> opt_owner_flag
%type <integer> opt_profile_flag
@ -627,6 +630,23 @@ opt_subset_flag: { /* nothing */ $$ = false; }
| TOK_SUBSET { $$ = true; }
| TOK_LE { $$ = true; }
opt_priority: { $$ = 0; }
| TOK_PRIORITY TOK_EQUALS TOK_VALUE
{
char *end;
long tmp = strtol($3, &end, 10);
if (end == $3 || *end != '\0')
yyerror("invalid priority %s", $3);
free($3);
/* see note on mediates_priority */
if (tmp > MAX_PRIORITY)
yyerror("invalid priority %l > %d", tmp, MAX_PRIORITY);
if (tmp < MIN_PRIORITY)
yyerror("invalid priority %l > %d", tmp, MIN_PRIORITY);
$$ = tmp;
}
opt_audit_flag: { /* nothing */ $$ = AUDIT_UNSPECIFIED; }
| TOK_AUDIT { $$ = AUDIT_FORCE; };
@ -639,11 +659,12 @@ opt_rule_mode: { /* nothing */ $$ = RULE_UNSPECIFIED; }
| TOK_DENY { $$ = RULE_DENY; }
| TOK_PROMPT { $$ = RULE_PROMPT; }
opt_prefix: opt_audit_flag opt_rule_mode opt_owner_flag
opt_prefix: opt_priority opt_audit_flag opt_rule_mode opt_owner_flag
{
$$.audit = $1;
$$.rule_mode = $2;
$$.owner = $3;
$$.priority = $1;
$$.audit = $2;
$$.rule_mode = $3;
$$.owner = $4;
}
rules: { /* nothing */
@ -680,6 +701,9 @@ rules: rules opt_prefix block
{
struct cod_entry *entry, *tmp;
if (($2).priority != 0) {
yyerror(_("priority is not allowed on rule blocks"));
}
PDEBUG("matched: %s%s%sblock\n",
$2.audit == AUDIT_FORCE ? "audit " : "",
$2.rule_mode == RULE_DENY ? "deny " : "",

View file

@ -82,11 +82,10 @@ class rule_t {
public:
int rule_type;
rule_flags_t flags;
int priority;
rule_t *removed_by;
rule_t(int t): rule_type(t), flags(RULE_FLAG_NONE), priority(0), removed_by(NULL) { }
rule_t(int t): rule_type(t), flags(RULE_FLAG_NONE), removed_by(NULL) { }
virtual ~rule_t() { };
bool is_type(int type) { return rule_type == type; }
@ -114,9 +113,6 @@ public:
virtual int expand_variables(void) = 0;
virtual int cmp(rule_t const &rhs) const {
int tmp = priority - rhs.priority;
if (tmp != 0)
return tmp;
return rule_type - rhs.rule_type;
}
virtual bool operator<(rule_t const &rhs) const {
@ -177,6 +173,7 @@ typedef enum { OWNER_UNSPECIFIED, OWNER_SPECIFIED, OWNER_NOT } owner_t;
*/
class prefixes {
public:
int priority;
audit_t audit;
rule_mode_t rule_mode;
owner_t owner;
@ -246,7 +243,10 @@ public:
}
int cmp(prefixes const &rhs) const {
int tmp = (int) audit - (int) rhs.audit;
int tmp = priority - rhs.priority;
if (tmp != 0)
return tmp;
tmp = (int) audit - (int) rhs.audit;
if (tmp != 0)
return tmp;
tmp = (int) rule_mode - (int) rhs.rule_mode;
@ -271,6 +271,7 @@ public:
prefix_rule_t(int t = RULE_TYPE_PREFIX) : rule_t(t)
{
/* Must construct prefix here see note on prefixes */
priority = 0;
audit = AUDIT_UNSPECIFIED;
rule_mode = RULE_UNSPECIFIED;
owner = OWNER_UNSPECIFIED;
@ -281,6 +282,19 @@ public:
virtual bool add_prefix(const prefixes &p, const char *&error) {
if (!valid_prefix(p, error))
return false;
// priority does NOT conflict but allowed at the block
// level yet. priority at the block level applies to
// the entire block, but only for the level of rules
// it is at.
// priority within the block arranges order of rules
// within the block.
if (priority != 0) {
error = "priority levels not supported";
return false;
}
priority = p.priority;
/* audit conflicts */
if (p.audit != AUDIT_UNSPECIFIED) {
if (audit != AUDIT_UNSPECIFIED &&

View file

@ -122,169 +122,175 @@ verify_binary_inequality()
verify_binary "inequality" "$@"
}
printf "Equality Tests:\n"
verify_binary_equality "dbus send" \
"/t { dbus send, }" \
"/t { dbus write, }" \
"/t { dbus w, }"
##########################################################################
### wrapper fn, should be indented but isn't to reduce wrap
verify_set()
{
local p1="$1"
local p2="$2"
echo -e "\n equality $e of '$p1' vs '$p2'\n"
verify_binary_equality "dbus receive" \
"/t { dbus receive, }" \
"/t { dbus read, }" \
"/t { dbus r, }"
verify_binary_equality "'$p1'x'$p2' dbus send" \
"/t { $p1 dbus send, }" \
"/t { $p2 dbus write, }" \
"/t { $p2 dbus w, }"
verify_binary_equality "dbus send + receive" \
"/t { dbus (send, receive), }" \
"/t { dbus (read, write), }" \
"/t { dbus (r, w), }" \
"/t { dbus (rw), }" \
"/t { dbus rw, }" \
verify_binary_equality "'$p1'x'$p2' dbus receive" \
"/t { $p1 dbus receive, }" \
"/t { $p2 dbus read, }" \
"/t { $p2 dbus r, }"
verify_binary_equality "dbus all accesses" \
"/t { dbus (send, receive, bind, eavesdrop), }" \
"/t { dbus (read, write, bind, eavesdrop), }" \
"/t { dbus (r, w, bind, eavesdrop), }" \
"/t { dbus (rw, bind, eavesdrop), }" \
"/t { dbus (), }" \
"/t { dbus, }" \
verify_binary_equality "'$p1'x'$p2' dbus send + receive" \
"/t { $p1 dbus (send, receive), }" \
"/t { $p2 dbus (read, write), }" \
"/t { $p2 dbus (r, w), }" \
"/t { $p2 dbus (rw), }" \
"/t { $p2 dbus rw, }" \
verify_binary_equality "dbus implied accesses with a bus conditional" \
"/t { dbus (send, receive, bind, eavesdrop) bus=session, }" \
"/t { dbus (read, write, bind, eavesdrop) bus=session, }" \
"/t { dbus (r, w, bind, eavesdrop) bus=session, }" \
"/t { dbus (rw, bind, eavesdrop) bus=session, }" \
"/t { dbus () bus=session, }" \
"/t { dbus bus=session, }" \
verify_binary_equality "'$p1'x'$p2' dbus all accesses" \
"/t { $p1 dbus (send, receive, bind, eavesdrop), }" \
"/t { $p2 dbus (read, write, bind, eavesdrop), }" \
"/t { $p2 dbus (r, w, bind, eavesdrop), }" \
"/t { $p2 dbus (rw, bind, eavesdrop), }" \
"/t { $p2 dbus (), }" \
"/t { $p2 dbus, }" \
verify_binary_equality "dbus implied accesses for services" \
"/t { dbus bind name=com.foo, }" \
"/t { dbus name=com.foo, }"
verify_binary_equality "'$p1'x'$p2' dbus implied accesses with a bus conditional" \
"/t { $p1 dbus (send, receive, bind, eavesdrop) bus=session, }" \
"/t { $p2 dbus (read, write, bind, eavesdrop) bus=session, }" \
"/t { $p2 dbus (r, w, bind, eavesdrop) bus=session, }" \
"/t { $p2 dbus (rw, bind, eavesdrop) bus=session, }" \
"/t { $p2 dbus () bus=session, }" \
"/t { $p2 dbus bus=session, }" \
verify_binary_equality "dbus implied accesses for messages" \
"/t { dbus (send, receive) path=/com/foo interface=org.foo, }" \
"/t { dbus path=/com/foo interface=org.foo, }"
verify_binary_equality "'$p1'x'$p2' dbus implied accesses for services" \
"/t { $p1 dbus bind name=com.foo, }" \
"/t { $p2 dbus name=com.foo, }"
verify_binary_equality "dbus implied accesses for messages with peer names" \
"/t { dbus (send, receive) path=/com/foo interface=org.foo peer=(name=com.foo), }" \
"/t { dbus path=/com/foo interface=org.foo peer=(name=com.foo), }" \
"/t { dbus (send, receive) path=/com/foo interface=org.foo peer=(name=(com.foo)), }" \
"/t { dbus path=/com/foo interface=org.foo peer=(name=(com.foo)), }"
verify_binary_equality "'$p1'x'$p2' dbus implied accesses for messages" \
"/t { $p1 dbus (send, receive) path=/com/foo interface=org.foo, }" \
"/t { $p2 dbus path=/com/foo interface=org.foo, }"
verify_binary_equality "dbus implied accesses for messages with peer labels" \
"/t { dbus (send, receive) path=/com/foo interface=org.foo peer=(label=/usr/bin/app), }" \
"/t { dbus path=/com/foo interface=org.foo peer=(label=/usr/bin/app), }"
verify_binary_equality "'$p1'x'$p2' dbus implied accesses for messages with peer names" \
"/t { $p1 dbus (send, receive) path=/com/foo interface=org.foo peer=(name=com.foo), }" \
"/t { $p2 dbus path=/com/foo interface=org.foo peer=(name=com.foo), }" \
"/t { $p2 dbus (send, receive) path=/com/foo interface=org.foo peer=(name=(com.foo)), }" \
"/t { $p2 dbus path=/com/foo interface=org.foo peer=(name=(com.foo)), }"
verify_binary_equality "dbus element parsing" \
"/t { dbus bus=b path=/ interface=i member=m peer=(name=n label=l), }" \
"/t { dbus bus=\"b\" path=\"/\" interface=\"i\" member=\"m\" peer=(name=\"n\" label=\"l\"), }" \
"/t { dbus bus=(b) path=(/) interface=(i) member=(m) peer=(name=(n) label=(l)), }" \
"/t { dbus bus=(\"b\") path=(\"/\") interface=(\"i\") member=(\"m\") peer=(name=(\"n\") label=(\"l\")), }" \
"/t { dbus bus =b path =/ interface =i member =m peer =(name =n label =l), }" \
"/t { dbus bus= b path= / interface= i member= m peer= (name= n label= l), }" \
"/t { dbus bus = b path = / interface = i member = m peer = ( name = n label = l ), }"
verify_binary_equality "'$p1'x'$p2' dbus implied accesses for messages with peer labels" \
"/t { $p1 dbus (send, receive) path=/com/foo interface=org.foo peer=(label=/usr/bin/app), }" \
"/t { $p2 dbus path=/com/foo interface=org.foo peer=(label=/usr/bin/app), }"
verify_binary_equality "dbus access parsing" \
"/t { dbus, }" \
"/t { dbus (), }" \
"/t { dbus (send, receive, bind, eavesdrop), }" \
"/t { dbus (send receive bind eavesdrop), }" \
"/t { dbus (send, receive bind, eavesdrop), }" \
"/t { dbus (send,receive,bind,eavesdrop), }" \
"/t { dbus (send,receive,,,,,,,,,,,,,,,,bind,eavesdrop), }" \
"/t { dbus (send,send,send,send send receive,bind eavesdrop), }" \
verify_binary_equality "'$p1'x'$p2' dbus element parsing" \
"/t { $p1 dbus bus=b path=/ interface=i member=m peer=(name=n label=l), }" \
"/t { $p2 dbus bus=\"b\" path=\"/\" interface=\"i\" member=\"m\" peer=(name=\"n\" label=\"l\"), }" \
"/t { $p2 dbus bus=(b) path=(/) interface=(i) member=(m) peer=(name=(n) label=(l)), }" \
"/t { $p2 dbus bus=(\"b\") path=(\"/\") interface=(\"i\") member=(\"m\") peer=(name=(\"n\") label=(\"l\")), }" \
"/t { $p2 dbus bus =b path =/ interface =i member =m peer =(name =n label =l), }" \
"/t { $p2 dbus bus= b path= / interface= i member= m peer= (name= n label= l), }" \
"/t { $p2 dbus bus = b path = / interface = i member = m peer = ( name = n label = l ), }"
verify_binary_equality "dbus variable expansion" \
"/t { dbus (send, receive) path=/com/foo member=spork interface=org.foo peer=(name=com.foo label=/com/foo), }" \
verify_binary_equality "'$p1'x'$p2' dbus access parsing" \
"/t { $p1 dbus, }" \
"/t { $p2 dbus (), }" \
"/t { $p2 dbus (send, receive, bind, eavesdrop), }" \
"/t { $p2 dbus (send receive bind eavesdrop), }" \
"/t { $p2 dbus (send, receive bind, eavesdrop), }" \
"/t { $p2 dbus (send,receive,bind,eavesdrop), }" \
"/t { $p2 dbus (send,receive,,,,,,,,,,,,,,,,bind,eavesdrop), }" \
"/t { $p2 dbus (send,send,send,send send receive,bind eavesdrop), }" \
verify_binary_equality "'$p1'x'$p2' dbus variable expansion" \
"/t { $p1 dbus (send, receive) path=/com/foo member=spork interface=org.foo peer=(name=com.foo label=/com/foo), }" \
"@{FOO}=foo
/t { dbus (send, receive) path=/com/@{FOO} member=spork interface=org.@{FOO} peer=(name=com.@{FOO} label=/com/@{FOO}), }" \
/t { $p2 dbus (send, receive) path=/com/@{FOO} member=spork interface=org.@{FOO} peer=(name=com.@{FOO} label=/com/@{FOO}), }" \
"@{FOO}=foo
@{SPORK}=spork
/t { dbus (send, receive) path=/com/@{FOO} member=@{SPORK} interface=org.@{FOO} peer=(name=com.@{FOO} label=/com/@{FOO}), }" \
/t { $p2 dbus (send, receive) path=/com/@{FOO} member=@{SPORK} interface=org.@{FOO} peer=(name=com.@{FOO} label=/com/@{FOO}), }" \
"@{FOO}=/com/foo
/t { dbus (send, receive) path=@{FOO} member=spork interface=org.foo peer=(name=com.foo label=@{FOO}), }" \
/t { $p2 dbus (send, receive) path=@{FOO} member=spork interface=org.foo peer=(name=com.foo label=@{FOO}), }" \
"@{FOO}=com
/t { dbus (send, receive) path=/@{FOO}/foo member=spork interface=org.foo peer=(name=@{FOO}.foo label=/@{FOO}/foo), }"
/t { $p2 dbus (send, receive) path=/@{FOO}/foo member=spork interface=org.foo peer=(name=@{FOO}.foo label=/@{FOO}/foo), }"
verify_binary_equality "dbus variable expansion, multiple values/rules" \
"/t { dbus (send, receive) path=/com/foo, dbus (send, receive) path=/com/bar, }" \
"/t { dbus (send, receive) path=/com/{foo,bar}, }" \
"/t { dbus (send, receive) path={/com/foo,/com/bar}, }" \
verify_binary_equality "'$p1'x'$p2' dbus variable expansion, multiple values/rules" \
"/t { $p1 dbus (send, receive) path=/com/foo, $p1 dbus (send, receive) path=/com/bar, }" \
"/t { $p2 dbus (send, receive) path=/com/{foo,bar}, }" \
"/t { $p2 dbus (send, receive) path={/com/foo,/com/bar}, }" \
"@{FOO}=foo
/t { dbus (send, receive) path=/com/@{FOO}, dbus (send, receive) path=/com/bar, }" \
/t { $p2 dbus (send, receive) path=/com/@{FOO}, $p2 dbus (send, receive) path=/com/bar, }" \
"@{FOO}=foo bar
/t { dbus (send, receive) path=/com/@{FOO}, }" \
/t { $p2 dbus (send, receive) path=/com/@{FOO}, }" \
"@{FOO}=bar foo
/t { dbus (send, receive) path=/com/@{FOO}, }" \
/t { $p2 dbus (send, receive) path=/com/@{FOO}, }" \
"@{FOO}={bar,foo}
/t { dbus (send, receive) path=/com/@{FOO}, }" \
/t { $p2 dbus (send, receive) path=/com/@{FOO}, }" \
"@{FOO}=foo
@{BAR}=bar
/t { dbus (send, receive) path=/com/{@{FOO},@{BAR}}, }" \
/t { $p2 dbus (send, receive) path=/com/{@{FOO},@{BAR}}, }" \
verify_binary_equality "dbus variable expansion, ensure rule de-duping occurs" \
"/t { dbus (send, receive) path=/com/foo, dbus (send, receive) path=/com/bar, }" \
"/t { dbus (send, receive) path=/com/foo, dbus (send, receive) path=/com/bar, dbus (send, receive) path=/com/bar, }" \
verify_binary_equality "'$p1'x'$p2' dbus variable expansion, ensure rule de-duping occurs" \
"/t { $p1 dbus (send, receive) path=/com/foo, $p1 dbus (send, receive) path=/com/bar, }" \
"/t { $p2 dbus (send, receive) path=/com/foo, $p2 dbus (send, receive) path=/com/bar, dbus (send, receive) path=/com/bar, }" \
"@{FOO}=bar foo bar foo
/t { dbus (send, receive) path=/com/@{FOO}, }" \
/t { $p2 dbus (send, receive) path=/com/@{FOO}, }" \
"@{FOO}=bar foo bar foo
/t { dbus (send, receive) path=/com/@{FOO}, dbus (send, receive) path=/com/@{FOO}, }"
/t { $p2 dbus (send, receive) path=/com/@{FOO}, $p2 dbus (send, receive) path=/com/@{FOO}, }"
verify_binary_equality "dbus minimization with all perms" \
"/t { dbus, }" \
"/t { dbus bus=session, dbus, }" \
"/t { dbus (send, receive, bind, eavesdrop), dbus, }"
verify_binary_equality "'$p1'x'$p2' dbus minimization with all perms" \
"/t { $p1 dbus, }" \
"/t { $p2 dbus bus=session, $p2 dbus, }" \
"/t { $p2 dbus (send, receive, bind, eavesdrop), $p2 dbus, }"
verify_binary_equality "dbus minimization with bind" \
"/t { dbus bind, }" \
"/t { dbus bind bus=session, dbus bind, }" \
"/t { dbus bind bus=system name=com.foo, dbus bind, }"
verify_binary_equality "'$p1'x'$p2' dbus minimization with bind" \
"/t { $p1 dbus bind, }" \
"/t { $p2 dbus bind bus=session, $p2 dbus bind, }" \
"/t { $p2 dbus bind bus=system name=com.foo, $p2 dbus bind, }"
verify_binary_equality "dbus minimization with send and a bus conditional" \
"/t { dbus send bus=system, }" \
"/t { dbus send bus=system path=/com/foo interface=com.foo member=bar, dbus send bus=system, }" \
"/t { dbus send bus=system peer=(label=/usr/bin/foo), dbus send bus=system, }"
verify_binary_equality "'$p1'x'$p2' dbus minimization with send and a bus conditional" \
"/t { $p1 dbus send bus=system, }" \
"/t { $p2 dbus send bus=system path=/com/foo interface=com.foo member=bar, dbus send bus=system, }" \
"/t { $p2 dbus send bus=system peer=(label=/usr/bin/foo), $p2 dbus send bus=system, }"
verify_binary_equality "dbus minimization with an audit modifier" \
"/t { audit dbus eavesdrop, }" \
"/t { audit dbus eavesdrop bus=session, audit dbus eavesdrop, }"
verify_binary_equality "'$p1'x'$p2' dbus minimization with an audit modifier" \
"/t { $p1 audit dbus eavesdrop, }" \
"/t { $p2 audit dbus eavesdrop bus=session, $p2 audit dbus eavesdrop, }"
verify_binary_equality "dbus minimization with a deny modifier" \
"/t { deny dbus send bus=system peer=(name=com.foo), }" \
"/t { deny dbus send bus=system peer=(name=com.foo label=/usr/bin/foo), deny dbus send bus=system peer=(name=com.foo), }" \
verify_binary_equality "'$p1'x'$p2' dbus minimization with a deny modifier" \
"/t { $p1 deny dbus send bus=system peer=(name=com.foo), }" \
"/t { $p2 deny dbus send bus=system peer=(name=com.foo label=/usr/bin/foo), $p2 deny dbus send bus=system peer=(name=com.foo), }" \
verify_binary_equality "dbus minimization found in dbus abstractions" \
"/t { dbus send bus=session, }" \
"/t { dbus send
verify_binary_equality "'$p1'x'$p2' dbus minimization found in dbus abstractions" \
"/t { $p1 dbus send bus=session, }" \
"/t { $p2 dbus send
bus=session
path=/org/freedesktop/DBus
interface=org.freedesktop.DBus
member={Hello,AddMatch,RemoveMatch,GetNameOwner,NameHasOwner,StartServiceByName}
peer=(name=org.freedesktop.DBus),
dbus send bus=session, }"
$p2 dbus send bus=session, }"
# verify slash filtering for dbus paths.
verify_binary_equality "dbus slash filtering for paths" \
"/t { dbus (send, receive) path=/com/foo, dbus (send, receive) path=/com/bar, }" \
"/t { dbus (send, receive) path=/com///foo, dbus (send, receive) path=///com/bar, }" \
"/t { dbus (send, receive) path=/com//{foo,bar}, }" \
"/t { dbus (send, receive) path={//com/foo,/com//bar}, }" \
verify_binary_equality "'$p1'x'$p2' dbus slash filtering for paths" \
"/t { $p1 dbus (send, receive) path=/com/foo, $p1 dbus (send, receive) path=/com/bar, }" \
"/t { $p2 dbus (send, receive) path=/com///foo, $p2 dbus (send, receive) path=///com/bar, }" \
"/t { $p2 dbus (send, receive) path=/com//{foo,bar}, }" \
"/t { $p2 dbus (send, receive) path={//com/foo,/com//bar}, }" \
"@{FOO}=/foo
/t { dbus (send, receive) path=/com/@{FOO}, dbus (send, receive) path=/com/bar, }" \
/t { $p2 dbus (send, receive) path=/com/@{FOO}, $p2 dbus (send, receive) path=/com/bar, }" \
"@{FOO}=/foo /bar
/t { dbus (send, receive) path=/com/@{FOO}, }" \
/t { $p2 dbus (send, receive) path=/com/@{FOO}, }" \
"@{FOO}=/bar //foo
/t { dbus (send, receive) path=/com/@{FOO}, }" \
/t { $p2 dbus (send, receive) path=/com/@{FOO}, }" \
"@{FOO}=//{bar,foo}
/t { dbus (send, receive) path=/com/@{FOO}, }" \
/t { $p2 dbus (send, receive) path=/com/@{FOO}, }" \
"@{FOO}=/foo
@{BAR}=bar
/t { dbus (send, receive) path=/com/@{FOO}, dbus (send, receive) path=/com//@{BAR}, }"
/t { $p2 dbus (send, receive) path=/com/@{FOO}, $p2 dbus (send, receive) path=/com//@{BAR}, }"
# Rules compatible with audit, deny, and audit deny
# note: change_profile does not support audit/allow/deny atm
for rule in "capability" "capability mac_admin" \
"network" "network tcp" "network inet6 tcp"\
"mount" "mount /a" "mount /a -> /b" "mount options in (ro) /a -> b" \
"remount" "remount /a" \
"umount" "umount /a" \
@ -302,6 +308,35 @@ for rule in "capability" "capability mac_admin" \
"link /a -> /b" "link subset /a -> /b" \
"l /a -> /b" "l subset /a -> /b" \
"file l /a -> /b" "l subset /a -> /b"
do
verify_binary_equality "'$p1'x'$p2' allow modifier for \"${rule}\"" \
"/t { $p1 ${rule}, }" \
"/t { $p2 allow ${rule}, }"
verify_binary_equality "'$p1'x'$p2' audit allow modifier for \"${rule}\"" \
"/t { $p1 audit ${rule}, }" \
"/t { $p2 audit allow ${rule}, }"
verify_binary_inequality "'$p1'x'$p2' audit, deny, and audit deny modifiers for \"${rule}\"" \
"/t { $p1 ${rule}, }" \
"/t { $p2 audit ${rule}, }" \
"/t { $p2 audit allow ${rule}, }" \
"/t { $p2 deny ${rule}, }" \
"/t { $p2 audit deny ${rule}, }"
verify_binary_inequality "'$p1'x'$p2' audit vs deny and audit deny modifiers for \"${rule}\"" \
"/t { $p1 audit ${rule}, }" \
"/t { $p2 deny ${rule}, }" \
"/t { $p2 audit deny ${rule}, }"
verify_binary_inequality "'$p1'x'$p2' deny and audit deny modifiers for \"${rule}\"" \
"/t { $p1 deny ${rule}, }" \
"/t { $p2 audit deny ${rule}, }"
done
####### special case for network TODO: for network above when network
####### rules fixed
for rule in "network" "network tcp" "network inet6 tcp"
do
verify_binary_equality "allow modifier for \"${rule}\"" \
"/t { ${rule}, }" \
@ -357,36 +392,36 @@ for rule in "/f ux" "/f Ux" "/f px" "/f Px" "/f cx" "/f Cx" "/f ix" \
"file /* cux -> b" "file /* Cux -> b" "file /* cix -> b" "file /* Cix -> b"
do
verify_binary_equality "allow modifier for \"${rule}\"" \
"/t { ${rule}, }" \
"/t { allow ${rule}, }"
verify_binary_equality "'$p1'x'$p2' allow modifier for \"${rule}\"" \
"/t { $p1 ${rule}, }" \
"/t { $p2 allow ${rule}, }"
verify_binary_equality "audit allow modifier for \"${rule}\"" \
"/t { audit ${rule}, }" \
"/t { audit allow ${rule}, }"
verify_binary_equality "'$p1'x'$p2' audit allow modifier for \"${rule}\"" \
"/t { $p1 audit ${rule}, }" \
"/t { $p2 audit allow ${rule}, }"
# skip rules that don't end with x perm
if [ -n "${rule##*x}" ] ; then continue ; fi
verify_binary_inequality "deny, audit deny modifier for \"${rule}\"" \
"/t { ${rule}, }" \
"/t { audit ${rule}, }" \
"/t { audit allow ${rule}, }" \
"/t { deny ${rule% *} x, }" \
"/t { audit deny ${rule% *} x, }"
verify_binary_inequality "'$p1'x'$p2' deny, audit deny modifier for \"${rule}\"" \
"/t { $p1 ${rule}, }" \
"/t { $p2 audit ${rule}, }" \
"/t { $p2 audit allow ${rule}, }" \
"/t { $p2 deny ${rule% *} x, }" \
"/t { $p2 audit deny ${rule% *} x, }"
verify_binary_inequality "audit vs deny and audit deny modifiers for \"${rule}\"" \
"/t { audit ${rule}, }" \
"/t { deny ${rule% *} x, }" \
"/t { audit deny ${rule% *} x, }"
verify_binary_inequality "'$p1'x'$p2' audit vs deny and audit deny modifiers for \"${rule}\"" \
"/t { $p1 audit ${rule}, }" \
"/t { $p2 deny ${rule% *} x, }" \
"/t { $p2 audit deny ${rule% *} x, }"
done
# verify deny and audit deny differ for x perms
for prefix in "/f" "/*" "file /f" "file /*" ; do
verify_binary_inequality "deny and audit deny x modifiers for \"${prefix}\"" \
"/t { deny ${prefix} x, }" \
"/t { audit deny ${prefix} x, }"
verify_binary_inequality "'$p1'x'$p2' deny and audit deny x modifiers for \"${prefix}\"" \
"/t { $p1 deny ${prefix} x, }" \
"/t { $p2 audit deny ${prefix} x, }"
done
#Test equality of leading and trailing file permissions
@ -403,26 +438,26 @@ for audit in "" "audit" ; do
"lkm" "rwlk" "rwlm" "rwkm" \
"ralk" "ralm" "wlkm" "alkm" \
"rwlkm" "ralkm" ; do
verify_binary_equality "leading and trailing perms for \"${perm}\"" \
"/t { ${prefix} /f ${perm}, }" \
"/t { ${prefix} ${perm} /f, }"
verify_binary_equality "'$p1'x'$p2' leading and trailing perms for \"${perm}\"" \
"/t { $p1 ${prefix} /f ${perm}, }" \
"/t { $p2 ${prefix} ${perm} /f, }"
done
if [ "$allow" == "deny" ] ; then continue ; fi
for perm in "ux" "Ux" "px" "Px" "cx" "Cx" \
"ix" "pux" "Pux" "pix" "Pix" \
"cux" "Cux" "cix" "Cix"
do
verify_binary_equality "leading and trailing perms for \"${perm}\"" \
"/t { ${prefix} /f ${perm}, }" \
"/t { ${prefix} ${perm} /f, }"
verify_binary_equality "'$p1'x'$p2' leading and trailing perms for \"${perm}\"" \
"/t { $p1 ${prefix} /f ${perm}, }" \
"/t { $p2 ${prefix} ${perm} /f, }"
done
for perm in "px" "Px" "cx" "Cx" \
"pux" "Pux" "pix" "Pix" \
"cux" "Cux" "cix" "Cix"
do
verify_binary_equality "leading and trailing perms for x-transition \"${perm}\"" \
"/t { ${prefix} /f ${perm} -> b, }" \
"/t { ${prefix} ${perm} /f -> b, }"
verify_binary_equality "'$p1'x'$p2' leading and trailing perms for x-transition \"${perm}\"" \
"/t { $p1 ${prefix} /f ${perm} -> b, }" \
"/t { $p2 ${prefix} ${perm} /f -> b, }"
done
done
done
@ -443,128 +478,103 @@ do
"cix -> b" "Cix -> b"
do
if [ "$perm1" == "$perm2" ] ; then
verify_binary_equality "Exec perm \"${perm1}\" - most specific match: same as glob" \
"/t { /* ${perm1}, /f ${perm2}, }" \
"/t { /* ${perm1}, }"
verify_binary_equality "'$p1'x'$p2' Exec perm \"${perm1}\" - most specific match: same as glob" \
"/t { $p1 /* ${perm1}, /f ${perm2}, }" \
"/t { $p2 /* ${perm1}, }"
else
verify_binary_inequality "Exec \"${perm1}\" vs \"${perm2}\" - most specific match: different from glob" \
"/t { /* ${perm1}, /f ${perm2}, }" \
"/t { /* ${perm1}, }"
verify_binary_inequality "'$p1'x'$p2' Exec \"${perm1}\" vs \"${perm2}\" - most specific match: different from glob" \
"/t { $p1 /* ${perm1}, /f ${perm2}, }" \
"/t { $p2 /* ${perm1}, }"
fi
done
verify_binary_inequality "Exec \"${perm1}\" vs deny x - most specific match: different from glob" \
"/t { /* ${perm1}, audit deny /f x, }" \
"/t { /* ${perm1}, }"
verify_binary_inequality "'$p1'x'$p2' Exec \"${perm1}\" vs deny x - most specific match: different from glob" \
"/t { $p1 /* ${perm1}, audit deny /f x, }" \
"/t { $p2 /* ${perm1}, }"
done
#Test deny carves out permission
verify_binary_inequality "Deny removes r perm" \
"/t { /foo/[abc] r, audit deny /foo/b r, }" \
"/t { /foo/[abc] r, }"
verify_binary_inequality "'$p1'x'$p2' Deny removes r perm" \
"/t { $p1 /foo/[abc] r, audit deny /foo/b r, }" \
"/t { $p2 /foo/[abc] r, }"
verify_binary_equality "Deny removes r perm" \
"/t { /foo/[abc] r, audit deny /foo/b r, }" \
"/t { /foo/[ac] r, }"
verify_binary_equality "'$p1'x'$p2' Deny removes r perm" \
"/t { $p1 /foo/[abc] r, audit deny /foo/b r, }" \
"/t { $p2 /foo/[ac] r, }"
#this one may not be true in the future depending on if the compiled profile
#is explicitly including deny permissions for dynamic composition
verify_binary_equality "Deny of ungranted perm" \
"/t { /foo/[abc] r, audit deny /foo/b w, }" \
"/t { /foo/[abc] r, }"
verify_binary_equality "'$p1'x'$p2' Deny of ungranted perm" \
"/t { $p1 /foo/[abc] r, audit deny /foo/b w, }" \
"/t { $p2 /foo/[abc] r, }"
verify_binary_equality "change_profile == change_profile -> **" \
"/t { change_profile, }" \
"/t { change_profile -> **, }"
verify_binary_equality "'$p1'x'$p2' change_profile == change_profile -> **" \
"/t { $p1 change_profile, }" \
"/t { $p2 change_profile -> **, }"
verify_binary_equality "change_profile /** == change_profile /** -> **" \
"/t { change_profile /**, }" \
"/t { change_profile /** -> **, }"
verify_binary_equality "'$p1'x'$p2' change_profile /** == change_profile /** -> **" \
"/t { $p1 change_profile /**, }" \
"/t { $p2 change_profile /** -> **, }"
verify_binary_equality "change_profile /** == change_profile /** -> **" \
"/t { change_profile unsafe /**, }" \
"/t { change_profile unsafe /** -> **, }"
verify_binary_equality "'$p1'x'$p2' change_profile /** == change_profile /** -> **" \
"/t { $p1 change_profile unsafe /**, }" \
"/t { $p2 change_profile unsafe /** -> **, }"
verify_binary_equality "change_profile /** == change_profile /** -> **" \
"/t { change_profile /**, }" \
"/t { change_profile safe /** -> **, }"
verify_binary_equality "'$p1'x'$p2' change_profile /** == change_profile /** -> **" \
"/t { $p1 change_profile /**, }" \
"/t { $p2 change_profile safe /** -> **, }"
verify_binary_inequality "change_profile /** == change_profile /** -> **" \
"/t { change_profile /**, }" \
"/t { change_profile unsafe /**, }"
verify_binary_inequality "'$p1'x'$p2' change_profile /** == change_profile /** -> **" \
"/t { $p1 change_profile /**, }" \
"/t { $p2 change_profile unsafe /**, }"
verify_binary_equality "profile name is hname in rule" \
":ns:/hname { signal peer=/hname, }" \
":ns:/hname { signal peer=@{profile_name}, }"
verify_binary_equality "'$p1'x'$p2' profile name is hname in rule" \
":ns:/hname { $p1 signal peer=/hname, }" \
":ns:/hname { $p2 signal peer=@{profile_name}, }"
verify_binary_inequality "profile name is NOT fq name in rule" \
":ns:/hname { signal peer=:ns:/hname, }" \
":ns:/hname { signal peer=@{profile_name}, }"
verify_binary_inequality "'$p1'x'$p2' profile name is NOT fq name in rule" \
":ns:/hname { $p1 signal peer=:ns:/hname, }" \
":ns:/hname { $p2 signal peer=@{profile_name}, }"
verify_binary_equality "profile name is hname in sub pofile rule" \
":ns:/hname { profile child { signal peer=/hname//child, } }" \
":ns:/hname { profile child { signal peer=@{profile_name}, } }"
verify_binary_equality "'$p1'x'$p2' profile name is hname in sub pofile rule" \
":ns:/hname { profile child { $p1 signal peer=/hname//child, } }" \
":ns:/hname { profile child { $p2 signal peer=@{profile_name}, } }"
verify_binary_inequality "profile name is NOT fq name in sub profile rule" \
":ns:/hname { profile child { signal peer=:ns:/hname//child, } }" \
":ns:/hname { profile child { signal peer=@{profile_name}, } }"
verify_binary_inequality "'$p1'x'$p2' profile name is NOT fq name in sub profile rule" \
":ns:/hname { profile child { $p1 signal peer=:ns:/hname//child, } }" \
":ns:/hname { profile child { $p2 signal peer=@{profile_name}, } }"
verify_binary_equality "profile name is hname in hat rule" \
":ns:/hname { ^child { signal peer=/hname//child, } }" \
":ns:/hname { ^child { signal peer=@{profile_name}, } }"
verify_binary_equality "'$p1'x'$p2' profile name is hname in hat rule" \
":ns:/hname { ^child { $p1 signal peer=/hname//child, } }" \
":ns:/hname { ^child { $p2 signal peer=@{profile_name}, } }"
verify_binary_inequality "profile name is NOT fq name in hat rule" \
":ns:/hname { ^child { signal peer=:ns:/hname//child, } }" \
":ns:/hname { ^child { signal peer=@{profile_name}, } }"
verify_binary_inequality "'$p1'x'$p2' profile name is NOT fq name in hat rule" \
":ns:/hname { ^child { $p1 signal peer=:ns:/hname//child, } }" \
":ns:/hname { ^child { $p2 signal peer=@{profile_name}, } }"
verify_binary_equality "@{profile_name} is literal in peer" \
"/{a,b} { signal peer=/\{a,b\}, }" \
"/{a,b} { signal peer=@{profile_name}, }"
verify_binary_equality "'$p1'x'$p2' @{profile_name} is literal in peer" \
"/{a,b} { $p1 signal peer=/\{a,b\}, }" \
"/{a,b} { $p2 signal peer=@{profile_name}, }"
verify_binary_equality "@{profile_name} is literal in peer with pattern" \
"/{a,b} { signal peer={/\{a,b\},c}, }" \
"/{a,b} { signal peer={@{profile_name},c}, }"
verify_binary_equality "'$p1'x'$p2' @{profile_name} is literal in peer with pattern" \
"/{a,b} { $p1 signal peer={/\{a,b\},c}, }" \
"/{a,b} { $p2 signal peer={@{profile_name},c}, }"
verify_binary_inequality "@{profile_name} is not pattern in peer" \
"/{a,b} { signal peer=/{a,b}, }" \
"/{a,b} { signal peer=@{profile_name}, }"
verify_binary_inequality "'$p1'x'$p2' @{profile_name} is not pattern in peer" \
"/{a,b} { $p1 signal peer=/{a,b}, }" \
"/{a,b} { $p2 signal peer=@{profile_name}, }"
verify_binary_equality "@{profile_name} is literal in peer with esc sequence" \
"/\\\\a { signal peer=/\\\\a, }" \
"/\\\\a { signal peer=@{profile_name}, }"
verify_binary_equality "'$p1'x'$p2' @{profile_name} is literal in peer with esc sequence" \
"/\\\\a { $p1 signal peer=/\\\\a, }" \
"/\\\\a { $p2 signal peer=@{profile_name}, }"
verify_binary_equality "@{profile_name} is literal in peer with esc alt sequence" \
"/\\{a,b\\},c { signal peer=/\\{a,b\\},c, }" \
"/\\{a,b\\},c { signal peer=@{profile_name}, }"
verify_binary_equality "'$p1'x'$p2' @{profile_name} is literal in peer with esc alt sequence" \
"/\\{a,b\\},c { $p1 signal peer=/\\{a,b\\},c, }" \
"/\\{a,b\\},c { $p2 signal peer=@{profile_name}, }"
# verify rlimit data conversions
verify_binary_equality "set rlimit rttime <= 12 weeks" \
"/t { set rlimit rttime <= 12 weeks, }" \
"/t { set rlimit rttime <= $((12 * 7)) days, }" \
"/t { set rlimit rttime <= $((12 * 7 * 24)) hours, }" \
"/t { set rlimit rttime <= $((12 * 7 * 24 * 60)) minutes, }" \
"/t { set rlimit rttime <= $((12 * 7 * 24 * 60 * 60)) seconds, }" \
"/t { set rlimit rttime <= $((12 * 7 * 24 * 60 * 60 * 1000)) ms, }" \
"/t { set rlimit rttime <= $((12 * 7 * 24 * 60 * 60 * 1000 * 1000)) us, }" \
"/t { set rlimit rttime <= $((12 * 7 * 24 * 60 * 60 * 1000 * 1000)), }"
verify_binary_equality "set rlimit cpu <= 42 weeks" \
"/t { set rlimit cpu <= 42 weeks, }" \
"/t { set rlimit cpu <= $((42 * 7)) days, }" \
"/t { set rlimit cpu <= $((42 * 7 * 24)) hours, }" \
"/t { set rlimit cpu <= $((42 * 7 * 24 * 60)) minutes, }" \
"/t { set rlimit cpu <= $((42 * 7 * 24 * 60 * 60)) seconds, }" \
"/t { set rlimit cpu <= $((42 * 7 * 24 * 60 * 60)), }"
verify_binary_equality "set rlimit memlock <= 2GB" \
"/t { set rlimit memlock <= 2GB, }" \
"/t { set rlimit memlock <= $((2 * 1024)) MB, }" \
"/t { set rlimit memlock <= $((2 * 1024 * 1024)) KB, }" \
"/t { set rlimit memlock <= $((2 * 1024 * 1024 * 1024)) , }"
# Unfortunately we can not just compare an empty profile and hat to a
# ie. "/t { ^test { /f r, }}"
# to the second profile with the equivalent rule inserted manually
@ -577,62 +587,62 @@ verify_binary_equality "set rlimit memlock <= 2GB" \
# the "write" permission in the second profile and the test will fail.
# If the parser is adding the change_hat proc attr rules then the
# rules should merge and be equivalent.
verify_binary_equality "change_hat rules automatically inserted"\
"/t { owner /proc/[0-9]*/attr/{apparmor/,}current a, ^test { owner /proc/[0-9]*/attr/{apparmor/,}current a, /f r, }}" \
"/t { owner /proc/[0-9]*/attr/{apparmor/,}current w, ^test { owner /proc/[0-9]*/attr/{apparmor/,}current w, /f r, }}"
verify_binary_equality "'$p1'x'$p2' change_hat rules automatically inserted"\
"/t { $p1 owner /proc/[0-9]*/attr/{apparmor/,}current a, ^test { $p2 owner /proc/[0-9]*/attr/{apparmor/,}current a, /f r, }}" \
"/t { $p2 owner /proc/[0-9]*/attr/{apparmor/,}current w, ^test { $p2 owner /proc/[0-9]*/attr/{apparmor/,}current w, /f r, }}"
# verify slash filtering for unix socket address paths.
# see https://bugs.launchpad.net/apparmor/+bug/1856738
verify_binary_equality "unix rules addr conditional" \
"/t { unix bind addr=@/a/bar, }" \
"/t { unix bind addr=@/a//bar, }" \
"/t { unix bind addr=@//a/bar, }" \
"/t { unix bind addr=@/a///bar, }" \
verify_binary_equality "'$p1'x'$p2' unix rules addr conditional" \
"/t { $p1 unix bind addr=@/a/bar, }" \
"/t { $p2 unix bind addr=@/a//bar, }" \
"/t { $p2 unix bind addr=@//a/bar, }" \
"/t { $p2 unix bind addr=@/a///bar, }" \
"@{HOME}=/a/
/t { unix bind addr=@@{HOME}/bar, }" \
/t { $p2 unix bind addr=@@{HOME}/bar, }" \
"@{HOME}=/a/
/t { unix bind addr=@//@{HOME}bar, }" \
/t { $p2 unix bind addr=@//@{HOME}bar, }" \
"@{HOME}=/a/
/t { unix bind addr=@/@{HOME}/bar, }"
/t { $p2 unix bind addr=@/@{HOME}/bar, }"
verify_binary_equality "unix rules peer addr conditional" \
"/t { unix peer=(addr=@/a/bar), }" \
"/t { unix peer=(addr=@/a//bar), }" \
"/t { unix peer=(addr=@//a/bar), }" \
"/t { unix peer=(addr=@/a///bar), }" \
verify_binary_equality "'$p1'x'$p2' unix rules peer addr conditional" \
"/t { $p1 unix peer=(addr=@/a/bar), }" \
"/t { $p2 unix peer=(addr=@/a//bar), }" \
"/t { $p2 unix peer=(addr=@//a/bar), }" \
"/t { $p2 unix peer=(addr=@/a///bar), }" \
"@{HOME}=/a/
/t { unix peer=(addr=@@{HOME}/bar), }" \
/t { $p2 unix peer=(addr=@@{HOME}/bar), }" \
"@{HOME}=/a/
/t { unix peer=(addr=@//@{HOME}bar), }" \
/t { $p2 unix peer=(addr=@//@{HOME}bar), }" \
"@{HOME}=/a/
/t { unix peer=(addr=@/@{HOME}/bar), }"
/t { $p2 unix peer=(addr=@/@{HOME}/bar), }"
# verify slash filtering for mount rules
verify_binary_equality "mount rules slash filtering" \
"/t { mount /dev/foo -> /mnt/bar, }" \
"/t { mount ///dev/foo -> /mnt/bar, }" \
"/t { mount /dev/foo -> /mnt//bar, }" \
"/t { mount /dev///foo -> ////mnt/bar, }" \
verify_binary_equality "'$p1'x'$p2' mount rules slash filtering" \
"/t { $p1 mount /dev/foo -> /mnt/bar, }" \
"/t { $p2 mount ///dev/foo -> /mnt/bar, }" \
"/t { $p2 mount /dev/foo -> /mnt//bar, }" \
"/t { $p2 mount /dev///foo -> ////mnt/bar, }" \
"@{MNT}=/mnt/
/t { mount /dev///foo -> @{MNT}/bar, }" \
/t { $p2 mount /dev///foo -> @{MNT}/bar, }" \
"@{FOO}=/foo
/t { mount /dev//@{FOO} -> /mnt/bar, }"
/t { $p2 mount /dev//@{FOO} -> /mnt/bar, }"
# verify slash filtering for link rules
verify_binary_equality "link rules slash filtering" \
"/t { link /dev/foo -> /mnt/bar, }" \
"/t { link ///dev/foo -> /mnt/bar, }" \
"/t { link /dev/foo -> /mnt//bar, }" \
"/t { link /dev///foo -> ////mnt/bar, }" \
verify_binary_equality "'$p1'x'$p2' link rules slash filtering" \
"/t { $p1 link /dev/foo -> /mnt/bar, }" \
"/t { $p2 link ///dev/foo -> /mnt/bar, }" \
"/t { $p2 link /dev/foo -> /mnt//bar, }" \
"/t { $p2 link /dev///foo -> ////mnt/bar, }" \
"@{BAR}=/mnt/
/t { link /dev///foo -> @{BAR}/bar, }" \
/t { $p2 link /dev///foo -> @{BAR}/bar, }" \
"@{FOO}=/dev/
/t { link @{FOO}//foo -> /mnt/bar, }" \
/t { $p2 link @{FOO}//foo -> /mnt/bar, }" \
"@{FOO}=/dev/
@{BAR}=/mnt/
/t { link @{FOO}/foo -> @{BAR}/bar, }"
/t { $p2 link @{FOO}/foo -> @{BAR}/bar, }"
verify_binary_equality "attachment slash filtering" \
verify_binary_equality "'$p1'x'$p2' attachment slash filtering" \
"/t /bin/foo { }" \
"/t /bin//foo { }" \
"@{BAR}=/bin/
@ -660,9 +670,9 @@ verify_binary_equality "value like comment at end of set var" \
# dfas dumped will be different, even if the binary is the same
# Note: this test in the future will require -O filter-deny and
# -O minimize and -O remove-unreachable.
verify_binary_equality "mount specific deny doesn't affect non-overlapping" \
"/t { mount options=bind /e/ -> /**, }" \
"/t { audit deny mount /s/** -> /**,
verify_binary_equality "'$p1'x'$p2' mount specific deny doesn't affect non-overlapping" \
"/t { $p1 mount options=bind /e/ -> /**, }" \
"/t { $p2 audit deny mount /s/** -> /**,
mount options=bind /e/ -> /**, }"
if [ $fails -ne 0 ] || [ $errors -ne 0 ]
@ -671,6 +681,139 @@ then
exit $((fails + errors))
fi
## priority override equivalence tests
## compare single rule, to multi-rule profile where one rule overrides
## the other rule via priority.
verify_binary_equality "'$p1'x'$p2' dbus variable expansion, multiple values/rules" \
"/t { dbus (send, receive) path=/com/foo, }" \
"/t { $p1 dbus (send, receive) path=/com/foo, $p2 dbus (send, receive) path=/com/foo, }" \
"@{FOO}=foo
/t { $p1 dbus (send, receive) path=/com/@{FOO}, $p2 dbus (send, receive) path=/com/foo, }" \
verify_binary_equality "'$p1'x'$p2' dbus variable expansion, ensure rule de-duping occurs" \
"/t { $p1 dbus (send, receive) path=/com/foo, dbus (send, receive) path=/com/bar, }" \
"/t { $p2 dbus (send, receive) path=/com/foo, dbus (send, receive) path=/com/bar, dbus (send, receive) path=/com/bar, }" \
"@{FOO}=bar foo bar foo
/t { $p2 dbus (send, receive) path=/com/@{FOO}, }" \
"@{FOO}=bar foo bar foo
/t { $p2 dbus (send, receive) path=/com/@{FOO}, dbus (send, receive) path=/com/@{FOO}, }"
verify_binary_equality "'$p1'x'$p2' dbus minimization with all perms" \
"/t { $p1 dbus, }" \
"/t { $p2 dbus bus=session, $p2 dbus, }" \
"/t { $p2 dbus (send, receive, bind, eavesdrop), $p2 dbus, }"
verify_binary_equality "'$p1'x'$p2' dbus minimization with bind" \
"/t { $p1 dbus bind, }" \
"/t { $p2 dbus bind bus=session, $p2 dbus bind, }" \
"/t { $p2 dbus bind bus=system name=com.foo, $p2 dbus bind, }"
verify_binary_equality "'$p1'x'$p2' dbus minimization with send and a bus conditional" \
"/t { $p1 dbus send bus=system, }" \
"/t { $p2 dbus send bus=system path=/com/foo interface=com.foo member=bar, dbus send bus=system, }" \
"/t { $p2 dbus send bus=system peer=(label=/usr/bin/foo), $p2 dbus send bus=system, }"
verify_binary_equality "'$p1'x'$p2' dbus minimization with an audit modifier" \
"/t { $p1 audit dbus eavesdrop, }" \
"/t { $p2 audit dbus eavesdrop bus=session, $p2 audit dbus eavesdrop, }"
verify_binary_equality "'$p1'x'$p2' dbus minimization with a deny modifier" \
"/t { $p1 deny dbus send bus=system peer=(name=com.foo), }" \
"/t { $p2 deny dbus send bus=system peer=(name=com.foo label=/usr/bin/foo), $p2 deny dbus send bus=system peer=(name=com.foo), }" \
verify_binary_equality "'$p1'x'$p2' dbus minimization found in dbus abstractions" \
"/t { $p1 dbus send bus=session, }" \
"/t { $p2 dbus send
bus=session
path=/org/freedesktop/DBus
interface=org.freedesktop.DBus
member={Hello,AddMatch,RemoveMatch,GetNameOwner,NameHasOwner,StartServiceByName}
peer=(name=org.freedesktop.DBus),
$p2 dbus send bus=session, }"
# verify slash filtering for dbus paths.
verify_binary_equality "'$p1'x'$p2' dbus slash filtering for paths" \
"/t { $p1 dbus (send, receive) path=/com/foo, dbus (send, receive) path=/com/bar, }" \
"/t { $p2 dbus (send, receive) path=/com///foo, dbus (send, receive) path=///com/bar, }" \
"/t { $p2 dbus (send, receive) path=/com//{foo,bar}, }" \
"/t { $p2 dbus (send, receive) path={//com/foo,/com//bar}, }" \
"@{FOO}=/foo
/t { $p2 dbus (send, receive) path=/com/@{FOO}, $p2 dbus (send, receive) path=/com/bar, }" \
"@{FOO}=/foo /bar
/t { $p2 dbus (send, receive) path=/com/@{FOO}, }" \
"@{FOO}=/bar //foo
/t { $p2 dbus (send, receive) path=/com/@{FOO}, }" \
"@{FOO}=//{bar,foo}
/t { $p2 dbus (send, receive) path=/com/@{FOO}, }" \
"@{FOO}=/foo
@{BAR}=bar
/t { $p2 dbus (send, receive) path=/com/@{FOO}, $p2 dbus (send, receive) path=/com//@{BAR}, }"
#### end of wrapper fn
}
printf "Equality Tests:\n"
#rules that don't support priority
# verify rlimit data conversions
verify_binary_equality "set rlimit rttime <= 12 weeks" \
"/t { set rlimit rttime <= 12 weeks, }" \
"/t { set rlimit rttime <= $((12 * 7)) days, }" \
"/t { set rlimit rttime <= $((12 * 7 * 24)) hours, }" \
"/t { set rlimit rttime <= $((12 * 7 * 24 * 60)) minutes, }" \
"/t { set rlimit rttime <= $((12 * 7 * 24 * 60 * 60)) seconds, }" \
"/t { set rlimit rttime <= $((12 * 7 * 24 * 60 * 60 * 1000)) ms, }" \
"/t { set rlimit rttime <= $((12 * 7 * 24 * 60 * 60 * 1000 * 1000)) us, }" \
"/t { set rlimit rttime <= $((12 * 7 * 24 * 60 * 60 * 1000 * 1000)), }"
verify_binary_equality "set rlimit cpu <= 42 weeks" \
"/t { set rlimit cpu <= 42 weeks, }" \
"/t { set rlimit cpu <= $((42 * 7)) days, }" \
"/t { set rlimit cpu <= $((42 * 7 * 24)) hours, }" \
"/t { set rlimit cpu <= $((42 * 7 * 24 * 60)) minutes, }" \
"/t { set rlimit cpu <= $((42 * 7 * 24 * 60 * 60)) seconds, }" \
"/t { set rlimit cpu <= $((42 * 7 * 24 * 60 * 60)), }"
verify_binary_equality "set rlimit memlock <= 2GB" \
"/t { set rlimit memlock <= 2GB, }" \
"/t { set rlimit memlock <= $((2 * 1024)) MB, }" \
"/t { set rlimit memlock <= $((2 * 1024 * 1024)) KB, }" \
"/t { set rlimit memlock <= $((2 * 1024 * 1024 * 1024)) , }"
# verify combinations of different priority levels
# for single rule comparisons, rules should keep same expected result
# even when the priorities are different.
# different priorities within a profile comparison resulting in
# different permission could affected expected results
priorities="none 0 1 -1"
for pri1 in $priorities ; do
if [ "$pri1" = "none" ] ; then
priority1=""
else
priority1="priority=$pri1"
fi
for pri2 in $priorities ; do
if [ "$pri2" = "none" ] ; then
priority2=""
else
priority2="priority=$pri2"
fi
verify_set "$priority1" "$priority2"
done
done
[ -z "${verbose}" ] && printf "\n"
printf "PASS\n"
exit 0

View file

@ -0,0 +1,24 @@
#
#=DESCRIPTION perms before pathname
#=EXRESULT PASS
#
/usr/bin/foo {
priority=-1 file r /foo1,
priority=-1 file w /foo1,
priority=-1 file a /foo1,
priority=-1 file k /foo1,
priority=-1 file m /foo1,
priority=-1 file l /foo1,
priority=-1 file px /foo1,
priority=-1 file Px /foo2,
priority=-1 file ux /foo3,
priority=-1 file Ux /foo4,
priority=-1 file ix /foo5,
priority=-1 file unsafe px /foo6,
priority=-1 file unsafe Px /foo7,
priority=-1 file unsafe ux /foo8,
priority=-1 file unsafe Ux /foo9,
priority=-1 file unsafe ix /foo10,
}

View file

@ -0,0 +1,24 @@
#
#=DESCRIPTION perms before pathname
#=EXRESULT PASS
#
/usr/bin/foo {
priority=-1 r /foo1,
priority=-1 w /foo1,
priority=-1 a /foo1,
priority=-1 k /foo1,
priority=-1 m /foo1,
priority=-1 l /foo1,
priority=-1 px /foo1,
priority=-1 Px /foo2,
priority=-1 ux /foo3,
priority=-1 Ux /foo4,
priority=-1 ix /foo5,
priority=-1 unsafe px /foo6,
priority=-1 unsafe Px /foo7,
priority=-1 unsafe ux /foo8,
priority=-1 unsafe Ux /foo9,
priority=-1 unsafe ix /foo10,
}

View file

@ -0,0 +1,7 @@
#
#=Description basic file rule
#=EXRESULT PASS
#
/usr/bin/foo {
priority=-1 /usr/bin/foo r,
}

View file

@ -0,0 +1,7 @@
#
#=Description basic uppercase permission file rule (should emit warning)
#=EXRESULT PASS
#
/usr/bin/foo {
priority=-1 /usr/bin/foo RWM,
}

View file

@ -0,0 +1,9 @@
#
#=DESCRIPTION A simple successful profile
#=EXRESULT PASS
#
/usr/bin/foo {
/usr/bin/foo r,
priority=-1 /usr/bin/blah rix,
}

View file

@ -0,0 +1,7 @@
#
#=Description basic inherit uppercase exec permission (should emit warning)
#=EXRESULT PASS
#
/usr/bin/foo {
priority=-1 /usr/bin/foo iX,
}

View file

@ -0,0 +1,7 @@
#
#=Description basic unconfined uppercase exec permission (should emit warning)
#=EXRESULT PASS
#
/usr/bin/foo {
priority=+5 /usr/bin/foo UX,
}

View file

@ -0,0 +1,7 @@
#
#=Description basic file rule w/alternations
#=EXRESULT PASS
#
/usr/bin/foo {
priority=0 /a/b/c/**{cache,data,download,/ext,fileadmin,files,images,joomla,moodledata/sessions}/** rw,
}

View file

@ -0,0 +1,7 @@
#
#=Description basic file rule w/nested alternations
#=EXRESULT PASS
#
/usr/bin/foo {
priority=-1 /a/b/c/**{cache,data,download,/ext,file{admin,s},images,joomla,moodledata/sessions}/** rw,
}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,13 @@
#
#=DESCRIPTION test append
#=EXRESULT PASS
#
/usr/bin/foo {
/bin/cat a,
/bin/true ra,
/bin/false ma,
priority=-1 /lib/libc.so la,
/bin/less ixa,
/bin/more pxa,
/a uxa,
}

View file

@ -0,0 +1,9 @@
#
#=DESCRIPTION simple link access test
#=EXRESULT PASS
#
profile test {
priority=-1 audit deny link /alpha/beta -> /tmp/**,
}

View file

@ -0,0 +1,8 @@
#
#=Description bare file rule
#=EXRESULT PASS
#=TODO https://launchpad.net/bugs/1215637
#
/usr/bin/foo {
priority=19 deny file,
}

View file

@ -0,0 +1,7 @@
#
#=DESCRIPTION carat in pathname
#=EXRESULT PASS
#
/usr/bin/foo {
priority=-1 /foo^bar r,
}

View file

@ -0,0 +1,7 @@
#
#=DESCRIPTION trailing carat in pathname
#=EXRESULT PASS
#
/usr/bin/foo {
priority=-1 /foo/bar^ r,
}

View file

@ -0,0 +1,7 @@
#
#=DESCRIPTION comma in pathname
#=EXRESULT PASS
#
/usr/bin/foo {
priority=-1 /foo,bar r,
}

View file

@ -0,0 +1,7 @@
#
#=DESCRIPTION comma at end of pathname
#=EXRESULT PASS
#
/usr/bin/foo {
priority=-1 "/foobar," r,
}

View file

@ -0,0 +1,9 @@
#
#=DESCRIPTION A simple deny rule
#=EXRESULT PASS
# vim:syntax=apparmor
#
/usr/bin/foo {
priority=-1 deny /usr/bin/foo r,
}

View file

@ -0,0 +1,9 @@
#
#=DESCRIPTION A simple deny rule
#=EXRESULT PASS
# vim:syntax=apparmor
#
/usr/bin/foo {
priority=-1 deny /usr/bin/foo r,
}

View file

@ -0,0 +1,10 @@
#
#=DESCRIPTION an overlapping deny rule
#=EXRESULT PASS
# vim:syntax=apparmor
#
/usr/bin/foo {
priority=-1 /usr/bin/** r,
priority=5 deny /usr/bin/foo r,
}

View file

@ -0,0 +1,10 @@
#
#=DESCRIPTION an exact overlapping deny rule
#=EXRESULT PASS
# vim:syntax=apparmor
#
/usr/bin/foo {
priority=-1 /usr/bin/foo r,
priority=-1 deny /usr/bin/foo r,
}

View file

@ -0,0 +1,9 @@
#
#=DESCRIPTION simple link access test
#=EXRESULT PASS
#
profile test {
priority=-1 deny link /alpha/beta -> /tmp/**,
}

View file

@ -0,0 +1,6 @@
#=DESCRIPTION Simple test case for embedded spaces
#=EXRESULT PASS
/bin/foo {
priority=-1 "/abc\ def" r,
}

View file

@ -0,0 +1,6 @@
#=DESCRIPTION Simple test case for embedded spaces
#=EXRESULT PASS
/bin/foo {
priority=-1 "/abc def" r,
}

View file

@ -0,0 +1,6 @@
#=DESCRIPTION Simple test case for embedded spaces
#=EXRESULT PASS
"/bin/fo o" {
priority=-1 "/abc def" r,
}

View file

@ -0,0 +1,6 @@
#=DESCRIPTION Simple test case for embedded spaces
#=EXRESULT PASS
/bin/foo {
priority=-1 /abc\ def r,
}

View file

@ -0,0 +1,7 @@
#
#=DESCRIPTION carat in pathname
#=EXRESULT PASS
#
/usr/bin/foo {
priority=-1 /foo[^me]bar r,
}

View file

@ -0,0 +1,10 @@
#
#=DESCRIPTION simple link access test
#=EXRESULT PASS
#
profile test {
priority=-1 /alpha/beta rl,
/gamma/* rwl,
}

View file

@ -0,0 +1,10 @@
#
#=DESCRIPTION simple link access test
#=EXRESULT PASS
#
profile test {
priority=-1 link /alpha/beta -> /tmp/**,
/tmp/** r,
}

View file

@ -0,0 +1,10 @@
#
#=DESCRIPTION simple link access test
#=EXRESULT PASS
#
profile test {
priority=-1 link subset /alpha/beta -> /tmp/**,
/tmp/** r,
}

View file

@ -0,0 +1,10 @@
#
#=DESCRIPTION link access test with audit deny and owner restriction
#=EXRESULT PASS
#
profile test {
priority=-1 audit deny owner link subset /alpha/beta -> /tmp/**,
/tmp/** r,
}

View file

@ -0,0 +1,10 @@
#
#=DESCRIPTION simple link access test with owner restriction
#=EXRESULT PASS
#
profile test {
priority=-1 owner link subset /alpha/beta -> /tmp/**,
/tmp/** r,
}

View file

@ -0,0 +1,17 @@
#
#=DESCRIPTION k and other perms do not conflict
#=EXRESULT PASS
#
/usr/bin/foo {
/bin/a k,
/bin/b rk,
/bin/c wk,
priority=-1 /bin/d ak,
/bin/e lk,
/bin/e mk,
/bin/f pxk,
/bin/g Pxk,
/bin/h ixk,
/bin/i uxk,
/bin/j Uxk,
}

View file

@ -0,0 +1,12 @@
#
#=DESCRIPTION m and [uUpPi]x do not conflict
#=EXRESULT PASS
#
/usr/bin/foo {
priority=-1 /bin/cat mix,
/bin/true mpx,
priority=-1 /bin/false mux,
priority=-1 /lib/libc.so rwlm,
/bin/less mUx,
priority=10 /bin/more mPx,
}

View file

@ -0,0 +1,14 @@
#
#=DESCRIPTION m and [upi]x do not conflict, separate rules
#=EXRESULT PASS
#
/usr/bin/foo {
/bin/cat rm,
/bin/cat ix,
priority=-1 /bin/true px,
/bin/true m,
/bin/false m,
/bin/false ux,
priority=-1 /lib/libc.so rwl,
/lib/libc.so m,
}

View file

@ -0,0 +1,8 @@
#
#=DESCRIPTION simple octal test
#=EXRESULT PASS
#
profile ascii {
priority=-1 /bin/\141bcde rix,
}

View file

@ -0,0 +1,8 @@
#
#=DESCRIPTION simple quoted octal expansion
#=EXRESULT PASS
#
profile octal {
priority=-1 "/bin/a b \143 d e" rix,
}

View file

@ -0,0 +1,7 @@
#
#=DESCRIPTION simple other flag test
#=EXRESULT PASS
profile test {
priority=-1 other /tmp/** rw,
}

View file

@ -0,0 +1,7 @@
#
#=DESCRIPTION simple deny other flag test
#=EXRESULT PASS
profile test {
priority=-1 deny other /tmp/** rw,
}

View file

@ -0,0 +1,7 @@
#
#=DESCRIPTION simple other flag test
#=EXRESULT PASS
profile test {
priority=-1 audit other /tmp/** rw,
}

View file

@ -0,0 +1,9 @@
#
#=DESCRIPTION simple quoted tab expansion
#=EXRESULT PASS
#
profile test {
priority=-1 "/bin/alpha\tbeta" rix,
}

View file

@ -0,0 +1,9 @@
#
#=DESCRIPTION simple quoted newline expansion
#=EXRESULT PASS
#
profile test {
priority=-1 "/bin/alpha\nbeta" rix,
}

View file

@ -0,0 +1,9 @@
#
#=DESCRIPTION simple quoted carriage return expansion
#=EXRESULT PASS
#
profile test {
priority=-1 "/bin/alpha\rbeta" rix,
}

View file

@ -0,0 +1,9 @@
#
#=DESCRIPTION simple quoted quote expansion
#=EXRESULT PASS
#
profile test {
priority=-1 "/bin/alpha\"beta" rix,
}

View file

@ -0,0 +1,9 @@
#
#=DESCRIPTION simple quoted backslash expansion
#=EXRESULT PASS
#
profile test {
priority=-1 "/bin/alpha\\beta" rix,
}

View file

@ -0,0 +1,8 @@
#
#=DESCRIPTION unnecessary slash quotes are okay (should emit warning)
#=EXRESULT PASS
#
profile blart {
priority=-1 /bingo/bang\o/bongo rw,
}

View file

@ -0,0 +1,7 @@
#
#=Description basic file exec rule with stacking target
#=EXRESULT PASS
#
/usr/bin/foo {
priority=-1 /bin/bar px -> &baz,
}

View file

@ -0,0 +1,10 @@
#
#=DESCRIPTION simple link access test
#=EXRESULT PASS
#
@{var}=/test
profile test {
priority=-1 audit deny link @{var} -> @{var},
}

View file

@ -0,0 +1,10 @@
#
#=DESCRIPTION simple link access test
#=EXRESULT PASS
#
@{var}=/test
profile test {
priority=-1 deny link @{var} -> @{var},
}

View file

@ -0,0 +1,11 @@
#
#=DESCRIPTION simple link access test
#=EXRESULT PASS
#
@{var}=/test
profile test {
priority=-1 @{var} rl,
priority=-1 /gamma/* rwl,
}

View file

@ -0,0 +1,11 @@
#
#=DESCRIPTION simple link access test
#=EXRESULT PASS
#
@{var}=/test
profile test {
priority=-1 link @{var} -> @{var},
priority=-1 @{var} r,
}

View file

@ -0,0 +1,11 @@
#
#=DESCRIPTION simple link access test
#=EXRESULT PASS
#
@{var}=/test
profile test {
priority=-1 link subset @{var} -> @{var},
priority=-1 @{var} r,
}

View file

@ -0,0 +1,10 @@
#
#=DESCRIPTION simple link access test
#=EXRESULT PASS
#
@{var}=/test
profile test {
priority=-1 audit deny link @{var} -> /tmp/**,
}

View file

@ -0,0 +1,10 @@
#
#=DESCRIPTION simple link access test
#=EXRESULT PASS
#
@{var}=/test
profile test {
priority=-1 deny link @{var} -> /tmp/**,
}

View file

@ -0,0 +1,11 @@
#
#=DESCRIPTION simple link access test
#=EXRESULT PASS
#
@{var}=/test
profile test {
priority=-1 @{var} rl,
priority=-1 /gamma/* rwl,
}

View file

@ -0,0 +1,11 @@
#
#=DESCRIPTION simple link access test
#=EXRESULT PASS
#
@{var}=/test
profile test {
priority=-1 link @{var} -> /tmp/**,
priority=-1 /tmp/** r,
}

View file

@ -0,0 +1,11 @@
#
#=DESCRIPTION simple link access test
#=EXRESULT PASS
#
@{var}=/test
profile test {
priority=-1 link subset @{var} -> /tmp/**,
/tmp/** r,
}

View file

@ -0,0 +1,10 @@
#
#=DESCRIPTION simple link access test
#=EXRESULT PASS
#
@{var}=/test
profile test {
priority=-1 audit deny link /alpha/beta -> @{var},
}

View file

@ -0,0 +1,10 @@
#
#=DESCRIPTION simple link access test
#=EXRESULT PASS
#
@{var}=/test
profile test {
priority=-1 deny link /alpha/beta -> @{var},
}

View file

@ -0,0 +1,11 @@
#
#=DESCRIPTION simple link access test
#=EXRESULT PASS
#
@{var}=/test
profile test {
priority=-1 /alpha/beta rl,
/gamma/* rwl,
}

View file

@ -0,0 +1,11 @@
#
#=DESCRIPTION simple link access test
#=EXRESULT PASS
#
@{var}=/test
profile test {
priority=-1 link /alpha/beta -> @{var},
priority=-1 @{var} r,
}

View file

@ -0,0 +1,11 @@
#
#=DESCRIPTION simple link access test
#=EXRESULT PASS
#
@{var}=/test
profile test {
priority=-1 link subset /alpha/beta -> @{var},
priority=-1 @{var} r,
}

View file

@ -0,0 +1,10 @@
#
#=DESCRIPTION simple link access test
#=EXRESULT PASS
#
@{var}=/test
profile test {
priority=-1 audit deny link /foo@{var} -> /foo@{var},
}

View file

@ -0,0 +1,10 @@
#
#=DESCRIPTION simple link access test
#=EXRESULT PASS
#
@{var}=/test
profile test {
priority=-1 deny link /foo@{var} -> /foo@{var},
}

View file

@ -0,0 +1,11 @@
#
#=DESCRIPTION simple link access test
#=EXRESULT PASS
#
@{var}=/test
profile test {
priority=11 /foo@{var} rl,
/gamma/* rwl,
}

View file

@ -0,0 +1,11 @@
#
#=DESCRIPTION simple link access test
#=EXRESULT PASS
#
@{var}=/test
profile test {
priority=-1 link /foo@{var} -> /foo@{var},
/foo@{var} r,
}

View file

@ -0,0 +1,11 @@
#
#=DESCRIPTION simple link access test
#=EXRESULT PASS
#
@{var}=/test
profile test {
priority=-1 link subset /foo@{var} -> /foo@{var},
/foo@{var} r,
}

View file

@ -0,0 +1,10 @@
#
#=DESCRIPTION simple link access test
#=EXRESULT PASS
#
@{var}=/test
profile test {
audit deny link /foo@{var} -> /tmp/**,
}

View file

@ -0,0 +1,10 @@
#
#=DESCRIPTION simple link access test
#=EXRESULT PASS
#
@{var}=/test
profile test {
deny link /foo@{var} -> /tmp/**,
}

View file

@ -0,0 +1,11 @@
#
#=DESCRIPTION simple link access test
#=EXRESULT PASS
#
@{var}=/test
profile test {
/foo@{var} rl,
/gamma/* rwl,
}

View file

@ -0,0 +1,11 @@
#
#=DESCRIPTION simple link access test
#=EXRESULT PASS
#
@{var}=/test
profile test {
link /foo@{var} -> /tmp/**,
/tmp/** r,
}

View file

@ -0,0 +1,11 @@
#
#=DESCRIPTION simple link access test
#=EXRESULT PASS
#
@{var}=/test
profile test {
link subset /foo@{var} -> /tmp/**,
/tmp/** r,
}

View file

@ -0,0 +1,10 @@
#
#=DESCRIPTION simple link access test
#=EXRESULT PASS
#
@{var}=/test
profile test {
priority=-1 audit deny link /alpha/beta -> /foo@{var},
}

View file

@ -0,0 +1,10 @@
#
#=DESCRIPTION simple link access test
#=EXRESULT PASS
#
@{var}=/test
profile test {
deny link /alpha/beta -> /foo@{var},
}

View file

@ -0,0 +1,11 @@
#
#=DESCRIPTION simple link access test
#=EXRESULT PASS
#
@{var}=/test
profile test {
priority=-1 /alpha/beta rl,
/gamma/* rwl,
}

View file

@ -0,0 +1,11 @@
#
#=DESCRIPTION simple link access test
#=EXRESULT PASS
#
@{var}=/test
profile test {
priority=-1 link /alpha/beta -> /foo@{var},
/foo@{var} r,
}

View file

@ -0,0 +1,11 @@
#
#=DESCRIPTION simple link access test
#=EXRESULT PASS
#
@{var}=/test
profile test {
priority=-1 link subset /alpha/beta -> /foo@{var},
/foo@{var} r,
}

View file

@ -35,6 +35,9 @@ skip_startswith = (
# Pux and Cux (which actually mean PUx and CUx) get rejected by the tools
'generated_x/exact-',
# don't handle rule priorities yet
'file/priority/',
)
# testcases that should raise an exception, but don't